📄 aaimap.cpp
字号:
insert_space = true;
for(int x = xPos-1; x >= xPos - cfg->MAX_XROW; x--)
{
if(buildmap[x+y*xMapSize] != building)
{
insert_space = false;
break;
}
}
}
if(insert_space)
{
// right side
cell = GetNextX(1, xPos+xSize, y, building);
if(cell != -1 && xPos+xSize+cfg->X_SPACE <= xMapSize)
{
BlockCells(cell, y, cfg->X_SPACE, 1, add, water);
//add blocking of the edges
if(y == yPos && (yPos - cfg->Y_SPACE) >= 0)
BlockCells(cell, yPos - cfg->Y_SPACE, cfg->X_SPACE, cfg->Y_SPACE, add, water);
if(y == yPos + ySize - 1)
BlockCells(cell, yPos + ySize, cfg->X_SPACE, cfg->Y_SPACE, add, water);
}
// left side
cell = GetNextX(0, xPos-1, y, building);
if(cell != -1 && cell-cfg->X_SPACE >= 0)
{
BlockCells(cell-cfg->X_SPACE, y, cfg->X_SPACE, 1, add, water);
// add diagonal blocks
if(y == yPos && (yPos - cfg->Y_SPACE) >= 0)
BlockCells(cell-cfg->X_SPACE, yPos - cfg->Y_SPACE, cfg->X_SPACE, cfg->Y_SPACE, add, water);
if(y == yPos + ySize - 1)
BlockCells(cell-cfg->X_SPACE, yPos + ySize, cfg->X_SPACE, cfg->Y_SPACE, add, water);
}
}
}
}
// check vertical space
if(yPos+ySize+cfg->MAX_YROW <= yMapSize && yPos - cfg->MAX_YROW >= 0)
{
for(int x = xPos; x < xPos + xSize; x++)
{
if(x >= xMapSize)
{
fprintf(ai->file, "ERROR: x = %i index out of range when checking vertical rows", x);
return;
}
// check downwards
insert_space = true;
for(int y = yPos+ySize; y < yPos+ySize+cfg->MAX_YROW; y++)
{
if(buildmap[x+y*xMapSize] != building)
{
insert_space = false;
break;
}
}
// check upwards
if(!insert_space)
{
insert_space = true;
for(int y = yPos-1; y >= yPos - cfg->MAX_YROW; y--)
{
if(buildmap[x+y*xMapSize] != building)
{
insert_space = false;
break;
}
}
}
if(insert_space)
{
// downwards
cell = GetNextY(1, x, yPos+ySize, building);
if(cell != -1 && yPos+ySize+cfg->Y_SPACE <= yMapSize)
{
BlockCells(x, cell, 1, cfg->Y_SPACE, add, water);
// add diagonal blocks
if(x == xPos && (xPos - cfg->X_SPACE) >= 0)
BlockCells(xPos-cfg->X_SPACE, cell, cfg->X_SPACE, cfg->Y_SPACE, add, water);
if(x == xPos + xSize - 1)
BlockCells(xPos + xSize, cell, cfg->X_SPACE, cfg->Y_SPACE, add, water);
}
// upwards
cell = GetNextY(0, x, yPos-1, building);
if(cell != -1 && cell-cfg->Y_SPACE >= 0)
{
BlockCells(x, cell-cfg->Y_SPACE, 1, cfg->Y_SPACE, add, water);
// add diagonal blocks
if(x == xPos && (xPos - cfg->X_SPACE) >= 0)
BlockCells(xPos-cfg->X_SPACE, cell-cfg->Y_SPACE, cfg->X_SPACE, cfg->Y_SPACE, add, water);
if(x == xPos + xSize - 1)
BlockCells(xPos + xSize, cell-cfg->Y_SPACE, cfg->X_SPACE, cfg->Y_SPACE, add, water);
}
}
}
}
}
void AAIMap::BlockCells(int xPos, int yPos, int width, int height, bool block, bool water)
{
// check range
if(xPos < 0 || yPos < 0 || xPos+width > xMapSize || yPos + height > yMapSize)
return;
//float3 my_pos;
int empty, cell;
if(water)
empty = 4;
else
empty = 0;
if(block) // block cells
{
for(int x = xPos; x < xPos + width; x++)
{
for(int y = yPos; y < yPos + height; y++)
{
cell = x + xMapSize*y;
// if no building ordered that cell to be blocked, update buildmap
// (only if space is not already occupied by a building)
if(!(blockmap[cell]++))
{
if(buildmap[cell] == empty)
{
buildmap[cell] = 2;
/*// debug
if(x%2 == 0 && y%2 == 0)
{
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, 1500, cb->GetMyAllyTeam(), true, true);
}*/
}
}
}
}
}
else // unblock cells
{
for(int x = xPos; x < xPos + width; x++)
{
for(int y = yPos; y < yPos + height; y++)
{
cell = x + xMapSize*y;
if(blockmap[cell])
{
// if cell is not blocked anymore, update buildmap
if(!(--blockmap[cell]))
{
if(buildmap[cell] == 2)
{
buildmap[cell] = empty;
// debug
/*if(x%2 == 0 && y%2 == 0)
{
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, 1500, cb->GetMyAllyTeam(), true, true);
}*/
}
}
}
}
}
}
}
void AAIMap::Pos2FinalBuildPos(float3 *pos, const UnitDef* def)
{
if(def->xsize&2) // check if xsize is a multiple of 4
pos->x=floor((pos->x)/(SQUARE_SIZE*2))*SQUARE_SIZE*2+8;
else
pos->x=floor((pos->x+8)/(SQUARE_SIZE*2))*SQUARE_SIZE*2;
if(def->ysize&2)
pos->z=floor((pos->z)/(SQUARE_SIZE*2))*SQUARE_SIZE*2+8;
else
pos->z=floor((pos->z+8)/(SQUARE_SIZE*2))*SQUARE_SIZE*2;
}
int AAIMap::GetNextX(int direction, int xPos, int yPos, int value)
{
int x = xPos;
// scan line until next free cell found
while(buildmap[x+yPos*xMapSize] == value)
{
if(direction)
x++;
else
x--;
// search went out of map
if(x < 0 || x >= xMapSize)
return -1;
}
return x;
}
int AAIMap::GetNextY(int direction, int xPos, int yPos, int value)
{
int y = yPos;
// scan line until next free cell found
while(buildmap[xPos+y*xMapSize] == value)
{
if(direction)
y++;
else
y--;
// search went out of map
if(y < 0 || y >= yMapSize)
return -1;
}
return y;
}
void AAIMap::GetSize(const UnitDef *def, int *xSize, int *ySize)
{
// calculate size of building
*xSize = def->xsize;
*ySize = def->ysize;
// if building is a factory additional vertical space is needed
if(bt->IsFactory(def->id))
{
*xSize += cfg->X_SPACE;
*ySize += ((float)cfg->Y_SPACE)*1.5;
}
}
int AAIMap::GetCliffyCells(int xPos, int yPos, int xSize, int ySize)
{
int cliffs = 0;
// count cells with big slope
for(int x = xPos; x < xPos + xSize; x++)
{
for(int y = yPos; y < yPos + ySize; y++)
{
if(buildmap[x+y*xMapSize] == 3)
++cliffs;
}
}
return cliffs;
}
int AAIMap::GetCliffyCellsInSector(AAISector *sector)
{
int cliffs = 0;
int xPos = sector->x * xSectorSize;
int yPos = sector->y * ySectorSize;
// count cells with big slope
for(int x = xPos; x < xPos + xSectorSizeMap; x++)
{
for(int y = yPos; y < yPos + ySectorSizeMap; y++)
{
if(buildmap[x+y*xMapSize] == 3)
cliffs++;
}
}
return cliffs;
}
void AAIMap::AnalyseMap()
{
float3 my_pos;
float slope;
const float *height_map = cb->GetHeightMap();
for(int x = 0; x < xMapSize; ++x)
{
for(int y = 0; y < yMapSize; ++y)
{
// check for water
if(height_map[y * xMapSize + x] < 0)
buildmap[x+y*xMapSize] = 4;
else if(x < xMapSize - 4 && y < yMapSize - 4)
// check slope
{
slope = (height_map[y * xMapSize + x] - height_map[y * xMapSize + x + 4])/64.0;
// check x-direction
if(slope > cfg->CLIFF_SLOPE || -slope > cfg->CLIFF_SLOPE)
buildmap[x+y*xMapSize] = 3;
else // check y-direction
{
slope = (height_map[y * xMapSize + x] - height_map[(y+4) * xMapSize + x])/64.0;
if(slope > cfg->CLIFF_SLOPE || -slope > cfg->CLIFF_SLOPE)
buildmap[x+y*xMapSize] = 3;
}
}
}
}
int xSize = xMapSize/2;
int ySize = yMapSize/2;
int TERRAIN_DETECTION_RANGE = 10;
float my_height, diff;
for(int x = TERRAIN_DETECTION_RANGE; x < xSize - TERRAIN_DETECTION_RANGE; ++x)
{
for(int y = TERRAIN_DETECTION_RANGE; y < ySize - TERRAIN_DETECTION_RANGE; ++y)
{
my_height = height_map[2 * x + 4 * y * xSize];
for(int i = x - TERRAIN_DETECTION_RANGE; i < x + TERRAIN_DETECTION_RANGE; ++i)
{
for(int j = y - TERRAIN_DETECTION_RANGE; j < y + TERRAIN_DETECTION_RANGE; ++j)
{
diff = (height_map[2 * i + 4 * j * xSize] - my_height);
if(diff > 0)
{
if(buildmap[2 * i + 4 * j * xSize] != 3)
plateau_map[i + j * xSize] += diff;
}
else
plateau_map[i + j * xSize] += diff;
}
}
}
}
for(int x = 0; x < xSize; ++x)
{
for(int y = 0; y < yMapSize/2; ++y)
{
if(plateau_map[x + y * xSize] >= 0)
plateau_map[x + y * xSize] = sqrt(plateau_map[x + y * xSize]);
else
plateau_map[x + y * xSize] = -1.0f * sqrt((-1.0f) * plateau_map[x + y * xSize]);
// debug
//if(plateau_map[x + y * xSize] >= 0)
//{
// my_pos.x = x * 16;
// my_pos.z = y * 16;
// my_pos.y = cb->GetElevation(my_pos.x, my_pos.z);
// cb->DrawUnit("ARMMINE1", my_pos, 0.0f, 1500, cb->GetMyAllyTeam(), false, true);
//}
}
}
}
// algorithm more or less by krogothe
// thx very much
void AAIMap::SearchMetalSpots()
{
const UnitDef* def = bt->unitList[bt->GetBiggestMex()-1];
metalMap = false;
bool Stopme = false;
int TotalMetal = 0;
int MaxMetal = 0;
int TempMetal = 0;
int SpotsFound = 0;
int coordx, coordy;
float AverageMetal;
AAIMetalSpot temp;
float3 pos;
int MinMetalForSpot = 30; // from 0-255, the minimum percentage of metal a spot needs to have
//from the maximum to be saved. Prevents crappier spots in between taken spaces.
//They are still perfectly valid and will generate metal mind you!
int MaxSpots = 5000; //If more spots than that are found the map is considered a metalmap, tweak this as needed
int MetalMapHeight = cb->GetMapHeight() / 2; //metal map has 1/2 resolution of normal map
int MetalMapWidth = cb->GetMapWidth() / 2;
int TotalCells = MetalMapHeight * MetalMapWidth;
unsigned char XtractorRadius = cb->GetExtractorRadius()/ 16.0;
unsigned char DoubleRadius = cb->GetExtractorRadius() / 8.0;
int SquareRadius = (cb->GetExtractorRadius() / 16.0) * (cb->GetExtractorRadius() / 16.0); //used to speed up loops so no recalculation needed
int DoubleSquareRadius = (cb->GetExtractorRadius() / 8.0) * (cb->GetExtractorRadius() / 8.0); // same as above
int CellsInRadius = PI * XtractorRadius * XtractorRadius; //yadda yadda
unsigned char* MexArrayA = new unsigned char [TotalCells];
unsigned char* MexArrayB = new unsigned char [TotalCells];
int* TempAverage = new int [TotalCells];
TotalMetal = MaxMetal = Stopme = SpotsFound = 0; //clear variables just in case!
//Load up the metal Values in each pixel
for (int i = 0; i != TotalCells - 1; i++)
{
MexArrayA[i] = *(cb->GetMetalMap() + i);
TotalMetal += MexArrayA[i]; // Count the total metal so you can work out an average of the whole map
}
AverageMetal = ((float)TotalMetal) / ((float)TotalCells); //do the average
// Now work out how much metal each spot can make by adding up the metal from nearby spots
for (int y = 0; y != MetalMapHeight; y++)
{
for (int x = 0; x != MetalMapWidth; x++)
{
TotalMetal = 0;
for (int myx = x - XtractorRadius; myx != x + XtractorRadius; myx++)
{
if (myx >= 0 && myx < MetalMapWidth)
{
for (int myy = y - XtractorRadius; myy != y + XtractorRadius; myy++)
{
if (myy >= 0 && myy < MetalMapHeight && ((x - myx)*(x - myx) + (y - myy)*(y - myy)) <= SquareRadius)
{
TotalMetal += MexArrayA[myy * MetalMapWidth + myx]; //get the metal from all pixels around the extractor radius
}
}
}
}
TempAverage[y * MetalMapWidth + x] = TotalMetal; //set that spots metal making ability (divide by cells to values are small)
if (MaxMetal < TotalMetal)
MaxMetal = TotalMetal; //find the spot with the highest metal to set as the map's max
}
}
for (int i = 0; i != TotalCells; i++) // this will get the total metal a mex placed at each spot would make
{
MexArrayB[i] = TempAverage[i] * 255 / MaxMetal; //scale the metal so any map will have values 0-255, no matter how much metal it has
}
for (int a = 0; a != MaxSpots; a++)
{
if(!Stopme)
TempMetal = 0; //reset tempmetal so it can find new spots
for (int i = 0; i != TotalCells; i=i+2)
{ //finds the best spot on the map and gets its coords
if (MexArrayB[i] > TempMetal && !Stopme)
{
TempMetal = MexArrayB[i];
coordx = i%MetalMapWidth;
coordy = i/MetalMapWidth;
}
}
if (TempMetal < MinMetalForSpot)
Stopme = 1; // if the spots get too crappy it will stop running the loops to speed it all up
if (!Stopme)
{
pos.x = coordx * 2 * SQUARE_SIZE;
pos.z = coordy * 2 * SQUARE_SIZE;
pos.y = cb->GetElevation(pos.x, pos.z);
Pos2FinalBuildPos(&pos, def);
temp.amount = TempMetal * cb->GetMaxMetal() * MaxMetal / 255.0;
temp.occupied = false;
temp.pos = pos;
//if(cb->CanBuildAt(def, pos))
//{
Pos2BuildMapPos(&pos, def);
if(pos.z >= 2 && pos.x >= 2 && pos.x < xMapSize-2 && pos.z < yMapSize-2)
{
if(CanBuildAt(pos.x, pos.z, def->xsize, def->ysize))
{
metal_spots.push_back(temp);
SpotsFound++;
if(pos.y >= 0)
SetBuildMap(pos.x-2, pos.z-2, def->xsize+4, def->ysize+4, 1);
else
SetBuildMap(pos.x-2, pos.z-2, def->xsize+4, def->ysize+4, 5);
}
}
//}
for (int myx = coordx - XtractorRadius; myx != coordx + XtractorRadius; myx++)
{
if (myx >= 0 && myx < MetalMapWidth)
{
for (int myy = coordy - XtractorRadius; myy != coordy + XtractorRadius; myy++)
{
if (myy >= 0 && myy < MetalMapHeight && ((coordx - myx)*(coordx - myx) + (coordy - myy)*(coordy - myy)) <= SquareRadius)
{
MexArrayA[myy * MetalMapWidth + myx] = 0; //wipes the metal around the spot so its not counted twice
MexArrayB[myy * MetalMapWidth + myx] = 0;
}
}
}
}
// Redo the whole averaging process around the picked spot so other spots can be found around it
for (int y = coordy - DoubleRadius; y != coordy + DoubleRadius; y++)
{
if(y >=0 && y < MetalMapHeight)
{
for (int x = coordx - DoubleRadius; x != coordx + DoubleRadius; x++)
{//funcion below is optimized so it will only update spots between r and 2r, greatly speeding it up
if((coordx - x)*(coordx - x) + (coordy - y)*(coordy - y) <= DoubleSquareRadius && x >=0 && x < MetalMapWidth && MexArrayB[y * MetalMapWidth + x])
{
TotalMetal = 0;
for (int myx = x - XtractorRadius; myx != x + XtractorRadius; myx++)
{
if (myx >= 0 && myx < MetalMapWidth)
{
for (int myy = y - XtractorRadius; myy != y + XtractorRadius; myy++)
{
if (myy >= 0 && myy < MetalMapHeight && ((x - myx)*(x - myx) + (y - myy)*(y - myy)) <= SquareRadius)
{
TotalMetal += MexArrayA[myy * MetalMapWidth + myx]; //recalculate nearby spots to account for deleted metal from chosen spot
}
}
}
}
MexArrayB[y * MetalMapWidth + x] = TotalMetal * 255 / MaxMetal;; //set that spots metal amount
}
}
}
}
}
}
if(SpotsFound > 500)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -