📄 aaimap.cpp
字号:
// -------------------------------------------------------------------------
// AAI
//
// A skirmish AI for the TA Spring engine.
// Copyright Alexander Seizinger
// Released under GPL license: see LICENSE.html for more information.
// -------------------------------------------------------------------------
#include "AAIMap.h"
#include "AAI.h"
#include "AAISector.h"
#include "AAIBuildTable.h"
// all the static vars
int AAIMap::aai_instances = 0;
int AAIMap::xMapSize;
int AAIMap::yMapSize;
int AAIMap::xDefMapSize;
int AAIMap::yDefMapSize;
int AAIMap::xSectors;
int AAIMap::ySectors;
int AAIMap::xSectorSize;
int AAIMap::ySectorSize;
int AAIMap::xSectorSizeMap;
int AAIMap::ySectorSizeMap;
list<AAIMetalSpot> AAIMap::metal_spots;
bool AAIMap::metalMap;
MapType AAIMap::mapType;
vector< vector<int> > AAIMap::team_sector_map;
vector<int> AAIMap::buildmap;
vector<int> AAIMap::blockmap;
vector<float> AAIMap::plateau_map;
list<UnitCategory> AAIMap::map_categories;
list<int> AAIMap::map_categories_id;
vector<vector<float> > AAIMap::map_usefulness;
AAIMap::AAIMap(AAI *ai)
{
// initialize random numbers generator
srand ( time(NULL) );
this->ai = ai;
bt = ai->bt;
cb = ai->cb;
initialized = false;
unitsInLos.resize(cfg->MAX_UNITS);
// set all values to 0 (to be able to detect num. of enemies in los later
for(int i = 0; i < cfg->MAX_UNITS; i++)
unitsInLos[i] = 0;
/*map_usefulness.resize(bt->assault_categories.size());
for(int i = 0; i < bt->assault_categories.size(); ++i)
map_usefulness[i].resize(cfg->SIDES);*/
units_spotted.resize(bt->combat_categories);
}
AAIMap::~AAIMap(void)
{
--aai_instances;
// delete common data only if last aai instace has gone
if(aai_instances == 0)
{
Learn();
// save map data
char filename[500];
char buffer[500];
strcpy(buffer, MAIN_PATH);
strcat(buffer, MAP_LEARN_PATH);
strcat(buffer, cb->GetMapName());
ReplaceExtension(buffer, filename, sizeof(filename), "_");
strcat(filename, cb->GetModName());
ReplaceExtension(filename, buffer, sizeof(filename), ".dat");
ai->cb->GetValue(AIVAL_LOCATE_FILE_W, buffer);
FILE *save_file = fopen(buffer, "w+");
fprintf(save_file, "%s \n",MAP_FILE_VERSION);
// save map type
fprintf(save_file, "%s \n", GetMapTypeString(mapType));
// save units map_usefulness
float sum;
for(int i = 0; i < cfg->SIDES; ++i)
{
// rebalance map_usefulness
if(mapType == LAND_MAP)
{
sum = map_usefulness[0][i] + map_usefulness[2][i];
map_usefulness[0][i] *= (100.0/sum);
map_usefulness[2][i] *= (100.0/sum);
}
else if(mapType == LAND_WATER_MAP)
{
sum = map_usefulness[0][i] + map_usefulness[2][i] + map_usefulness[3][i] + map_usefulness[4][i];
map_usefulness[0][i] *= (100.0/sum);
map_usefulness[2][i] *= (100.0/sum);
map_usefulness[3][i] *= (100.0/sum);
map_usefulness[4][i] *= (100.0/sum);
}
else if(mapType == WATER_MAP)
{
sum = map_usefulness[2][i] + map_usefulness[3][i] + map_usefulness[4][i];
map_usefulness[2][i] *= (100.0/sum);
map_usefulness[3][i] *= (100.0/sum);
map_usefulness[4][i] *= (100.0/sum);
}
// save
for(int j = 0; j < bt->assault_categories.size(); ++j)
fprintf(save_file, "%f ", map_usefulness[j][i]);
}
fprintf(save_file, "\n");
for(int y = 0; y < ySectors; y++)
{
for(int x = 0; x < xSectors; x++)
{
// save sector data
fprintf(save_file, "%f %f %f", sector[x][y].flat_ratio, sector[x][y].water_ratio, sector[x][y].importance_this_game);
// save combat data
for(int cat = 0; cat < bt->assault_categories.size(); ++cat)
fprintf(save_file, "%f %f ", sector[x][y].attacked_by_this_game[cat], sector[x][y].combats_this_game[cat]);
}
fprintf(save_file, "\n");
}
fclose(save_file);
buildmap.clear();
blockmap.clear();
defence_map.clear();
air_defence_map.clear();
plateau_map.clear();
}
}
void AAIMap::Init()
{
++aai_instances;
// all static vars are only initialized by the first aai instance
if(aai_instances == 1)
{
// get size
xMapSize = cb->GetMapWidth();
yMapSize = cb->GetMapHeight();
xDefMapSize = xMapSize / 2;
yDefMapSize = yMapSize / 2;
// calculate number of sectors
xSectors = floor(0.5f + ((float) xMapSize)/cfg->SECTOR_SIZE);
ySectors = floor(0.5f + ((float) yMapSize)/cfg->SECTOR_SIZE);
// calculate effective sector size
xSectorSizeMap = floor( ((float) xMapSize) / ((float) xSectors) );
ySectorSizeMap = floor( ((float) yMapSize) / ((float) ySectors) );
xSectorSize = 8 * xSectorSizeMap;
ySectorSize = 8 * ySectorSizeMap;
blockmap.resize(xMapSize*yMapSize, 0);
plateau_map.resize(xMapSize*yMapSize / 4, 0);
// create map that stores which aai player has occupied which sector (visible to all aai players)
team_sector_map.resize(xSectors);
for(int x = 0; x < xSectors; ++x)
team_sector_map[x].resize(ySectors, -1);
ReadCacheFile();
}
// create field of sectors
sector.resize(xSectors);
for(int x = 0; x < xSectors; ++x)
sector[x].resize(ySectors);
for(int j = 0; j < ySectors; ++j)
{
for(int i = 0; i < xSectors; ++i)
// provide ai callback to sectors & set coordinates of the sectors
sector[i][j].Init(ai, i, j, xSectorSize*i, xSectorSize*(i+1), ySectorSize * j, ySectorSize * (j+1));
}
// add metalspots to their sectors
int k, l;
for(list<AAIMetalSpot>::iterator spot = metal_spots.begin(); spot != metal_spots.end(); ++spot)
{
k = spot->pos.x/xSectorSize;
l = spot->pos.z/ySectorSize;
if(k < xSectors && l < ySectors)
sector[k][l].AddMetalSpot(&(*spot));
}
ReadMapLearnFile(true);
// for scouting
unitsInSector.resize(xSectors*ySectors);
// create defence
defence_map.resize(xDefMapSize*yDefMapSize, 0);
air_defence_map.resize(xDefMapSize*yDefMapSize, 0);
initialized = true;
// for log file
fprintf(ai->file, "Map: %s\n",cb->GetMapName());
fprintf(ai->file, "Mapsize is %i x %i\n", cb->GetMapWidth(),cb->GetMapHeight());
fprintf(ai->file, "%i sectors in x direction\n", xSectors);
fprintf(ai->file, "%i sectors in y direction\n", ySectors);
fprintf(ai->file, "x-sectorsize is %i (Map %i)\n", xSectorSize, xSectorSizeMap);
fprintf(ai->file, "y-sectorsize is %i (Map %i)\n", ySectorSize, ySectorSizeMap);
fprintf(ai->file, "%i metal spots found \n \n",metal_spots.size());
//debug
/*float3 my_pos;
for(int x = 0; x < xMapSize; x+=2)
{
for(int y = 0; y < yMapSize; y+=2)
{
if(buildmap[x + y*xMapSize] == 1 || buildmap[x + y*xMapSize] == 5)
{
my_pos.x = x * 8;
my_pos.z = y * 8;
my_pos.y = cb->GetElevation(my_pos.x, my_pos.z);
cb->DrawUnit("ARMMINE1", my_pos, 0.0f, 8000, cb->GetMyAllyTeam(), true, true);
}
}
}*/
}
void AAIMap::ReadCacheFile()
{
// try to read cache file
bool loaded = false;
char filename[500];
char buffer[500];
strcpy(buffer, MAIN_PATH);
strcat(buffer, MAP_CACHE_PATH);
strcat(buffer, cb->GetMapName());
ReplaceExtension(buffer, filename, sizeof(filename), ".dat");
ai->cb->GetValue(AIVAL_LOCATE_FILE_R, filename);
FILE *file;
if(file = fopen(filename, "r"))
{
// check if correct version
fscanf(file, "%s ", buffer);
if(strcmp(buffer, MAP_DATA_VERSION))
{
cb->SendTextMsg("Mapcache out of date - creating new one", 0);
fprintf(ai->file, "Map cache-file out of date - new one has been created\n");
}
else
{
int temp;
float temp_float;
// load if its a metal map
fscanf(file, "%i ", &temp);
metalMap = (bool)temp;
// load buildmap
for(int i = 0; i < xMapSize*yMapSize; ++i)
{
//fread(&temp, sizeof(int), 1, file);
fscanf(file, "%i ", &temp);
buildmap.push_back(temp);
}
// load plateau map
for(int i = 0; i < xMapSize*yMapSize/4; ++i)
{
//fread(&temp_float, sizeof(float), 1, file);
fscanf(file, "%f ", &temp_float);
buildmap.push_back(temp_float);
}
AAIMetalSpot spot;
fscanf(file, "%i ", &temp);
// load mex spots
for(int i = 0; i < temp; ++i)
{
fscanf(file, "%f %f %f %f ", &(spot.pos.x), &(spot.pos.y), &(spot.pos.z), &(spot.amount));
spot.occupied = false;
metal_spots.push_back(spot);
}
fprintf(ai->file, "Map cache file succesfully loaded\n");
loaded = true;
fclose(file);
}
}
if(!loaded) // create new map data
{
buildmap.resize(xMapSize*yMapSize, 0);
// look for metalspots
SearchMetalSpots();
AnalyseMap();
strcpy(buffer, MAIN_PATH);
strcat(buffer, MAP_CACHE_PATH);
strcat(buffer, cb->GetMapName());
ReplaceExtension(buffer, filename, sizeof(filename), ".dat");
ai->cb->GetValue(AIVAL_LOCATE_FILE_W, filename);
// save data
file = fopen(filename, "w+");
fprintf(file, "%s\n", MAP_DATA_VERSION);
// save if its a metal map
fprintf(file, "%i\n", (int)metalMap);
// save buildmap
for(int i = 0; i < xMapSize*yMapSize; ++i)
// fwrite(&buildmap[i], sizeof(int), 1, file);
fprintf(file, "%i ", buildmap[i]);
// save plateau map
for(int i = 0; i < xMapSize*yMapSize/4; ++i)
// fwrite(&plateau_map[i], sizeof(float), 1, file);
fprintf(file, "%f ", plateau_map[i]);
// save mex spots
fprintf(file, "\n %i \n", metal_spots.size());
for(list<AAIMetalSpot>::iterator spot = metal_spots.begin(); spot != metal_spots.end(); spot++)
fprintf(file, "%f %f %f %f \n", spot->pos.x, spot->pos.y, spot->pos.z, spot->amount);
fclose(file);
fprintf(ai->file, "New map cache-file created\n");
}
// determine map type
loaded = true;
strcpy(buffer, MAIN_PATH);
strcat(buffer, MAP_CFG_PATH);
strcat(buffer, cb->GetMapName());
ReplaceExtension(buffer, filename, sizeof(filename), ".cfg");
ai->cb->GetValue(AIVAL_LOCATE_FILE_R, filename);
if(file = fopen(filename, "r"))
{
// read map type
fscanf(file, "%s ", buffer);
if(!strcmp(buffer, "LAND_MAP"))
mapType = LAND_MAP;
else if(!strcmp(buffer, "AIR_MAP"))
mapType = AIR_MAP;
else if(!strcmp(buffer, "LAND_WATER_MAP"))
mapType = LAND_WATER_MAP;
else if(!strcmp(buffer, "WATER_MAP"))
mapType = WATER_MAP;
else
mapType = UNKNOWN_MAP;
if(mapType >= 0 && mapType <= WATER_MAP)
{
this->mapType = (MapType) mapType;
// logging
sprintf(buffer, "%s detected", GetMapTypeTextString(mapType));
fprintf(ai->file, "\nLoading map type:\n");
fprintf(ai->file, buffer);
fprintf(ai->file, "\n\n");
if(bt->aai_instances == 1)
ai->cb->SendTextMsg(buffer, 0);
}
else
loaded = false;
fclose(file);
}
else
loaded = false;
if(!loaded)
{
float water_ratio = 0;
for(int x = 0; x < xMapSize; ++x)
{
for(int y = 0; y < yMapSize; ++y)
{
if(buildmap[x + y*xMapSize] == 4)
++water_ratio;
}
}
water_ratio = water_ratio / ((float)(xMapSize*yMapSize));
if(water_ratio > 0.80f)
this->mapType = WATER_MAP;
else if(water_ratio > 0.25f)
this->mapType = LAND_WATER_MAP;
else
this->mapType = LAND_MAP;
// logging
sprintf(buffer, "%s detected", GetMapTypeTextString(this->mapType));
ai->cb->SendTextMsg(buffer, 0);
fprintf(ai->file, "\nAutodetecting map type:\n");
fprintf(ai->file, buffer);
fprintf(ai->file, "\n\n");
// save results to cfg file
strcpy(buffer, MAIN_PATH);
strcat(buffer, MAP_CFG_PATH);
strcat(buffer, cb->GetMapName());
ReplaceExtension(buffer, filename, sizeof(filename), ".cfg");
ai->cb->GetValue(AIVAL_LOCATE_FILE_W, filename);
file = fopen(filename, "w+");
fprintf(file, "%s\n", GetMapTypeString(this->mapType));
fclose(file);
}
// determine important unit categories on this map
if(cfg->AIR_ONLY_MOD)
{
map_categories.push_back(GROUND_ASSAULT);
map_categories.push_back(AIR_ASSAULT);
map_categories.push_back(HOVER_ASSAULT);
map_categories.push_back(SEA_ASSAULT);
map_categories_id.push_back(0);
map_categories_id.push_back(1);
map_categories_id.push_back(2);
map_categories_id.push_back(3);
}
else
{
if(mapType == LAND_MAP)
{
map_categories.push_back(GROUND_ASSAULT);
map_categories.push_back(AIR_ASSAULT);
map_categories.push_back(HOVER_ASSAULT);
map_categories_id.push_back(0);
map_categories_id.push_back(1);
map_categories_id.push_back(2);
}
else if(mapType == LAND_WATER_MAP)
{
map_categories.push_back(GROUND_ASSAULT);
map_categories.push_back(AIR_ASSAULT);
map_categories.push_back(HOVER_ASSAULT);
map_categories.push_back(SEA_ASSAULT);
map_categories.push_back(SUBMARINE_ASSAULT);
map_categories_id.push_back(0);
map_categories_id.push_back(1);
map_categories_id.push_back(2);
map_categories_id.push_back(3);
map_categories_id.push_back(4);
}
else if(mapType == WATER_MAP)
{
map_categories.push_back(AIR_ASSAULT);
map_categories.push_back(HOVER_ASSAULT);
map_categories.push_back(SEA_ASSAULT);
map_categories.push_back(SUBMARINE_ASSAULT);
map_categories_id.push_back(1);
map_categories_id.push_back(2);
map_categories_id.push_back(3);
map_categories_id.push_back(4);
}
else
{
map_categories.push_back(AIR_ASSAULT);
map_categories_id.push_back(1);
}
}
}
void AAIMap::ReadMapLearnFile(bool auto_set)
{
// get filename
char filename[500];
char buffer[500];
strcpy(buffer, MAIN_PATH);
strcat(buffer, MAP_LEARN_PATH);
strcat(buffer, cb->GetMapName());
ReplaceExtension(buffer, filename, sizeof(filename), "_");
strcpy(buffer, filename);
strcat(buffer, cb->GetModName());
ReplaceExtension(buffer, filename, sizeof(filename), ".dat");
ai->cb->GetValue(AIVAL_LOCATE_FILE_R, filename);
// open learning files
FILE *load_file = fopen(filename, "r");
// check if correct map file version
if(load_file)
{
fscanf(load_file, "%s", buffer);
// file version out of date
if(strcmp(buffer, MAP_FILE_VERSION))
{
cb->SendTextMsg("Map learning file version out of date, creating new one", 0);
fclose(load_file);
load_file = 0;
}
else
{
// check if map type matches (aai will recreate map learn files if maptype has changed)
fscanf(load_file, "%s", buffer);
// map type does not match
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -