/*********************************************************************** Iterates through reachable cities and appraises them as a possible base for air operations by (air)unit punit. Returns NULL if not found. The path is stored in the path argument if not NULL. **********************************************************************/ static struct tile *dai_find_strategic_airbase(struct ai_type *ait, const struct unit *punit, struct pf_path **path) { struct player *pplayer = unit_owner(punit); struct pf_parameter parameter; struct pf_map *pfm; struct tile *best_tile = NULL; struct city *pcity; struct unit *pvirtual = NULL; int best_worth = 0, target_worth; pft_fill_unit_parameter(¶meter, punit); pfm = pf_map_new(¶meter); pf_map_move_costs_iterate(pfm, ptile, move_cost, FALSE) { if (move_cost >= punit->moves_left) { break; /* Too far! */ } if (!is_airunit_refuel_point(ptile, pplayer, unit_type(punit), FALSE)) { continue; /* Cannot refuel here. */ } if ((pcity = tile_city(ptile)) && def_ai_city_data(pcity, ait)->grave_danger != 0) { best_tile = ptile; break; /* Fly there immediately!! */ } if (!pvirtual) { pvirtual = unit_virtual_create(pplayer, player_city_by_number(pplayer, punit->homecity), unit_type(punit), punit->veteran); } unit_tile_set(pvirtual, ptile); target_worth = find_something_to_bomb(ait, pvirtual, NULL, NULL); if (target_worth > best_worth) { /* It's either a first find or it's better than the previous. */ best_worth = target_worth; best_tile = ptile; /* We can still look for something better. */ } } pf_map_move_costs_iterate_end; if (pvirtual) { unit_virtual_destroy(pvirtual); } if (path) { /* Stores the path. */ *path = best_tile ? pf_map_path(pfm, best_tile) : NULL; } pf_map_destroy(pfm); return best_tile; }
/***************************************************************************** Find best tile the paratrooper should jump to. *****************************************************************************/ static struct tile *find_best_tile_to_paradrop_to(struct ai_type *ait, struct unit *punit) { int best = 0; int val; struct tile* best_tile = NULL; int range = unit_type(punit)->paratroopers_range; struct city* acity; struct player* pplayer = unit_owner(punit); /* First, we search for undefended cities in danger */ square_iterate(unit_tile(punit), range, ptile) { if (!map_is_known(ptile, pplayer)) { continue; } acity = tile_city(ptile); if (acity && city_owner(acity) == unit_owner(punit) && unit_list_size(ptile->units) == 0) { val = city_size_get(acity) * def_ai_city_data(acity, ait)->urgency; if (val > best) { best = val; best_tile = ptile; } } } square_iterate_end; if (best_tile != NULL) { acity = tile_city(best_tile); UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "Choose to jump in order to protect allied city %s (%d %d). " "Benefit: %d", city_name(acity), TILE_XY(best_tile), best); return best_tile; } /* Second, we search for undefended enemy cities */ square_iterate(unit_tile(punit), range, ptile) { acity = tile_city(ptile); if (acity && pplayers_at_war(unit_owner(punit), city_owner(acity)) && (unit_list_size(ptile->units) == 0)) { if (!map_is_known_and_seen(ptile, pplayer, V_MAIN) && ai_handicap(pplayer, H_FOG)) { continue; } /* Prefer big cities on other continents */ val = city_size_get(acity) + (tile_continent(unit_tile(punit)) != tile_continent(ptile)); if (val > best) { best = val; best_tile = ptile; } } } square_iterate_end;
/********************************************************************** Very preliminary estimate for our intent to attack the tile (x, y). Used by bombers only. **********************************************************************/ static bool dai_should_we_air_attack_tile(struct ai_type *ait, struct unit *punit, struct tile *ptile) { struct city *acity = tile_city(ptile); /* For a virtual unit (punit->id == 0), all targets are good */ /* TODO: There is a danger of producing too many units that will not * attack anything. Production should not happen if there is an idle * unit of the same type nearby */ if (acity && punit->id != 0 && def_ai_city_data(acity, ait)->invasion.occupy == 0 && !unit_can_take_over(punit)) { /* No units capable of occupying are invading */ log_debug("Don't want to attack %s, although we could", city_name(acity)); return FALSE; } return TRUE; }