📄 aaiattackmanager.cpp
字号:
// -------------------------------------------------------------------------
// AAI
//
// A skirmish AI for the TA Spring engine.
// Copyright Alexander Seizinger
//
// Released under GPL license: see LICENSE.html for more information.
// -------------------------------------------------------------------------
#include "AAIAttackManager.h"
#include "AAI.h"
#include "AAIBrain.h"
#include "AAIBuildTable.h"
#include "AAIGroup.h"
#include "AAIMap.h"
#include "AAIAttack.h"
AAIAttackManager::AAIAttackManager(AAI *ai, IAICallback *cb, AAIBuildTable *bt)
{
this->ai = ai;
brain = ai->brain;
this->bt = bt;
this->cb = cb;
this->map = ai->map;
// available_combat_cat = new int[bt->combat_categories];
available_combat_cat.resize(bt->combat_categories);
}
AAIAttackManager::~AAIAttackManager(void)
{
for(list<AAIAttack*>::iterator a = attacks.begin(); a != attacks.end(); ++a)
delete (*a);
// delete [] available_combat_cat;
}
void AAIAttackManager::Update()
{
for(list<AAIAttack*>::iterator a = attacks.begin(); a != attacks.end(); ++a)
{
// drop failed attacks
if((*a)->Failed())
{
(*a)->StopAttack();
delete (*a);
attacks.erase(a);
break;
}
// check if sector cleared
if((*a)->dest)
{
if((*a)->dest->enemy_structures <= 0)
GetNextDest(*a);
}
}
if(attacks.size() < cfg->MAX_ATTACKS)
{
LaunchAttack();
}
}
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)->move_type == SEA)
suitable = false;
if(water && (*group)->move_type == GROUND)
suitable = false;
if(suitable && !(*group)->attack && (*group)->task == GROUP_IDLE )
{
if((*group)->group_type == ASSAULT_UNIT && (*group)->SufficientAttackPower())
combat_available.insert(*group);
else if((*group)->group_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();
}
}
void AAIAttackManager::StopAttack(AAIAttack *attack)
{
for(list<AAIAttack*>::iterator a = attacks.begin(); a != attacks.end(); ++a)
{
if(*a == attack)
{
(*a)->StopAttack();
delete (*a);
attacks.erase(a);
break;
}
}
}
void AAIAttackManager::CheckAttack(AAIAttack *attack)
{
// prevent command overflow
if((cb->GetCurrentFrame() - attack->lastAttack) < 30)
return;
// drop failed attacks
if(attack->Failed())
{
// delete attack from list
for(list<AAIAttack*>::iterator a = attacks.begin(); a != attacks.end(); ++a)
{
if(*a == attack)
{
attacks.erase(a);
attack->StopAttack();
delete attack;
break;
}
}
}
}
void AAIAttackManager::GetNextDest(AAIAttack *attack)
{
// prevent command overflow
if((cb->GetCurrentFrame() - attack->lastAttack) < 60)
return;
// get new target sector
AAISector *dest = ai->brain->GetNextAttackDest(attack->dest, attack->land, attack->water);
//fprintf(ai->file, "Getting next dest\n");
if(dest && SufficientAttackPowerVS(dest, &(attack->combat_groups), 2))
attack->AttackSector(dest, attack->type);
else
attack->StopAttack();
}
bool AAIAttackManager::SufficientAttackPowerVS(AAISector *dest, set<AAIGroup*> *combat_groups, float aggressiveness)
{
if(dest && combat_groups->size() > 0)
{
// check attack power
float attack_power = 0.5;
float sector_defence = 0;
int total_units = 1;
// store ammount and category of involved groups;
for(int i = 0; i < bt->combat_categories; ++i)
available_combat_cat[i] = 0;
// get total att power
for(set<AAIGroup*>::iterator group = combat_groups->begin(); group != combat_groups->end(); ++group)
{
attack_power += (*group)->GetPowerVS(5);
available_combat_cat[(*group)->combat_category] += (*group)->size;
total_units += (*group)->size;
}
attack_power += (float)total_units * 0.2f;
// get expected def power
for(int i = 0; i < bt->ass_categories; ++i)
sector_defence += dest->stat_combat_power[i] * (float)available_combat_cat[i];
sector_defence /= (float)total_units;
//fprintf(ai->file, "Checking attack power - att power / def power %f %f\n", aggressiveness * attack_power, sector_defence);
if(aggressiveness * attack_power >= sector_defence)
return true;
}
return false;
}
bool AAIAttackManager::SufficientCombatPowerAt(AAISector *dest, set<AAIGroup*> *combat_groups, float aggressiveness)
{
if(dest && combat_groups->size() > 0)
{
// store ammount and category of involved groups;
double my_power = 0, enemy_power = 0;
int total_units = 0, cat;
// reset counter
for(int i = 0; i < bt->combat_categories; ++i)
available_combat_cat[i] = 0;
// get total att power
for(int i = 0; i < bt->combat_categories; ++i)
{
cat = (int) bt->GetAssaultCategoryOfID(i);
// skip if no enemy units of that category present
if(dest->enemyUnitsOfType[cat] > 0)
{
// filter out air in normal mods
if(i != 1 || cfg->AIR_ONLY_MOD)
{
for(set<AAIGroup*>::iterator group = combat_groups->begin(); group != combat_groups->end(); ++group)
my_power += (*group)->GetPowerVS(i) * dest->enemyUnitsOfType[cat];
total_units += dest->enemyUnitsOfType[cat];
}
}
}
// skip if no enemy units found
if(total_units == 0)
return true;
my_power += (float) total_units * 0.20f;
my_power /= (float)total_units;
// get ammount of involved groups per category
total_units = 1;
for(set<AAIGroup*>::iterator group = combat_groups->begin(); group != combat_groups->end(); ++group)
{
available_combat_cat[(*group)->combat_category] += (*group)->size;
total_units += (*group)->size;
}
// get total enemy power
for(int i = 0; i < bt->combat_categories; ++i)
enemy_power += dest->GetAreaCombatPowerVs(i, 0.25) * (float)available_combat_cat[i];
enemy_power /= (float)total_units;
//fprintf(ai->file, "Checking combat power - att power / def power %f %f\n", aggressiveness * my_power, enemy_power);
if(aggressiveness * my_power >= enemy_power)
return true;
}
return false;
}
bool AAIAttackManager::SufficientDefencePowerAt(AAISector *dest, float aggressiveness)
{
if(dest)
{
// store ammount and category of involved groups;
double my_power = 0, enemy_power = 0;
int cat;
float temp, enemies = 0;
// get defence power
for(int i = 0; i < bt->combat_categories; ++i)
{
cat = (int) bt->GetAssaultCategoryOfID(i);
// only check if enemies of that category present
if(dest->enemyUnitsOfType[cat] > 0)
{
temp = 0;
enemies += dest->enemyUnitsOfType[cat];
for(list<AAIDefence>::iterator def = dest->defences.begin(); def != dest->defences.end(); ++def)
temp += bt->units_static[def->def_id].efficiency[i];
my_power += temp * dest->enemyUnitsOfType[cat];
}
}
if(enemies > 0)
my_power /= enemies;
// get enemy attack power vs buildings
enemy_power = dest->GetAreaCombatPowerVs(5, 0.5);
//fprintf(ai->file, "Checking defence power - att power / def power %f %f\n", aggressiveness * my_power, enemy_power);
if(aggressiveness * my_power >= enemy_power)
return true;
}
return false;
}
void AAIAttackManager::RallyGroups(AAIAttack *attack)
{
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -