📄 aaibrain.cpp
字号:
// -------------------------------------------------------------------------
// AAI
//
// A skirmish AI for the TA Spring engine.
// Copyright Alexander Seizinger
//
// Released under GPL license: see LICENSE.html for more information.
// -------------------------------------------------------------------------
#include "AAIBrain.h"
#include "AAI.h"
#include "AAIMap.h"
AAIBrain::AAIBrain(AAI *ai)
{
this->ai = ai;
this->map = ai->map;
cb = ai->cb;
bt = ai->bt;
execute = 0;
freeBaseSpots = false;
expandable = true;
// initialize random numbers generator
srand ( time(NULL) );
max_distance = ai->map->xSectors + ai->map->ySectors - 2;
// sectors = new list<AAISector*>[max_distance];
sectors.resize(max_distance);
base_center = ZeroVector;
// max_units_spotted = new float[bt->combat_categories];
max_units_spotted.resize(bt->combat_categories);
// attacked_by = new float[bt->combat_categories];
attacked_by.resize(bt->combat_categories);
// defence_power_vs = new float[bt->combat_categories];
defence_power_vs.resize(bt->combat_categories);
for(int i = 0; i < bt->combat_categories; ++i)
{
max_units_spotted[i] = 0;
attacked_by[i] = 0;
defence_power_vs[i] = 0;
}
}
AAIBrain::~AAIBrain(void)
{
// delete [] sectors;
// delete [] max_units_spotted;
// delete [] attacked_by;
// delete [] defence_power_vs;
}
AAISector* AAIBrain::GetAttackDest(bool land, bool water, AttackType type)
{
float best_rating = 0, my_rating;
AAISector *dest = 0, *sector;
int side = ai->side-1;
float ground = map->map_usefulness[0][side]/100.0f;
float air = map->map_usefulness[1][side]/100.0f;
float hover = map->map_usefulness[2][side]/100.0f;
float sea = map->map_usefulness[3][side]/100.0f;
float submarine = map->map_usefulness[4][side]/100.0f;
// TODO: improve destination sector selection
for(int x = 0; x < map->xSectors; x++)
{
for(int y = 0; y < map->ySectors; y++)
{
sector = &map->sector[x][y];
if(sector->distance_to_base == 0 || sector->enemy_structures == 0)
my_rating = 0;
else if(type == BASE_ATTACK)
{
if(land && sector->water_ratio < 0.35)
{
my_rating = sector->enemy_structures / (2 * sector->GetThreatTo(ground, air, hover, sea, submarine) + pow(sector->GetLostUnits(ground, air, hover, sea, submarine) + 1, 1.5f) + 1);
my_rating /= (8 + sector->distance_to_base);
}
else if(water && sector->water_ratio > 0.65)
{
my_rating = sector->enemy_structures / (2 * sector->GetThreatTo(ground, air, hover, sea, submarine) + pow(sector->GetLostUnits(ground, air, hover, sea, submarine) + 1, 1.5f) + 1);
my_rating /= (8 + sector->distance_to_base);
}
else
my_rating = 0;
}
else if(type == OUTPOST_ATTACK)
{
if(land && sector->water_ratio < 0.35)
{
my_rating = 1 / (1 + pow(sector->GetThreatTo(ground, air, hover, sea, submarine), 2.0f) + pow(sector->GetLostUnits(ground, air, hover, sea, submarine) + 1, 1.5f));
my_rating /= (2 + sector->distance_to_base);
}
else if(water && sector->water_ratio > 0.65)
{
my_rating = 1 / (1 + pow(sector->GetThreatTo(ground, air, hover, sea, submarine), 2.0f) + pow(sector->GetLostUnits(ground, air, hover, sea, submarine) + 1, 1.5f));
my_rating /= (2 + sector->distance_to_base);
}
else
my_rating = 0;
}
if(my_rating > best_rating)
{
dest = sector;
best_rating = my_rating;
}
}
}
return dest;
}
AAISector* AAIBrain::GetNextAttackDest(AAISector *current_sector, bool land, bool water)
{
float best_rating = 0, my_rating, dist;
AAISector *dest = 0, *sector;
int side = ai->side-1;
float ground = map->map_usefulness[0][side]/100.0f;
float air = map->map_usefulness[1][side]/100.0f;
float hover = map->map_usefulness[2][side]/100.0f;
float sea = map->map_usefulness[3][side]/100.0f;
float submarine = map->map_usefulness[4][side]/100.0f;
// TODO: improve destination sector selection
for(int x = 0; x < map->xSectors; x++)
{
for(int y = 0; y < map->ySectors; y++)
{
sector = &map->sector[x][y];
if(sector->distance_to_base == 0 || sector->enemy_structures == 0)
my_rating = 0;
else
{
if(land && sector->water_ratio < 0.35)
{
dist = sqrt( pow((float)sector->x - current_sector->x, 2) + pow((float)sector->y - current_sector->y , 2) );
my_rating = 1 / (1 + pow(sector->GetThreatTo(ground, air, hover, sea, submarine), 2.0f) + pow(sector->GetLostUnits(ground, air, hover, sea, submarine) + 1, 1.5f));
}
else if(water && sector->water_ratio > 0.65)
{
dist = sqrt( pow((float)(sector->x - current_sector->x), 2) + pow((float)(sector->y - current_sector->y), 2) );
my_rating = 1 / (1 + pow(sector->GetThreatTo(ground, air, hover, sea, submarine), 2.0f) + pow(sector->GetLostUnits(ground, air, hover, sea, submarine) + 1, 1.5f));
my_rating /= (1 + dist);
}
else
my_rating = 0;
}
if(my_rating > best_rating)
{
dest = sector;
best_rating = my_rating;
}
}
}
return dest;
}
AAISector* AAIBrain::GetNewScoutDest(int scout)
{
// TODO: take scouts pos into account
float my_rating, best_rating = 0;
AAISector *scout_sector = 0, *sector;
const UnitDef *def = cb->GetUnitDef(scout);
for(int x = 0; x < map->xSectors; x++)
{
for(int y = 0; y < map->ySectors; y++)
{
sector = &map->sector[x][y];
if(sector->distance_to_base > 0)
{
// land sector
if(sector->water_ratio > 0.7)
{
if(! (bt->units_static[def->id].movement_type & MOVE_TYPE_GROUND))
{
my_rating = sector->importance_this_game * sector->last_scout;
++sector->last_scout;
}
else
my_rating = 0;
}
// water sector
else if(sector->water_ratio < 0.3)
{
if(! (bt->units_static[def->id].movement_type & MOVE_TYPE_SEA))
{
my_rating = sector->importance_this_game * sector->last_scout;
++sector->last_scout;
}
else
my_rating = 0;
}
// land/water sector
else
{
my_rating = sector->importance_this_game * sector->last_scout;
++sector->last_scout;
}
if(my_rating > best_rating)
{
best_rating = my_rating;
scout_sector = sector;
}
}
}
}
// set dest sector as visited
if(scout_sector)
scout_sector->last_scout = 1;
return scout_sector;
}
bool AAIBrain::MetalForConstr(int unit, int workertime)
{
// check index
if(unit >= bt->numOfUnits)
{
fprintf(ai->file, "ERROR: MetalForConstr(): index %i out of range, max units are: %i\n", unit, bt->numOfSides);
return false;
}
int metal = (bt->unitList[unit-1]->buildTime/workertime) * (cb->GetMetalIncome()-(cb->GetMetalUsage()) + cb->GetMetal());
int total_cost = bt->unitList[unit-1]->metalCost;
if(metal > total_cost)
return true;
return false;
}
bool AAIBrain::EnergyForConstr(int unit, int wokertime)
{
// check index
if(unit >= bt->numOfUnits)
{
fprintf(ai->file, "ERROR: EnergyForConstr(): index %i out of range, max units are: %i\n", unit, bt->numOfSides);
return false;
}
// check energy
int energy = bt->unitList[unit-1]->buildTime * (cb->GetEnergyIncome()-(cb->GetEnergyUsage()/2));
return true;
//return (energy > bt->unitList[unit-1]->energyCost);
}
bool AAIBrain::RessourcesForConstr(int unit, int wokertime)
{
// check metal and energy
/*if(MetalForConstr(unit) && EnergyForConstr(unit))
return true;
return false;*/
return true;
}
void AAIBrain::AddSector(AAISector *sector)
{
sectors[0].push_back(sector);
sector->SetBase(true);
}
void AAIBrain::DefendCommander(int attacker)
{
float3 pos = cb->GetUnitPos(ai->ut->cmdr);
float importance = 120;
Command c;
// evacuate cmdr
/*if(ai->cmdr->task != BUILDING)
{
AAISector *sector = GetSafestSector();
if(sector != 0)
{
pos = sector->GetCenter();
if(pos.x > 0 && pos.z > 0)
{
pos.y = cb->GetElevation(pos.x, pos.z);
execute->moveUnitTo(ai->cmdr->unit_id, &pos);
}
}
}*/
}
void AAIBrain::UpdateBaseCenter()
{
base_center = ZeroVector;
for(list<AAISector*>::iterator sector = sectors[0].begin(); sector != sectors[0].end(); ++sector)
{
base_center.x += (0.5 + (*sector)->x) * map->xSectorSize;
base_center.z += (0.5 + (*sector)->y) * map->ySectorSize;
}
base_center.x /= sectors[0].size();
base_center.z /= sectors[0].size();
}
void AAIBrain::UpdateNeighbouringSectors()
{
int x,y,neighbours;
// delete old values
for(x = 0; x < map->xSectors; ++x)
{
for(y = 0; y < map->ySectors; ++y)
{
if(map->sector[x][y].distance_to_base > 0)
map->sector[x][y].distance_to_base = -1;
}
}
for(int i = 1; i < max_distance; ++i)
{
// delete old sectors
sectors[i].clear();
neighbours = 0;
for(list<AAISector*>::iterator sector = sectors[i-1].begin(); sector != sectors[i-1].end(); ++sector)
{
x = (*sector)->x;
y = (*sector)->y;
// check left neighbour
if(x > 0 && map->sector[x-1][y].distance_to_base == -1)
{
map->sector[x-1][y].distance_to_base = i;
sectors[i].push_back(&map->sector[x-1][y]);
++neighbours;
}
// check right neighbour
if(x < (ai->map->xSectors - 1) && ai->map->sector[x+1][y].distance_to_base == -1)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -