mirror of
https://github.com/OpenDriver2/REDRIVER2.git
synced 2024-11-25 11:52:32 +01:00
506 lines
11 KiB
C
506 lines
11 KiB
C
#include "driver2.h"
|
|
#include "denting.h"
|
|
#include "system.h"
|
|
#include "mission.h"
|
|
#include "cars.h"
|
|
#include "convert.h"
|
|
#include "pause.h"
|
|
#include "camera.h"
|
|
#include "draw.h"
|
|
#include "dr2roads.h"
|
|
#include "debris.h"
|
|
#include "players.h"
|
|
#include "main.h"
|
|
|
|
char* DentingFiles[] =
|
|
{
|
|
"LEVELS\\CHICAGO.DEN",
|
|
"LEVELS\\HAVANA.DEN",
|
|
"LEVELS\\VEGAS.DEN",
|
|
"LEVELS\\RIO.DEN",
|
|
};
|
|
|
|
// DO NOT CHANGE THIS!
|
|
#define NUM_DAMAGE_ZONES 6
|
|
#define MAX_FILE_DAMAGE_ZONE_VERTS 50
|
|
#define MAX_FILE_DAMAGE_ZONE_POLYS 70
|
|
#define MAX_FILE_DAMAGE_LEVELS 256
|
|
|
|
u_char gCarDamageZoneVerts[MAX_CAR_MODELS][NUM_DAMAGE_ZONES][MAX_DAMAGE_ZONE_VERTS];
|
|
u_char gHDCarDamageZonePolys[MAX_CAR_MODELS][NUM_DAMAGE_ZONES][MAX_DAMAGE_ZONE_POLYS];
|
|
u_char gHDCarDamageLevels[MAX_CAR_MODELS][MAX_DAMAGE_LEVELS];
|
|
|
|
// [D] [T]
|
|
void InitialiseDenting(void)
|
|
{
|
|
LoadDenting(GameLevel);
|
|
InitHubcap();
|
|
}
|
|
|
|
// [D] [T]
|
|
void DentCar(CAR_DATA *cp)
|
|
{
|
|
int Zone;
|
|
int Damage;
|
|
int MaxDamage;
|
|
DENTUVS *dentptr;
|
|
SVECTOR *CleanVertPtr;
|
|
int VertNo;
|
|
unsigned char *DamPtr;
|
|
SVECTOR *DamVertPtr;
|
|
MODEL *pCleanModel;
|
|
int model;
|
|
int Poly;
|
|
|
|
short tempDamage[256];
|
|
memset((u_char*)tempDamage, 0, sizeof(tempDamage));
|
|
|
|
MaxDamage = 0;
|
|
model = cp->ap.model;
|
|
cp->lowDetail = -1;
|
|
cp->ap.qy = 0;
|
|
cp->ap.qw = 0;
|
|
|
|
pCleanModel = gCarCleanModelPtr[model];
|
|
|
|
// collect vertices from zones
|
|
if (pCleanModel != NULL)
|
|
{
|
|
VertNo = 0;
|
|
while (VertNo < pCleanModel->num_vertices)
|
|
tempDamage[VertNo++] = 0;
|
|
|
|
Zone = 0;
|
|
do {
|
|
Damage = cp->ap.damage[Zone];
|
|
|
|
if (Damage > MaxDamage)
|
|
MaxDamage = Damage;
|
|
|
|
DamPtr = gCarDamageZoneVerts[cp->ap.model][Zone];
|
|
|
|
VertNo = 0;
|
|
while (VertNo < MAX_DAMAGE_ZONE_VERTS && *DamPtr != 0xFF)
|
|
{
|
|
if (tempDamage[*DamPtr] == 0)
|
|
tempDamage[*DamPtr] += Damage;
|
|
else
|
|
tempDamage[*DamPtr] += Damage / 2;
|
|
|
|
DamPtr++;
|
|
|
|
VertNo++;
|
|
}
|
|
|
|
Zone++;
|
|
} while (Zone < NUM_DAMAGE_ZONES);
|
|
}
|
|
|
|
// update vertices positon
|
|
if (gCarCleanModelPtr[model] != NULL && gCarDamModelPtr[model] != NULL)
|
|
{
|
|
DamVertPtr = (SVECTOR *)gCarDamModelPtr[model]->vertices;
|
|
CleanVertPtr = (SVECTOR *)gCarCleanModelPtr[model]->vertices;
|
|
|
|
VertNo = 0;
|
|
while (VertNo < pCleanModel->num_vertices)
|
|
{
|
|
gTempCarVertDump[cp->id][VertNo].vx = CleanVertPtr->vx + FIXEDH((DamVertPtr->vx - CleanVertPtr->vx) * tempDamage[VertNo] / 2);
|
|
gTempCarVertDump[cp->id][VertNo].vy = CleanVertPtr->vy + FIXEDH((DamVertPtr->vy - CleanVertPtr->vy) * tempDamage[VertNo] / 2);
|
|
gTempCarVertDump[cp->id][VertNo].vz = CleanVertPtr->vz + FIXEDH((DamVertPtr->vz - CleanVertPtr->vz) * tempDamage[VertNo] / 2);
|
|
|
|
DamVertPtr++;
|
|
CleanVertPtr++;
|
|
|
|
VertNo++;
|
|
}
|
|
}
|
|
|
|
// update polygon UVs
|
|
if (pCleanModel != NULL)
|
|
{
|
|
dentptr = gTempHDCarUVDump[cp->id];
|
|
|
|
// reset UV coordinates
|
|
Poly = 0;
|
|
while (Poly < pCleanModel->num_polys)
|
|
{
|
|
dentptr->u3 = 0;
|
|
Poly++;
|
|
dentptr++;
|
|
}
|
|
|
|
Zone = 0;
|
|
do {
|
|
Damage = cp->ap.damage[Zone];
|
|
|
|
Poly = 0;
|
|
while (Poly < MAX_DAMAGE_ZONE_POLYS && gHDCarDamageZonePolys[cp->ap.model][Zone][Poly] != 0xFF)
|
|
{
|
|
dentptr = gTempHDCarUVDump[cp->id] + gHDCarDamageZonePolys[cp->ap.model][Zone][Poly];
|
|
|
|
// add a damage level
|
|
dentptr->u3 += (Damage >> 0xA);
|
|
|
|
// clamp level
|
|
if (dentptr->u3 > 2)
|
|
dentptr->u3 = 2;
|
|
|
|
Poly++;
|
|
}
|
|
|
|
Zone++;
|
|
} while (Zone < NUM_DAMAGE_ZONES);
|
|
|
|
Poly = 0;
|
|
|
|
DamPtr = gHDCarDamageLevels[model];
|
|
dentptr = gTempHDCarUVDump[cp->id];
|
|
|
|
while (Poly < pCleanModel->num_polys)
|
|
{
|
|
// calculate the UV offset with strange XORs
|
|
if(dentptr->u3 > 0)
|
|
dentptr->u3 = (*DamPtr ^ 1 ^ (*DamPtr ^ 1 | dentptr->u3)) * 64;
|
|
|
|
dentptr++;
|
|
|
|
DamPtr++;
|
|
Poly++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void CreateDentableCar(CAR_DATA *cp)
|
|
{
|
|
MODEL *srcModel;
|
|
SVECTOR *dst;
|
|
int count;
|
|
SVECTOR *src;
|
|
int vcount;
|
|
int model;
|
|
|
|
model = cp->ap.model;
|
|
|
|
srcModel = gCarCleanModelPtr[model];
|
|
if (srcModel != NULL)
|
|
{
|
|
src = (SVECTOR *)srcModel->vertices;
|
|
dst = gTempCarVertDump[cp->id];
|
|
|
|
vcount = srcModel->num_vertices;
|
|
|
|
while (vcount-- != -1)
|
|
*dst++ = *src++;
|
|
|
|
count = 0;
|
|
while (count < srcModel->num_polys)
|
|
{
|
|
gTempHDCarUVDump[cp->id][count].u3 = 0;
|
|
count++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printError("gCarCleanModelPtr is NULL in CreateDentableCar\n");
|
|
}
|
|
|
|
srcModel = gCarLowModelPtr[model];
|
|
if (srcModel != NULL)
|
|
{
|
|
count = 0;
|
|
while (count < srcModel->num_polys)
|
|
{
|
|
gTempLDCarUVDump[cp->id][count].u3 = 0;
|
|
count++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printError("gCarLowModelPtr is NULL in CreateDentableCar\n");
|
|
}
|
|
|
|
if (gDontResetCarDamage == 0)
|
|
{
|
|
count = 0;
|
|
while (count < NUM_DAMAGE_ZONES)
|
|
{
|
|
cp->ap.damage[count] = 0;
|
|
count++;
|
|
}
|
|
|
|
cp->totalDamage = 0;
|
|
}
|
|
}
|
|
|
|
extern HUBCAP gHubcap;
|
|
int gHubcapTime = 0;
|
|
|
|
// [D] [T]
|
|
void InitHubcap(void)
|
|
{
|
|
gHubcapTime = Random2(1) & 0x7ff;
|
|
}
|
|
|
|
|
|
// [D] [T]
|
|
void LoseHubcap(int car, int Hubcap, int Velocity)
|
|
{
|
|
SVECTOR InitialLocalAngle = { 0, 0, 10 };
|
|
CAR_DATA* cp;
|
|
|
|
SVECTOR* wheelDisp;
|
|
|
|
cp = &car_data[car];
|
|
|
|
// check speed and if hubcap lost
|
|
if (cp->hd.wheel_speed < 0 || (cp->ap.flags & 1 << Hubcap))
|
|
return;
|
|
|
|
wheelDisp = &cp->ap.carCos->wheelDisp[Hubcap];
|
|
|
|
cp->ap.flags |= (1 << Hubcap); // [A] cars now hold hubcaps
|
|
|
|
gHubcap.Position.vx = wheelDisp->vx;
|
|
gHubcap.Position.vy = wheelDisp->vy;
|
|
gHubcap.Position.vz = wheelDisp->vz;
|
|
|
|
SetRotMatrix(&cp->hd.where);
|
|
_MatrixRotate(&gHubcap.Position);
|
|
|
|
gHubcap.Position.vx += cp->hd.where.t[0];
|
|
gHubcap.Position.vy -= cp->hd.where.t[1];
|
|
gHubcap.Position.vz += cp->hd.where.t[2];
|
|
|
|
gHubcap.Orientation = cp->hd.where;
|
|
gHubcap.Rotation = 0;
|
|
|
|
if (Hubcap > 1)
|
|
{
|
|
gHubcap.Orientation.m[0][0] = -gHubcap.Orientation.m[0][0];
|
|
gHubcap.Orientation.m[1][0] = -gHubcap.Orientation.m[1][0];
|
|
|
|
gHubcap.Orientation.m[2][0] = -gHubcap.Orientation.m[2][0];
|
|
gHubcap.Orientation.m[0][2] = -gHubcap.Orientation.m[0][2];
|
|
|
|
gHubcap.Orientation.m[1][2] = -gHubcap.Orientation.m[1][2];
|
|
gHubcap.Orientation.m[2][2] = -gHubcap.Orientation.m[2][2];
|
|
}
|
|
|
|
gHubcap.Duration = 100;
|
|
|
|
gHubcap.Direction.vx = FIXEDH(FIXEDH(cp->st.n.angularVelocity[1]) * wheelDisp->vz) + FIXEDH(cp->st.n.linearVelocity[0]);
|
|
gHubcap.Direction.vy = FIXEDH(cp->st.n.linearVelocity[1]);
|
|
gHubcap.Direction.vz = FIXEDH(-FIXEDH(cp->st.n.angularVelocity[1]) * wheelDisp->vx) + FIXEDH(cp->st.n.linearVelocity[2]);
|
|
}
|
|
|
|
|
|
// [A]
|
|
void HandlePlayerHubcaps(int playerId)
|
|
{
|
|
int VelocityMagnitude;
|
|
CAR_DATA* cp;
|
|
int playerCarId;
|
|
|
|
playerCarId = player[playerId].playerCarId;
|
|
|
|
if (playerCarId < 0)
|
|
return;
|
|
|
|
cp = &car_data[playerCarId];
|
|
|
|
if (gHubcap.Duration < 1 && gHubcapTime == 0)
|
|
{
|
|
VelocityMagnitude = cp->st.n.angularVelocity[0] + cp->st.n.angularVelocity[1] + cp->st.n.angularVelocity[2];
|
|
|
|
if (VelocityMagnitude < -1000000)
|
|
{
|
|
LoseHubcap(playerCarId, Random2(2) & 1, VelocityMagnitude);
|
|
VelocityMagnitude = 3;
|
|
}
|
|
else if (VelocityMagnitude > 1000001)
|
|
{
|
|
LoseHubcap(playerCarId, Random2(4) & 1 | 2, VelocityMagnitude);
|
|
VelocityMagnitude = 5;
|
|
}
|
|
else
|
|
return;
|
|
|
|
gHubcapTime = Random2(VelocityMagnitude) & 0x417;
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void MoveHubcap()
|
|
{
|
|
int CurrentMapHeight;
|
|
int savecombo;
|
|
int cmb;
|
|
VECTOR ShadowPos;
|
|
VECTOR Position;
|
|
MATRIX Orientation;
|
|
CVECTOR col = {72,72,72};
|
|
|
|
InitMatrix(Orientation);
|
|
|
|
if (pauseflag == 0)
|
|
{
|
|
if(gHubcapTime > 0)
|
|
gHubcapTime--;
|
|
}
|
|
|
|
// draw current hubcap
|
|
if (gHubcap.Duration > 0)
|
|
{
|
|
if (pauseflag == 0 && CurrentPlayerView == 0)
|
|
{
|
|
gHubcap.Duration--;
|
|
|
|
// move hubcap
|
|
gHubcap.Position.vx += gHubcap.Direction.vx;
|
|
gHubcap.Position.vy += gHubcap.Direction.vy;
|
|
gHubcap.Position.vz += gHubcap.Direction.vz;
|
|
|
|
gHubcap.Rotation -= 220;
|
|
|
|
_RotMatrixX(&Orientation, gHubcap.Rotation);
|
|
|
|
gHubcap.Direction.vy += 5;
|
|
|
|
CurrentMapHeight = MapHeight(&gHubcap.Position);
|
|
|
|
if (gHubcap.Position.vy >= -40 - CurrentMapHeight)
|
|
{
|
|
gHubcap.Direction.vy = -(gHubcap.Direction.vy / 2);
|
|
gHubcap.Position.vy = -40 - CurrentMapHeight;
|
|
}
|
|
}
|
|
|
|
MulMatrix0(&gHubcap.Orientation, &Orientation, &Orientation);
|
|
|
|
ShadowPos.vx = gHubcap.Position.vx - camera_position.vx;
|
|
ShadowPos.vy = -MapHeight(&gHubcap.Position);
|
|
ShadowPos.vz = gHubcap.Position.vz - camera_position.vz;
|
|
|
|
Position.vx = ShadowPos.vx;
|
|
Position.vy = gHubcap.Position.vy - camera_position.vy;
|
|
Position.vz = ShadowPos.vz;
|
|
|
|
SetRotMatrix(&inv_camera_matrix);
|
|
|
|
_MatrixRotate(&Position);
|
|
savecombo = combointensity;
|
|
|
|
if (gTimeOfDay == 3)
|
|
{
|
|
cmb = (combointensity & 0xffU) / 3;
|
|
combointensity = cmb << 0x10 | cmb << 8 | cmb;
|
|
}
|
|
|
|
RenderModel(gHubcapModelPtr, &Orientation, &Position, 0, 0, 0, 0);
|
|
ShadowPos.vy -= camera_position.vy;
|
|
|
|
combointensity = savecombo;
|
|
|
|
RoundShadow(&ShadowPos, &col, 65);
|
|
}
|
|
}
|
|
|
|
#ifndef PSX
|
|
// [A] loads car model from file
|
|
char* LoadCarDentingFromFile(char* dest, int modelNumber)
|
|
{
|
|
char* mem;
|
|
char filename[64];
|
|
|
|
sprintf(filename, "LEVELS\\%s\\CARMODEL_%d.DEN", LevelNames[GameLevel], modelNumber);
|
|
if(FileExists(filename))
|
|
{
|
|
mem = dest ? dest : ((char*)_other_buffer + modelNumber * 4096);
|
|
|
|
// get model from file
|
|
Loadfile(filename, mem);
|
|
return mem;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
// [D] [T]
|
|
void ProcessDentLump(char *lump_ptr, int lump_size)
|
|
{
|
|
int model;
|
|
int i;
|
|
int offset;
|
|
u_char* mem;
|
|
|
|
i = 0;
|
|
|
|
while (i < MAX_CAR_MODELS)
|
|
{
|
|
model = MissionHeader->residentModels[i];
|
|
|
|
if (model == 13)
|
|
{
|
|
model = 10 - (MissionHeader->residentModels[0] + MissionHeader->residentModels[1] + MissionHeader->residentModels[2]);
|
|
|
|
if (model < 1)
|
|
model = 1;
|
|
else if(model > 4)
|
|
model = 4;
|
|
}
|
|
|
|
if (model != -1)
|
|
{
|
|
offset = *(int *)(lump_ptr + model * 4);
|
|
mem = (u_char*)lump_ptr;
|
|
#ifndef PSX
|
|
char* newDenting = LoadCarDentingFromFile(NULL, model);
|
|
if(newDenting)
|
|
{
|
|
mem = (u_char*)newDenting;
|
|
offset = 0;
|
|
}
|
|
#endif
|
|
|
|
memcpy((u_char*)gCarDamageZoneVerts[i], mem + offset, NUM_DAMAGE_ZONES * MAX_FILE_DAMAGE_ZONE_VERTS);
|
|
offset += NUM_DAMAGE_ZONES * MAX_FILE_DAMAGE_ZONE_VERTS;
|
|
|
|
memcpy((u_char*)gHDCarDamageZonePolys[i], mem + offset, NUM_DAMAGE_ZONES * MAX_FILE_DAMAGE_ZONE_POLYS);
|
|
offset += NUM_DAMAGE_ZONES * MAX_FILE_DAMAGE_ZONE_POLYS;
|
|
|
|
memcpy((u_char*)gHDCarDamageLevels[i], mem + offset, MAX_FILE_DAMAGE_LEVELS);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
|
|
// [D] [T]
|
|
void SetupSpecDenting(char *loadbuffer)
|
|
{
|
|
int offset;
|
|
|
|
// [A] this is better
|
|
memcpy((u_char*)gCarDamageZoneVerts[4], (u_char*)loadbuffer, NUM_DAMAGE_ZONES * MAX_FILE_DAMAGE_ZONE_VERTS);
|
|
offset = NUM_DAMAGE_ZONES * MAX_FILE_DAMAGE_ZONE_VERTS;
|
|
|
|
memcpy((u_char*)gHDCarDamageZonePolys[4], (u_char*)loadbuffer + offset, NUM_DAMAGE_ZONES * MAX_FILE_DAMAGE_ZONE_POLYS);
|
|
offset += NUM_DAMAGE_ZONES * MAX_FILE_DAMAGE_ZONE_POLYS;
|
|
|
|
memcpy((u_char*)gHDCarDamageLevels[4], (u_char*)loadbuffer + offset, MAX_FILE_DAMAGE_LEVELS);
|
|
}
|
|
|
|
// [D] [T]
|
|
void LoadDenting(int level)
|
|
{
|
|
LoadfileSeg(DentingFiles[level], (char*)_other_buffer, 0, 12727);
|
|
ProcessDentLump((char*)_other_buffer, 0);
|
|
}
|
|
|
|
|
|
|