📄 aaibuildtable.cpp
字号:
// -------------------------------------------------------------------------
// AAI
//
// A skirmish AI for the TA Spring engine.
// Copyright Alexander Seizinger
//
// Released under GPL license: see LICENSE.html for more information.
// -------------------------------------------------------------------------
#include "AAIBuildTable.h"
#include "AAI.h"
// all the static vars
const UnitDef** AAIBuildTable::unitList = 0;
list<int>* AAIBuildTable::units_of_category[MOBILE_CONSTRUCTOR+1];
int AAIBuildTable::aai_instances = 0;
float* AAIBuildTable::avg_cost[MOBILE_CONSTRUCTOR+1];
float* AAIBuildTable::avg_buildtime[MOBILE_CONSTRUCTOR+1];
float* AAIBuildTable::avg_value[MOBILE_CONSTRUCTOR+1];
float* AAIBuildTable::max_cost[MOBILE_CONSTRUCTOR+1];
float* AAIBuildTable::max_buildtime[MOBILE_CONSTRUCTOR+1];
float* AAIBuildTable::max_value[MOBILE_CONSTRUCTOR+1];
float* AAIBuildTable::min_cost[MOBILE_CONSTRUCTOR+1];
float* AAIBuildTable::min_buildtime[MOBILE_CONSTRUCTOR+1];
float* AAIBuildTable::min_value[MOBILE_CONSTRUCTOR+1];
float** AAIBuildTable::avg_speed;
float** AAIBuildTable::min_speed;
float** AAIBuildTable::max_speed;
float** AAIBuildTable::group_speed;
float** AAIBuildTable::attacked_by_category[2];
float*** AAIBuildTable::mod_usefulness;
vector<UnitTypeStatic> AAIBuildTable::units_static;
vector<vector<double> >AAIBuildTable::def_power;
vector<double>AAIBuildTable::max_pplant_eff;
float* AAIBuildTable::max_builder_buildtime;
float* AAIBuildTable::max_builder_cost;
float* AAIBuildTable::max_builder_buildspeed;
vector< vector< vector<float> > > AAIBuildTable::avg_eff;
vector< vector< vector<float> > > AAIBuildTable::max_eff;
vector< vector< vector<float> > > AAIBuildTable::min_eff;
vector< vector< vector<float> > > AAIBuildTable::total_eff;
vector< vector<float> > AAIBuildTable::fixed_eff;
AAIBuildTable::AAIBuildTable(IAICallback *cb, AAI* ai)
{
this->cb = cb;
this->ai = ai;
initialized = false;
numOfUnits = 0;
numOfSides = cfg->SIDES;
startUnits.resize(numOfSides);
sideNames.resize(numOfSides+1);
sideNames[0] = "Neutral";
const UnitDef *temp;
for(int i = 0; i < numOfSides; i++)
{
temp = cb->GetUnitDef(cfg->START_UNITS[i]);
if(temp)
startUnits[i] = temp->id;
else
{
startUnits[i] = -1;
char c[120];
sprintf(c, "Error: starting unit %s not found\n", cfg->START_UNITS[i]);
cb->SendTextMsg(c,0);
fprintf(ai->file, c);
}
sideNames[i+1].assign(cfg->SIDE_NAMES[i]);
}
// add assault categories
assault_categories.push_back(GROUND_ASSAULT);
assault_categories.push_back(AIR_ASSAULT);
assault_categories.push_back(HOVER_ASSAULT);
assault_categories.push_back(SEA_ASSAULT);
assault_categories.push_back(SUBMARINE_ASSAULT);
//ass_categories = (int)assault_categories.size();
//combat_categories = ass_categories + 1;
// one more instance
++aai_instances;
ai->aai_instance = aai_instances;
// only set up static things if first aai intsance is iniatialized
if(aai_instances == 1)
{
for(int i = 0; i <= MOBILE_CONSTRUCTOR; ++i)
{
// set up the unit lists
units_of_category[i] = new list<int>[numOfSides];
// statistical values (mod sepcific)
avg_cost[i] = new float[numOfSides];
avg_buildtime[i] = new float[numOfSides];
avg_value[i] = new float[numOfSides];
max_cost[i] = new float[numOfSides];
max_buildtime[i] = new float[numOfSides];
max_value[i] = new float[numOfSides];
min_cost[i] = new float[numOfSides];
min_buildtime[i] = new float[numOfSides];
min_value[i] = new float[numOfSides];
for(int s = 0; s < numOfSides; ++s)
{
avg_cost[i][s] = -1;
avg_buildtime[i][s] = -1;
avg_value[i][s] = -1;
max_cost[i][s] = -1;
max_buildtime[i][s] = -1;
max_value[i][s] = -1;
min_cost[i][s] = -1;
min_buildtime[i][s] = -1;
min_value[i][s] = -1;
}
}
// statistical values for builders (map specific)
max_builder_buildtime = new float[numOfSides];
max_builder_cost = new float[numOfSides];
max_builder_buildspeed = new float[numOfSides];
for(int s = 0; s < numOfSides; ++s)
{
max_builder_buildtime[s] = -1;
max_builder_cost[s] = -1;
max_builder_buildspeed[s] = -1;
}
// set up speed and attacked_by table
avg_speed = new float*[combat_categories];
max_speed = new float*[combat_categories];
min_speed = new float*[combat_categories];
group_speed = new float*[combat_categories];
attacked_by_category[0] = new float*[combat_categories];
attacked_by_category[1] = new float*[combat_categories];
for(int i = 0; i < combat_categories; ++i)
{
avg_speed[i] = new float[numOfSides];
max_speed[i] = new float[numOfSides];
min_speed[i] = new float[numOfSides];
group_speed[i] = new float[numOfSides];
attacked_by_category[0][i] = new float[4];
attacked_by_category[1][i] = new float[4];
}
// set up mod_usefulness
mod_usefulness = new float**[assault_categories.size()];
for(int i = 0; i < assault_categories.size(); ++i)
{
mod_usefulness[i] = new float*[cfg->SIDES];
for(int j = 0; j < cfg->SIDES; ++j)
mod_usefulness[i][j] = new float[WATER_MAP+1];
}
// init eff stats
avg_eff.resize(numOfSides, vector< vector<float> >(combat_categories, vector<float>(combat_categories, 1)));
max_eff.resize(numOfSides, vector< vector<float> >(combat_categories, vector<float>(combat_categories, 1)));
min_eff.resize(numOfSides, vector< vector<float> >(combat_categories, vector<float>(combat_categories, 1)));
total_eff.resize(numOfSides, vector< vector<float> >(combat_categories, vector<float>(combat_categories, 1)));
}
}
AAIBuildTable::~AAIBuildTable(void)
{
// one instance less
--aai_instances;
// delete common data only if last aai instace has gone
if(aai_instances == 0)
{
delete [] unitList;
for(int i = 0; i <= MOBILE_CONSTRUCTOR; ++i)
{
delete [] units_of_category[i];
delete [] avg_cost[i];
delete [] avg_buildtime[i];
delete [] avg_value[i];
delete [] max_cost[i];
delete [] max_buildtime[i];
delete [] max_value[i];
delete [] min_cost[i];
delete [] min_buildtime[i];
delete [] min_value[i];
}
delete [] max_builder_buildtime;
delete [] max_builder_cost;
delete [] max_builder_buildspeed;
for(int i = 0; i < combat_categories; ++i)
{
delete [] avg_speed[i];
delete [] max_speed[i];
delete [] min_speed[i];
delete [] group_speed[i];
delete [] attacked_by_category[0][i];
delete [] attacked_by_category[1][i];
}
delete [] avg_speed;
delete [] max_speed;
delete [] min_speed;
delete [] group_speed;
delete [] attacked_by_category[0];
delete [] attacked_by_category[1];
// clean up mod usefulness
for(int i = 0; i < assault_categories.size(); ++i)
{
for(int j = 0; j < cfg->SIDES; ++j)
delete [] mod_usefulness[i][j];
delete [] mod_usefulness[i];
}
delete [] mod_usefulness;
avg_eff.clear();
max_eff.clear();
min_eff.clear();
total_eff.clear();
}
}
void AAIBuildTable::Init()
{
float max_cost = 0, min_cost = 1000000, eff;
// initialize random numbers generator
srand ( time(NULL) );
// get number of units and alloc memory for unit list
numOfUnits = cb->GetNumUnitDefs();
// one more than needed because 0 is dummy object (so UnitDef->id can be used to adress that unit in the array)
units_dynamic.resize(numOfUnits+1);
for(int i = 0; i <= numOfUnits; i++)
{
units_dynamic[i].active = 0;
units_dynamic[i].requested = 0;
units_dynamic[i].buildersAvailable = 0;
units_dynamic[i].buildersRequested = 0;
}
// get unit defs from game
if(!unitList)
{
unitList = new const UnitDef*[numOfUnits];
cb->GetUnitDefList(unitList);
}
// Try to load buildtable, if not possible create new one
if(!LoadBuildTable())
{
// one more than needed because 0 is dummy object (so UnitDef->id can be used to adress that unit in the array)
units_static.resize(numOfUnits+1);
fixed_eff.resize(numOfUnits+1, vector<float>(combat_categories));
// temporary list to sort air unit in air only mods
list<int> *temp_list;
temp_list = new list<int>[numOfSides];
units_static[0].def_id = 0;
units_static[0].side = 0;
// add units to buildtable
for(int i = 1; i <= numOfUnits; ++i)
{
// get id
units_static[i].def_id = unitList[i-1]->id;
units_static[i].cost = (unitList[i-1]->metalCost + (unitList[i-1]->energyCost / 75.0f)) / 10.0f;
if(units_static[i].cost > max_cost)
max_cost = units_static[i].cost;
if(units_static[i].cost < min_cost)
min_cost = units_static[i].cost;
units_static[i].builder_cost = 0; // will be added later when calculating the buildtree
// side has not been assigned - will be done later
units_static[i].side = 0;
units_static[i].range = 0;
units_static[i].category = UNKNOWN;
units_static[i].unit_type = 0;
// get build options
for(map<int, string>::const_iterator j = unitList[i-1]->buildOptions.begin(); j != unitList[i-1]->buildOptions.end(); ++j)
{
units_static[i].canBuildList.push_back(cb->GetUnitDef(j->second.c_str())->id);
}
}
// now set the sides and create buildtree
for(int s = 0; s < numOfSides; s++)
{
// set side of the start unit (eg commander) and continue recursively
units_static[startUnits[s]].side = s+1;
CalcBuildTree(startUnits[s]);
}
// now calculate efficiency of combat units and get max range
for(int i = 1; i <= numOfUnits; i++)
{
// effiency has starting value of 1
if(!unitList[i-1]->weapons.empty())
{
// get range
units_static[i].range = GetMaxRange(i);
// get memory for eff
// units_static[i].efficiency = new float[combat_categories];
units_static[i].efficiency.resize(combat_categories);
eff = 5 + 25 * (units_static[i].cost - min_cost)/(max_cost - min_cost);
for(int k = 0; k < combat_categories; ++k)
{
units_static[i].efficiency[k] = eff;
fixed_eff[i][k] = eff;
}
}
else
{
units_static[i].range = 0;
// get memory for eff
// units_static[i].efficiency = new float[combat_categories];
units_static[i].efficiency.resize(combat_categories);
for(int k = 0; k < combat_categories; ++k)
units_static[i].efficiency[k] = -1;
}
}
//
// determine movement type
//
for(int i = 1; i <= numOfUnits; i++)
{
units_static[i].movement_type = 0;
if(unitList[i-1]->movedata)
{
if(unitList[i-1]->movedata->moveType == MoveData::Ground_Move)
units_static[i].movement_type |= MOVE_TYPE_GROUND;
else if(unitList[i-1]->movedata->moveType == MoveData::Hover_Move)
units_static[i].movement_type |= MOVE_TYPE_HOVER;
// ship
else if(unitList[i-1]->movedata->moveType == MoveData::Ship_Move)
{
units_static[i].movement_type |= MOVE_TYPE_SEA;
if(unitList[i-1]->categoryString.find("UNDERWATER") != string::npos)
units_static[i].movement_type |= MOVE_TYPE_UNDERWATER;
else
units_static[i].movement_type |= MOVE_TYPE_FLOATER;
}
}
// aircraft
else if(unitList[i-1]->canfly)
units_static[i].movement_type |= MOVE_TYPE_AIR;
// stationary
else
{
units_static[i].movement_type |= MOVE_TYPE_STATIC;
if(unitList[i-1]->minWaterDepth <= 0)
{
units_static[i].movement_type |= MOVE_TYPE_STATIC_LAND;
}
else
{
units_static[i].movement_type |= MOVE_TYPE_STATIC_WATER;
if(unitList[i-1]->floater)
units_static[i].movement_type |= MOVE_TYPE_FLOATER;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -