Files
firestorm/Gameleap/code/mw4/Code/AI test/movezone.cpp
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

728 lines
15 KiB
C++

#pragma warning (disable:4786)
#include <utils\utils.h>
#include "map.hpp"
#include "move.hpp"
#include "movezone.hpp"
#include <map>
CMapCell g_MapCells[MAPCELLCOUNT][MAPCELLCOUNT];
std::map<int,float> pathmapzone[MAPCELLCOUNT][MAPCELLCOUNT][2]; // index is for the topleft cell of each src,dest pair the 2 is for the offset table-2
bool SetWeight (int sx,int sy,int offset,int areaentry,int areaexit,float newweight)
{
int ix,iy,io;
int index;
int temp;
std::map<int,float>::iterator iter;
ix = sx;
iy = sy;
io = offset;
switch (offsetzone[offset][2])
{
case 0:
ix--;
temp = areaentry;
areaentry = areaexit;
areaexit = temp;
break;
case 1:
iy--;
temp = areaentry;
areaentry = areaexit;
areaexit = temp;
break;
case 2:
io-=2;
break;
case 3:
io-=2;
break;
}
assert (ix>=0);
assert (ix<MAPCELLCOUNT);
assert (iy>=0);
assert (iy<MAPCELLCOUNT);
assert (io>=0);
assert (io<2);
index = areaentry<<4;
index += areaexit;
iter = pathmapzone[ix][iy][io].find (index);
if (iter == pathmapzone[ix][iy][io].end ())
{
pathmapzone[ix][iy][io][index] = newweight;
return true;
}
if ((*iter).second > newweight)
{
pathmapzone[ix][iy][io][index] = newweight;
return true;
}
return false;
}
float GetWeight (int sx,int sy,int dx,int dy,int areaentry,int areaexit)
{
if (abs (sx-dx))
{
if (sx > dx)
return GetWeight (sx,sy,0,areaentry,areaexit);
else
return GetWeight (sx,sy,2,areaentry,areaexit);
}
else if (abs(sy-dy))
{
if (sy > dy)
return GetWeight (sx,sy,1,areaentry,areaexit);
else
return GetWeight (sx,sy,3,areaentry,areaexit);
}
assert (false);
return -1.0;
}
float GetWeight (int sx,int sy,int offset,int areaentry,int areaexit)
{
int ix,iy,io;
int index;
int temp;
std::map<int,float>::iterator iter;
ix = sx;
iy = sy;
io = offset;
switch (offsetzone[offset][2])
{
case 0:
ix--;
temp = areaentry;
areaentry = areaexit;
areaexit = temp;
break;
case 1:
iy--;
temp = areaentry;
areaentry = areaexit;
areaexit = temp;
break;
case 2:
io-=2;
break;
case 3:
io-=2;
break;
}
if (ix<0)
return -1;
if (ix>=MAPCELLCOUNT)
return -1;
if (iy<0)
return -1;
if (iy>=MAPCELLCOUNT)
return -1;
assert (io>=0);
assert (io<2);
index = areaentry<<4;
index += areaexit;
iter = pathmapzone[ix][iy][io].find (index);
if (iter == pathmapzone[ix][iy][io].end ())
{
return -1.0;
}
return (*iter).second;
}
void InitMoveZoneData (void)
{
int curx,cury;
int x,y;
for (y=0,cury = 0;y<MAPCELLCOUNT;y++,cury+=(MAPCELLSIZE-1))
for (x=0,curx=0;x<MAPCELLCOUNT;x++,curx+=(MAPCELLSIZE-1))
{
int left,right,top,bottom;
left = clamp<int> (0,curx,MAPSIZE-1);
right = clamp<int> (0,left+MAPCELLSIZE-1,MAPSIZE-1);
top = clamp<int> (0,cury,MAPSIZE-1);
bottom = clamp<int> (0,top+MAPCELLSIZE-1,MAPSIZE-1);
g_MapCells[x][y].SetSize (left,top,right,bottom);
}
for (y=0;y<MAPCELLCOUNT;y++)
for (x=0;x<MAPCELLCOUNT;x++)
{
g_MapCells[x][y].CalcWeight ();
g_MapCells[x][y].CalcInterior ();
g_MapCells[x][y].CalcEdges ();
}
}
CMapCell::CMapCell (void)
{
m_WeightAverage = 0;
m_PassAverage = 0;
}
CMapCell::~CMapCell (void)
{
}
void CMapCell::CalcWeight (void)
{
int midx,midy,count;
m_PassAverage = 0;
m_WeightAverage = 0;
count = 0;
for (midx = m_Left;midx<=m_Right;midx++)
{
for (midy=m_Top;midy<=m_Bottom;midy++)
{
count++;
m_WeightAverage+=g_Map[midx][midy].weight;
if (g_Map[midx][midy].passable)
{
m_PassAverage++;
}
}
}
m_PassAverage /= count;
m_WeightAverage /= count;
}
void CMapCell::CalcEdges (void)
{
int x,y;
for (x=m_Left;x<=m_Right;x++)
{
m_AreaData[m_Areas[x-m_Left][0]].flags |= TOPEDGEMASK;
m_AreaData[m_Areas[x-m_Left][MAPCELLSIZE-1]].flags |= BOTTOMEDGEMASK;
}
for (y=m_Top;y<=m_Bottom;y++)
{
m_AreaData[m_Areas[0][y-m_Top]].flags |= LEFTEDGEMASK;
m_AreaData[m_Areas[MAPCELLSIZE-1][y-m_Top]].flags |= RIGHTEDGEMASK;
}
}
void CMapCell::CalcArea (int sx,int sy,int id,int info)
{
if (sx < 0)
return;
if (sy<0)
return;
if (sx>=MAPCELLSIZE)
return;
if (sy>=MAPCELLSIZE)
return;
if ((m_Areas[sx][sy] == 0) && (SquareInfo (sx+m_Left,sy+m_Top)==info))
{
m_Areas[sx][sy] = id;
CalcArea (sx-1,sy,id,info);
CalcArea (sx+1,sy,id,info);
CalcArea (sx,sy-1,id,info);
CalcArea (sx,sy+1,id,info);
}
}
void CMapCell::CalcInterior (void)
{
int x,y,id;
float count[MAXAREAS];
for (x=0;x<MAPCELLSIZE;x++)
{
for (y=0;y<MAPCELLSIZE;y++)
{
m_Areas[x][y] = 0;
}
}
id = 1;
for (x=0;x<MAPCELLSIZE;x++)
{
for (y=0;y<MAPCELLSIZE;y++)
{
if (m_Areas[x][y])
continue;
assert (id<MAXAREAS);
m_AreaData[id].info = SquareInfo (x+m_Left,y+m_Top);
if (Passable (x+m_Left,y+m_Top))
m_AreaData[id].passable = 1;
else
m_AreaData[id].passable = 0;
CalcArea (x,y,id++,SquareInfo (x+m_Left,y+m_Top));
}
}
memset (count,0,sizeof(int)*MAXAREAS);
for (id=0;id<MAXAREAS;id++)
m_AreaData[id].weight = 0;
for (x=0;x<MAPCELLSIZE;x++)
{
for (y=0;y<MAPCELLSIZE;y++)
{
m_AreaData[m_Areas[x][y]].weight += g_Map[x+m_Left][y+m_Top].weight;
count[m_Areas[x][y]]++;
}
}
for (id=1;id<MAXAREAS;id++)
{
if (count[id] != 0)
m_AreaData[id].weight /= count[id];
}
}
void CMapCell::RenderEdges (CDIBSurface& dest,int dx)
{
int x,y;
for (x=m_Left;x<=m_Right;x++)
{
dest.Fill (dx+x*DRAWCELLSIZE,m_Top*DRAWCELLSIZE,dx+(x+1)*DRAWCELLSIZE,(m_Top+1)*DRAWCELLSIZE,RGB (0,255,0));
dest.Fill (dx+x*DRAWCELLSIZE,m_Bottom*DRAWCELLSIZE,dx+(x+1)*DRAWCELLSIZE,(m_Bottom+1)*DRAWCELLSIZE,RGB (0,255,0));
}
for (y=m_Top;y<=m_Bottom;y++)
{
dest.Fill (dx+m_Left*DRAWCELLSIZE,y*DRAWCELLSIZE,dx+(m_Left+1)*DRAWCELLSIZE,(y+1)*DRAWCELLSIZE,RGB (0,255,0));
dest.Fill (dx+m_Right*DRAWCELLSIZE,y*DRAWCELLSIZE,dx+(m_Right+1)*DRAWCELLSIZE,(y+1)*DRAWCELLSIZE,RGB (0,255,0));
}
}
FixedHeap<CALCZONEELEMENT> CALCZONEELEMENT::m_EmptyCalcZoneElement(1);
void CALCZONEELEMENT::operator =(FibHeapNode& RHS)
{
CALCZONEELEMENT& fred = (CALCZONEELEMENT&) RHS;
sx = fred.sx;
sy = fred.sy;
dx = fred.dx;
dy = fred.dy;
sarea = fred.sarea;
darea = fred.darea;
dir = fred.dir;
}
bool CALCZONEELEMENT::operator ==(FibHeapNode& RHS)
{
CALCZONEELEMENT& fred = (CALCZONEELEMENT&) RHS;
if (sx != fred.sx)
return false;
if (sy != fred.sy)
return false;
if (dx != fred.dx)
return false;
if (dy != fred.dy)
return false;
if (sarea != fred.sarea)
return false;
if (darea != fred.darea)
return false;
if (dir != fred.dir)
return false;
return true;
}
bool CALCZONEELEMENT::operator <(FibHeapNode& RHS)
{
CALCZONEELEMENT& fred = (CALCZONEELEMENT&) RHS;
float sw,dw;
sw = GetWeight (sx,sy,dx,dy,sarea,darea);
dw = GetWeight (fred.sx,fred.sy,fred.dx,fred.dy,fred.sarea,fred.darea);
if (sw < dw)
return true;
if (dw < sw)
return false;
if (fred.sx < sx)
return false;
if (sx < fred.sx)
return true;
if (fred.dx < dx)
return false;
if (dx < fred.dx)
return true;
if (fred.sy < sy)
return false;
if (sy < fred.sy)
return true;
if (fred.dy < dy)
return false;
if (dy < fred.dy)
return true;
if (sarea < fred.sarea)
return true;
if (darea < fred.darea)
return true;
if (dir < fred.dir)
return true;
return true;
}
float GetOneCostZone (int sx,int sy,int offset,int areaentry,int areaexit,int newarea)
{
float toret;
int dx,dy;
dx = sx + offsetzone[offset][0];
dy = sy + offsetzone[offset][1];
if (dx<0)
return -1.0;
if (dy<0)
return -1.0;
if (dx>=MAPCELLCOUNT)
return -1.0;
if (dy>=MAPCELLCOUNT)
return -1.0;
if (areaentry == areaexit)
{
if (!g_MapCells[sx][sy].AreaData (areaentry).passable)
return -1.0;
toret = g_MapCells[sx][sy].AreaData (areaentry).weight;
}
else
{
if (!g_MapCells[sx][sy].AreaData (areaentry).passable)
return -1.0;
if (!g_MapCells[sx][sy].AreaData (areaexit).passable)
return -1.0;
toret = g_MapCells[sx][sy].AreaData (areaentry).weight/2.0 + g_MapCells[sx][sy].AreaData (areaexit).weight/2.0;
}
//TODO: add support for connection of areas within the zone
#if 0
int x,y;
bool flag;
switch (offsetzone[offset][2])
{
case 0:
for (y=0;y<MAPCELLSIZE;y++)
{
if (g_Map)
{
}
}
break;
case 1:
break;
case 2:
break;
case 3:
break;
}
#endif
if (offsetzone[offset][3] != 4) // just and area change, no new zone
{
if (!g_MapCells[dx][dy].AreaData (newarea).passable)
return -1.0;
toret += g_MapCells[dx][dy].AreaData (newarea).weight;
toret *= 0.5;
}
return toret;
}
float PathCostGuessZone (int sx,int sy,int dx,int dy)
{
int t1,t2;
t1 = dx - sx;
t2 = dy - dx;
__asm
{
mov eax,t1
cdq
xor eax,edx
sub eax,edx
mov t1,eax
mov eax,t2
cdq
xor eax,edx
sub eax,edx
mov t2,eax
}
// return t1+t2;
return t2 < t1 ? (t1+(t2>>1)) : (t2+(t1>>1));
}
CPoint GlobalToCellIndex (CPoint src)
{
int i;
CPoint toret(-1,-1);
for (i=0;i<MAPCELLCOUNT;i++)
{
if (src.x >= g_MapCells[i][0].Left () && src.x <= g_MapCells[i][0].Right())
{
toret.x = i;
break;
}
}
for (i=0;i<MAPCELLCOUNT;i++)
{
if (src.y >= g_MapCells[0][i].Top () && src.y <= g_MapCells[0][i].Bottom())
{
toret.y = i;
break;
}
}
return toret;
}
void FindLowerEdge (int dx,int dy,int endarea,int& sx,int& sy,int& curarea,int& dir,int startx,int starty,int startarea)
{
int i,j;
float cost;
float minvalue;
minvalue = FLT_MAX;
for (j=1;j<MAXAREAS;j++)
{
for (i=0;i<OFFSIZEZONE;i++)
{
cost = GetWeight (dx,dy,i,j,endarea);
if (cost != -1)
{
if ((startx == dx+offsetzone[i][0]) && (starty == dy+offsetzone[i][1]) && (startarea == j))
{
sx = startx;
sy = starty;
curarea = j;
dir = (offsetzone[i][2]+2)& 0x03;
return;
}
if (cost<minvalue)
{
minvalue = cost;
sx = dx + offsetzone[i][0];
sy = dy + offsetzone[i][1];
curarea = j;
dir = (offsetzone[i][2]+2) & 0x03;
}
}
}
}
}
bool AddCalcElements (FibHeap& calc,int sx,int sy,int area,float startweight)
{
int i,j,temparea;
int x,y;
float cost;
CALCZONEELEMENT *temp;
AREADATA& tempdata = g_MapCells[sx][sy].AreaData (area);
if (tempdata.left_connect)
{
i = sx-1;
j = sy;
if (i>=0)
{
for (y=0;y<MAPCELLSIZE;y++)
{
if (g_MapCells[sx][sy].m_Areas[0][y] == area)
{
temparea = g_MapCells[i][j].m_Areas[MAPCELLSIZE-1][y];
cost = GetOneCostZone (sx,sy,0,area,area,temparea);
assert (cost != -1);
cost += startweight;
if (SetWeight (sx,sy,0,area,temparea,cost))
{
temp = new CALCZONEELEMENT (sx,sy,i,j,area,temparea,LEFTEDGE);
calc.Insert (temp);
}
}
}
}
}
if (tempdata.top_connect)
{
i = sx;
j = sy-1;
if (j>=0)
{
for (x=0;x<MAPCELLSIZE;x++)
{
if (g_MapCells[sx][sy].m_Areas[x][0] == area)
{
temparea = g_MapCells[i][j].m_Areas[x][MAPCELLSIZE-1];
cost = GetOneCostZone (sx,sy,1,area,area,temparea);
assert (cost != -1);
cost += startweight;
if (SetWeight (sx,sy,1,area,temparea,cost))
{
temp = new CALCZONEELEMENT (sx,sy,i,j,area,temparea,TOPEDGE);
calc.Insert (temp);
}
}
}
}
}
if (tempdata.right_connect)
{
i = sx+1;
j = sy;
if (i<MAPCELLCOUNT)
{
for (y=0;y<MAPCELLSIZE;y++)
{
if (g_MapCells[sx][sy].m_Areas[MAPCELLSIZE-1][y] == area)
{
temparea = g_MapCells[i][j].m_Areas[0][y];
cost = GetOneCostZone (sx,sy,2,area,area,temparea);
assert (cost != -1);
cost += startweight;
if (SetWeight (sx,sy,2,area,temparea,cost))
{
temp = new CALCZONEELEMENT (sx,sy,i,j,area,temparea,RIGHTEDGE);
calc.Insert (temp);
}
}
}
}
}
if (tempdata.bottom_connect)
{
i = sx;
j = sy+1;
if (j<MAPCELLCOUNT)
{
for (x=0;x<MAPCELLSIZE;x++)
{
if (g_MapCells[sx][sy].m_Areas[x][MAPCELLSIZE-1] == area)
{
temparea = g_MapCells[i][j].m_Areas[x][0];
cost = GetOneCostZone (sx,sy,3,area,area,temparea);
assert (cost != -1);
cost += startweight;
if (SetWeight (sx,sy,3,area,temparea,cost))
{
temp = new CALCZONEELEMENT (sx,sy,i,j,area,temparea,BOTTOMEDGE);
calc.Insert (temp);
}
}
}
}
}
return true;
}
bool CalcPathZone (std::stack<PATHZONEELEMENT> *dest,CPoint gstart,CPoint gend)
{
int curarea,endarea,startarea;
int i,j,k;
FibHeap calc;
CALCZONEELEMENT *temp;
CPoint start,end;
assert (gstart.x>=0);
assert (gstart.x<MAPSIZE);
assert (gstart.y>=0);
assert (gstart.y<MAPSIZE);
start = GlobalToCellIndex (gstart);
end = GlobalToCellIndex (gend);
assert (start.x != -1);
assert (start.y != -1);
assert (end.x != -1);
assert (end.y != -1);
if (start == end)
{
// TODO: need to update if start and end zones are the same yet can't get there
dest->push (PATHZONEELEMENT (start.x,start.y,end.x,end.y,g_MapCells[start.x][start.y].AreaGlobal (gstart.x,gstart.y),g_MapCells[end.x][end.y].AreaGlobal (gend.x,gend.y),-1));
return true;
}
int x=-1,y=-1;
bool done;
while (!dest->empty ())
dest->pop ();
for (i=0;i<MAPCELLSIZE;i++)
for (j=0;j<MAPCELLSIZE;j++)
for (k=0;k<OFFSIZEZONE;k++)
{
pathmapzone[i][j][k].clear ();
}
endarea = g_MapCells[end.x][end.y].AreaGlobal (gend.x,gend.y);
curarea = g_MapCells[start.x][start.y].AreaGlobal (gstart.x,gstart.y);
startarea = curarea;
AREADATA& tempdata = g_MapCells[start.x][start.y].AreaData (curarea);
AddCalcElements (calc,start.x,start.y,curarea,0);
done = false;
while (!done)
{
temp = (CALCZONEELEMENT *) calc.ExtractMin ();
if (temp == NULL)
break;
if ((temp->dx == end.x) && (temp->dy == end.y) && (temp->darea == endarea))
done = true;
else
AddCalcElements (calc,temp->dx,temp->dy,temp->darea,GetWeight (temp->sx,temp->sy,temp->dx,temp->dy,temp->sarea,temp->darea));
delete temp;
}
while (temp = (CALCZONEELEMENT *) calc.ExtractMin ())
delete temp;
if (!done)
return false;
done = false;
int curx,cury;
curx = end.x;
cury = end.y;
curarea = endarea;
while (!done)
{
int dx,dy,darea,dir;
FindLowerEdge (curx,cury,curarea,dx,dy,darea,dir,start.x,start.y,startarea);
dest->push (PATHZONEELEMENT (dx,dy,curx,cury,darea,curarea,dir));
curx = dx;
cury = dy;
curarea = darea;
if ((curx == start.x) && (cury == start.y) && (curarea == startarea))
{
done = true;
}
}
return true;
}