static void draw_minimap_buildings(minimap_t *minimap, frame_t *frame) { const int building_remap[] = { BUILDING_CASTLE, BUILDING_STOCK, BUILDING_TOWER, BUILDING_HUT, BUILDING_FORTRESS, BUILDING_TOOLMAKER, BUILDING_SAWMILL, BUILDING_WEAPONSMITH, BUILDING_STONECUTTER, BUILDING_BOATBUILDER, BUILDING_FORESTER, BUILDING_LUMBERJACK, BUILDING_PIGFARM, BUILDING_FARM, BUILDING_FISHER, BUILDING_MILL, BUILDING_BUTCHER, BUILDING_BAKER, BUILDING_STONEMINE, BUILDING_COALMINE, BUILDING_IRONMINE, BUILDING_GOLDMINE, BUILDING_STEELSMELTER, BUILDING_GOLDSMELTER }; for (int row = 0; row < game.map.rows; row++) { for (int col = 0; col < game.map.cols; col++) { int pos = MAP_POS(col, row); int obj = MAP_OBJ(pos); if (obj > MAP_OBJ_FLAG && obj <= MAP_OBJ_CASTLE) { int color = game.player[MAP_OWNER(pos)]->color; if (minimap->advanced > 0) { building_t *bld = game_get_building(MAP_OBJ_INDEX(pos)); if (BUILDING_TYPE(bld) == building_remap[minimap->advanced]) { draw_minimap_point(minimap, col, row, color, minimap->scale, frame); } } else { draw_minimap_point(minimap, col, row, color, minimap->scale, frame); } } } } }
static int available_knights_at_pos(player_t *player, map_pos_t pos, int index, int dist) { const int min_level_hut[] = { 1, 1, 2, 2, 3 }; const int min_level_tower[] = { 1, 2, 3, 4, 6 }; const int min_level_fortress[] = { 1, 3, 6, 9, 12 }; if (MAP_OWNER(pos) != player->player_num || MAP_TYPE_UP(pos) < 4 || MAP_TYPE_DOWN(pos) < 4 || MAP_OBJ(pos) < MAP_OBJ_SMALL_BUILDING || MAP_OBJ(pos) > MAP_OBJ_CASTLE) { return index; } int bld_index = MAP_OBJ_INDEX(pos); for (int i = 0; i < index; i++) { if (player->attacking_buildings[i] == bld_index) { return index; } } building_t *building = game_get_building(bld_index); if (!BUILDING_IS_DONE(building) || BUILDING_IS_BURNING(building)) { return index; } const int *min_level = NULL; switch (BUILDING_TYPE(building)) { case BUILDING_HUT: min_level = min_level_hut; break; case BUILDING_TOWER: min_level = min_level_tower; break; case BUILDING_FORTRESS: min_level = min_level_fortress; break; default: return index; break; } if (index >= 64) return index; player->attacking_buildings[index] = bld_index; int state = BUILDING_STATE(building); int knights_present = building->stock[0].available; int to_send = knights_present - min_level[player->knight_occupation[state] & 0xf]; if (to_send > 0) player->attacking_knights[dist] += to_send; return index + 1; }
static void draw_minimap_ownership(minimap_t *minimap, int density, frame_t *frame) { for (int row = 0; row < game.map.rows; row++) { for (int col = 0; col < game.map.cols; col++) { map_pos_t pos = MAP_POS(col, row); if (MAP_HAS_OWNER(pos)) { int color = game.player[MAP_OWNER(pos)]->color; draw_minimap_point(minimap, col, row, color, density, frame); } } } }
static void draw_minimap_traffic(minimap_t *minimap, frame_t *frame) { for (int row = 0; row < game.map.rows; row++) { for (int col = 0; col < game.map.cols; col++) { int pos = MAP_POS(col, row); if (MAP_IDLE_SERF(pos)) { int color = game.player[MAP_OWNER(pos)]->color; draw_minimap_point(minimap, col, row, color, minimap->scale, frame); } } } }
static void draw_minimap_ownership(minimap_t *minimap, int density, frame_t *frame) { const int player_colors[] = { 64, 72, 68, 76 }; for (int row = 0; row < game.map.rows; row++) { for (int col = 0; col < game.map.cols; col++) { map_pos_t pos = MAP_POS(col, row); if (MAP_HAS_OWNER(pos)) { int color = player_colors[MAP_OWNER(pos)]; draw_minimap_point(minimap, col, row, color, density, frame); } } } }
static void draw_minimap_traffic(minimap_t *minimap, frame_t *frame) { const int player_colors[] = { 64, 72, 68, 76 }; for (int row = 0; row < game.map.rows; row++) { for (int col = 0; col < game.map.cols; col++) { int pos = MAP_POS(col, row); if (MAP_IDLE_SERF(pos)) { int color = player_colors[MAP_OWNER(pos)]; draw_minimap_point(minimap, col, row, color, minimap->scale, frame); } } } }
void player_start_attack(player_t *player) { const int min_level_hut[] = { 1, 1, 2, 2, 3 }; const int min_level_tower[] = { 1, 2, 3, 4, 6 }; const int min_level_fortress[] = { 1, 3, 6, 9, 12 }; building_t *target = game_get_building(player->building_attacked); if (!BUILDING_IS_DONE(target) || (BUILDING_TYPE(target) != BUILDING_HUT && BUILDING_TYPE(target) != BUILDING_TOWER && BUILDING_TYPE(target) != BUILDING_FORTRESS && BUILDING_TYPE(target) != BUILDING_CASTLE) || !BUILDING_IS_ACTIVE(target) || BUILDING_STATE(target) != 3) { return; } for (int i = 0; i < player->attacking_building_count; i++) { /* TODO building index may not be valid any more(?). */ building_t *b = game_get_building(player->attacking_buildings[i]); if (BUILDING_IS_BURNING(b) || MAP_OWNER(b->pos) != player->player_num) { continue; } map_pos_t flag_pos = MAP_MOVE_DOWN_RIGHT(b->pos); if (MAP_SERF_INDEX(flag_pos) != 0) { /* Check if building is under siege. */ serf_t *s = game_get_serf(MAP_SERF_INDEX(flag_pos)); if (SERF_PLAYER(s) != player->player_num) continue; } const int *min_level = NULL; switch (BUILDING_TYPE(b)) { case BUILDING_HUT: min_level = min_level_hut; break; case BUILDING_TOWER: min_level = min_level_tower; break; case BUILDING_FORTRESS: min_level = min_level_fortress; break; default: continue; break; } int state = BUILDING_STATE(b); int knights_present = b->stock[0].available; int to_send = knights_present - min_level[player->knight_occupation[state] & 0xf]; for (int j = 0; j < to_send; j++) { /* Find most approriate knight to send according to player settings. */ int best_type = PLAYER_SEND_STRONGEST(player) ? SERF_KNIGHT_0 : SERF_KNIGHT_4; int best_index = -1; int knight_index = b->serf_index; while (knight_index != 0) { serf_t *knight = game_get_serf(knight_index); if (PLAYER_SEND_STRONGEST(player)) { if (SERF_TYPE(knight) >= best_type) { best_index = knight_index; best_type = SERF_TYPE(knight); } } else { if (SERF_TYPE(knight) <= best_type) { best_index = knight_index; best_type = SERF_TYPE(knight); } } knight_index = knight->s.defending.next_knight; } /* Unlink knight from list. */ int *def_index = &b->serf_index; serf_t *def_serf = game_get_serf(*def_index); while (*def_index != best_index) { def_index = &def_serf->s.defending.next_knight; def_serf = game_get_serf(*def_index); } *def_index = def_serf->s.defending.next_knight; b->stock[0].available -= 1; target->progress |= BIT(0); /* Calculate distance to target. */ int dist_col = (MAP_POS_COL(target->pos) - MAP_POS_COL(def_serf->pos)) & game.map.col_mask; if (dist_col >= game.map.cols/2) dist_col -= game.map.cols; int dist_row = (MAP_POS_ROW(target->pos) - MAP_POS_ROW(def_serf->pos)) & game.map.row_mask; if (dist_row >= game.map.rows/2) dist_row -= game.map.rows; /* Send this serf off to fight. */ serf_log_state_change(def_serf, SERF_STATE_KNIGHT_LEAVE_FOR_WALK_TO_FIGHT); def_serf->state = SERF_STATE_KNIGHT_LEAVE_FOR_WALK_TO_FIGHT; def_serf->s.leave_for_walk_to_fight.dist_col = dist_col; def_serf->s.leave_for_walk_to_fight.dist_row = dist_row; def_serf->s.leave_for_walk_to_fight.field_D = 0; def_serf->s.leave_for_walk_to_fight.field_E = 0; def_serf->s.leave_for_walk_to_fight.next_state = SERF_STATE_KNIGHT_FREE_WALKING; player->knights_attacking -= 1; if (player->knights_attacking == 0) return; } } }