📄 aaiexecute.cpp
字号:
// -------------------------------------------------------------------------
// AAI
//
// A skirmish AI for the TA Spring engine.
// Copyright Alexander Seizinger
//
// Released under GPL license: see LICENSE.html for more information.
// -------------------------------------------------------------------------
#include "AAIExecute.h"
#include "AAIBuildTable.h"
// all the static vars
float AAIExecute::current = 0.5;
float AAIExecute::learned = 2.5;
AAIExecute::AAIExecute(AAI *ai, AAIBrain *brain)
{
this->ai = ai;
this->cb = ai->cb;
this->bt = ai->bt;
this->brain = brain;
this->map = ai->map;
this->ut = ai->ut;
brain->execute = this;
// buildques = 0;
// factory_table = 0;
unitProductionRate = 1;
futureRequestedMetal = 0;
futureRequestedEnergy = 0;
futureAvailableMetal = 0;
futureAvailableEnergy = 0;
futureStoredMetal = 0;
futureStoredEnergy = 0;
averageMetalUsage = 0;
averageEnergyUsage = 0;
averageMetalSurplus = 0;
averageEnergySurplus = 0;
disabledMMakers = 0;
next_defence = 0;
def_category = UNKNOWN;
for(int i = 0; i <= METAL_MAKER; ++i)
urgency[i] = 0;
for(int i = 0; i < 8; i++)
{
metalSurplus[i] = 0;
energySurplus[i] = 0;
}
counter = 0;
srand( time(NULL) );
}
AAIExecute::~AAIExecute(void)
{
// if(buildques)
// {
// for(int i = 0; i < numOfFactories; ++i)
// buildques[i].clear();
// delete [] buildques;
// }
// if(factory_table)
// delete [] factory_table;
}
void AAIExecute::moveUnitTo(int unit, float3 *position)
{
Command c;
c.id = CMD_MOVE;
c.params.resize(3);
c.params[0] = position->x;
c.params[1] = position->y;
c.params[2] = position->z;
cb->GiveOrder(unit, &c);
ut->SetUnitStatus(unit, MOVING);
}
void AAIExecute::stopUnit(int unit)
{
Command c;
c.id = CMD_STOP;
cb->GiveOrder(unit, &c);
ut->SetUnitStatus(unit, UNIT_IDLE);
}
// returns true if unit is busy
bool AAIExecute::IsBusy(int unit)
{
const CCommandQueue* commands = cb->GetCurrentUnitCommands(unit);
if(commands->empty())
return false;
return true;
}
// adds a unit to the group of attackers
void AAIExecute::AddUnitToGroup(int unit_id, int def_id, UnitCategory category)
{
UnitType unit_type = bt->GetUnitType(def_id);
for(list<AAIGroup*>::iterator group = ai->group_list[category].begin(); group != ai->group_list[category].end(); ++group)
{
if((*group)->AddUnit(unit_id, def_id, unit_type))
{
ai->ut->units[unit_id].group = *group;
return;
}
}
// end of grouplist has been reached and unit has not been assigned to any group
// -> create newone
AAIGroup *new_group;
try
{
new_group = new AAIGroup(cb, ai, bt->unitList[def_id-1], unit_type);
}
catch(...) //catches everything
{
fprintf(ai->file, "Exception thrown when allocating memory for new group");
return;
}
ai->group_list[category].push_back(new_group);
new_group->AddUnit(unit_id, def_id, unit_type);
ai->ut->units[unit_id].group = new_group;
}
void AAIExecute::UpdateRecon()
{
float3 pos;
// update units in los
ai->map->UpdateRecon();
// explore map -> send scouts to different sectors, build new scouts if needed etc.
// check number of scouts and order new ones if necessary
if(ai->activeScouts + ai->futureScouts < cfg->MAX_SCOUTS)
{
int scout = 0;
float cost;
float los;
int period = brain->GetGamePeriod();
if(period == 0)
{
cost = 2;
los = 0.5;
}
else if(period == 1)
{
cost = 1;
los = 2;
}
else
{
cost = 0.5;
los = 4.0;
}
// determine movement type of scout based on map
unsigned int allowed_movement_types = 0;
allowed_movement_types |= MOVE_TYPE_AIR;
if(map->mapType == LAND_MAP)
{
allowed_movement_types |= MOVE_TYPE_GROUND;
allowed_movement_types |= MOVE_TYPE_HOVER;
}
else if(map->mapType == LAND_WATER_MAP)
{
allowed_movement_types |= MOVE_TYPE_GROUND;
allowed_movement_types |= MOVE_TYPE_SEA;
allowed_movement_types |= MOVE_TYPE_HOVER;
}
else if(map->mapType == WATER_MAP)
{
allowed_movement_types |= MOVE_TYPE_SEA;
allowed_movement_types |= MOVE_TYPE_HOVER;
}
// request cloakable scouts from time to time
if(rand()%5 == 1)
scout = bt->GetScout(ai->side, los, cost, allowed_movement_types, 10, true, true);
else
scout = bt->GetScout(ai->side, los, cost, allowed_movement_types, 10, false, true);
if(scout)
{
if(AddUnitToBuildque(scout, 1, false))
{
++ai->futureScouts;
++bt->units_dynamic[scout].requested;
//char c[120];
//sprintf(c, "requested scout: %i", ai->futureScouts);
//cb->SendTextMsg(c, 0);
}
}
}
AAISector *dest;
int scout_x, scout_y;
// get idle scouts and let them explore the map
for(list<int>::iterator scout = ai->scouts.begin(); scout != ai->scouts.end(); ++scout)
{
if(!IsBusy(*scout))
{
// get scout dest
dest = brain->GetNewScoutDest(*scout);
// get sector of scout
pos = cb->GetUnitPos(*scout);
scout_x = pos.x/map->xSectorSize;
scout_y = pos.z/map->xSectorSize;
if(dest->x > scout_x)
pos.x = (dest->left + 7 * dest->right)/8;
else if(dest->x < scout_x)
pos.x = (7 * dest->left + dest->right)/8;
else
pos.x = (dest->left + dest->right)/2;
if(dest->y > scout_y)
pos.z = (7 * dest->bottom + dest->top)/8;
else if(dest->y < scout_y)
pos.z = (dest->bottom + 7 * dest->top)/8;
else
pos.z = (dest->bottom + dest->top)/2;
pos.y = cb->GetElevation(pos.x, pos.z);
moveUnitTo(*scout, &pos);
}
}
}
float3 AAIExecute::GetBuildsite(int builder, int building, UnitCategory category)
{
float3 pos;
float3 builder_pos;
const UnitDef *def = bt->unitList[building-1];
// check the sector of the builder
builder_pos = cb->GetUnitPos(builder);
// look in the builders sector first
int x = builder_pos.x/ai->map->xSectorSize;
int y = builder_pos.z/ai->map->ySectorSize;
if(ai->map->sector[x][y].distance_to_base == 0)
{
pos = ai->map->sector[x][y].GetBuildsite(building);
// if suitable location found, return pos...
if(pos.x)
return pos;
}
// look in any of the base sectors
for(list<AAISector*>::iterator s = brain->sectors[0].begin(); s != brain->sectors[0].end(); ++s)
{
pos = (*s)->GetBuildsite(building);
// if suitable location found, return pos...
if(pos.x)
return pos;
}
pos.x = pos.y = pos.z = 0;
return pos;
}
float3 AAIExecute::GetUnitBuildsite(int builder, int unit)
{
float3 builder_pos = cb->GetUnitPos(builder);
float3 pos = ZeroVector, best_pos = ZeroVector;
float min_dist = 1000000, dist;
for(list<AAISector*>::iterator s = brain->sectors[1].begin(); s != brain->sectors[1].end(); ++s)
{
bool water = false;
if(bt->IsSea(unit))
water = true;
pos = (*s)->GetBuildsite(unit, water);
if(pos.x)
{
dist = sqrt( pow(pos.x - best_pos.x ,2.0f) + pow(pos.z - best_pos.z, 2.0f) );
if(dist < min_dist)
{
min_dist = dist;
best_pos = pos;
}
}
}
return best_pos;
}
AAIMetalSpot* AAIExecute::FindMetalSpot(bool land, bool water)
{
// prevent crashes on smaller maps
int max_distance = min(cfg->MAX_MEX_DISTANCE, brain->max_distance);
for(int sector_dist = 0; sector_dist < max_distance; ++sector_dist)
{
for(list<AAISector*>::iterator sector = brain->sectors[sector_dist].begin();sector != brain->sectors[sector_dist].end(); sector++)
{
if(sector_dist == 0)
{
if((*sector)->freeMetalSpots)
{
for(list<AAIMetalSpot*>::iterator spot = (*sector)->metalSpots.begin(); spot != (*sector)->metalSpots.end(); ++spot)
{
if(!(*spot)->occupied)
{
if( (land && (*spot)->pos.y >= 0) ||(water && (*spot)->pos.y < 0) )
return *spot;
}
}
}
}
else
{
if((*sector)->freeMetalSpots && brain->IsSafeSector(*sector) && map->team_sector_map[(*sector)->x][(*sector)->y] == -1 )
{
for(list<AAIMetalSpot*>::iterator spot = (*sector)->metalSpots.begin(); spot != (*sector)->metalSpots.end(); ++spot)
{
if(!(*spot)->occupied)
{
if( (land && (*spot)->pos.y >= 0) ||(water && (*spot)->pos.y < 0) )
return *spot;
}
}
}
}
}
}
return 0;
}
AAIMetalSpot* AAIExecute::FindMetalSpotClosestToBuilder(int land_mex, int water_mex)
{
AAIMetalSpot *best_spot = 0;
float shortest_dist = 10000.0f, dist;
float3 builder_pos;
AAIConstructor *builder = 0;
// prevent crashes on smaller maps
int max_distance = min(cfg->MAX_MEX_DISTANCE, brain->max_distance);
// dont search for too long if possible spot already found
int min_spot_dist = -1;
// look for free spots in all sectors within max range
for(int sector_dist = 0; sector_dist < max_distance; ++sector_dist)
{
// skip search if spot already found
if(min_spot_dist >= 0 && sector_dist - min_spot_dist > 2)
return best_spot;
for(list<AAISector*>::iterator sector = brain->sectors[sector_dist].begin(); sector != brain->sectors[sector_dist].end(); sector++)
{
if((*sector)->freeMetalSpots && (*sector)->enemy_structures <= 0 && (*sector)->lost_units[MOBILE_CONSTRUCTOR-COMMANDER] < 0.5 && (*sector)->threat <= 0)
{
for(list<AAIMetalSpot*>::iterator spot = (*sector)->metalSpots.begin(); spot != (*sector)->metalSpots.end(); ++spot)
{
if(!(*spot)->occupied)
{
if((*spot)->pos.y > 0)
builder = ut->FindClosestBuilder(land_mex, (*spot)->pos, true, 10);
else
builder = ut->FindClosestBuilder(water_mex, (*spot)->pos, true, 10);
if(builder)
{
// get distance to pos
builder_pos = cb->GetUnitPos(builder->unit_id);
dist = sqrt( pow(((*spot)->pos.x - builder_pos.x), 2) + pow(((*spot)->pos.z - builder_pos.z),2) ) / bt->unitList[builder->def_id-1]->speed;
if(dist < shortest_dist)
{
best_spot = *spot;
shortest_dist = dist;
min_spot_dist = sector_dist;
}
}
}
}
}
}
}
return best_spot;
}
float AAIExecute::GetTotalGroundPower()
{
float power = 0;
// get ground power of all ground assault units
for(list<AAIGroup*>::iterator group = ai->group_list[GROUND_ASSAULT].begin(); group != ai->group_list[GROUND_ASSAULT].end(); group++)
power += (*group)->GetPowerVS(0);
return power;
}
float AAIExecute::GetTotalAirPower()
{
float power = 0;
for(list<AAIGroup*>::iterator group = ai->group_list[GROUND_ASSAULT].begin(); group != ai->group_list[GROUND_ASSAULT].end(); group++)
{
power += (*group)->GetPowerVS(1);
}
return power;
}
list<int>* AAIExecute::GetBuildqueOfFactory(int def_id)
{
for(int i = 0; i < numOfFactories; ++i)
{
if(factory_table[i] == def_id)
return &buildques[i];
}
return 0;
}
bool AAIExecute::AddUnitToBuildque(int def_id, int number, bool urgent)
{
urgent = false;
UnitCategory category = bt->units_static[def_id].category;
if(category == UNKNOWN)
return false;
list<int> *buildque = 0, *temp = 0;
float my_rating, best_rating = 0;
for(list<int>::iterator fac = bt->units_static[def_id].builtByList.begin(); fac != bt->units_static[def_id].builtByList.end(); ++fac)
{
if(bt->units_dynamic[*fac].active > 0)
{
temp = GetBuildqueOfFactory(*fac);
if(temp)
{
my_rating = (1 + 2 * (float) bt->units_dynamic[*fac].active) / (temp->size() + 3);
if(map->mapType == WATER_MAP && !bt->CanPlacedWater(*fac))
my_rating /= 10.0;
}
else
my_rating = 0;
}
else
my_rating = 0;
if(my_rating > best_rating)
{
best_rating = my_rating;
buildque = temp;
}
}
// determine position
if(buildque)
{
//fprintf(ai->file, "Found builque for %s\n", bt->unitList[def_id-1]->humanName.c_str());
if(bt->IsBuilder(def_id))
{
buildque->insert(buildque->begin(), number, def_id);
return true;
}
else if(category == SCOUT)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -