mirror of
https://github.com/OpenDriver2/REDRIVER2.git
synced 2024-11-26 04:12:34 +01:00
1968 lines
36 KiB
C
1968 lines
36 KiB
C
#include "driver2.h"
|
|
#include "overmap.h"
|
|
#include "texture.h"
|
|
#include "cars.h"
|
|
#include "system.h"
|
|
#include "mission.h"
|
|
#include "mdraw.h"
|
|
#include "players.h"
|
|
#include "overlay.h"
|
|
#include "debris.h"
|
|
#include "map.h"
|
|
#include "convert.h"
|
|
#include "pres.h"
|
|
#include "cop_ai.h"
|
|
#include "camera.h"
|
|
#include "felony.h"
|
|
#include "pad.h"
|
|
#include "ASM/rnc_2.h"
|
|
|
|
struct MAPTEX
|
|
{
|
|
short u, w, v, h;
|
|
};
|
|
|
|
struct OVERMAP
|
|
{
|
|
int x_offset, y_offset;
|
|
int width, height;
|
|
u_char toptile;
|
|
u_char dummy;
|
|
int scale;
|
|
};
|
|
|
|
OVERMAP overlaidmaps[4] =
|
|
{
|
|
{ 197, 318, 384, 672, 252, 0x99, 2145 },
|
|
{ 229, 85, 544, 352, 187, 0x88, 2048 },
|
|
{ 68, 457, 288, 672, 189, 0xBB, 1911 },
|
|
{ 159, 207, 416, 576, 252, 0x44, 2048 }
|
|
};
|
|
|
|
SXYPAIR MapSegmentPos[16];
|
|
|
|
XYPAIR NVertex[4] = {
|
|
{ -2, 3 },
|
|
{ -2, -3 },
|
|
{ 2, 3 },
|
|
{ 2, -3 }
|
|
};
|
|
|
|
XYPAIR north[4] = {
|
|
{ 0, 20 },
|
|
{ 0, 20 },
|
|
{ 0, 20 },
|
|
{ 0, 20 }
|
|
};
|
|
|
|
static short big_north[] =
|
|
{
|
|
2048, 2048, 2048, 2048
|
|
};
|
|
|
|
VECTOR player_position = { 0, 0, 0, 0 };
|
|
MATRIX map_matrix;
|
|
|
|
char* MapBitMaps;
|
|
static char MapBuffer[520];
|
|
static unsigned short MapClut;
|
|
static RECT16 MapRect;
|
|
|
|
static int tilehnum = 0;
|
|
static char maptile[4][4];
|
|
static char tile_size = 32;
|
|
|
|
static int old_x_mod = 0;
|
|
static int old_y_mod = 0;
|
|
|
|
static int x_map = 0;
|
|
static int y_map = 0;
|
|
|
|
static int map_x_offset = 0;
|
|
static int map_z_offset = 0;
|
|
int map_x_shift = 0;
|
|
int map_z_shift = 0;
|
|
|
|
|
|
static unsigned short MapTPage = 0;
|
|
|
|
static int gUseRotatedMap = 0;
|
|
|
|
int gMapXOffset = 249;
|
|
int gMapYOffset = 181;
|
|
|
|
void WorldToOverheadMapPositions(VECTOR * pGlobalPosition, VECTOR * pOverheadMapPosition, int count, char inputRelative, int outputRelative);
|
|
void WorldToMultiplayerMap(VECTOR * in, VECTOR * out);
|
|
void WorldToFullscreenMap(VECTOR * in, VECTOR * out);
|
|
void WorldToFullscreenMap2(VECTOR * in, VECTOR * out);
|
|
|
|
// [D] [T]
|
|
void DrawTargetBlip(VECTOR *pos, u_char r, u_char g, u_char b, int flags)
|
|
{
|
|
int ysize;
|
|
POLY_FT4 *poly;
|
|
VECTOR vec;
|
|
|
|
int map_minX, map_maxX;
|
|
int map_minY, map_maxY;
|
|
|
|
map_minX = gMapXOffset;
|
|
map_maxX = gMapXOffset + MAP_SIZE_W;
|
|
map_minY = gMapYOffset;
|
|
map_maxY = gMapYOffset + MAP_SIZE_H;
|
|
|
|
if (flags & 0x20)
|
|
{
|
|
WorldToMultiplayerMap(pos, &vec);
|
|
|
|
vec.vx += gMapXOffset;
|
|
vec.vz += 96;
|
|
}
|
|
else if (flags & 0x8)
|
|
{
|
|
vec.vx = pos->vx;
|
|
vec.vz = pos->vz;
|
|
}
|
|
else if (flags & 0x1)
|
|
{
|
|
WorldToOverheadMapPositions(pos, &vec, 1, 0, 0);
|
|
|
|
if (vec.vx <= map_minX || vec.vx >= map_maxX || vec.vz <= map_minY || vec.vz >= map_maxY)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WorldToFullscreenMap2(pos, &vec);
|
|
}
|
|
|
|
if ((flags & 1) == 0)
|
|
{
|
|
vec.vx += map_x_offset;
|
|
vec.vz += map_z_offset;
|
|
}
|
|
|
|
if (flags & 0x10)
|
|
ysize = OverlayFlashValue / 2;
|
|
else if (flags & 0x2)
|
|
ysize = 3;
|
|
else
|
|
ysize = 4;
|
|
|
|
poly = (POLY_FT4 *)current->primptr;
|
|
|
|
setPolyFT4(poly);
|
|
setSemiTrans(poly, 1);
|
|
|
|
poly->x0 = vec.vx - ysize;
|
|
poly->y0 = vec.vz - ysize;
|
|
|
|
poly->x1 = vec.vx + ysize;
|
|
poly->y1 = vec.vz - ysize;
|
|
|
|
poly->x2 = vec.vx - ysize;
|
|
poly->y2 = vec.vz + ysize;
|
|
|
|
poly->x3 = vec.vx + ysize;
|
|
poly->y3 = vec.vz + ysize;
|
|
|
|
poly->r0 = r;
|
|
poly->g0 = g;
|
|
poly->b0 = b;
|
|
|
|
*(ushort*)&poly->u0 = *(ushort*)&light_texture.coords.u0;
|
|
*(ushort*)&poly->u1 = *(ushort*)&light_texture.coords.u1;
|
|
*(ushort*)&poly->u2 = *(ushort*)&light_texture.coords.u2;
|
|
*(ushort*)&poly->u3 = *(ushort*)&light_texture.coords.u3;
|
|
|
|
if (flags & 0x2)
|
|
poly->tpage = light_texture.tpageid | 0x40;
|
|
else
|
|
poly->tpage = light_texture.tpageid | 0x20;
|
|
|
|
poly->clut = light_texture.clutid;
|
|
|
|
if (flags & 0x4)
|
|
{
|
|
// fullscreen map mode
|
|
DrawPrim(poly);
|
|
}
|
|
else
|
|
{
|
|
addPrim(current->ot + 1, poly);
|
|
current->primptr += sizeof(POLY_FT4);
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void DrawTargetArrow(VECTOR *pos, int flags)
|
|
{
|
|
int dy;
|
|
int dx;
|
|
POLY_G3 *poly;
|
|
VECTOR vec;
|
|
VECTOR vec2;
|
|
|
|
if (flags & 0x8)
|
|
{
|
|
vec.vx = pos->vx;
|
|
vec.vz = pos->vz;
|
|
}
|
|
else if (flags & 0x1)
|
|
{
|
|
WorldToOverheadMapPositions(pos, &vec, 1, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
WorldToFullscreenMap2(pos, &vec);
|
|
}
|
|
|
|
if (flags & 0x1)
|
|
{
|
|
WorldToOverheadMapPositions((VECTOR *)player, &vec2, 1, '\0', 0);
|
|
}
|
|
else
|
|
{
|
|
vec.vx = vec.vx + map_x_offset;
|
|
vec.vz = vec.vz + map_z_offset;
|
|
|
|
vec2.vx = map_x_offset + 160;
|
|
vec2.vz = map_z_offset + 128;
|
|
}
|
|
|
|
// target arrow perpendicular
|
|
dx = (vec2.vx - vec.vx) / 8;
|
|
dy = (vec2.vz - vec.vz) / 8;
|
|
|
|
poly = (POLY_G3 *)current->primptr;
|
|
|
|
setPolyG3(poly);
|
|
setSemiTrans(poly, 1);
|
|
|
|
poly->r0 = poly->r1 = 24;
|
|
poly->g0 = poly->g1 = 24;
|
|
poly->b0 = poly->b1 = 24;
|
|
|
|
poly->r2 = 64;
|
|
poly->g2 = 64;
|
|
poly->b2 = 64;
|
|
|
|
poly->x0 = vec2.vx + dy;
|
|
poly->y0 = vec2.vz - dx;
|
|
|
|
poly->x1 = vec2.vx - dy;
|
|
poly->y1 = vec2.vz + dx;
|
|
|
|
poly->x2 = vec.vx;
|
|
poly->y2 = vec.vz;
|
|
|
|
POLY_FT3* null = (POLY_FT3*)(poly + 1);
|
|
|
|
setPolyFT3(null);
|
|
setSemiTrans(null, 1);
|
|
|
|
null->x0 = -1;
|
|
null->y0 = -1;
|
|
null->x1 = -1;
|
|
null->y1 = -1;
|
|
null->x2 = -1;
|
|
null->y2 = -1;
|
|
|
|
null->tpage = 0x40;
|
|
|
|
if (flags & 0x4)
|
|
{
|
|
// fullscreen map
|
|
DrawPrim(null);
|
|
DrawPrim(poly);
|
|
}
|
|
else
|
|
{
|
|
addPrim(current->ot + 1, poly);
|
|
addPrim(current->ot + 1, null);
|
|
|
|
current->primptr += sizeof(POLY_G3) + sizeof(POLY_FT3);
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void DrawPlayerDot(VECTOR *pos, short rot, u_char r, u_char g, u_char b, int flags)
|
|
{
|
|
int sn;
|
|
int cs;
|
|
POLY_F3 *poly;
|
|
VECTOR opos[3];
|
|
VECTOR vec;
|
|
|
|
if (flags & 0x20)
|
|
{
|
|
WorldToMultiplayerMap(pos, &vec);
|
|
|
|
vec.vx += gMapXOffset;
|
|
vec.vz += 96;
|
|
}
|
|
else
|
|
{
|
|
if (flags & 0x8)
|
|
{
|
|
vec.vx = pos->vx;
|
|
vec.vz = pos->vz;
|
|
}
|
|
else if (flags & 0x1)
|
|
{
|
|
WorldToOverheadMapPositions(pos, &vec, 1, 0, 0);
|
|
|
|
if (vec.vx - 233U > 94)
|
|
return;
|
|
|
|
if (vec.vz < 174 || vec.vz > 250)
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
WorldToFullscreenMap2(pos, &vec);
|
|
}
|
|
}
|
|
|
|
if ((flags & 0x1) == 0)
|
|
{
|
|
vec.vx += map_x_offset;
|
|
vec.vz += map_z_offset;
|
|
}
|
|
|
|
sn = RSIN(rot);
|
|
cs = RCOS(rot);
|
|
|
|
opos[2].vx = vec.vx;
|
|
opos[2].vz = vec.vz;
|
|
|
|
opos[0].vx = vec.vx + FIXEDH(sn * -3);
|
|
opos[0].vz = vec.vz + FIXEDH(cs * -3);
|
|
|
|
opos[1].vx = vec.vx + FIXEDH(sn * 3 + cs * -2);
|
|
opos[1].vz = vec.vz + FIXEDH(cs * 3 + sn * 2);
|
|
|
|
opos[2].vx = vec.vx + FIXEDH(cs * 2 + sn * 3);
|
|
opos[2].vz = vec.vz + FIXEDH(sn * -2 + cs * 3);
|
|
|
|
poly = (POLY_F3 *)current->primptr;
|
|
setPolyF3(poly);
|
|
|
|
poly->r0 = r;
|
|
poly->g0 = g;
|
|
poly->b0 = b;
|
|
|
|
poly->x0 = opos[0].vx;
|
|
poly->y0 = opos[0].vz;
|
|
|
|
poly->x1 = opos[1].vx;
|
|
poly->y1 = opos[1].vz;
|
|
|
|
poly->x2 = opos[2].vx;
|
|
poly->y2 = opos[2].vz;
|
|
|
|
if (flags & 0x4)
|
|
{
|
|
DrawPrim(poly);
|
|
}
|
|
else
|
|
{
|
|
addPrim(current->ot + 1, poly);
|
|
current->primptr += sizeof(POLY_F3);
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void ProcessOverlayLump(char *lump_ptr, int lump_size)
|
|
{
|
|
int i;
|
|
TEXTURE_DETAILS info;
|
|
|
|
GetTextureDetails("OVERHEAD", &info);
|
|
|
|
MapTPage = info.tpageid;
|
|
MapClut = GetClut(mapclutpos.x, mapclutpos.y);
|
|
|
|
MapRect.w = 64;
|
|
MapRect.h = 256;
|
|
MapRect.x = (MapTPage & 15) << 6;
|
|
MapRect.y = (MapTPage & 16) << 4;
|
|
|
|
// place map segments inside rectangle
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
MapSegmentPos[i].x = info.coords.u0 + (i & 3) * 32;
|
|
MapSegmentPos[i].y = info.coords.v0 + (i / 4) * 32;
|
|
}
|
|
|
|
D_MALLOC_BEGIN()
|
|
|
|
MapBitMaps = D_MALLOC(lump_size);
|
|
memcpy((u_char*)MapBitMaps, (u_char*)lump_ptr, lump_size);
|
|
|
|
D_MALLOC_END();
|
|
|
|
// load CLUT
|
|
LoadImage(&mapclutpos, (u_long *)(MapBitMaps + 512));
|
|
DrawSync(0);
|
|
}
|
|
|
|
|
|
// [D] [T]
|
|
void LoadMapTile(int tpage, int x, int y)
|
|
{
|
|
int idx, temp, count;
|
|
RECT16 MapSegment;
|
|
|
|
MapSegment.w = 8;
|
|
MapSegment.h = 32;
|
|
|
|
MapSegment.x = MapRect.x + (MapSegmentPos[tpage].x >> 2);
|
|
MapSegment.y = MapRect.y + MapSegmentPos[tpage].y;
|
|
|
|
idx = x + y * tilehnum;
|
|
temp = x * 32;
|
|
|
|
if (idx > -1 && idx < overlaidmaps[GameLevel].toptile &&
|
|
temp > -1 && (temp < overlaidmaps[GameLevel].width))
|
|
{
|
|
UnpackRNC(MapBitMaps + *((ushort*)MapBitMaps + idx), MapBuffer);
|
|
}
|
|
else
|
|
{
|
|
for (count = 0; count < 512; count++)
|
|
MapBuffer[count++] = overlaidmaps[GameLevel].dummy;
|
|
}
|
|
|
|
#ifdef PSX
|
|
DrawSync(0);
|
|
LoadImage(&MapSegment, (u_long*)MapBuffer);
|
|
DrawSync(0);
|
|
#else
|
|
LoadImage(&MapSegment, (u_long*)MapBuffer);
|
|
#endif
|
|
}
|
|
|
|
// [D] [T]
|
|
void SetMapPos(void)
|
|
{
|
|
int scale;
|
|
|
|
scale = overlaidmaps[GameLevel].scale;
|
|
|
|
x_map = overlaidmaps[GameLevel].x_offset + player[0].pos[0] / scale + 1;
|
|
y_map = overlaidmaps[GameLevel].y_offset - player[0].pos[2] / scale + 1;
|
|
}
|
|
|
|
// [D] [T]
|
|
void draw_box(int yPos, int h)
|
|
{
|
|
LINE_F4* linef4 = (LINE_F4*)current->primptr;
|
|
setLineF4(linef4);
|
|
|
|
linef4->r0 = 0;
|
|
linef4->g0 = 0;
|
|
linef4->b0 = 128;
|
|
|
|
linef4->x0 = gMapXOffset;
|
|
linef4->y0 = yPos;
|
|
|
|
linef4->x1 = gMapXOffset + MAP_SIZE_W;
|
|
linef4->x2 = gMapXOffset + MAP_SIZE_W;
|
|
|
|
linef4->y1 = yPos;
|
|
linef4->x3 = gMapXOffset;
|
|
|
|
linef4->y2 = yPos + h;
|
|
linef4->y3 = yPos + h;
|
|
|
|
addPrim(current->ot, linef4);
|
|
current->primptr += sizeof(LINE_F4);
|
|
|
|
LINE_F2* linef2 = (LINE_F2*)current->primptr;
|
|
setLineF2(linef2);
|
|
|
|
linef2->r0 = 0;
|
|
linef2->g0 = 0;
|
|
linef2->b0 = 128;
|
|
|
|
linef2->x0 = gMapXOffset;
|
|
linef2->y0 = yPos;
|
|
|
|
linef2->x1 = gMapXOffset;
|
|
linef2->y1 = yPos + h;
|
|
|
|
addPrim(current->ot, linef2);
|
|
current->primptr += sizeof(LINE_F2);
|
|
}
|
|
|
|
// [D] [T]
|
|
void DrawN(VECTOR *pScreenPosition, int direct)
|
|
{
|
|
int i;
|
|
|
|
LINE_F2 *linef2;
|
|
XYPAIR *pPoint;
|
|
XYPAIR lastPoint;
|
|
|
|
pPoint = NVertex;
|
|
i = 0;
|
|
|
|
lastPoint.x = NVertex[0].x + pScreenPosition->vx;
|
|
lastPoint.y = NVertex[0].y + pScreenPosition->vz;
|
|
|
|
do {
|
|
pPoint++;
|
|
linef2 = (LINE_F2 *)current->primptr;
|
|
|
|
setLineF2(linef2);
|
|
|
|
linef2->x0 = lastPoint.x;
|
|
linef2->y0 = lastPoint.y;
|
|
|
|
lastPoint.x = pPoint->x + pScreenPosition->vx;
|
|
lastPoint.y = pPoint->y + pScreenPosition->vz;
|
|
|
|
linef2->x1 = lastPoint.x;
|
|
linef2->y1 = lastPoint.y;
|
|
|
|
if (gTimeOfDay == 3)
|
|
{
|
|
linef2->r0 = 75;
|
|
linef2->g0 = 75;
|
|
linef2->b0 = 75;
|
|
}
|
|
else
|
|
{
|
|
linef2->r0 = 96;
|
|
linef2->g0 = 96;
|
|
linef2->b0 = 96;
|
|
}
|
|
|
|
setSemiTrans(linef2, 1);
|
|
linef2->code = linef2->code | 2;
|
|
|
|
if (direct == 0)
|
|
{
|
|
addPrim(current->ot + 1, linef2);
|
|
current->primptr += sizeof(LINE_F2);
|
|
}
|
|
else
|
|
{
|
|
DrawPrim(linef2);
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
} while (i < 3);
|
|
}
|
|
|
|
// [D] [T]
|
|
void DrawCompass(void)
|
|
{
|
|
int i;
|
|
LINE_G2 *lineg2;
|
|
VECTOR *pPosition;
|
|
OTTYPE *potz;
|
|
VECTOR position[5];
|
|
|
|
position[1].vx = north[GameLevel].x * overlaidmaps[GameLevel].scale;
|
|
position[1].vz = north[GameLevel].y * overlaidmaps[GameLevel].scale;
|
|
position[0].vx = position[1].vx * 20 + 8 >> 4;
|
|
position[2].vx = position[1].vx + 2 >> 2;
|
|
position[0].vz = position[1].vz * 20 + 8 >> 4;
|
|
position[2].vz = position[1].vz + 2 >> 2;
|
|
position[3].vx = (position[1].vz - position[1].vx) * 171 >> 10;
|
|
position[3].vz = (-position[1].vx - position[1].vz) * 171 >> 10;
|
|
position[4].vz = -position[3].vx;
|
|
position[4].vx = position[3].vz;
|
|
|
|
WorldToOverheadMapPositions(position, position, 3, 1, 0);
|
|
WorldToOverheadMapPositions(position + 3, position + 3, 2, 1, 1);
|
|
|
|
position[3].vx = position[3].vx + position[1].vx;
|
|
position[3].vz = position[3].vz + position[1].vz;
|
|
position[4].vx = position[4].vx + position[1].vx;
|
|
position[4].vz = position[4].vz + position[1].vz;
|
|
|
|
potz = current->ot + 1;
|
|
|
|
pPosition = position + 2;
|
|
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
lineg2 = (LINE_G2 *)current->primptr;
|
|
|
|
setLineG2(lineg2);
|
|
setSemiTrans(lineg2, 1);
|
|
|
|
lineg2->x0 = position[1].vx;
|
|
lineg2->y0 = position[1].vz;
|
|
|
|
lineg2->x1 = pPosition->vx;
|
|
lineg2->y1 = pPosition->vz;
|
|
|
|
|
|
lineg2->r0 = 96;
|
|
lineg2->g0 = 96;
|
|
lineg2->b0 = 96;
|
|
|
|
lineg2->r1 = 0;
|
|
lineg2->g1 = 0;
|
|
lineg2->b1 = 0;
|
|
|
|
addPrim(potz, lineg2);
|
|
|
|
current->primptr += sizeof(LINE_G2);
|
|
|
|
pPosition++;
|
|
}
|
|
|
|
DrawN(position, 0);
|
|
|
|
TransparencyOn(potz, 0x20);
|
|
}
|
|
|
|
// [D] [T]
|
|
void DrawBigCompass(VECTOR *root, int angle)
|
|
{
|
|
int i;
|
|
LINE_G2 *lineg2;
|
|
int ang, ang2, sn, cs;
|
|
VECTOR *pPosition;
|
|
VECTOR position[5];
|
|
|
|
ang = big_north[GameLevel] + angle & 0xfff;
|
|
|
|
position[2].vx = root->vx + map_x_offset;
|
|
position[2].vy = root->vz + map_z_offset;
|
|
|
|
sn = RSIN(ang);
|
|
cs = RCOS(ang);
|
|
|
|
position[1].vx = position[2].vx + (sn * 0x19 >> 0xc);
|
|
position[0].vx = position[2].vx + (sn * 0xf >> 0xb);
|
|
|
|
position[1].vy = position[2].vy + (cs * 0x19 >> 0xc);
|
|
position[0].vz = position[2].vy + (cs * 0xf >> 0xb);
|
|
|
|
ang2 = ang - 200 & 0xfff;
|
|
sn = RSIN(ang2);
|
|
cs = RCOS(ang2);
|
|
|
|
position[3].vx = position[2].vx + (sn * 5 >> 10);
|
|
position[3].vy = position[2].vy + (cs * 5 >> 10);
|
|
|
|
ang2 = ang + 200 & 0xfff;
|
|
sn = RSIN(ang2);
|
|
cs = RCOS(ang2);
|
|
|
|
position[4].vx = position[2].vx + (sn * 5 >> 10);
|
|
position[4].vy = position[2].vy + (cs * 5 >> 10);
|
|
|
|
pPosition = position + 2;
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
lineg2 = (LINE_G2*)current->primptr;
|
|
|
|
setLineG2(lineg2);
|
|
setSemiTrans(lineg2, 1);
|
|
|
|
lineg2->x0 = position[1].vx;
|
|
lineg2->y0 = position[1].vy;
|
|
|
|
lineg2->x1 = pPosition->vx;
|
|
lineg2->y1 = pPosition->vy;
|
|
|
|
lineg2->r0 = 96;
|
|
lineg2->g0 = 96;
|
|
lineg2->b0 = 96;
|
|
|
|
lineg2->r1 = 0;
|
|
lineg2->g1 = 0;
|
|
lineg2->b1 = 0;
|
|
|
|
DrawPrim(lineg2);
|
|
|
|
pPosition++;
|
|
//current->primptr += sizeof(LINE_G2);
|
|
}
|
|
|
|
DrawN(position, 1);
|
|
}
|
|
|
|
// [D] [T]
|
|
void CopIndicator(int xpos, int strength)
|
|
{
|
|
int startH, endH;
|
|
int str2;
|
|
POLY_F3 *poly;
|
|
|
|
startH = SCREEN_H;
|
|
endH = SCREEN_H - 30;
|
|
|
|
if (strength > 255)
|
|
strength = 255;
|
|
|
|
poly = (POLY_F3 *)current->primptr;
|
|
|
|
setPolyF3(poly);
|
|
setSemiTrans(poly, 1);
|
|
|
|
poly->r0 = strength;
|
|
|
|
str2 = (strength >> 2);
|
|
|
|
poly->g0 = str2;
|
|
poly->b0 = str2;
|
|
poly->x0 = xpos - 12;
|
|
poly->y0 = startH;
|
|
poly->x1 = xpos;
|
|
poly->y1 = endH;
|
|
poly->x2 = xpos + 12;
|
|
poly->y2 = startH;
|
|
|
|
addPrim(current->ot + 1, poly);
|
|
current->primptr += sizeof(POLY_F3);
|
|
|
|
TransparencyOn(current->ot + 1, 0x20);
|
|
|
|
poly = (POLY_F3 *)current->primptr;
|
|
|
|
setPolyF3(poly);
|
|
setSemiTrans(poly, 1);
|
|
|
|
str2 = strength * (strength + 256) >> 9;
|
|
|
|
poly->r0 = str2;
|
|
poly->g0 = str2;
|
|
poly->b0 = str2;
|
|
|
|
poly->x0 = xpos - 12;
|
|
poly->y0 = startH;
|
|
poly->y1 = endH;
|
|
poly->x2 = xpos + 12;
|
|
poly->y2 = startH;
|
|
poly->x1 = xpos;
|
|
|
|
addPrim(current->ot + 1, poly);
|
|
current->primptr += sizeof(POLY_F3);
|
|
|
|
TransparencyOn(current->ot + 1, 0x40);
|
|
}
|
|
|
|
// [D] [T]
|
|
void DrawSightCone(COP_SIGHT_DATA *pCopSightData, VECTOR *pPosition, int direction, int flags)
|
|
{
|
|
short temp;
|
|
int dir;
|
|
VECTOR *pNextVertex;
|
|
POLY_G3 *poly;
|
|
TILE_1* tile1;
|
|
VECTOR *pVertex;
|
|
VECTOR vertex[9];
|
|
int angle;
|
|
int frontViewAngle;
|
|
int frontViewDistance;
|
|
int surroundViewDistance;
|
|
|
|
frontViewDistance = pCopSightData->frontViewDistance;
|
|
surroundViewDistance = pCopSightData->surroundViewDistance;
|
|
frontViewAngle = pCopSightData->frontViewAngle;
|
|
|
|
vertex[0].vx = pPosition->vx;
|
|
vertex[0].vz = pPosition->vz;
|
|
|
|
pVertex = vertex + 1;
|
|
|
|
angle = 0;
|
|
do {
|
|
|
|
if (angle > frontViewAngle && angle < 4096 - frontViewAngle)
|
|
temp = surroundViewDistance;
|
|
else
|
|
temp = frontViewDistance;
|
|
|
|
dir = angle + direction & 0xfff;
|
|
|
|
angle += 512;
|
|
pVertex->vx = vertex[0].vx + FIXEDH(RSIN(dir) * temp);
|
|
pVertex->vz = vertex[0].vz + FIXEDH(RCOS(dir) * temp);
|
|
|
|
pVertex++;
|
|
|
|
} while (angle < 4096);
|
|
|
|
WorldToOverheadMapPositions(vertex, vertex, 9, 0, 0);
|
|
|
|
pVertex = vertex + 1;
|
|
|
|
while (pVertex < &vertex[9])
|
|
{
|
|
pNextVertex = pVertex + 1;
|
|
|
|
if (pNextVertex > vertex + 8)
|
|
pNextVertex = vertex + 1;
|
|
|
|
poly = (POLY_G3 *)current->primptr;
|
|
setPolyG3(poly);
|
|
setSemiTrans(poly, 1);
|
|
|
|
poly->x0 = vertex[0].vx;
|
|
poly->y0 = vertex[0].vz;
|
|
poly->x1 = pVertex->vx;
|
|
poly->y1 = pVertex->vz;
|
|
poly->x2 = pNextVertex->vx;
|
|
poly->y2 = pNextVertex->vz;
|
|
|
|
poly->r0 = poly->g0 = poly->b0 = 96;
|
|
poly->r1 = poly->g1 = poly->b1 = 0;
|
|
poly->r2 = poly->g2 = poly->b2 = 0;
|
|
|
|
addPrim(current->ot + 1, poly);
|
|
|
|
current->primptr += sizeof(POLY_G3);
|
|
|
|
pVertex++;
|
|
}
|
|
|
|
// draw center
|
|
if(flags & 0x1)
|
|
{
|
|
tile1 = (TILE_1*)current->primptr;
|
|
setTile1(tile1);
|
|
|
|
tile1->r0 = tile1->g0 = tile1->b0 = (CameraCnt & 7) > 3 ? 255 : 0;
|
|
|
|
tile1->x0 = vertex[0].vx;
|
|
tile1->y0 = vertex[0].vz;
|
|
|
|
addPrim(current->ot + 1, tile1);
|
|
current->primptr += sizeof(TILE_1);
|
|
}
|
|
|
|
TransparencyOn(current->ot + 1, 0x20);
|
|
}
|
|
|
|
// [D] [T]
|
|
u_int Long2DDistance(VECTOR *pPoint1, VECTOR *pPoint2)
|
|
{
|
|
int tempTheta;
|
|
int theta;
|
|
u_int result;
|
|
VECTOR delta;
|
|
|
|
delta.vx = ABS(pPoint1->vx - pPoint2->vx);
|
|
delta.vz = ABS(pPoint1->vz - pPoint2->vz);
|
|
|
|
theta = ratan2(delta.vz, delta.vx);
|
|
|
|
if ((theta & 0x7ff) - 512U <= 1024)
|
|
{
|
|
tempTheta = RSIN(theta);
|
|
result = delta.vz;
|
|
}
|
|
else
|
|
{
|
|
tempTheta = RCOS(theta);
|
|
result = delta.vx;
|
|
}
|
|
|
|
if (result < 0x80000)
|
|
result = (result << 12) / tempTheta;
|
|
else
|
|
result = (result << 9) / tempTheta << 3;
|
|
|
|
return result;
|
|
}
|
|
|
|
// [D] [T]
|
|
void InitMultiplayerMap(void)
|
|
{
|
|
RECT16 rect;
|
|
char filename[32];
|
|
|
|
if (MissionHeader->region == 0)
|
|
return;
|
|
|
|
// multiplayer maps loaded externally
|
|
sprintf(filename, "MAPS\\REG%d.%d", MissionHeader->region, GameLevel);
|
|
|
|
if (FileExists(filename))
|
|
{
|
|
Loadfile(filename, MapBitMaps);
|
|
|
|
rect.x = MapRect.x + MapSegmentPos[0].x / 4;
|
|
rect.y = MapRect.y + MapSegmentPos[0].y;
|
|
rect.w = 16;
|
|
rect.h = 64;
|
|
|
|
LoadImage(&rect, (u_long *)MapBitMaps);
|
|
|
|
DrawSync(0);
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void InitOverheadMap(void)
|
|
{
|
|
int c, d;
|
|
int tpage;
|
|
|
|
if (NumPlayers > 1)
|
|
gMapYOffset = (SCREEN_H - MAP_SIZE_H) / 2 - 2;// 96;
|
|
else
|
|
gMapYOffset = SCREEN_H - MAP_SIZE_H - 15; //181;
|
|
|
|
if (gMultiplayerLevels)
|
|
{
|
|
InitMultiplayerMap();
|
|
return;
|
|
}
|
|
|
|
SetMapPos();
|
|
tilehnum = overlaidmaps[GameLevel].width / 32;
|
|
|
|
tpage = 0;
|
|
|
|
for (c = 0; c < 4; c++)
|
|
{
|
|
for (d = 0; d < 4; d++)
|
|
{
|
|
maptile[d][c] = tpage;
|
|
|
|
LoadMapTile(tpage, (x_map >> 5) + d, (y_map >> 5) + c);
|
|
tpage++;
|
|
}
|
|
}
|
|
|
|
old_x_mod = x_map & 0x1f;
|
|
old_y_mod = y_map & 0x1f;
|
|
}
|
|
|
|
|
|
// [D] [T]
|
|
void FlashOverheadMap(int r, int g, int b)
|
|
{
|
|
TILE *prim;
|
|
POLY_FT3 *null;
|
|
|
|
prim = (TILE *)current->primptr;
|
|
setTile(prim);
|
|
setSemiTrans(prim, 1);
|
|
|
|
prim->r0 = r;
|
|
prim->g0 = g;
|
|
prim->b0 = b;
|
|
|
|
prim->x0 = gMapXOffset;
|
|
prim->y0 = gMapYOffset;
|
|
prim->w = MAP_SIZE_W;
|
|
prim->h = MAP_SIZE_H;
|
|
|
|
|
|
addPrim(current->ot + 1, prim);
|
|
|
|
current->primptr += sizeof(TILE);
|
|
|
|
null = (POLY_FT3 *)current->primptr;
|
|
setPolyFT3(null);
|
|
|
|
null = (POLY_FT3 *)current->primptr;
|
|
setPolyFT3(null);
|
|
null->x0 = -1;
|
|
null->y0 = -1;
|
|
null->x1 = -1;
|
|
null->y1 = -1;
|
|
null->x2 = -1;
|
|
null->y2 = -1;
|
|
null->tpage = 0x20; // [A] correct me if I'm wrong
|
|
|
|
addPrim(current->ot + 1, null);
|
|
|
|
current->primptr += sizeof(POLY_FT3);
|
|
}
|
|
|
|
|
|
// [D] [T]
|
|
void DrawMultiplayerMap(void)
|
|
{
|
|
POLY_FT4 *poly;
|
|
PLAYER *pl;
|
|
int i;
|
|
u_char g;
|
|
u_char r;
|
|
int xPos, yPos;
|
|
VECTOR target;
|
|
int px, py;
|
|
|
|
map_x_offset = 0;
|
|
map_z_offset = 0;
|
|
|
|
xPos = gMapXOffset;
|
|
yPos = gMapYOffset;
|
|
|
|
DrawMultiplayerTargets();
|
|
|
|
r = 255;
|
|
g = 0;
|
|
|
|
for (i = 0; i < NumPlayers; i++)
|
|
{
|
|
pl = &player[i];
|
|
|
|
target.vx = pl->pos[0];
|
|
target.vz = pl->pos[2];
|
|
|
|
target.vy = 0;
|
|
|
|
WorldToMultiplayerMap(&target, &target);
|
|
|
|
target.vx += xPos;
|
|
target.vz += yPos;
|
|
|
|
DrawPlayerDot(&target, -pl->dir, r, g, 0, 0x8);
|
|
|
|
r++;
|
|
g--;
|
|
}
|
|
|
|
draw_box(yPos, 64);
|
|
|
|
// draw map image
|
|
poly = (POLY_FT4 *)current->primptr;
|
|
setPolyFT4(poly);
|
|
setSemiTrans(poly, 1);
|
|
|
|
poly->x0 = xPos;
|
|
poly->y0 = yPos;
|
|
poly->x1 = xPos + MAP_SIZE_W;
|
|
poly->y1 = yPos;
|
|
poly->x2 = xPos;
|
|
poly->x3 = xPos + MAP_SIZE_W;
|
|
poly->y2 = yPos + 64;
|
|
poly->y3 = yPos + 64;
|
|
|
|
px = MapSegmentPos[0].x;
|
|
py = MapSegmentPos[0].y;
|
|
|
|
poly->u0 = px;
|
|
poly->v0 = py;
|
|
poly->u1 = px + 63;
|
|
poly->v1 = py;
|
|
poly->u2 = px;
|
|
poly->v2 = py + 63;
|
|
poly->u3 = px + 63;
|
|
poly->v3 = py + 63;
|
|
|
|
poly->clut = MapClut;
|
|
poly->tpage = MapTPage;
|
|
|
|
if (gTimeOfDay == 3)
|
|
r = 50;
|
|
else
|
|
r = 100;
|
|
|
|
poly->r0 = poly->g0 = poly->b0 = r;
|
|
|
|
addPrim(current->ot + 1, poly);
|
|
current->primptr += sizeof(POLY_FT4);
|
|
}
|
|
|
|
// [D] [T]
|
|
void DrawOverheadMap(void)
|
|
{
|
|
u_char tmp;
|
|
short *playerFelony;
|
|
TILE_1 *tile1;
|
|
POLY_F4 *sptb;
|
|
POLY_FT4 *spt;
|
|
POLY_FT3 *null;
|
|
CAR_DATA *cp;
|
|
DR_AREA *drarea;
|
|
int intens;
|
|
|
|
SVECTOR MapMesh[5][5];
|
|
VECTOR MapMeshO[5][5];
|
|
MAPTEX MapTex[4];
|
|
|
|
SVECTOR direction;
|
|
RECT16 clipped_size;
|
|
VECTOR vec;
|
|
long flag;
|
|
int i, j;
|
|
int tw, th;
|
|
int x_mod, y_mod;
|
|
int MeshWidth, MeshHeight;
|
|
int map_minX, map_maxX;
|
|
int map_minY, map_maxY;
|
|
|
|
static int flashtimer = 0;
|
|
static u_char ptab[] = {
|
|
255, 240, 170, 120,
|
|
80, 55, 38, 23,
|
|
13, 10, 0, 0,
|
|
0, 0, 0, 0,
|
|
};
|
|
|
|
static u_char ptab2[] = {
|
|
255, 255, 240, 170,
|
|
120, 80, 55, 38,
|
|
23, 13, 10, 0,
|
|
0
|
|
};
|
|
|
|
if (MissionHeader->region != 0)
|
|
{
|
|
DrawMultiplayerMap();
|
|
return;
|
|
}
|
|
|
|
if (NumPlayers > 1)
|
|
return;
|
|
|
|
map_minX = gMapXOffset;
|
|
map_minY = gMapYOffset;
|
|
map_maxX = map_minX + MAP_SIZE_W;
|
|
map_maxY = map_minY + MAP_SIZE_H;
|
|
|
|
VECTOR translate = {
|
|
map_minX + MAP_SIZE_W/2,
|
|
0,
|
|
map_minY + MAP_SIZE_H/2
|
|
};
|
|
|
|
SetMapPos();
|
|
draw_box(map_minY, MAP_SIZE_H);
|
|
|
|
// flash the overhead map
|
|
if (player_position_known > 0)
|
|
{
|
|
if (player[0].playerCarId < 0)
|
|
playerFelony = &pedestrianFelony;
|
|
else
|
|
playerFelony = &car_data[player[0].playerCarId].felonyRating;
|
|
|
|
if (*playerFelony > FELONY_PURSUIT_MIN_VALUE)
|
|
FlashOverheadMap(ptab[CameraCnt & 0xf], 0, ptab[CameraCnt + 8U & 0xf]);
|
|
}
|
|
else
|
|
{
|
|
if (player_position_known == -1)
|
|
{
|
|
if (flashtimer == 0)
|
|
{
|
|
if (player[0].playerCarId < 0)
|
|
playerFelony = &pedestrianFelony;
|
|
else
|
|
playerFelony = &car_data[player[0].playerCarId].felonyRating;
|
|
|
|
if (*playerFelony > FELONY_PURSUIT_MIN_VALUE)
|
|
flashtimer = 48;
|
|
}
|
|
}
|
|
|
|
if (flashtimer)
|
|
{
|
|
flashtimer--;
|
|
intens = -flashtimer;
|
|
|
|
intens = ptab2[intens + 47 >> 2] + ptab2[intens + 48 >> 2] + ptab2[intens + 49 >> 2] + ptab2[intens + 50 >> 2] >> 2;
|
|
FlashOverheadMap(intens, intens, intens);
|
|
}
|
|
}
|
|
|
|
// for restoring
|
|
drarea = (DR_AREA *)current->primptr;
|
|
SetDrawArea(drarea, ¤t->draw.clip);
|
|
|
|
addPrim(current->ot + 1, drarea);
|
|
current->primptr += sizeof(DR_AREA);
|
|
|
|
WorldToOverheadMapPositions((VECTOR *)player->pos, &vec, 1, 0, 0);
|
|
|
|
// draw map center
|
|
if (vec.vx > map_minX && vec.vx < map_maxX &&
|
|
vec.vz > map_minY && vec.vz < map_maxY)
|
|
{
|
|
tile1 = (TILE_1 *)current->primptr;
|
|
setTile1(tile1);
|
|
|
|
tile1->r0 = 255;
|
|
tile1->g0 = 255;
|
|
tile1->b0 = 255;
|
|
|
|
tile1->x0 = vec.vx;
|
|
tile1->y0 = vec.vz;
|
|
|
|
addPrim(current->ot, tile1);
|
|
current->primptr += sizeof(TILE_1);
|
|
}
|
|
|
|
DrawTargetBlip((VECTOR *)player->pos, 64, 64, 64, 3);
|
|
|
|
DrawCompass();
|
|
|
|
DrawOverheadTargets();
|
|
|
|
// draw cop sight
|
|
cp = car_data;
|
|
do {
|
|
if (cp->controlType == CONTROL_TYPE_PURSUER_AI && cp->ai.p.dying == 0 || (cp->controlFlags & CONTROL_FLAG_COP))
|
|
DrawSightCone(&copSightData, (VECTOR *)cp->hd.where.t, cp->hd.direction, cp->controlType == CONTROL_TYPE_PURSUER_AI);
|
|
|
|
cp++;
|
|
} while (cp <= &car_data[MAX_CARS]);
|
|
|
|
x_mod = x_map & 31;
|
|
y_mod = y_map & 31;
|
|
|
|
// next code loads map tiles depending on player position changes
|
|
|
|
// X axis
|
|
if (x_mod < 16 && old_x_mod > 16)
|
|
{
|
|
// left
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
tmp = maptile[0][i];
|
|
|
|
maptile[0][i] = maptile[1][i];
|
|
maptile[1][i] = maptile[2][i];
|
|
maptile[2][i] = maptile[3][i];
|
|
maptile[3][i] = tmp;
|
|
|
|
LoadMapTile(tmp, (x_map >> 5) + 3, (y_map >> 5) + i);
|
|
}
|
|
}
|
|
|
|
if (x_mod > 16 && old_x_mod < 16)
|
|
{
|
|
// right
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
tmp = maptile[3][i];
|
|
|
|
maptile[3][i] = maptile[2][i];
|
|
maptile[2][i] = maptile[1][i];
|
|
maptile[1][i] = maptile[0][i];
|
|
maptile[0][i] = tmp;
|
|
|
|
LoadMapTile(tmp, (x_map >> 5), (y_map >> 5) + i);
|
|
}
|
|
}
|
|
|
|
// Z axis
|
|
if (y_mod < 16 && old_y_mod > 16)
|
|
{
|
|
// down
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
tmp = maptile[i][0];
|
|
|
|
maptile[i][0] = maptile[i][1];
|
|
maptile[i][1] = maptile[i][2];
|
|
maptile[i][2] = maptile[i][3];
|
|
maptile[i][3] = tmp;
|
|
|
|
LoadMapTile(tmp, (x_map >> 5) + i, (y_map >> 5) + 3);
|
|
}
|
|
}
|
|
|
|
if (y_mod > 16 && old_y_mod < 16)
|
|
{
|
|
// up
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
tmp = maptile[i][3];
|
|
|
|
maptile[i][3] = maptile[i][2];
|
|
maptile[i][2] = maptile[i][1];
|
|
maptile[i][1] = maptile[i][0];
|
|
maptile[i][0] = tmp;
|
|
|
|
LoadMapTile(tmp, (x_map >> 5) + i, (y_map >> 5));
|
|
}
|
|
}
|
|
|
|
old_x_mod = x_mod;
|
|
old_y_mod = y_mod;
|
|
|
|
// make grid coordinates
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
MapMesh[0][i].vx = -44;
|
|
MapMesh[i][0].vz = -44;
|
|
|
|
MapMesh[1][i].vx = -x_mod - 16;
|
|
MapMesh[i][1].vz = -y_mod - 16;
|
|
|
|
MapMesh[2][i].vx = -x_mod + 16;
|
|
MapMesh[i][2].vz = -y_mod + 16;
|
|
|
|
MapMesh[3][i].vx = -x_mod + 48;
|
|
MapMesh[i][3].vz = -y_mod + 48;
|
|
|
|
MapMesh[4][i].vx = 44;
|
|
MapMesh[i][4].vz = 44;
|
|
}
|
|
|
|
MapTex[1].w = MapTex[2].w = tile_size;
|
|
MapTex[1].u = MapTex[2].u = MapTex[3].u = 0;
|
|
|
|
MapTex[1].h = MapTex[2].h = tile_size;
|
|
MapTex[1].v = MapTex[2].v = MapTex[3].v = 0;
|
|
|
|
MapTex[0].u = 32 - ABS(MapMesh[0][0].vx - MapMesh[1][0].vx);
|
|
MapTex[0].w = ABS(MapMesh[0][0].vx - MapMesh[1][0].vx);
|
|
|
|
MapTex[3].w = ABS(MapMesh[3][0].vx - MapMesh[4][0].vx);
|
|
MapTex[0].v = 32 - ABS(MapMesh[0][0].vz - MapMesh[0][1].vz);
|
|
|
|
MapTex[0].h = ABS(MapMesh[0][0].vz - MapMesh[0][1].vz);
|
|
MapTex[3].h = ABS(MapMesh[0][3].vz - MapMesh[0][4].vz);
|
|
|
|
direction.vx = 0;
|
|
direction.vz = 0;
|
|
direction.vy = player[0].dir & 0xfff;
|
|
|
|
InitMatrix(map_matrix);
|
|
_RotMatrixY(&map_matrix, player[0].dir & 0xfff);
|
|
|
|
gte_SetRotMatrix(&map_matrix);
|
|
gte_SetTransVector(&translate);
|
|
|
|
MeshWidth = x_mod ? 4 : 3;
|
|
MeshHeight = y_mod ? 4 : 3;
|
|
|
|
// transform the map mesh
|
|
for (i = 0; i <= MeshWidth; i++)
|
|
{
|
|
for(j = 0; j <= MeshHeight; j++)
|
|
{
|
|
RotTrans(&MapMesh[i][j], &MapMeshO[i][j], &flag);
|
|
}
|
|
}
|
|
|
|
// draw map mesh booooi
|
|
for (i = 0; i < MeshHeight; i++)
|
|
{
|
|
for (j = 0; j < MeshWidth; j++)
|
|
{
|
|
int tile, px, py;
|
|
|
|
tile = maptile[j][i];
|
|
tw = MapTex[j].w - 1;
|
|
th = MapTex[i].h - 1;
|
|
#ifndef PSX
|
|
// make map fully detailed when filtering is not available
|
|
if (!g_cfg_bilinearFiltering)
|
|
{
|
|
tw += 1;
|
|
th += 1;
|
|
}
|
|
#endif
|
|
|
|
spt = (POLY_FT4*)current->primptr;
|
|
|
|
setPolyFT4(spt);
|
|
setSemiTrans(spt, 1);
|
|
|
|
if (gTimeOfDay == 3)
|
|
spt->r0 = spt->g0 = spt->b0 = 50;
|
|
else
|
|
spt->r0 = spt->g0 = spt->b0 = 100;
|
|
|
|
spt->clut = MapClut;
|
|
spt->tpage = MapTPage;
|
|
|
|
spt->x0 = MapMeshO[j][i].vx;
|
|
spt->y0 = MapMeshO[j][i].vz;
|
|
|
|
spt->x1 = MapMeshO[j+1][i].vx;
|
|
spt->y1 = MapMeshO[j+1][i].vz;
|
|
|
|
spt->x2 = MapMeshO[j][i+1].vx;
|
|
spt->y2 = MapMeshO[j][i+1].vz;
|
|
|
|
spt->x3 = MapMeshO[j+1][i+1].vx;
|
|
spt->y3 = MapMeshO[j+1][i+1].vz;
|
|
|
|
px = MapSegmentPos[tile].x;
|
|
py = MapSegmentPos[tile].y;
|
|
|
|
spt->u0 = MIN(255, MapTex[j].u + px);
|
|
spt->v0 = MIN(255, MapTex[i].v + py);
|
|
|
|
spt->u1 = MIN(255, MapTex[j].u + px + tw);
|
|
spt->v1 = MIN(255, MapTex[i].v + py);
|
|
|
|
spt->u2 = MIN(255, MapTex[j].u + px);
|
|
spt->v2 = MIN(255, MapTex[i].v + py + th);
|
|
|
|
spt->u3 = MIN(255, MapTex[j].u + px + tw);
|
|
spt->v3 = MIN(255, MapTex[i].v + py + th);
|
|
|
|
addPrim(current->ot + 1, spt);
|
|
|
|
current->primptr += sizeof(POLY_FT4);
|
|
}
|
|
}
|
|
|
|
sptb = (POLY_F4 *)current->primptr;
|
|
|
|
setPolyF4(sptb);
|
|
setSemiTrans(sptb, 1);
|
|
|
|
sptb->r0 = 60;
|
|
sptb->g0 = 60;
|
|
sptb->b0 = 60;
|
|
|
|
sptb->y0 = map_minY;
|
|
sptb->y1 = map_minY;
|
|
sptb->x0 = map_minX;
|
|
sptb->x1 = map_maxX;
|
|
sptb->x2 = map_minX;
|
|
sptb->y2 = map_maxY;
|
|
sptb->x3 = map_maxX;
|
|
sptb->y3 = map_maxY;
|
|
|
|
addPrim(current->ot + 1, sptb);
|
|
current->primptr += sizeof(POLY_F4);
|
|
|
|
null = (POLY_FT3 *)current->primptr;
|
|
setPolyFT3(null);
|
|
|
|
null->x0 = -1;
|
|
null->y0 = -1;
|
|
null->x1 = -1;
|
|
null->y1 = -1;
|
|
null->x2 = -1;
|
|
null->y2 = -1;
|
|
null->tpage = 0;
|
|
|
|
addPrim(current->ot + 1, null);
|
|
current->primptr += sizeof(POLY_FT3);
|
|
|
|
clipped_size.x = map_minX + 1;
|
|
clipped_size.w = MAP_SIZE_W - 1;
|
|
clipped_size.h = MAP_SIZE_H;
|
|
clipped_size.y = current->draw.clip.y + map_minY;// +1;
|
|
|
|
drarea = (DR_AREA*)current->primptr;
|
|
|
|
SetDrawArea(drarea, &clipped_size);
|
|
addPrim(current->ot + 1, drarea);
|
|
current->primptr += sizeof(DR_AREA);
|
|
}
|
|
|
|
// [D] [T]
|
|
void SetFullscreenMapMatrix(void)
|
|
{
|
|
VECTOR translate = { 160, 0, 128 };
|
|
int direction;
|
|
|
|
if (gUseRotatedMap == 0)
|
|
direction = 0;
|
|
else
|
|
direction = player[0].dir & 0xfff;
|
|
|
|
InitMatrix(map_matrix);
|
|
_RotMatrixY(&map_matrix, direction);
|
|
|
|
gte_SetRotMatrix(&map_matrix);
|
|
gte_SetTransVector(&translate);
|
|
}
|
|
|
|
// [D] [T]
|
|
void DrawFullscreenMap(void)
|
|
{
|
|
char str[64];
|
|
TILE *polys;
|
|
TILE_1 *tile1;
|
|
POLY_FT4 *back, *prevback;
|
|
POLY_FT3 *null;
|
|
int x, y;
|
|
int clipped;
|
|
int px, py;
|
|
SVECTOR mesh[4];
|
|
VECTOR meshO[4];
|
|
VECTOR target;
|
|
VECTOR vec;
|
|
long flag;
|
|
int width, height;
|
|
int ntiles, count;
|
|
int tw, th;
|
|
|
|
// toggle rotated map
|
|
if (Pads[0].dirnew & 0x20)
|
|
{
|
|
map_x_offset = 0;
|
|
map_z_offset = 0;
|
|
map_x_shift = 0;
|
|
map_z_shift = 0;
|
|
|
|
gUseRotatedMap ^= 1;
|
|
}
|
|
|
|
SetFullscreenMapMatrix();
|
|
|
|
tw = tile_size - 1;
|
|
th = tile_size - 1;
|
|
|
|
#ifndef PSX
|
|
/* It will look funny when enabled
|
|
// make map fully detailed when filtering is not available
|
|
if (!g_cfg_bilinearFiltering)
|
|
{
|
|
tw += 1;
|
|
th += 1;
|
|
}
|
|
*/
|
|
#else
|
|
polys = (TILE*)current->primptr;
|
|
|
|
setTile(polys);
|
|
|
|
polys->r0 = 0;
|
|
polys->g0 = 0;
|
|
polys->b0 = 0;
|
|
|
|
polys->x0 = 0;
|
|
polys->y0 = 0;
|
|
polys->w = 320;
|
|
polys->h = 256;
|
|
|
|
DrawPrim(polys);
|
|
DrawSync(0);
|
|
#endif
|
|
|
|
width = overlaidmaps[GameLevel].width;
|
|
height = overlaidmaps[GameLevel].height;
|
|
|
|
WorldToFullscreenMap((VECTOR *)player->pos, &player_position);
|
|
|
|
// do map movement
|
|
if (gUseRotatedMap)
|
|
{
|
|
if (Pads[0].direct & 0x8000)
|
|
map_x_offset += 8;
|
|
else if (Pads[0].direct & 0x2000)
|
|
map_x_offset -= 8;
|
|
|
|
if (Pads[0].direct & 0x1000)
|
|
map_z_offset += 8;
|
|
else if (Pads[0].direct & 0x4000)
|
|
map_z_offset -= 8;
|
|
|
|
if (map_x_offset < -128)
|
|
map_x_offset = -128;
|
|
|
|
if (map_x_offset > 128)
|
|
map_x_offset = 128;
|
|
|
|
if (map_z_offset < -128)
|
|
map_z_offset = -128;
|
|
|
|
if (map_z_offset > 128)
|
|
map_z_offset = 128;
|
|
|
|
map_x_shift = 0;
|
|
map_z_shift = 0;
|
|
}
|
|
else
|
|
{
|
|
if(player_position.vx + 160 <= width)
|
|
{
|
|
map_x_offset = player_position.vx - 160;
|
|
|
|
if(map_x_offset > -1)
|
|
map_x_offset = 0;
|
|
}
|
|
else
|
|
{
|
|
map_x_offset = (player_position.vx + 160) - width;
|
|
}
|
|
|
|
if(player_position.vz + 128 <= height)
|
|
{
|
|
map_z_offset = player_position.vz - 128;
|
|
|
|
if (map_z_offset > -1)
|
|
map_z_offset = 0;
|
|
}
|
|
else
|
|
{
|
|
map_z_offset = (player_position.vz + 128) - height;
|
|
}
|
|
|
|
if (Pads[0].direct & 0x8000)
|
|
{
|
|
if (player_position.vx - map_x_offset - 160 - map_x_shift > 0)
|
|
{
|
|
map_x_shift += 8;
|
|
}
|
|
}
|
|
else if(Pads[0].direct & 0x2000)
|
|
{
|
|
if (player_position.vx - map_x_offset + 160 - map_x_shift < width)
|
|
{
|
|
map_x_shift -= 8;
|
|
}
|
|
}
|
|
|
|
if (Pads[0].direct & 0x1000)
|
|
{
|
|
if (player_position.vz - map_z_offset - 128 - map_z_shift > 0)
|
|
{
|
|
map_z_shift += 8;
|
|
}
|
|
}
|
|
else if(Pads[0].direct & 0x4000)
|
|
{
|
|
if (player_position.vz - map_z_offset + 128 - map_z_shift < height)
|
|
{
|
|
map_z_shift -= 8;
|
|
}
|
|
}
|
|
|
|
map_x_offset += map_x_shift;
|
|
map_z_offset += map_z_shift;
|
|
}
|
|
|
|
|
|
null = (POLY_FT3 *)current->primptr;
|
|
|
|
setPolyFT3(null);
|
|
null->x0 = -1;
|
|
null->y0 = -1;
|
|
null->x1 = -1;
|
|
null->y1 = -1;
|
|
null->x2 = -1;
|
|
null->y2 = -1;
|
|
null->tpage = MapTPage;
|
|
|
|
DrawPrim(null);
|
|
DrawSync(0);
|
|
|
|
width >>= 5;
|
|
height >>= 5;
|
|
|
|
#ifndef PSX
|
|
RECT16 emuViewport;
|
|
PsyX_GetPSXWidescreenMappedViewport(&emuViewport);
|
|
|
|
prevback = NULL;
|
|
#endif
|
|
|
|
ntiles = 0;
|
|
|
|
for(x = 0; x < width; x++)
|
|
{
|
|
for(y = 0; y < height; y++)
|
|
{
|
|
mesh[0].vy = 0;
|
|
mesh[1].vy = 0;
|
|
mesh[2].vy = 0;
|
|
mesh[3].vy = 0;
|
|
mesh[0].vx = x * 32 - player_position.vx;
|
|
mesh[1].vx = mesh[0].vx + 32;
|
|
mesh[0].vz = y * 32 - player_position.vz;
|
|
mesh[2].vz = mesh[0].vz + 32;
|
|
mesh[1].vz = mesh[0].vz;
|
|
mesh[2].vx = mesh[0].vx;
|
|
mesh[3].vx = mesh[1].vx;
|
|
mesh[3].vz = mesh[2].vz;
|
|
|
|
// rotate and clip polygons
|
|
clipped = 0;
|
|
|
|
for (count = 0; count < 4; count++)
|
|
{
|
|
RotTrans(&mesh[count], &meshO[count], &flag);
|
|
|
|
meshO[count].vx += map_x_offset;
|
|
meshO[count].vz += map_z_offset;
|
|
|
|
#ifndef PSX
|
|
if (meshO[count].vx > emuViewport.w || meshO[count].vz > emuViewport.w ||
|
|
meshO[count].vx < emuViewport.x || meshO[count].vz < emuViewport.y)
|
|
{
|
|
clipped++;
|
|
}
|
|
#else
|
|
if (meshO[count].vx > 320 || meshO[count].vz > 256 ||
|
|
meshO[count].vx < 0 || meshO[count].vz < 0)
|
|
{
|
|
clipped++;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if(clipped == 4)
|
|
continue;
|
|
|
|
LoadMapTile(ntiles & 15, x, y);
|
|
|
|
back = (POLY_FT4 *)current->primptr;
|
|
setPolyFT4(back);
|
|
|
|
back->r0 = back->g0 = back->b0 = 88;
|
|
|
|
back->x0 = meshO[0].vx;
|
|
back->y0 = meshO[0].vz;
|
|
|
|
back->x1 = meshO[1].vx;
|
|
back->y1 = meshO[1].vz;
|
|
|
|
back->x2 = meshO[2].vx;
|
|
back->y2 = meshO[2].vz;
|
|
|
|
back->x3 = meshO[3].vx;
|
|
back->y3 = meshO[3].vz;
|
|
|
|
px = MapSegmentPos[ntiles & 15].x;
|
|
py = MapSegmentPos[ntiles & 15].y;
|
|
|
|
back->u0 = px;
|
|
back->v0 = py;
|
|
|
|
back->u1 = MIN(255, px + tw);
|
|
back->v1 = MIN(255, py);
|
|
|
|
back->u2 = px;
|
|
back->v2 = MIN(255, py + th);
|
|
|
|
back->u3 = MIN(255, px + tw);
|
|
back->v3 = MIN(255, py + th);
|
|
|
|
back->clut = MapClut;
|
|
back->tpage = MapTPage;
|
|
#ifdef PSX
|
|
DrawPrim(back);
|
|
DrawSync(0);
|
|
ntiles++;
|
|
#else
|
|
current->primptr += sizeof(POLY_FT4);
|
|
|
|
if (!prevback)
|
|
prevback = back;
|
|
|
|
// draw if map tiles are filled or we reached horizontal end
|
|
if ((ntiles & 15) == 0 || x == width - 1 || y == height - 1)
|
|
{
|
|
// upload map to GPU
|
|
DrawSync(0);
|
|
|
|
// draw all polys
|
|
while(prevback <= back)
|
|
DrawPrim(prevback++);
|
|
|
|
DrawSync(0);
|
|
}
|
|
ntiles++;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
target.vx = 160;
|
|
target.vz = 128;
|
|
|
|
DrawFullscreenTargets();
|
|
|
|
if (gUseRotatedMap)
|
|
DrawBigCompass(&target, player[0].dir);
|
|
else
|
|
DrawBigCompass(&target, 0);
|
|
|
|
DrawTargetBlip(&target, 64, 64, 64, 14);
|
|
|
|
vec.vx = target.vx + map_x_offset;
|
|
vec.vz = target.vz + map_z_offset;
|
|
|
|
tile1 = (TILE_1 *)current->primptr;
|
|
setTile1(tile1);
|
|
|
|
tile1->r0 = -1;
|
|
tile1->g0 = -1;
|
|
tile1->b0 = -1;
|
|
tile1->x0 = vec.vx;
|
|
tile1->y0 = vec.vz;
|
|
|
|
DrawPrim(tile1);
|
|
|
|
null = (POLY_FT3 *)current->primptr;
|
|
setPolyFT3(null);
|
|
|
|
null->x0 = -1;
|
|
null->y0 = -1;
|
|
null->x1 = -1;
|
|
null->y1 = -1;
|
|
null->x2 = -1;
|
|
null->y2 = -1;
|
|
null->tpage = fonttpage;
|
|
|
|
DrawPrim(null);
|
|
DrawSync(0);
|
|
|
|
SetTextColour(128, 128, 128);
|
|
|
|
// print string with special characters representing some images inserted into it
|
|
sprintf(str, "\x80 %s \x81 %s \x8a %s", G_LTXT(GTXT_Exit), G_LTXT(GTXT_Rotation), G_LTXT(GTXT_Move));
|
|
PrintStringCentred(str, SCREEN_H - 30); // 226
|
|
}
|
|
|
|
// [D] [T]
|
|
void DrawCopIndicators(void)
|
|
{
|
|
int cc, cs;
|
|
int dx, dz;
|
|
int p, q;
|
|
CAR_DATA *cp;
|
|
|
|
cc = RCOS(player[0].dir);
|
|
cs = RSIN(player[0].dir);
|
|
|
|
cp = car_data;
|
|
do {
|
|
if (cp->controlType == CONTROL_TYPE_PURSUER_AI && cp->ai.p.dying == 0)
|
|
{
|
|
dx = cp->hd.where.t[0] - player[0].pos[0];
|
|
dz = cp->hd.where.t[2] - player[0].pos[2];
|
|
|
|
p = FIXEDH(dx * cc - dz * cs) * 3 >> 2;
|
|
q = -FIXEDH(dx * cs + dz * cc);
|
|
|
|
if (ABS(p) < q)
|
|
{
|
|
CopIndicator((p * 266) / q + 160, 0x3fff0 / ((q >> 3) + 600));
|
|
}
|
|
}
|
|
cp++;
|
|
} while (cp <= &car_data[MAX_CARS]);
|
|
}
|
|
|
|
// [D] [T]
|
|
void WorldToMultiplayerMap(VECTOR *in, VECTOR *out)
|
|
{
|
|
int z;
|
|
int x;
|
|
|
|
if (MissionHeader->region == 0)
|
|
{
|
|
out->vx = 32;
|
|
out->vz = 32;
|
|
return;
|
|
}
|
|
|
|
x = in->vx - (((MissionHeader->region % regions_across) << 16) - cells_across * MAP_CELL_SIZE/2);
|
|
z = in->vz - (((MissionHeader->region / regions_across) << 16) - cells_down * MAP_CELL_SIZE/2);
|
|
|
|
out->vx = x / MAP_CELL_SIZE;
|
|
out->vz = MAP_REGION_SIZE - z / MAP_CELL_SIZE;
|
|
}
|
|
|
|
// [D] [T]
|
|
void WorldToOverheadMapPositions(VECTOR *pGlobalPosition, VECTOR *pOverheadMapPosition, int count, char inputRelative,int outputRelative)
|
|
{
|
|
int scale, cs, sn;
|
|
MATRIX tempMatrix;
|
|
SVECTOR tempVector;
|
|
XZPAIR playerPos;
|
|
long flag;
|
|
|
|
cs = RCOS(player[0].dir);
|
|
sn = RSIN(player[0].dir);
|
|
|
|
tempMatrix.m[0][1] = 0;
|
|
tempMatrix.m[1][0] = 0;
|
|
tempMatrix.m[1][2] = 0;
|
|
tempMatrix.m[2][1] = 0;
|
|
|
|
tempMatrix.m[0][0] = cs;
|
|
tempMatrix.m[2][2] = cs;
|
|
|
|
tempMatrix.m[2][0] = -sn;
|
|
tempMatrix.m[0][2] = sn;
|
|
|
|
tempMatrix.t[1] = 0;
|
|
|
|
if (outputRelative == 0)
|
|
{
|
|
tempMatrix.t[0] = gMapXOffset + MAP_SIZE_W/2;
|
|
tempMatrix.t[2] = gMapYOffset + MAP_SIZE_H/2;
|
|
}
|
|
else
|
|
{
|
|
tempMatrix.t[0] = 0;
|
|
tempMatrix.t[2] = 0;
|
|
}
|
|
|
|
gte_SetRotMatrix(&tempMatrix);
|
|
gte_SetTransMatrix(&tempMatrix);
|
|
|
|
scale = overlaidmaps[GameLevel].scale;
|
|
playerPos.x = player[0].pos[0];
|
|
playerPos.z = player[0].pos[2];
|
|
|
|
count--;
|
|
while (count >= 0)
|
|
{
|
|
tempVector.vy = 0;
|
|
if (inputRelative)
|
|
{
|
|
tempVector.vx = pGlobalPosition->vx / scale;
|
|
tempVector.vz = -pGlobalPosition->vz / scale;
|
|
}
|
|
else
|
|
{
|
|
tempVector.vx = (pGlobalPosition->vx - playerPos.x) / scale;
|
|
tempVector.vz = (playerPos.z - pGlobalPosition->vz) / scale;
|
|
}
|
|
|
|
RotTrans(&tempVector, pOverheadMapPosition, &flag);
|
|
|
|
// might be faster on OG hardware... but not sure.
|
|
// pOverheadMapPosition->vx = tempMatrix.t[0] + (cs * tempVector.vx + sn * tempVector.vz >> 12);
|
|
// pOverheadMapPosition->vz = tempMatrix.t[2] + (cs * tempVector.vz - sn * tempVector.vx >> 12);
|
|
|
|
count--;
|
|
pGlobalPosition++;
|
|
pOverheadMapPosition++;
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void WorldToFullscreenMap(VECTOR *in, VECTOR *out)
|
|
{
|
|
int scale;
|
|
|
|
scale = overlaidmaps[GameLevel].scale;
|
|
out->vy = 0;
|
|
out->vx = overlaidmaps[GameLevel].x_offset + in->vx / scale + 49;
|
|
out->vz = overlaidmaps[GameLevel].y_offset - (in->vz / scale - 49);
|
|
}
|
|
|
|
// [D] [T]
|
|
void WorldToFullscreenMap2(VECTOR *in, VECTOR *out)
|
|
{
|
|
SVECTOR pos;
|
|
long flag;
|
|
int scale;
|
|
|
|
scale = overlaidmaps[GameLevel].scale;
|
|
|
|
pos.vy = 0;
|
|
pos.vx = overlaidmaps[GameLevel].x_offset + (in->vx / scale + 49) - player_position.vx;
|
|
pos.vz = overlaidmaps[GameLevel].y_offset - (in->vz / scale - 49) - player_position.vz;
|
|
|
|
RotTrans(&pos, out, &flag);
|
|
}
|
|
|
|
|
|
|
|
|
|
|