void AAIAttackManager::LaunchAttack() { ////////////////////////////////////////////////////////////////////////////////////////////// // get all available combat/aa/arty groups for attack ////////////////////////////////////////////////////////////////////////////////////////////// int total_combat_groups = 0; for(list<UnitCategory>::iterator category = ai->Getbt()->assault_categories.begin(); category != ai->Getbt()->assault_categories.end(); ++category) { for(list<AAIGroup*>::iterator group = ai->Getgroup_list()[*category].begin(); group != ai->Getgroup_list()[*category].end(); ++group) { if( (*group)->AvailableForAttack() ) { if((*group)->group_movement_type & MOVE_TYPE_CONTINENT_BOUND) { if((*group)->group_unit_type == ASSAULT_UNIT) { available_combat_groups_continent[(*group)->continent].push_back(*group); ++total_combat_groups; } else available_aa_groups_continent[(*group)->continent].push_back(*group); } else { if((*group)->group_unit_type == ASSAULT_UNIT) { available_combat_groups_global.push_back(*group); ++total_combat_groups; } else available_aa_groups_global.push_back(*group); } } } } // stop planing an attack if there are no combat groups available at the moment if(total_combat_groups == 0) return; ////////////////////////////////////////////////////////////////////////////////////////////// // calculate max attack power for each continent ////////////////////////////////////////////////////////////////////////////////////////////// fill(attack_power_global.begin(), attack_power_global.end(), 0.0f); for(list<AAIGroup*>::iterator group = available_combat_groups_global.begin(); group != available_combat_groups_global.end(); ++group) (*group)->GetCombatPower( &attack_power_global ); for(size_t continent = 0; continent < available_combat_groups_continent.size(); ++continent) { fill(attack_power_continent[continent].begin(), attack_power_continent[continent].end(), 0.0f); for(list<AAIGroup*>::iterator group = available_combat_groups_continent[continent].begin(); group != available_combat_groups_continent[continent].end(); ++group) (*group)->GetCombatPower( &(attack_power_continent[continent]) ); } // determine max lost units float max_lost_units = 0.0f; for(int x = 0; x < ai->Getmap()->xSectors; ++x) { for(int y = 0; y < ai->Getmap()->ySectors; ++y) { float lost_units = ai->Getmap()->sector[x][y].GetLostUnits(1.0f, 1.0f, 1.0f, 1.0f, 1.0f); if(lost_units > max_lost_units) max_lost_units = lost_units; } } ////////////////////////////////////////////////////////////////////////////////////////////// // determine attack sector ////////////////////////////////////////////////////////////////////////////////////////////// float def_power; float att_power; float best_rating = 0.0f; AAISector* sector; AAISector* dest = NULL; for(int x = 0; x < ai->Getmap()->xSectors; ++x) { for(int y = 0; y < ai->Getmap()->ySectors; ++y) { sector = &ai->Getmap()->sector[x][y]; float my_rating; // max_lost_units check to prevent SIGFPE, later on if(sector->distance_to_base == 0 || sector->enemy_structures < 0.0001 || max_lost_units <= 0.0f) my_rating = 0.0f; else { if(ai->Getmap()->continents[sector->continent].water) { def_power = sector->GetEnemyDefencePower(0.0f, 0.0f, 0.5f, 1.0f, 1.0f) + 0.01; att_power = attack_power_global[5] + attack_power_continent[sector->continent][5]; } else { def_power = sector->GetEnemyDefencePower(1.0f, 0.0f, 0.5f, 0.0f, 0.0f) + 0.01; att_power = attack_power_global[5] + attack_power_continent[sector->continent][5]; } my_rating = (1.0f - sector->GetLostUnits(1.0f, 1.0f, 1.0f, 1.0f, 1.0f) / max_lost_units) * sector->enemy_structures * att_power / ( def_power * (float)(2 + sector->distance_to_base) ); //if(SufficientAttackPowerVS(dest, &combat_available, 2)) } if(my_rating > best_rating) { dest = sector; best_rating = my_rating; } } } ////////////////////////////////////////////////////////////////////////////////////////////// // order attack ////////////////////////////////////////////////////////////////////////////////////////////// if(dest) { AAIAttack *attack = new AAIAttack(ai); attacks.push_back(attack); // add combat groups for(list<AAIGroup*>::iterator group = available_combat_groups_continent[dest->continent].begin(); group != available_combat_groups_continent[dest->continent].end(); ++group) attack->AddGroup(*group); for(list<AAIGroup*>::iterator group = available_combat_groups_global.begin(); group != available_combat_groups_global.end(); ++group) attack->AddGroup(*group); // add anti-air defence int aa_added = 0, max_aa; // check how much aa sensible if(ai->Getbrain()->max_combat_units_spotted[1] < 0.2) max_aa = 0; else max_aa = 1; for(list<AAIGroup*>::iterator group = available_aa_groups_continent[dest->continent].begin(); group != available_aa_groups_continent[dest->continent].end(); ++group) { if(aa_added >= max_aa) break; attack->AddGroup(*group); ++aa_added; } for(list<AAIGroup*>::iterator group = available_aa_groups_global.begin(); group != available_aa_groups_global.end(); ++group) { if(aa_added >= max_aa) break; attack->AddGroup(*group); ++aa_added; } // rally attacking groups //RallyGroups(attack); // start the attack attack->AttackSector(dest); } }
void AAIAttackManager::LaunchAttack() { AAISector *dest; AttackType a_type; bool suitable, land, water; // determine attack sector // todo: improve decision when to attack base or outposts a_type = OUTPOST_ATTACK; if(cfg->AIR_ONLY_MOD) { land = true; water = true; } else { if(map->mapType == LAND_MAP) { land = true; water = false; } else if(map->mapType == LAND_WATER_MAP) { land = true; water = true; } else if(map->mapType == WATER_MAP) { land = false; water = true; } else { land = true; water = false; } } // get target sector dest = ai->brain->GetAttackDest(land, water, a_type); if(dest) { // get all available combat/aa/arty groups for attack set<AAIGroup*> combat_available; set<AAIGroup*> aa_available; if(cfg->AIR_ONLY_MOD) { for(list<UnitCategory>::iterator category = bt->assault_categories.begin(); category != bt->assault_categories.end(); ++category) { for(list<AAIGroup*>::iterator group = ai->group_list[*category].begin(); group != ai->group_list[*category].end(); ++group) { if(!(*group)->attack && (*group)->SufficientAttackPower()) combat_available.insert(*group); } } } else // non air only mods must take movement type into account { // todo: improve by checking how to reach that sector if(dest->water_ratio > 0.65) { land = false; water = true; } else { water = false; land = true; } for(list<UnitCategory>::iterator category = bt->assault_categories.begin(); category != bt->assault_categories.end(); ++category) { for(list<AAIGroup*>::iterator group = ai->group_list[*category].begin(); group != ai->group_list[*category].end(); ++group) { // check movement type first suitable = true; if(land && (*group)->group_movement_type & MOVE_TYPE_SEA) suitable = false; if(water && (*group)->group_movement_type & MOVE_TYPE_GROUND) suitable = false; if(suitable && !(*group)->attack && (*group)->task == GROUP_IDLE ) { if((*group)->group_unit_type == ASSAULT_UNIT && (*group)->SufficientAttackPower()) combat_available.insert(*group); else if((*group)->group_unit_type == ANTI_AIR_UNIT) aa_available.insert(*group); } } } } if((combat_available.size() > 0 && SufficientAttackPowerVS(dest, &combat_available, 2)) || combat_available.size() > 10) { AAIAttack *attack; try { attack = new AAIAttack(ai); } catch(...) { fprintf(ai->file, "Exception thrown when allocating memory for AAIAttack"); return; } attacks.push_back(attack); attack->land = land; attack->water = water; // add combat groups for(set<AAIGroup*>::iterator group = combat_available.begin(); group != combat_available.end(); ++group) attack->AddGroup(*group); // add antiair defence if(!aa_available.empty()) { int aa_added = 0, max_aa; // check how much aa sensible if(brain->max_units_spotted[1] < 0.2) max_aa = 0; else max_aa = 1; for(set<AAIGroup*>::iterator group = aa_available.begin(); group != aa_available.end(); ++group) { attack->AddGroup(*group); ++aa_added; if(aa_added >= max_aa) break; } } // rally attacking groups //this->RallyGroups(attack); // start the attack attack->AttackSector(dest, a_type); } // clean up aa_available.clear(); combat_available.clear(); } }