/********************************************************************** Find something to bomb Air-units specific victim search Returns the want for the best target. The targets are stored in the path and pptile arguments if not NULL. TODO: take counterattack dangers into account TODO: make separate handicaps for air units seeing targets IMO should be more restrictive than general H_MAP, H_FOG *********************************************************************/ static int find_something_to_bomb(struct ai_type *ait, struct unit *punit, struct pf_path **path, struct tile **pptile) { struct player *pplayer = unit_owner(punit); struct pf_parameter parameter; struct pf_map *pfm; struct tile *best_tile = NULL; int best = 0; pft_fill_unit_parameter(¶meter, punit); pfm = pf_map_new(¶meter); /* Let's find something to bomb */ pf_map_move_costs_iterate(pfm, ptile, move_cost, FALSE) { if (move_cost >= punit->moves_left) { /* Too far! */ break; } if (ai_handicap(pplayer, H_MAP) && !map_is_known(ptile, pplayer)) { /* The target tile is unknown */ continue; } if (ai_handicap(pplayer, H_FOG) && !map_is_known_and_seen(ptile, pplayer, V_MAIN)) { /* The tile is fogged */ continue; } if (is_enemy_unit_tile(ptile, pplayer) && dai_should_we_air_attack_tile(ait, punit, ptile) && can_unit_attack_tile(punit, ptile)) { int new_best = dai_evaluate_tile_for_air_attack(punit, ptile); if (new_best > best) { best_tile = ptile; best = new_best; log_debug("%s wants to attack tile (%d, %d)", unit_rule_name(punit), TILE_XY(ptile)); } } } pf_map_positions_iterate_end; /* Return the best values. */ if (pptile) { *pptile = best_tile; } if (path) { *path = best_tile ? pf_map_path(pfm, best_tile) : NULL; } pf_map_destroy(pfm); return best; }
/******************************************************************* Chooses the best available and usable air unit and records it in choice, if it's better than previous choice The interface is somewhat different from other ai_choose, but that's what it should be like, I believe -- GB ******************************************************************/ bool dai_choose_attacker_air(struct ai_type *ait, struct player *pplayer, struct city *pcity, struct adv_choice *choice) { bool want_something = FALSE; /* This AI doesn't know to build planes */ if (ai_handicap(pplayer, H_NOPLANES)) { return FALSE; } /* military_advisor_choose_build does something idiotic, * this function should not be called if there is danger... */ if (choice->want >= 100 && choice->type != CT_ATTACKER) { return FALSE; } if (!player_knows_techs_with_flag(pplayer, TF_BUILD_AIRBORNE)) { return FALSE; } unit_type_iterate(punittype) { struct unit_class *pclass = utype_class(punittype); if (pclass->adv.land_move == MOVE_NONE || pclass->adv.sea_move == MOVE_NONE || uclass_has_flag(pclass, UCF_TERRAIN_SPEED) || unit_type_is_losing_hp(pplayer, punittype)) { /* We don't consider this a plane */ continue; } if (can_city_build_unit_now(pcity, punittype)) { struct unit *virtual_unit = unit_virtual_create(pplayer, pcity, punittype, do_make_unit_veteran(pcity, punittype)); int profit = find_something_to_bomb(ait, virtual_unit, NULL, NULL); if (profit > choice->want){ /* Update choice */ choice->want = profit; choice->value.utype = punittype; choice->type = CT_ATTACKER; choice->need_boat = FALSE; want_something = TRUE; log_debug("%s wants to build %s (want=%d)", city_name(pcity), utype_rule_name(punittype), profit); } else { log_debug("%s doesn't want to build %s (want=%d)", city_name(pcity), utype_rule_name(punittype), profit); } unit_virtual_destroy(virtual_unit); } } unit_type_iterate_end; return want_something; }
/***************************************************************************** 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;