mirror of
https://github.com/OpenDriver2/REDRIVER2.git
synced 2024-11-23 02:42:38 +01:00
1230 lines
21 KiB
C
1230 lines
21 KiB
C
#include "driver2.h"
|
|
#include "pathfind.h"
|
|
#include "system.h"
|
|
#include "cop_ai.h"
|
|
#include "objcoll.h"
|
|
#include "dr2roads.h"
|
|
#include "players.h"
|
|
#include "cars.h"
|
|
#include "camera.h"
|
|
#include "felony.h"
|
|
#include "map.h"
|
|
|
|
#define DEBUG_PATHFINDING_VIEW 0
|
|
|
|
#if DEBUG_PATHFINDING_VIEW && !defined(PSX)
|
|
#include "SDL.h"
|
|
#include <stdint.h>
|
|
#endif
|
|
|
|
struct tNode
|
|
{
|
|
int vx;
|
|
int vy;
|
|
int vz;
|
|
u_short dist;
|
|
u_short ptoey; // just a padding.
|
|
};
|
|
|
|
struct XZDIR
|
|
{
|
|
short dx;
|
|
short dz;
|
|
};
|
|
|
|
ushort distanceCache[16384];
|
|
char omap[128][16]; // obstacle map
|
|
int dunyet[32][2]; // scanned cell map
|
|
int pathIterations;
|
|
|
|
int pathFrames;
|
|
int DoExtraWorkForNFrames;
|
|
|
|
VECTOR searchTarget;
|
|
int playerTargetDistanceSq;
|
|
|
|
int distanceReturnedLog[8];
|
|
int distLogIndex;
|
|
int lastDistanceFound;
|
|
|
|
tNode heap[201];
|
|
u_int numHeapEntries = 0;
|
|
|
|
XZDIR ends[6][2] = {
|
|
{
|
|
{0, 0},
|
|
{512, 0}
|
|
},
|
|
|
|
{
|
|
{0, 0},
|
|
{256, 512 }
|
|
},
|
|
|
|
{
|
|
{256, 512},
|
|
{512, 0}
|
|
},
|
|
|
|
{
|
|
{256, 512},
|
|
{-256, 512}
|
|
},
|
|
|
|
{
|
|
{256, 512},
|
|
{0, 1024}
|
|
},
|
|
{
|
|
{256, 512 },
|
|
{512, 1024}
|
|
}
|
|
};
|
|
|
|
XZDIR dirs[6] = {
|
|
{
|
|
512,0
|
|
},
|
|
{
|
|
256,-512
|
|
},
|
|
{
|
|
-256,-512
|
|
},
|
|
{
|
|
-512,0
|
|
},
|
|
{
|
|
-256,512
|
|
},
|
|
{
|
|
256,512
|
|
},
|
|
};
|
|
|
|
// cx, cz in range of 0..128
|
|
#define OMAP_V(cx, cz) omap[((cx) & 0x7f)][((cz) & 0x7f) >> 3]
|
|
#define OMAP_GETVALUE(cx, cz) (OMAP_V(cx,cz) >> ((cz) & 7) & 1)
|
|
|
|
// cx, cz in range of 0...128
|
|
// FIXME: really bad
|
|
#define DONEMAP_V(cx, cz) dunyet[(cx & 0x1fU)][(cz & 1)]
|
|
#define DONEMAP_GETVALUE(cx, cz, x, i) (3 << (cz & 0x1e) & ((((cx & 0x3fU) >> 5 | cz & 2) ^ i) << (cz & 0x1e) ^ x))
|
|
|
|
#define DISTMAP_V(px, py, pz) distanceCache[(px >> 2 & 0x3f80U | pz >> 9 & 0x7fU) ^ (py & 1) * 0x2040 ^ (py & 2) << 0xc]
|
|
|
|
// [A] sets obstacle map bit
|
|
inline void OMapSet(int cellX, int cellZ, int val)
|
|
{
|
|
u_char prev = OMAP_V(cellX, cellZ);
|
|
int bit = (1 << (cellZ & 7));
|
|
OMAP_V(cellX, cellZ) = prev ^ bit & (prev ^ (val ? 0xFF : 0));
|
|
}
|
|
|
|
// [A] debug obstacle map display with new debug window
|
|
void DebugDisplayObstacleMap()
|
|
{
|
|
#if DEBUG_PATHFINDING_VIEW && !defined(PSX)
|
|
static SDL_Window* occlusionWindow;
|
|
static SDL_Surface* occlSurface;
|
|
static SDL_Texture* occlTexture;
|
|
static SDL_Surface* windowSurf;
|
|
|
|
if (!occlusionWindow)
|
|
{
|
|
occlusionWindow = SDL_CreateWindow("Data Graphics View", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 512, 512, SDL_WINDOW_TOOLTIP);
|
|
occlSurface = SDL_CreateRGBSurface(0, 128, 128, 24, 0xFF, 0xFF, 0xFF, 0);
|
|
}
|
|
|
|
SDL_LockSurface(occlSurface);
|
|
|
|
int pos_x = player[0].pos[0] >> 8;
|
|
int pos_z = player[0].pos[2] >> 8;
|
|
int pos_y = player[0].pos[1];
|
|
|
|
tNode n;
|
|
n.vx = player[0].pos[0];
|
|
n.vz = player[0].pos[2];
|
|
n.vy = pos_y;
|
|
n.vy = MapHeight((VECTOR*)&n);
|
|
|
|
for (int i = 0; i < 128; i++)
|
|
{
|
|
unsigned char* rgbLine = (unsigned char*)occlSurface->pixels + 128 * i * 3;
|
|
|
|
for (int j = 0; j < 128; j++)
|
|
{
|
|
int px = pos_x + i - 64;
|
|
int pz = pos_z + j - 64;
|
|
|
|
if (OMAP_GETVALUE(px,pz))
|
|
{
|
|
rgbLine[j * 3] = 128;
|
|
rgbLine[j * 3 + 1] = 128;
|
|
rgbLine[j * 3 + 2] = 32;
|
|
}
|
|
else
|
|
{
|
|
rgbLine[j * 3] = 0;
|
|
rgbLine[j * 3 + 1] = 0;
|
|
rgbLine[j * 3 + 2] = 0;
|
|
}
|
|
|
|
//local_v0_152 = dunyet[(bPos.vx >> 10 & 0x1fU)][((bPos.vz >> 10) & 1)];
|
|
|
|
// NEW METHOD
|
|
// int val = dunyet[px >> 2 & 0x1f][pz >> 6 & 1]; // dunyet[px >> 2 & 0x1f][pz >> 2 & 1];
|
|
// val = val >> (pz >> 2 & 0x1f) & 1;
|
|
|
|
n.vx = px << 8;
|
|
n.vz = pz << 8;
|
|
n.vy = MapHeight((VECTOR*)&n);
|
|
|
|
int dist = distanceCache[(n.vx >> 2 & 0x3f80U | n.vz >> 9 & 0x7fU) ^ (n.vy & 1U) * 0x2040 ^ (n.vy & 2U) << 0xc];// distanceCache[((pos_x+i & 127) * 128) + (j + pos_z & 127)];
|
|
|
|
int prev = DONEMAP_V(px >> 2, pz >> 2);
|
|
int val = DONEMAP_GETVALUE(px >> 2, pz >> 2, prev, 0);
|
|
|
|
if (val != 0)
|
|
rgbLine[j * 3] = 128;
|
|
|
|
if (rgbLine[j * 3] == 0 && rgbLine[j * 3 + 2] == 0)
|
|
rgbLine[j * 3 + 1] = dist / 64;
|
|
}
|
|
}
|
|
|
|
SDL_UnlockSurface(occlSurface);
|
|
|
|
windowSurf = SDL_GetWindowSurface(occlusionWindow);
|
|
|
|
SDL_Rect rect;
|
|
rect.x = 1;
|
|
rect.y = 1;
|
|
rect.w = 511;
|
|
rect.h = 511;
|
|
|
|
SDL_BlitScaled(occlSurface, NULL, windowSurf, &rect);
|
|
SDL_UpdateWindowSurface(occlusionWindow);
|
|
|
|
SDL_FreeSurface(windowSurf);
|
|
#endif
|
|
}
|
|
|
|
// [D] [T]
|
|
void popNode(tNode* __return_storage_ptr__)
|
|
{
|
|
int num;
|
|
int child;
|
|
ushort d;
|
|
int here;
|
|
tNode res;
|
|
ushort lastDist;
|
|
|
|
here = 1;
|
|
res = heap[here];
|
|
|
|
if (numHeapEntries > 1)
|
|
{
|
|
lastDist = heap[numHeapEntries].dist;
|
|
|
|
while (true)
|
|
{
|
|
child = here * 2;
|
|
|
|
d = heap[child].dist;
|
|
|
|
if (child >= numHeapEntries - 2 || d > heap[child + 1].dist)
|
|
{
|
|
d = heap[child + 1].dist;
|
|
child++;
|
|
}
|
|
|
|
if ((numHeapEntries - 2 < child) || (lastDist <= d))
|
|
break;
|
|
|
|
copyVector(&heap[here], &heap[child]);
|
|
heap[here].dist = d;
|
|
|
|
here = child;
|
|
}
|
|
|
|
heap[here] = heap[numHeapEntries];
|
|
}
|
|
|
|
numHeapEntries--;
|
|
|
|
*__return_storage_ptr__ = res;
|
|
}
|
|
|
|
// [D] [T]
|
|
void WunCell(VECTOR* pbase)
|
|
{
|
|
VECTOR v[2];
|
|
int height1;
|
|
int i, j;
|
|
|
|
// [A] hack with height map (fixes some bits in Havana)
|
|
height1 = MapHeight(pbase);
|
|
|
|
pbase->vx += 512;
|
|
pbase->vz += 512;
|
|
|
|
v[0].vy = MapHeight(pbase);
|
|
|
|
pbase->vx -= 512;
|
|
pbase->vz -= 512;
|
|
|
|
if (height1 - v[0].vy > 100)
|
|
v[0].vy = height1;
|
|
|
|
v[0].vy += 32;
|
|
v[1].vy = v[0].vy;
|
|
|
|
// [A] definitely better code
|
|
// new 16 vs old 12 passes but map is not leaky at all
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
v[0].vx = pbase->vx + i * 256 + 128;
|
|
v[0].vz = pbase->vz + j * 256 + 128;
|
|
|
|
OMapSet(v[0].vx >> 8, v[0].vz >> 8, CellAtPositionEmpty(&v[0], 128) == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// [A] function that invalidates map at ends
|
|
// fixes bug with not being able to update navigation cells
|
|
void InvalidateMapEnds()
|
|
{
|
|
int x, z;
|
|
int tile;
|
|
int i;
|
|
XZPAIR pos;
|
|
pos.x = (player[0].pos[0] & 0xfffffc00) >> 10;
|
|
pos.z = (player[0].pos[2] & 0xfffffc00) >> 10;
|
|
|
|
for(i = 0; i < 32; i++)
|
|
{
|
|
x = pos.x + 15 + i;
|
|
z = pos.z + 16;
|
|
|
|
tile = DONEMAP_V(x, z);
|
|
DONEMAP_V(x, z) = tile ^ DONEMAP_GETVALUE(x, z, tile, 3);
|
|
|
|
x = pos.x + 16;
|
|
z = pos.z + 15 + i;
|
|
|
|
tile = DONEMAP_V(x, z);
|
|
DONEMAP_V(x, z) = tile ^ DONEMAP_GETVALUE(x, z, tile, 3);
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void InvalidateMap(void)
|
|
{
|
|
int dir;
|
|
int p;
|
|
int q;
|
|
int count;
|
|
int px, pz;
|
|
VECTOR bPos;
|
|
int tile, i;
|
|
|
|
q = 0;
|
|
p = 0;
|
|
dir = 0;
|
|
|
|
bPos.vx = player[0].pos[0] & 0xfffffc00;
|
|
bPos.vz = player[0].pos[2] & 0xfffffc00;
|
|
|
|
count = 0;
|
|
do
|
|
{
|
|
px = bPos.vx >> 10;
|
|
pz = bPos.vz >> 10;
|
|
|
|
tile = DONEMAP_V(px, pz);
|
|
i = DONEMAP_GETVALUE(px, pz, tile, 3);
|
|
|
|
DONEMAP_V(px, pz) = tile ^ i;
|
|
|
|
if (dir == 0)
|
|
{
|
|
p++;
|
|
bPos.vx += MAP_CELL_SIZE / 2;
|
|
|
|
if (p + q == 1)
|
|
dir = 1;
|
|
}
|
|
else if (dir == 1)
|
|
{
|
|
q++;
|
|
bPos.vz += MAP_CELL_SIZE / 2;
|
|
|
|
if (p == q)
|
|
dir = 2;
|
|
}
|
|
else if (dir == 2)
|
|
{
|
|
p--;
|
|
bPos.vx -= MAP_CELL_SIZE / 2;
|
|
|
|
if (p + q == 0)
|
|
dir = 3;
|
|
}
|
|
else
|
|
{
|
|
q--;
|
|
bPos.vz -= MAP_CELL_SIZE / 2;
|
|
|
|
if (p == q)
|
|
dir = 0;
|
|
}
|
|
|
|
count++;
|
|
}while (count < 1024);
|
|
}
|
|
|
|
|
|
u_int cellsThisFrame;
|
|
u_int cellsPerFrame = 4;
|
|
|
|
// [D] [T]
|
|
void BloodyHell(void)
|
|
{
|
|
int dir;
|
|
int p;
|
|
int q;
|
|
int px, pz;
|
|
u_int howMany;
|
|
int count;
|
|
VECTOR bPos;
|
|
int tile, i;
|
|
|
|
cellsThisFrame = 0;
|
|
|
|
// [A] really it should be based on player's height
|
|
bPos.vy = player[0].pos[1] ;
|
|
|
|
bPos.vx = player[0].pos[0] & 0xfffffc00;
|
|
bPos.vz = player[0].pos[2] & 0xfffffc00;
|
|
|
|
howMany = cellsPerFrame;
|
|
|
|
if (CameraCnt < 4)
|
|
howMany = cellsPerFrame + 20;
|
|
|
|
q = 0;
|
|
|
|
if (CameraCnt < 8)
|
|
howMany += 4;
|
|
|
|
p = 0;
|
|
dir = 0;
|
|
count = 0;
|
|
|
|
InvalidateMapEnds();
|
|
|
|
do {
|
|
if (count == 200)
|
|
howMany--;
|
|
|
|
px = bPos.vx >> 10;
|
|
pz = bPos.vz >> 10;
|
|
|
|
tile = DONEMAP_V(px, pz);
|
|
i = DONEMAP_GETVALUE(px, pz, tile, 0);
|
|
|
|
if (i != 0)
|
|
{
|
|
DONEMAP_V(px, pz) = tile ^ i;
|
|
|
|
WunCell(&bPos);
|
|
|
|
cellsThisFrame++;
|
|
|
|
if (cellsThisFrame >= howMany)
|
|
return;
|
|
}
|
|
|
|
if (dir == 0)
|
|
{
|
|
p++;
|
|
bPos.vx += MAP_CELL_SIZE / 2;
|
|
|
|
if (p + q == 1)
|
|
dir = 1;
|
|
}
|
|
else if (dir == 1)
|
|
{
|
|
q++;
|
|
bPos.vz += MAP_CELL_SIZE / 2;
|
|
|
|
if (p == q)
|
|
dir = 2;
|
|
}
|
|
else if (dir == 2)
|
|
{
|
|
p--;
|
|
|
|
bPos.vx -= MAP_CELL_SIZE / 2;
|
|
|
|
if (p + q == 0)
|
|
dir = 3;
|
|
}
|
|
else
|
|
{
|
|
q--;
|
|
bPos.vz -= MAP_CELL_SIZE / 2;
|
|
|
|
if (p == q)
|
|
dir = 0;
|
|
}
|
|
|
|
count++;
|
|
} while( count < 840 );
|
|
}
|
|
|
|
int slowWallTests = 0;
|
|
|
|
// [D] [T]
|
|
int blocked(tNode* v1, tNode* v2)
|
|
{
|
|
int x, z;
|
|
|
|
if (slowWallTests != 0)
|
|
return lineClear((VECTOR*)v1, (VECTOR*)v2) == 0;
|
|
|
|
x = v1->vx + v1->vx >> 9;
|
|
z = v1->vz + v2->vz >> 9;
|
|
|
|
return OMAP_GETVALUE(x, z);
|
|
}
|
|
|
|
// [D] [T]
|
|
void setDistance(tNode* n, ushort dist)
|
|
{
|
|
n->dist = dist | 1; // valid bit for this frame
|
|
|
|
distanceCache[(n->vx >> 2 & 0x3f80U | n->vz >> 9 & 0x7fU) ^ (n->vy & 1U) * 0x2040 ^ (n->vy & 2U) << 0xc] = dist | 1;
|
|
}
|
|
|
|
// [D] [T]
|
|
void iterate(void)
|
|
{
|
|
tNode pathNodes[8];
|
|
|
|
int dist;
|
|
tNode* nbr;
|
|
int dir;
|
|
tNode itHere;
|
|
|
|
ushort nl, nr;
|
|
int a;
|
|
u_int pnode;
|
|
u_int parent;
|
|
u_int i;
|
|
int r;
|
|
|
|
if (numHeapEntries == 0)
|
|
return;
|
|
|
|
popNode(&itHere);
|
|
nbr = pathNodes;
|
|
|
|
// check directions
|
|
for(dir = 0; dir < 6; dir++)
|
|
{
|
|
nbr++;
|
|
|
|
nbr->vx = itHere.vx + dirs[dir].dx;
|
|
nbr->vy = itHere.vy;
|
|
nbr->vz = itHere.vz + dirs[dir].dz;
|
|
|
|
dist = DISTMAP_V(nbr->vx, nbr->vy, nbr->vz);
|
|
|
|
nbr->dist = dist;
|
|
|
|
if ((dist & 1) == 0)
|
|
{
|
|
if (blocked(&itHere, nbr) == 0)
|
|
{
|
|
if (ABS(nbr->vy - itHere.vy) < 201)
|
|
{
|
|
if ((dist & 1) == 0)
|
|
nbr->dist = 0;
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
nbr->dist = 1;
|
|
}
|
|
else
|
|
{
|
|
if (dist <= itHere.dist - 288)
|
|
{
|
|
nbr->dist = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// now we have distance let's compute the rest of the map
|
|
for(dir = 0; dir < 6; dir++)
|
|
{
|
|
if (pathNodes[dir + 1].dist != 0)
|
|
continue;
|
|
|
|
if (dir != 5)
|
|
nr = pathNodes[dir + 2].dist;
|
|
else
|
|
nr = pathNodes[1].dist;
|
|
|
|
if (dir != 0)
|
|
nl = pathNodes[dir].dist;
|
|
else
|
|
nl = pathNodes[6].dist;
|
|
|
|
// uhhmm... distance function selection?
|
|
if (nl < 2)
|
|
{
|
|
if (nr < 2)
|
|
dist = itHere.dist + 256;
|
|
else
|
|
dist = (nr + itHere.dist >> 1) + 221;
|
|
}
|
|
else
|
|
{
|
|
if (nr < 2)
|
|
{
|
|
dist = (nl + itHere.dist >> 1) + 221;
|
|
}
|
|
else
|
|
{
|
|
r = nr - nl;
|
|
dist = 0x10000 - (r * r) / 3;
|
|
|
|
if (dist < 0)
|
|
{
|
|
dist = 0;
|
|
}
|
|
else
|
|
{
|
|
a = (dist >> 9) + 128;
|
|
dist = dist / a + a >> 1;
|
|
}
|
|
|
|
dist += itHere.dist;
|
|
}
|
|
}
|
|
|
|
dist &= 0xffff;
|
|
|
|
// store distance and get to the next lesser node
|
|
if (numHeapEntries != 198)
|
|
{
|
|
setDistance(&pathNodes[dir + 1], dist);
|
|
|
|
i = numHeapEntries + 1;
|
|
|
|
pnode = i;
|
|
parent = i >> 1;
|
|
|
|
while (parent != 0 && dist < heap[parent].dist)
|
|
{
|
|
heap[i] = heap[parent];
|
|
|
|
pnode = parent;
|
|
parent >>= 1;
|
|
}
|
|
|
|
heap[pnode] = pathNodes[dir + 1];
|
|
numHeapEntries++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void InitPathFinding(void)
|
|
{
|
|
int i;
|
|
|
|
setMem16((ushort*)distanceCache, 0xfffe, sizeof(distanceCache) / sizeof(short));
|
|
ClearMem((char*)omap, sizeof(omap));
|
|
ClearMem((char*)dunyet, sizeof(dunyet));
|
|
InvalidateMap();
|
|
|
|
lastDistanceFound = 18000;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
distanceReturnedLog[i++] = 18000;
|
|
|
|
pathFrames = 80;
|
|
DoExtraWorkForNFrames = 6;
|
|
distLogIndex = 0;
|
|
searchTarget.vx = 0;
|
|
searchTarget.vy = -12367;
|
|
searchTarget.vz = 0;
|
|
playerTargetDistanceSq = 0;
|
|
pathFrames = 0;
|
|
pathIterations = 129;
|
|
}
|
|
|
|
extern int sdLevel; // D2ROADS
|
|
|
|
// [D] [T]
|
|
int getInterpolatedDistance(VECTOR* pos)
|
|
{
|
|
int res;
|
|
int x;
|
|
int dist;
|
|
int min;
|
|
int a,b,c;
|
|
int fx;
|
|
int fz;
|
|
tNode n;
|
|
VECTOR sp;
|
|
|
|
// WHY?
|
|
n.vx = ((pos->vx + (pos->vz >> 1 & 0x1ffU)) >> 9) * 512 - ((pos->vz & 0x200) >> 1);
|
|
n.vy = pos->vy;
|
|
n.vz = (pos->vz >> 9) << 9;
|
|
|
|
if (OMAP_GETVALUE(n.vx >> 8, n.vz >> 8) != 0)
|
|
{
|
|
res = MapHeight((VECTOR*)&n);
|
|
n.vy = res ^ (res ^ sdLevel) & 3;
|
|
}
|
|
else
|
|
{
|
|
n.vy = 0;
|
|
}
|
|
|
|
fz = pos->vz - n.vz;
|
|
fx = (pos->vx - n.vx) + (fz >> 1);
|
|
|
|
sp.vx = n.vx + 256;
|
|
sp.vz = n.vz + 512;
|
|
|
|
n.dist = distanceCache[(n.vx >> 2 & 0x3f80U | n.vz >> 9 & 0x7fU) ^ (n.vy & 1U) * 0x2040 ^ (n.vy & 2U) << 0xc];
|
|
a = n.dist;
|
|
|
|
n.vx = sp.vx;
|
|
n.vz = sp.vz;
|
|
|
|
if (OMAP_GETVALUE(sp.vx >> 8, sp.vz >> 8) != 0)
|
|
{
|
|
res = MapHeight((VECTOR*)&n);
|
|
n.vy = res ^ (res ^ sdLevel) & 3;
|
|
}
|
|
else
|
|
{
|
|
n.vy = 0;
|
|
}
|
|
|
|
n.dist = distanceCache[(n.vx >> 2 & 0x3f80U | n.vz >> 9 & 0x7fU) ^ (n.vy & 1U) * 0x2040 ^ (n.vy & 2U) << 0xc];
|
|
b = n.dist;
|
|
|
|
if (a < b)
|
|
min = a;
|
|
else
|
|
min = b;
|
|
|
|
if (fz < fx)
|
|
{
|
|
n.vx = sp.vx + 256;
|
|
n.vz = sp.vz - 512;
|
|
|
|
if (OMAP_GETVALUE(n.vx >> 8, n.vz >> 8) != 0)
|
|
{
|
|
res = MapHeight((VECTOR*)&n);
|
|
res = res ^ (res ^ sdLevel) & 3;
|
|
}
|
|
else
|
|
{
|
|
res = 0;
|
|
}
|
|
|
|
dist = distanceCache[(n.vx >> 2 & 0x3f80U | n.vz >> 9 & 0x7fU) ^ (res & 1) * 0x2040 ^ (res & 2) << 0xc];
|
|
|
|
if (min < dist)
|
|
c = min;
|
|
else
|
|
c = dist;
|
|
|
|
c += 341;
|
|
|
|
if (c > 0xffff)
|
|
c = 0xffff;
|
|
else if (a > c)
|
|
a = c;
|
|
|
|
if (b > c)
|
|
b = c;
|
|
|
|
x = dist - a;
|
|
|
|
if (c < dist)
|
|
{
|
|
x = c - a;
|
|
dist = c;
|
|
}
|
|
|
|
x = x * fx;
|
|
res = (b - dist) * fz;
|
|
}
|
|
else
|
|
{
|
|
n.vx = sp.vx - 512;
|
|
n.vz = sp.vz;
|
|
|
|
if (OMAP_GETVALUE(n.vx >> 8, n.vz >> 8) != 0)
|
|
{
|
|
res = MapHeight((VECTOR*)&n);
|
|
res = res ^ (res ^ sdLevel) & 3;
|
|
}
|
|
else
|
|
{
|
|
res = 0;
|
|
}
|
|
|
|
dist = distanceCache[(n.vx >> 2 & 0x3f80U | n.vz >> 9 & 0x7fU) ^ (res & 1) * 0x2040 ^ (res & 2) << 0xc];
|
|
|
|
if (min < dist)
|
|
c = min;
|
|
else
|
|
c = dist;
|
|
|
|
c += 341;
|
|
|
|
if (c > 0xffff)
|
|
c = 0xffff;
|
|
else if (a > c)
|
|
a = c;
|
|
|
|
if (b > c)
|
|
b = c;
|
|
|
|
x = dist - a;
|
|
|
|
if (c < dist)
|
|
{
|
|
x = c - a;
|
|
dist = c;
|
|
}
|
|
|
|
x = x * fz;
|
|
res = (b - dist) * fx;
|
|
}
|
|
|
|
a = a + (x + res >> 9);
|
|
|
|
lastDistanceFound = a ^ (a & 1 ^ a) & 1;
|
|
|
|
return lastDistanceFound;
|
|
}
|
|
|
|
// [D] [T]
|
|
void addCivs(void)
|
|
{
|
|
unsigned char bits;
|
|
int rx, rz;
|
|
int x, z, vx, vz;
|
|
int vx2, vz2;
|
|
CAR_DATA* cp;
|
|
|
|
cp = car_data;
|
|
do {
|
|
if (cp->controlType == CONTROL_TYPE_CIV_AI)
|
|
{
|
|
rx = cp->hd.oBox.radii[2].vx;
|
|
rz = cp->hd.oBox.radii[2].vz;
|
|
|
|
x = cp->hd.oBox.location.vx;
|
|
z = cp->hd.oBox.location.vz;
|
|
|
|
vx = x + rx >> 8;
|
|
vz = z + rz >> 8;
|
|
|
|
bits = 3 << (vz & 6);
|
|
|
|
OMAP_V(vx, vz) ^= bits;
|
|
OMAP_V(vx+1, vz) ^= bits;
|
|
|
|
vx2 = x - rx >> 8;
|
|
vz2 = z - rz >> 8;
|
|
|
|
if ((vx ^ (vz & 0x7e) << 8) == vx2 &&
|
|
(vz2 & 0x7e) != 0 || (vz2 & 0x7e << 8) != 1)
|
|
{
|
|
bits = 3 << (vz2 & 6);
|
|
|
|
OMAP_V(vx2, vz2) ^= bits;
|
|
OMAP_V(vx2+1, vz2) ^= bits;
|
|
}
|
|
}
|
|
|
|
cp++;
|
|
} while (cp < &car_data[MAX_CARS - 1]);
|
|
}
|
|
|
|
// [D] [T]
|
|
void UpdateCopMap(void)
|
|
{
|
|
int d;
|
|
int dist;
|
|
int dx, dy, dz;
|
|
int i, maxret;
|
|
int res;
|
|
tNode startNode;
|
|
u_int pnode;
|
|
u_int parent;
|
|
|
|
BloodyHell();
|
|
|
|
// quickly invalidate and do extra
|
|
if (player_position_known == 1 || CameraCnt == 6)
|
|
{
|
|
pathFrames = 0;
|
|
setMem16((ushort*)distanceCache, 0xfffe, 0x4000);
|
|
DoExtraWorkForNFrames = 3;
|
|
}
|
|
|
|
if (pathFrames != 0)
|
|
{
|
|
int iterations;
|
|
|
|
// add cars
|
|
addCivs();
|
|
|
|
iterations = cellsThisFrame;
|
|
|
|
if (iterations > 6)
|
|
iterations = 6;
|
|
|
|
i = pathIterations - iterations * 4 * 4 - iterations * 5;
|
|
|
|
if (DoExtraWorkForNFrames != 0)
|
|
{
|
|
DoExtraWorkForNFrames--;
|
|
i += 60;
|
|
}
|
|
|
|
if (i < 36)
|
|
i = 36;
|
|
|
|
while (--i >= 0)
|
|
iterate();
|
|
|
|
DebugDisplayObstacleMap();
|
|
|
|
// remove cars
|
|
addCivs();
|
|
}
|
|
else
|
|
{
|
|
// restart from new search target position
|
|
if (player[0].playerType == 1 && (CopsCanSeePlayer != 0 || numActiveCops == 0))
|
|
{
|
|
CAR_DATA* cp;
|
|
cp = &car_data[player[0].playerCarId];
|
|
|
|
searchTarget.vx = cp->hd.where.t[0] + FIXEDH(cp->st.n.linearVelocity[0]) * 8;
|
|
searchTarget.vy = cp->hd.where.t[1] + FIXEDH(cp->st.n.linearVelocity[1]) * 4;
|
|
searchTarget.vz = cp->hd.where.t[2] + FIXEDH(cp->st.n.linearVelocity[2]) * 8;
|
|
}
|
|
else if (searchTarget.vy == -0x304f)
|
|
{
|
|
searchTarget.vx = player[0].pos[0];
|
|
searchTarget.vy = player[0].pos[1];
|
|
searchTarget.vz = player[0].pos[2];
|
|
}
|
|
|
|
// step up distance frame (and invalidate by setting bit 1)
|
|
for (i = 0; i < 16384; i++)
|
|
{
|
|
d = distanceCache[i] + 8192;
|
|
|
|
if ((d & 1) != 0)
|
|
d ^= 1;
|
|
|
|
if (d > 0xfffe)
|
|
d = 0xfffe;
|
|
|
|
distanceCache[i] = d;
|
|
}
|
|
|
|
startNode.vx = ((searchTarget.vx + (searchTarget.vz >> 1 & 0x1ffU)) >> 9) * 512 - ((searchTarget.vz & 0x200U) >> 1);
|
|
startNode.vz = (searchTarget.vz >> 9) << 9;
|
|
startNode.vy = searchTarget.vy;
|
|
|
|
numHeapEntries = 0;
|
|
|
|
// pick the height
|
|
if(OMAP_GETVALUE(startNode.vx >> 8, startNode.vz >> 8) != 0)
|
|
{
|
|
res = MapHeight((VECTOR*)&startNode);
|
|
startNode.vy = res ^ (res ^ sdLevel) & 3;
|
|
}
|
|
else
|
|
{
|
|
startNode.vy = 0;
|
|
}
|
|
|
|
dx = searchTarget.vx - startNode.vx;
|
|
dz = searchTarget.vz - startNode.vz;
|
|
|
|
if (dz < dx + dz / 2)
|
|
{
|
|
dx = startNode.vx - searchTarget.vx;
|
|
dz = startNode.vz - searchTarget.vz;
|
|
|
|
dist = SquareRoot0(dx * dx + (dz) * (dz));
|
|
dist = dist / 2 & 0xffff;
|
|
|
|
if (numHeapEntries != 198)
|
|
{
|
|
setDistance(&startNode, dist);
|
|
|
|
i = numHeapEntries + 1;
|
|
|
|
pnode = i;
|
|
parent = i >> 1;
|
|
|
|
while (parent != 0 && dist < heap[parent].dist)
|
|
{
|
|
heap[i] = heap[parent];
|
|
|
|
pnode = parent;
|
|
parent >>= 1;
|
|
}
|
|
|
|
heap[pnode] = startNode;
|
|
numHeapEntries++;
|
|
}
|
|
|
|
startNode.vx += 256;
|
|
startNode.vz += 512;
|
|
|
|
dist = SquareRoot0((startNode.vx - searchTarget.vx) * (startNode.vx - searchTarget.vx) + (startNode.vz - searchTarget.vz) * (startNode.vz - searchTarget.vz));
|
|
dist = dist / 2 & 0xffff;
|
|
|
|
if (numHeapEntries != 198)
|
|
{
|
|
setDistance(&startNode, dist);
|
|
|
|
i = numHeapEntries + 1;
|
|
|
|
pnode = i;
|
|
parent = i >> 1;
|
|
|
|
while (parent != 0 && dist < heap[parent].dist)
|
|
{
|
|
heap[i] = heap[parent];
|
|
|
|
pnode = parent;
|
|
parent >>= 1;
|
|
}
|
|
|
|
heap[pnode] = startNode;
|
|
numHeapEntries++;
|
|
}
|
|
|
|
startNode.vx += 256;
|
|
startNode.vz -= 512;
|
|
|
|
dist = SquareRoot0((startNode.vx - searchTarget.vx) * (startNode.vx - searchTarget.vx) + (startNode.vz - searchTarget.vz) * (startNode.vz - searchTarget.vz));
|
|
dist = dist / 2 & 0xffff;
|
|
|
|
if (numHeapEntries != 198)
|
|
{
|
|
setDistance(&startNode, dist);
|
|
|
|
i = numHeapEntries + 1;
|
|
|
|
pnode = i;
|
|
parent = i >> 1;
|
|
|
|
while (parent != 0 && dist < heap[parent].dist)
|
|
{
|
|
heap[i] = heap[parent];
|
|
|
|
pnode = parent;
|
|
parent >>= 1;
|
|
}
|
|
|
|
heap[pnode] = startNode;
|
|
numHeapEntries++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dx = startNode.vx - searchTarget.vx;
|
|
dz = startNode.vz - searchTarget.vz;
|
|
|
|
dist = SquareRoot0(dx * dx + dz * dz);
|
|
dist = dist / 2 & 0xffff;
|
|
|
|
if (numHeapEntries != 198)
|
|
{
|
|
setDistance(&startNode, dist);
|
|
|
|
i = numHeapEntries + 1;
|
|
|
|
pnode = i;
|
|
parent = i >> 1;
|
|
|
|
while (parent != 0 && dist < heap[parent].dist)
|
|
{
|
|
heap[i] = heap[parent];
|
|
|
|
pnode = parent;
|
|
parent >>= 1;
|
|
}
|
|
|
|
heap[pnode] = startNode;
|
|
numHeapEntries++;
|
|
}
|
|
|
|
startNode.vx += 256;
|
|
startNode.vz += 512;
|
|
|
|
dist = SquareRoot0((startNode.vx - searchTarget.vx) * (startNode.vx - searchTarget.vx) + (startNode.vz - searchTarget.vz) * (startNode.vz - searchTarget.vz));
|
|
dist = dist / 2 & 0xffff;
|
|
|
|
if (numHeapEntries != 198)
|
|
{
|
|
setDistance(&startNode, dist);
|
|
|
|
i = numHeapEntries + 1;
|
|
|
|
pnode = i;
|
|
parent = i >> 1;
|
|
|
|
while (parent != 0 && dist < heap[parent].dist)
|
|
{
|
|
heap[i] = heap[parent];
|
|
|
|
pnode = parent;
|
|
parent >>= 1;
|
|
}
|
|
|
|
heap[pnode] = startNode;
|
|
numHeapEntries++;
|
|
}
|
|
|
|
startNode.vx -= 512;
|
|
|
|
dist = SquareRoot0((startNode.vx - searchTarget.vx) * (startNode.vx - searchTarget.vx) + (startNode.vz - searchTarget.vz) * (startNode.vz - searchTarget.vz));
|
|
dist = dist / 2 & 0xffff;
|
|
|
|
if (numHeapEntries != 198)
|
|
{
|
|
setDistance(&startNode, dist);
|
|
|
|
i = numHeapEntries + 1;
|
|
|
|
pnode = i;
|
|
parent = i >> 1;
|
|
|
|
while (parent != 0 && dist < heap[parent].dist)
|
|
{
|
|
heap[i] = heap[parent];
|
|
|
|
pnode = parent;
|
|
parent >>= 1;
|
|
}
|
|
|
|
heap[pnode] = startNode;
|
|
numHeapEntries++;
|
|
}
|
|
}
|
|
}
|
|
|
|
pathFrames++;
|
|
|
|
maxret = 0;
|
|
for(i = 0; i < 8; i++)
|
|
{
|
|
if (distanceReturnedLog[i] > maxret)
|
|
maxret = distanceReturnedLog[i];
|
|
}
|
|
|
|
if (pathFrames > 250 || // [A] was (pathFrames < pathFrames)
|
|
heap[1].dist - maxret > 3000)
|
|
{
|
|
pathFrames = 0;
|
|
}
|
|
|
|
dx = searchTarget.vx - player[0].pos[0] >> 4;
|
|
dy = searchTarget.vy - player[0].pos[1] >> 4;
|
|
dz = searchTarget.vz - player[0].pos[2] >> 4;
|
|
|
|
playerTargetDistanceSq = dx * dx + dy * dy + dz * dz;
|
|
}
|
|
|
|
// [D] [T]
|
|
int getHeadingToPlayer(int vx, int vy, int vz)
|
|
{
|
|
int d1, d2, d3;
|
|
int playerHereDistSq;
|
|
int dx, dy, dz;
|
|
int val;
|
|
VECTOR pos;
|
|
|
|
dx = vx - player[0].pos[0] >> 4;
|
|
dy = vy - player[0].pos[1] >> 4;
|
|
dz = vz - player[0].pos[2] >> 4;
|
|
|
|
val = 4004;
|
|
|
|
playerHereDistSq = (dx * dx + dy * dy + dz * dz);
|
|
|
|
if (playerTargetDistanceSq * 2 <= playerHereDistSq * 3)
|
|
{
|
|
pos.vy = vy;
|
|
|
|
pos.vx = vx - 128;
|
|
pos.vz = vz - 128;
|
|
|
|
d1 = getInterpolatedDistance(&pos);
|
|
|
|
pos.vx = vx + 128;
|
|
pos.vz = vz - 128;
|
|
d2 = getInterpolatedDistance(&pos);
|
|
|
|
pos.vz = vz + 128;
|
|
pos.vx = vx;
|
|
d3 = getInterpolatedDistance(&pos);
|
|
|
|
if (d3 > 61440)
|
|
{
|
|
ReplayLog_Fnarr_He_Said_Log(0x3e9);
|
|
|
|
dx = lastKnownPosition.vx - pos.vx;
|
|
dz = lastKnownPosition.vz - pos.vz;
|
|
|
|
return ratan2(dx, dz) + 4096;
|
|
}
|
|
|
|
val = 0xbbb;
|
|
|
|
if (d3 > 1536)
|
|
{
|
|
ReplayLog_Fnarr_He_Said_Log(0x7d2);
|
|
|
|
return ratan2((d1 - d2) * 2, d1 + d2 - d3 * 2) & 0xfff;
|
|
}
|
|
}
|
|
|
|
ReplayLog_Fnarr_He_Said_Log(val);
|
|
|
|
dx = player[0].pos[0] - vx;
|
|
dz = player[0].pos[2] - vz;
|
|
|
|
return ratan2(dx, dz) + 4096;
|
|
}
|