📄 aaisector.cpp
字号:
// ------------------------------------------------------------------------
// AAI
//
// A skirmish AI for the TA Spring engine.
// Copyright Alexander Seizinger
//
// Released under GPL license: see LICENSE.html for more information.
// ------------------------------------------------------------------------
#include "AAISector.h"
#include "AAI.h"
#include "AAIMap.h"
AAISector::AAISector()
{
}
AAISector::~AAISector(void)
{
defences.clear();
attacked_by_this_game.clear();
attacked_by_learned.clear();
stat_combat_power.clear();
mobile_combat_power.clear();
combats_learned.clear();
combats_this_game.clear();
lost_units.clear();
}
void AAISector::Init(AAI *ai, int x, int y, int left, int right, int top, int bottom)
{
this->ai = ai;
this->ut = ai->ut;
this->map = ai->map;
// set coordinates of the corners
this->x = x;
this->y = y;
this->left = left;
this->right = right;
this->top = top;
this->bottom = bottom;
// init all kind of stuff
freeMetalSpots = false;
interior = false;
distance_to_base = -1;
last_scout = 1;
// nothing sighted in that sector
enemy_structures = 0;
own_structures = 0;
allied_structures = 0;
threat = 0;
failed_defences = 0;
int categories = ai->bt->assault_categories.size();
combats_learned.resize(categories, 0);
combats_this_game.resize(categories, 0);
importance_this_game = 1.0f + (rand()%5)/20.0f;
attacked_by_this_game.resize(categories, 0);
attacked_by_learned.resize(categories, 0);
lost_units.resize((int)MOBILE_CONSTRUCTOR-(int)COMMANDER+1.0);
enemyUnitsOfType.resize((int)MOBILE_CONSTRUCTOR+1, 0);
unitsOfType.resize((int)MOBILE_CONSTRUCTOR+1, 0);
stat_combat_power.resize(categories, 0);
mobile_combat_power.resize(categories+1, 0);
}
void AAISector::AddMetalSpot(AAIMetalSpot *spot)
{
metalSpots.push_back(spot);
freeMetalSpots = true;
}
int AAISector::GetNumberOfMetalSpots()
{
return metalSpots.size();
}
bool AAISector::SetBase(bool base)
{
if(base)
{
// check if already occupied (may happen if two coms start in same sector)
if(map->team_sector_map[x][y] >= 0)
{
fprintf(ai->file, "\nTeam %i could not add sector %i,%i to base, already occupied by ally team %i!\n\n",ai->cb->GetMyTeam(), x, y, map->team_sector_map[x][y]);
return false;
}
distance_to_base = 0;
// if free metal spots in this sectors, base has free spots
for(list<AAIMetalSpot*>::iterator spot = metalSpots.begin(); spot != metalSpots.end(); ++spot)
{
if(!(*spot)->occupied)
{
ai->brain->freeBaseSpots = true;
break;
}
}
// increase importance
importance_this_game += 1;
map->team_sector_map[x][y] = ai->cb->GetMyAllyTeam();
if(importance_this_game > cfg->MAX_SECTOR_IMPORTANCE)
importance_this_game = cfg->MAX_SECTOR_IMPORTANCE;
return true;
}
else // remove from base
{
distance_to_base = 1;
map->team_sector_map[x][y] = -1;
return true;
}
}
void AAISector::Update()
{
// decrease values (so the ai "forgets" values from time to time)...
//ground_threat *= 0.995;
//air_threat *= 0.995;
for(int i = 0; i < MOBILE_CONSTRUCTOR-COMMANDER; ++i)
lost_units[i] *= 0.92f;
}
AAIMetalSpot* AAISector::GetFreeMetalSpot()
{
// look for the first unoccupied metalspot
for(list<AAIMetalSpot*>::iterator i = metalSpots.begin(); i != metalSpots.end(); i++)
{
// if metalspot is occupied, try next one
if(!(*i)->occupied)
return *i;
}
return 0;
}
void AAISector::FreeMetalSpot(float3 pos, const UnitDef *extractor)
{
float3 spot_pos;
// get metalspot according to position
for(list<AAIMetalSpot*>::iterator spot = metalSpots.begin(); spot != metalSpots.end(); ++spot)
{
// only check occupied spots
if((*spot)->occupied)
{
// compare positions
spot_pos = (*spot)->pos;
ai->map->Pos2FinalBuildPos(&spot_pos, extractor);
if(pos.x == spot_pos.x && pos.z == spot_pos.z)
{
(*spot)->occupied = false;
(*spot)->extractor = -1;
(*spot)->extractor_def = -1;
freeMetalSpots = true;
// if part of the base, tell the brain that the base has now free spots again
if(distance_to_base == 0)
ai->brain->freeBaseSpots = true;
return;
}
}
}
}
void AAISector::AddExtractor(int unit_id, int def_id, float3 *pos)
{
float3 spot_pos;
// get metalspot according to position
for(list<AAIMetalSpot*>::iterator spot = metalSpots.begin(); spot != metalSpots.end(); ++spot)
{
// only check occupied spots
if((*spot)->occupied)
{
// compare positions
spot_pos = (*spot)->pos;
ai->map->Pos2FinalBuildPos(&spot_pos, ai->bt->unitList[def_id-1]);
if(pos->x == spot_pos.x && pos->z == spot_pos.z)
{
(*spot)->extractor = unit_id;
(*spot)->extractor_def = def_id;
}
}
}
}
float3 AAISector::GetCenter()
{
float3 pos;
pos.x = (left + right)/2.0;
pos.z = (top + bottom)/2.0;
return pos;
}
float3 AAISector::GetBuildsite(int building, bool water)
{
int xStart, xEnd, yStart, yEnd;
GetBuildsiteRectangle(&xStart, &xEnd, &yStart, &yEnd);
return map->GetBuildSiteInRect(ai->bt->unitList[building-1], xStart, xEnd, yStart, yEnd, water);
}
float3 AAISector::GetDefenceBuildsite(int building, UnitCategory category, float terrain_modifier, bool water)
{
float3 best_pos = ZeroVector, pos;
const UnitDef *def = ai->bt->unitList[building-1];
int my_team = ai->cb->GetMyAllyTeam();
float my_rating, best_rating = -10000;
list<Direction> directions;
// get possible directions
if(category == AIR_ASSAULT && !cfg->AIR_ONLY_MOD)
{
directions.push_back(CENTER);
}
else
{
if(distance_to_base > 0)
directions.push_back(CENTER);
else
{
// filter out frontiers to other base sectors
if(x > 0 && map->sector[x-1][y].distance_to_base > 0 && map->sector[x-1][y].allied_structures < 100 && map->team_sector_map[x-1][y] != my_team )
directions.push_back(WEST);
if(x < map->xSectors-1 && map->sector[x+1][y].distance_to_base > 0 && map->sector[x+1][y].allied_structures < 100 && map->team_sector_map[x+1][y] != my_team)
directions.push_back(EAST);
if(y > 0 && map->sector[x][y-1].distance_to_base > 0 && map->sector[x][y-1].allied_structures < 100 && map->team_sector_map[x][y-1] != my_team)
directions.push_back(NORTH);
if(y < map->ySectors-1 && map->sector[x][y+1].distance_to_base > 0 && map->sector[x][y+1].allied_structures < 100 && map->team_sector_map[x][y+1] != my_team)
directions.push_back(SOUTH);
}
}
int xStart = 0;
int xEnd = 0;
int yStart = 0;
int yEnd = 0;
// check possible directions
for(list<Direction>::iterator dir =directions.begin(); dir != directions.end(); ++dir)
{
// get area to perform search
if(*dir == CENTER)
{
xStart = x * map->xSectorSizeMap;
xEnd = (x+1) * map->xSectorSizeMap;
yStart = y * map->ySectorSizeMap;
yEnd = (y+1) * map->ySectorSizeMap;
}
else if(*dir == WEST)
{
xStart = x * map->xSectorSizeMap;
xEnd = x * map->xSectorSizeMap + map->xSectorSizeMap/4.0f;
yStart = y * map->ySectorSizeMap;
yEnd = (y+1) * map->ySectorSizeMap;
}
else if(*dir == EAST)
{
xStart = (x+1) * map->xSectorSizeMap - map->xSectorSizeMap/4.0f;
xEnd = (x+1) * map->xSectorSizeMap;
yStart = y * map->ySectorSizeMap;
yEnd = (y+1) * map->ySectorSizeMap;
}
else if(*dir == NORTH)
{
xStart = x * map->xSectorSizeMap;
xEnd = (x+1) * map->xSectorSizeMap;
yStart = y * map->ySectorSizeMap;
yEnd = y * map->ySectorSizeMap + map->ySectorSizeMap/4.0f;
}
else if(*dir == SOUTH)
{
xStart = x * map->xSectorSizeMap ;
xEnd = (x+1) * map->xSectorSizeMap;
yStart = (y+1) * map->ySectorSizeMap - map->ySectorSizeMap/4.0f;
yEnd = (y+1) * map->ySectorSizeMap;
}
//
my_rating = map->GetDefenceBuildsite(&pos, def, xStart, xEnd, yStart, yEnd, category, terrain_modifier, water);
if(my_rating > best_rating)
{
best_pos = pos;
best_rating = my_rating;
}
}
return best_pos;
}
float3 AAISector::GetCenterBuildsite(int building, bool water)
{
int xStart, xEnd, yStart, yEnd;
GetBuildsiteRectangle(&xStart, &xEnd, &yStart, &yEnd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -