REDRIVER2/src_rebuild/Game/C/denting.c
2022-01-21 21:00:11 +03:00

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);
}