void game_reset_gamedata(GameData* game) { game->current = 0; game->magic = SAVE_MAGIC; game->version = 0; item_shuffleTypes((int*)game->charmTypes, CHARM_MAX); item_shuffleTypes((int*)game->conchTypes, CONCH_MAX); int i; for(i=0; i<MAX_FATHOMS; i++) { int j; game->fathoms[i] = game_null_fathomdata(); feature_process(game, &game->fathoms[i], i); int threat = 7+i*4; if(i==MAX_FATHOMS-1) threat *= 2; while(threat > 0) { int type = ET_MAX_ENEMY; while(type >= ET_MAX_ENEMY) { type = 0; for(j=0; j<(i*2)/3+2; j++) type += sys_randint(2); } Entity e = spawn_entity(type); if(e.flags & EF_TOOLED) { Item i = spawn_item(game, sys_randint(IT_MAX-1)); i.active = true; if(i.type == IT_CHARM) i.worn = true; if(i.type != IT_CONCH || i.conchSubtype != CONCH_DEATH) // death isn't fair e.inventory[0] = i; } game_spawn(&game->fathoms[i], e); threat -= type+1; } for(j=0; j<(MAX_FATHOMS-i)/4+4; j++) game_spawn(&game->fathoms[i], spawn_entity(ET_BUBBLE)); int numSpawns; if(sys_randint(3)==0) game_place(&game->fathoms[i], spawn_item(game, IT_CONCH)); if(sys_randint(5)==0) game_place(&game->fathoms[i], spawn_item(game, IT_CHARM)); numSpawns = (i == MAX_FATHOMS-1) ? 5 : 0; for(j=0; j<numSpawns; j++) game_place(&game->fathoms[i], spawn_item(game, IT_DOUBLOON)); } game_spawn(&game->fathoms[0], spawn_entity(ET_SCUBA)); }
void GameInit() { g_game_rand = random(GetTickCount()); g_game._player = spawn_entity(&g_game, new player(), vec2(10.0f, 9.5f)); for(int j = 0; j < MAP_HEIGHT; j++) { for(int i = 0; i < MAP_WIDTH; i++) { if (tile* t = g_game.get(i, j)) { if (j < 10) { t->type = ((i == 0) || (i == MAP_WIDTH - 1)) ? TT_VOID : TT_EMPTY; } else if (j < (MAP_HEIGHT - 2)) { t->type = ((i == 0) || (i == MAP_WIDTH - 1)) ? TT_WALL : TT_SOLID; if ((i > 0) && (i < MAP_WIDTH - 1)) { int wall_c = max(20 - ((j - 10) / 2), 5); if (g_game_rand.rand(0, 150) == 0) { if (j > 20) t->ore = -1; } else if (g_game_rand.rand(0, wall_c) == 0) { t->type = TT_WALL; } } } else t->type = TT_WALL; } } int ores = clamp(j / 15, 1, 10) + g_game_rand.rand(0, 2); for(int z = 0; z < ores; z++) { int i = g_game_rand.rand(1, MAP_WIDTH - 2); if (tile* t = g_game.get(i, j)) { if (t->type == TT_SOLID) { if (t->ore == 0) { t->ore = 1; for(int z = j / 15; z > 0; z--) t->ore += g_game_rand.rand(0, 4) == 0; } } } } } }
void ProductionSystem::update(tdt::real delta) { for(auto& ent : entities_.get_component_container<ProductionComponent>()) { if(ent.second.curr_produced >= ent.second.max_produced) continue; if(ent.second.curr_cd < ent.second.cooldown) ent.second.curr_cd += delta * time_multiplier_; else { spawn_entity(ent.first, ent.second.product_blueprint); ++ent.second.curr_produced; ent.second.curr_cd = REAL_ZERO; } } }
void GameUpdate() { game* g = &g_game; if (is_key_pressed(KEY_RESET)) { memset(g->_map, 0, sizeof(g->_map)); g->_entities.free(); g->_player = 0; g->_cam_pos = vec2(MAP_WIDTH * 0.5f, 8.5f); g->_target_cam_y = 8.5f; g->_diff = 1; g->_diff_dmg = 1; g->_spawn_time = 800; g->_spawn_count = 6; g->_wave_incoming = true; g->_plr_dmg = 1; GameInit(); g_title = true; } if (g_title) { set_camera(vec2(), 10.0f); float ratio = g_WinSize.y / (float)g_WinSize.x; vec2 orig(-10.0f, -10.0f * ratio); draw_string(vec2(0.0f, -4.75), 0.15f, TEXT_CENTRE, colour(0.5f, 0.5f, 1.0f, 1.0f), "Tunnel Defense"); float y = -3.25f; draw_string(vec2(0.0f, y), 0.05f, TEXT_CENTRE, colour(0.3f, 0.3f, 0.6f, 1.0f), "Originally made for LD29 - post competition version"); y += 0.5f; y += 0.5f; draw_string(vec2(0.0f, y), 0.05f, TEXT_CENTRE, colour(0.6f, 0.3f, 0.3f, 1.0f), "Dig for your life, the creeps are coming and the"); y += 0.5f; draw_string(vec2(0.0f, y), 0.05f, TEXT_CENTRE, colour(0.6f, 0.3f, 0.3f, 1.0f), "only safe place is underground! Collect resources"); y += 0.5f; draw_string(vec2(0.0f, y), 0.05f, TEXT_CENTRE, colour(0.6f, 0.3f, 0.3f, 1.0f), "and build turrets to protect yourself."); y += 0.5f; y += 0.25f; float r = 5.0f; draw_string(vec2(-r, y), 0.05f, TEXT_LEFT, colour(0.6f, 0.6f, 0.6f, 1.0f), "\001\002\003\004"); draw_string(vec2(r, y), 0.05f, TEXT_RIGHT, colour(0.3f, 0.6f, 0.3f, 1.0f), "Move + Aim"); y += 0.5f; draw_string(vec2(-r, y), 0.05f, TEXT_LEFT, colour(0.6f, 0.6f, 0.6f, 1.0f), "%c", g_LocKeyZ); draw_string(vec2(r, y), 0.05f, TEXT_RIGHT, colour(0.3f, 0.6f, 0.3f, 1.0f), "Jump"); y += 0.5f; draw_string(vec2(-r, y), 0.05f, TEXT_LEFT, colour(0.6f, 0.6f, 0.6f, 1.0f), "%c", g_LocKeyX); draw_string(vec2(r, y), 0.05f, TEXT_RIGHT, colour(0.3f, 0.6f, 0.3f, 1.0f), "Dig block / shoot"); y += 0.5f; draw_string(vec2(-r, y), 0.05f, TEXT_LEFT, colour(0.6f, 0.6f, 0.6f, 1.0f), "%c", g_LocKeyC); draw_string(vec2(r, y), 0.05f, TEXT_RIGHT, colour(0.3f, 0.6f, 0.3f, 1.0f), "Build / upgrade turret"); y += 0.5f; y += 0.25f; draw_string(vec2(0.0f, y), 0.05f, TEXT_CENTRE, colour(0.15f, 0.3f, 0.15f, 1.0f), "Alternate controls - %c%c%c%c, %c, %c, %c", g_LocKeyW, g_LocKeyA, g_LocKeyS, g_LocKeyD, g_LocKeyI, g_LocKeyO, g_LocKeyP); y += 0.5f; y += 0.25f; draw_string(vec2(0.0f, y), 0.05f, TEXT_CENTRE, colour(0.3f, 0.15f, 0.3f, 1.0f), "Building / upgrading a turret costs 3 metal."); y += 0.5f; draw_string(vec2(0.0f, y), 0.05f, TEXT_CENTRE, colour(0.3f, 0.15f, 0.3f, 1.0f), "Building a turret increases your shot power."); y += 0.5f; y += 0.25f; draw_string(vec2(0.0f, y), 0.05f, TEXT_CENTRE, colour(0.5f, 0.5f, 0.5f, 1.0f), "press SPACE to START"); y+= 0.5f; y += 0.5f; draw_string(vec2(0.0f, y), 0.035f, TEXT_CENTRE, colour(0.15f, 0.15f, 0.15f, 1.0f), "by Stephen Cakebread @quantumrain"); if (is_key_pressed(KEY_FIRE) || is_key_pressed(KEY_ALT_FIRE)) g_title = false; return; } if (player* p = g->_player) { vec2 target_cam_pos = vec2(MAP_WIDTH * 0.5f, p->centre().y); float dy = target_cam_pos.y - g->_target_cam_y; float hyst = 1.25f; if (fabsf(dy) > hyst) { if (dy > 0.0f) g->_target_cam_y += dy - hyst; else g->_target_cam_y += dy + hyst; } target_cam_pos.y = g->_target_cam_y; update_search(g, to_ivec2(p->centre())); g->_cam_pos = lerp(g->_cam_pos, target_cam_pos, 0.2f); g->_plr_dmg = 1; for(uint32_t i = 0; i < g->_entities.size(); i++) { entity* e = g->_entities[i]; if (!(e->_flags & entity::FLAG_DESTROYED)) { if (e->_type == ET_TURRET) g->_plr_dmg++; } } } set_camera(g->_cam_pos, 15.0f); if (g->_player) { if (--g->_spawn_time <= 0) { if (g->_wave_incoming) { g->_spawn_count = 4 + 4 * (int)g->_diff; g->_diff_dmg = (int)(2.5f * (1 + g->_diff)) - 1; } g->_wave_incoming = false; vec2 pos(g_game_rand.frand(1.0f, MAP_WIDTH - 1.0f), 2.0f); if (bug* e = spawn_entity(&g_game, new bug(), pos)) { e->_max_damage = g->_diff_dmg; if (g_game_rand.rand(0, 5) == 0) e->_max_damage += g_game_rand.rand(0, g->_diff_dmg); if (g_game_rand.rand(0, 15) == 0) e->_max_damage += g_game_rand.rand(0, g->_diff_dmg); if (g_game_rand.rand(0, 30) == 0) e->_max_damage += g_game_rand.rand(0, g->_diff_dmg); } g->_spawn_time = clamp(60 - ((g->_diff * 5) / 4), 10, 60); if (--g->_spawn_count <= 0){ g->_diff += 1 + (g->_diff / 5); g->_spawn_time = 600; g->_wave_incoming = true; } } } tick_entities(g); purge_entities(g); update_particles(g); colour sky0(0.4f, 0.7f, 1.0f, 1.0f); colour sky1(0.45f, 0.75f, 1.0f, 1.0f); colour sky2(0.3f, 0.6f, 0.9f, 1.0f); colour sky3(0.35f, 0.65f, 0.9f, 1.0f); sky0 *= colour(0.65f, 0.0f); sky1 *= colour(0.65f, 0.0f); sky2 *= colour(0.35f, 1.0f); sky3 *= colour(0.35f, 1.0f); float sky_space = 4.5f; float sky_top = 4.75f; float sky_y = 10.0f; float sky_yf = 10.5f; float sky_yb = 11.0f; for(int j = 0; j < MAP_HEIGHT; j++) { colour bk_colour(get_master_colour(j) * colour(0.2f, 1.0f)); for(int i = 0; i < MAP_WIDTH; i++) { int t = g->get_tile(i, j); if (t == TT_EMPTY || t == TT_TURRET) { int hash = ((i * 7) ^ (j * 3)) + (i + j); hash ^= ((hash >> 3) * 9); int tile_num = 132 + (hash % 4); draw_tile(vec2((float)i, (float)j), vec2(i + 1.0f, j + 1.0f), bk_colour, tile_num, 0); } } }
void _do_fire(GameData* game, Entity* e, int index, Direction direction) { FathomData* fathom = &game->fathoms[game->current]; Item* item = &e->inventory[index]; Point vector = directionToPoint(direction); Point pos = pointAddPoint(e->pos, vector); int distance = 3 + sys_randint(3); int i; Entity nullEntity = NULL_ENTITY; switch(item->conchSubtype) { case CONCH_BUBBLE: { int spawnType = sys_randint(ET_MAX_ENEMY); for(i=0; i<distance; i++) { if(sys_randint(4)==0) game_spawnAt(fathom, spawn_entity(spawnType), pos); else game_spawnAt(fathom, spawn_entity(ET_BUBBLE), pos); pos = pointAddPoint(pos, vector); } break; } case CONCH_DIG: { Tile nullTile = NULL_TILE; for(i=0; i<distance; i++) { int index = tilemap_indexFromTilePosition(&fathom->tileMap, pos); if(index != -1) fathom->tileMap.tiles[index] = nullTile; pos = pointAddPoint(pos, vector); } break; } case CONCH_JUMP: { pos = pointAddPoint(pos, pointMultiply(vector, distance)); Point invert = pointInverse(vector); for(i=distance-1; i>0; i--) { if(game_pointFree(fathom, pos)) { e->pos = pos; break; } pos = pointAddPoint(pos, invert); } break; } case CONCH_DEATH: { if(e->o2 > 4) e->o2 = e->o2/4; for(i=0; i<distance; i++) { int index = game_pointEntityIndex(fathom, pos); if(index != -1) fathom->entities[index] = nullEntity; pos = pointAddPoint(pos, vector); } break; } case CONCH_POLYMORPH: { for(i=0; i<distance; i++) { int index = game_pointEntityIndex(fathom, pos); if(index != -1) { bool player = fathom->entities[index].player; fathom->entities[index] = nullEntity; Entity e = spawn_entity(sys_randint(ET_MAX_ENEMY)); e.player = player; game_spawnAt(fathom, e, pos); } int j; for(j=0; j<MAX_ITEMS; j++) { Item* item = &fathom->items[j]; if(!item->active) continue; if(pos.x != item->pos.x || pos.y != item->pos.y) continue; *item = spawn_item(game, item->type); item->pos = pos; item->active = true; } pos = pointAddPoint(pos, vector); } break; } case CONCH_MAPPING: { for(i=0; i<fathom->tileMap.size.x*fathom->tileMap.size.y; i++) fathom->tileMap.tiles[i].seen = true; break; } default: LOG("Trying to cast invalid conch."); break; } game_addMessage(fathom, e->pos, "%s fired %s %s.", _getName(e->name), item_subtypeDescription(item->subtype), item_typeName(item->type)); if(sys_randint(5)==0) { Item nullItem = NULL_ITEM; game_addMessage(fathom, e->pos, "the %s %s falls apart.", item_subtypeDescription(item->subtype), item_typeName(item->type)); *item = nullItem; } }
void game_update_and_render(RenderQueue* render_queue, Game* game, Input* input, u64 dt) { if (game->entities.entity_count == 0) { V2i pos; pos.x = 7; pos.y = 5; u32 id = spawn_entity(&game->entities); register_location(&game->entities, id, pos, SOUTH); register_appearance(&game->entities, id, 7723); register_controlled(&game->entities, id); } // Handle user input if (input->keys[ESCAPE] != 0) { game->should_end = true; } u32 entity_to_control_mask_include = ENTITY_LOCATED_BIT | ENTITY_CONTROLLED_BIT; u32 entity_to_control_mask_exclude = ENTITY_MOVING_BIT; u32 entity_to_control_count = 0; u32 entity_to_control[MAX_ENTITY_COUNT]; filter_entities(&game->entities, entity_to_control_mask_include, entity_to_control_mask_exclude, entity_to_control, &entity_to_control_count); V2i positions[MAX_ENTITY_COUNT]; for (u32 i = 0; i < entity_to_control_count; i++) { for (u32 j = 0; j < game->entities.located_count; j++) { if (entity_to_control[i] == game->entities.located[j]) { positions[i] = game->entities.positions[j]; break; } } } bool moved = false; Direction direction = NORTH; V2i destination_diff; for (u32 i = 1; i < 5; i++) { i32 key_state = input->keys[i] + game->previous_key_state[i]; if (key_state && entity_to_control_count > 0) { moved = true; destination_diff.x = 0; destination_diff.y = 0; switch (i) { case W: direction = NORTH; destination_diff.y -= 1; break; case A: direction = WEST; destination_diff.x -= 1; break; case S: direction = SOUTH; destination_diff.y += 1; break; case D: direction = EAST; destination_diff.x += 1; break; default: assert(!(bool)"Unreachable!"); break; } } game->previous_key_state[i] = key_state % 2; } if (moved) { for (u32 j = 0; j < entity_to_control_count; j++) { f32 distance = 0.0f; V2i destination; destination.x = positions[j].x + destination_diff.x; destination.y = positions[j].y + destination_diff.y; u32 id = entity_to_control[j]; register_moving(&game->entities, id, destination, distance); update_located_direction(&game->entities, id, direction); } } // Update game->tick += dt; if (game->tick > MS_TO_NS(2000)) { game->tick = 0; for (int y = 0; y < 11; y++) { for (int x = 0; x < 15; x++) { game->tiles[x][y] = rand() % 101925; } } } { // Update moving entities u32 movable_mask = ENTITY_LOCATED_BIT | ENTITY_MOVING_BIT; u32 entities_to_move_count = 0; u32 entities_to_move[MAX_ENTITY_COUNT]; filter_entities(&game->entities, movable_mask, 0, entities_to_move, &entities_to_move_count); u32 not_moving_count = 0; u32 not_moving[MAX_ENTITY_COUNT]; for (u32 i = 0; i < entities_to_move_count; i++) { u32 id = entities_to_move[i]; u32 located_index = 0; for (u32 j = 0; j < game->entities.located_count; j++) { if (game->entities.located[j] == id) { located_index = j; break; } } u32 moving_index = 0; for (u32 j = 0; j < game->entities.moving_count; j++) { if (game->entities.moving[j] == id) { moving_index = j; break; } } if (game->entities.distances[moving_index] >= 1.0f) { game->entities.positions[located_index] = game->entities.destinations[moving_index]; game->entities.distances[moving_index] = 0.0f; not_moving[not_moving_count] = id; not_moving_count += 1; } else { game->entities.distances[moving_index] += 0.1f; } } for (u32 i = 0; i < not_moving_count; i++) { deregister_moving(&game->entities, not_moving[i]); } } // Render render_queue_push_clear(render_queue, 0.0f, 0.0f, 0.0f, 0.0f); game->camera_x = 7.0f; game->camera_y = 5.0f; u32 tile_size = 64; for (u32 r = 0; r < 128; r++) { for (u32 c = 0; c < 128; c++) { f32 x = c - game->camera_x + 7; f32 y = r - game->camera_y + 5; if (0.0f <= x && x < 16.0f && 0 <= y && y < 12.0f) { render_queue_push_sprite(render_queue, game->world[r][c], (i32)(x * tile_size + tile_size), (i32)(y * tile_size + tile_size), tile_size); } } } u32 drawable_mask = ENTITY_LOCATED_BIT | ENTITY_APPEARANCE_BIT; u32 entities_to_draw_count = 0; u32 entities_to_draw[MAX_ENTITY_COUNT]; filter_entities(&game->entities, drawable_mask, 0, entities_to_draw, &entities_to_draw_count); u32 ms[MAX_ENTITY_COUNT]; for (u32 i = 0; i < entities_to_draw_count; i++) { for (u32 j = 0; j < game->entities.entity_count; j++) { if (entities_to_draw[i] == game->entities.ids[j]) { assert((game->entities.masks[j] & drawable_mask) == drawable_mask); ms[i] = game->entities.masks[j]; break; } } } u32 ss[MAX_ENTITY_COUNT]; for (u32 i = 0; i < entities_to_draw_count; i++) { u32 id = entities_to_draw[i]; for (u32 j = 0; j < game->entities.appearance_count; j++) { if (game->entities.appearance[j] == id) { ss[i] = game->entities.sprites[j]; break; } } } f32 xs[MAX_ENTITY_COUNT]; f32 ys[MAX_ENTITY_COUNT]; Direction dirs[MAX_ENTITY_COUNT]; for (u32 i = 0; i < entities_to_draw_count; i++) { u32 id = entities_to_draw[i]; for (u32 j = 0; j < game->entities.located_count; j++) { if (game->entities.located[j] == id) { xs[i] = (f32)game->entities.positions[j].x; ys[i] = (f32)game->entities.positions[j].y; dirs[i] = game->entities.directions[j]; break; } } } f32 dists[MAX_ENTITY_COUNT]; for (u32 i = 0; i < entities_to_draw_count; i++) { for (u32 j = 0; j < game->entities.moving_count; j++) { if (entities_to_draw[i] == game->entities.moving[j]) { dists[i] = game->entities.distances[j]; break; } } } for (u32 i = 0; i < entities_to_draw_count; i++) { u32 sprite_offset = 0; if (ms[i] & ENTITY_MOVING_BIT) { f32 animation_frames = 4.0f; f32 n = (dists[i] / (1.0f / animation_frames)); sprite_offset += (u32)n * 4; switch (dirs[i]) { case NORTH: case SOUTH: sprite_offset += ((u32)ys[i] % 2) * (4 * 4); break; case WEST: case EAST: sprite_offset += ((u32)xs[i] % 2) * (4 * 4); break; } } switch (dirs[i]) { case NORTH: ss[i] = 7721 + sprite_offset; break; case EAST: ss[i] = 7722 + sprite_offset; break; case SOUTH: ss[i] = 7723 + sprite_offset; break; case WEST: ss[i] = 7724 + sprite_offset; break; } } for (u32 i = 0; i < entities_to_draw_count; i++) { if (ms[i] & ENTITY_MOVING_BIT) { V2f v; v.x = xs[i]; v.y = ys[i]; for (u32 j = 0; j < game->entities.moving_count; j++) { if (game->entities.moving[j] == entities_to_draw[i]) { switch (game->entities.directions[j]) { case NORTH: v.y -= game->entities.distances[j]; break; case WEST: v.x -= game->entities.distances[j]; break; case SOUTH: v.y += game->entities.distances[j]; break; case EAST: v.x += game->entities.distances[j]; break; } break; } } xs[i] = v.x - game->camera_x + 7.0f; ys[i] = v.y - game->camera_y + 5.0f; } } for (u32 i = 0; i < entities_to_draw_count; i++) { i32 ts = (i32)tile_size; render_queue_push_sprite(render_queue, ss[i], (i32)(xs[i] * ts + ts), (i32)(ys[i] * ts + ts), ts); } }