REDRIVER2/src_rebuild/Game/C/drivinggames.c
Ilya Shurumov 0cfa16e3d5 - rcossin_tbl[*] -> RSIN/RCOS
- some OD2 porting prepaprations
- fix CreateRoadblock refactoring bug (missing noMoreCars setup)
2022-01-21 21:01:05 +03:00

552 lines
10 KiB
C

#include "driver2.h"
#include "drivinggames.h"
#include "scores.h"
#include "mission.h"
#include "cutscene.h"
#include "main.h"
#include "system.h"
#include "draw.h"
#include "cars.h"
#include "players.h"
#include "cosmetic.h"
#include "bcollide.h"
#include "camera.h"
#include "convert.h"
#include "gamesnd.h"
#include "map.h"
#include "sound.h"
#include "glaunch.h"
#include "ASM/rndrasm.h"
struct TRAILBLAZER_DATA
{
int x, z;
short y, rot;
};
struct SMASHED_CONE
{
char cone;
u_char active : 7;
u_char side : 1;
short rot_speed;
VECTOR velocity;
};
MODEL* gTrailblazerConeModel;
SMASHED_CONE smashed_cones[MAX_SMASHED_CONES];
TRAILBLAZER_DATA *gTrailblazerData;
int gTrailblazerConeCount;
int gTrailblazerConeIndex;
static int gTrailblazerPrevConeDelay = 0;
static int wrongside[2][MAX_SMASHED_CONES];
static int current_smashed_cone = 0;
// [D] [T]
void InitDrivingGames(void)
{
char filename[64];
int i;
int j;
if (NewLevel)
gTrailblazerData = NULL;
gPlayerScore.time = 0;
gPlayerScore.items = 0;
gPlayerScore.P2time = 0;
gPlayerScore.P2items = 0;
if (GameType == GAME_GATERACE || GameType == GAME_TRAILBLAZER)
{
gTrailblazerConeCount = 0;
gTrailblazerConeIndex = 0;
if(NewLevel)
{
gTrailblazerData = (TRAILBLAZER_DATA*)D_MALLOC(1200); // [A] use malloc
sprintf(filename, "TRAILS\\TRAIL.%d", gCurrentMissionNumber);
if (FileExists(filename) != 0)
Loadfile(filename, (char*)gTrailblazerData);
}
}
for (i = 0; i < 2; i++)
{
for (j = 0; j < MAX_SMASHED_CONES; j++)
wrongside[i][j] = 0;
}
for (i = 0; i < MAX_SMASHED_CONES; i++)
{
smashed_cones[i].cone = -1;
smashed_cones[i].active = 0;
smashed_cones[i].side = 0;
smashed_cones[i].rot_speed = 0;
}
current_smashed_cone = 0;
gTrailblazerPrevConeDelay = 0;
}
// [D] [T]
int CarConeCollision(VECTOR *pPos, int car)
{
int model;
CDATA2D cd[2];
CAR_DATA* cp1;
cd[0].x.vx = pPos->vx;
cd[0].x.vz = pPos->vz;
cd[0].length[0] = 40;
cd[0].length[1] = 40;
cd[0].theta = pPos->pad;
cp1 = &car_data[car];
if (cp1->controlType == CONTROL_TYPE_NONE)
return 0;
model = cp1->ap.model;
cd[1].x.vx = cp1->hd.where.t[0];
cd[1].length[0] = car_cosmetics[model].colBox.vz;
cd[1].length[1] = car_cosmetics[model].colBox.vx;
cd[1].theta = cp1->hd.direction;
cd[1].x.vz = cp1->hd.where.t[2];
return bcollided2d(cd);
}
// [D] [T]
void SetSmashedCone(int cone, VECTOR *velocity, int player, int side)
{
int chan;
TRAILBLAZER_DATA *tbd;
SMASHED_CONE *sc;
sc = smashed_cones + current_smashed_cone;
current_smashed_cone++;
if (current_smashed_cone > MAX_SMASHED_CONES-1)
current_smashed_cone = 0;
sc->rot_speed = 256;
sc->side = side;
sc->cone = cone;
sc->velocity.vx = velocity->vx >> 10;
sc->velocity.vz = velocity->vz >> 10;
if (sc->velocity.vx < 0)
sc->velocity.vy = velocity->vx;
else
sc->velocity.vy = -velocity->vx;
if (sc->velocity.vz < 0)
sc->velocity.vy += velocity->vz;
else
sc->velocity.vy -= velocity->vz;
sc->velocity.vy /= 2;
if ((rand() & 1) == 0)
sc->rot_speed = -sc->velocity.vy;
else
sc->rot_speed = sc->velocity.vy;
if (sc->velocity.vy < -67)
sc->velocity.vy = -67;
chan = GetFreeChannel();
if (chan != -1)
{
if (NumPlayers > 1 && NoPlayerControl == 0)
SetPlayerOwnsChannel(chan, player);
tbd = &gTrailblazerData[cone];
Start3DSoundVolPitch(chan, SOUND_BANK_SFX, 1, tbd->x, tbd->y, tbd->z, -2000, 800);
}
}
// [D] [T]
void MoveSmashedCones(void)
{
TRAILBLAZER_DATA *tbd;
SMASHED_CONE *sc;
int i;
if (gTrailblazerData == NULL)
return;
sc = smashed_cones;
for (i = 0; i < MAX_SMASHED_CONES; i++)
{
if (sc->cone != -1)
{
tbd = &gTrailblazerData[sc->cone];
if (tbd->y < 50 - player[0].pos[1])
{
tbd->x += sc->velocity.vx;
tbd->y += sc->velocity.vy;
tbd->z += sc->velocity.vz;
sc->velocity.vy += 10;
sc->active++;
}
else
{
sc->cone = -1;
sc->active = 0;
}
}
sc++;
}
}
// [D] [T]
void DrawCone(VECTOR *position, int cone)
{
MATRIX matrix;
VECTOR pos;
if (gTrailblazerData == NULL)
return;
if (PositionVisible(position) == 0 || FrustrumCheck(position, gTrailblazerConeModel->bounding_sphere) == -1)
return;
InitMatrix(matrix);
_RotMatrixY(&matrix, gTrailblazerData[cone].rot);
pos.vx = position->vx - camera_position.vx;
pos.vy = position->vy - camera_position.vy;
pos.vz = position->vz - camera_position.vz;
gte_SetRotMatrix(&inv_camera_matrix);
_MatrixRotate(&pos);
RenderModel(gTrailblazerConeModel, &matrix, &pos, 0, 0, 0, 0);
}
// [D] [T]
void DrawSmashedCone(SMASHED_CONE *sc, VECTOR *wpos)
{
MATRIX object_matrix;
VECTOR pos;
InitMatrix(object_matrix);
RotMatrixY(sc->rot_speed * sc->active * 3 & 0xfff, &object_matrix);
RotMatrixZ(sc->rot_speed * sc->active & 0xfff, &object_matrix);
pos.vx = wpos->vx - camera_position.vx;
pos.vy = wpos->vy - camera_position.vy;
pos.vz = wpos->vz - camera_position.vz;
Apply_Inv_CameraMatrix(&pos);
SetRotMatrix(&object_matrix);
gte_SetTransVector(&pos);
SetFrustrumMatrix();
if (FrustrumCheck(wpos, gTrailblazerConeModel->bounding_sphere) != -1)
{
PlotMDL_less_than_128(gTrailblazerConeModel);
}
}
// [D] [T]
void GetConePos(int cone, VECTOR *pos, int side)
{
TRAILBLAZER_DATA *tbd;
int x, z;
int radius;
tbd = &gTrailblazerData[cone];
if (side == -1)
{
pos->vx = tbd->x;
pos->vy = tbd->y;
pos->vz = tbd->z;
pos->pad = tbd->rot; // [A] store cone rotation
}
else
{
radius = cone * -4 + 600;
x = radius * RCOS(tbd->rot);
z = -radius * RSIN(tbd->rot);
if (side == 0)
{
pos->vx = tbd->x - FIXED(x);
pos->vy = tbd->y;
pos->vz = tbd->z - FIXED(z);
}
else
{
pos->vx = tbd->x + FIXED(x);
pos->vy = tbd->y;
pos->vz = tbd->z + FIXED(z);
}
pos->pad = tbd->rot; // [A] store cone rotation
}
}
// [D] [T]
void DrawSmashedCones(void)
{
SMASHED_CONE* sc;
int i;
VECTOR wpos;
if (gTrailblazerData == NULL)
return;
for (i = 0; i < MAX_SMASHED_CONES; i++)
{
sc = &smashed_cones[i];
if (sc->active)
{
if (GameType == GAME_GATERACE)
{
GetConePos(sc->cone, &wpos, sc->side);
DrawSmashedCone(sc, &wpos);
}
else
{
GetConePos(sc->cone, &wpos, -1);
DrawSmashedCone(sc, &wpos);
}
}
}
}
// [D] [T]
void HandleDrivingGames(void)
{
char playerCarId;
TRAILBLAZER_DATA* tbd;
int id;
VECTOR vel;
VECTOR pos1;
VECTOR pos2;
int i, j, k;
int side;
int cone;
if (gTrailblazerPrevConeDelay > 0)
gTrailblazerPrevConeDelay--;
if (gTrailblazerData)
{
if (GameType == GAME_GATERACE)
{
MoveSmashedCones();
for (id = 0; id < NumPlayers; id++)
{
playerCarId = player[id].playerCarId;
for (i = 0; i < MAX_SMASHED_CONES; i++)
{
cone = gTrailblazerConeIndex + i;
if (cone < 100)
{
GetConePos(cone, &pos1, 0);
GetConePos(cone, &pos2, 1);
side = 0;
if (CarConeCollision(&pos1, playerCarId))
side = 1;
else if (CarConeCollision(&pos2, playerCarId))
side = 2;
if (side == 0)
{
int sn, cs;
int dx, dz;
int radius;
tbd = &gTrailblazerData[cone];
radius = (600 - (gTrailblazerConeIndex * 400 + i) / 100) * 4096;
sn = RSIN(tbd->rot);
cs = RCOS(tbd->rot);
dx = player[id].pos[0] - tbd->x;
dz = player[id].pos[2] - tbd->z;
if (dx * sn + dz * cs < 1)
{
wrongside[id][i] = 1;
continue;
}
if (wrongside[id][i] == 0)
continue;
wrongside[id][i] = 0;
if (ABS(dx * cs - dz * sn) < radius)
{
gTrailblazerConeCount++;
Mission.timer[id].count += 3000;
if (id == 0)
gPlayerScore.items++;
else
gPlayerScore.P2items++;
gTrailblazerConeIndex += i + 1;
gTrailblazerPrevConeDelay = 10;
}
// reset side
for (j = 0; j < 2; j++)
{
for (k = 0; k < MAX_SMASHED_CONES; k++)
wrongside[j][k] = 0;
}
}
else
{
vel.vx = FIXED(car_data[playerCarId].st.n.linearVelocity[0]);
vel.vy = -17;
vel.vz = FIXED(car_data[playerCarId].st.n.linearVelocity[2]);
SetSmashedCone(cone, &vel, id, side - 1);
gTrailblazerConeIndex += i + 1;
Mission.timer[id].count -= 3000;
SetPlayerMessage(id, G_LTXT(GTXT_Minus1second), 2, 1);
}
}
}
}
if (gTrailblazerConeIndex == 100)
MissionTargets[NumPlayers - 1].s.target_flags |= TARGET_FLAG_COMPLETED_ALLP;
}
else if (GameType == GAME_TRAILBLAZER)
{
MoveSmashedCones();
for (id = 0; id < NumPlayers; id++)
{
playerCarId = player[id].playerCarId;
for (i = 0; i < MAX_SMASHED_CONES; i++)
{
cone = gTrailblazerConeIndex + i;
if (cone < 100)
{
GetConePos(cone, &pos1, -1);
if (CarConeCollision(&pos1, playerCarId))
{
Mission.timer[id].count += 3000;
vel.vx = FIXED(car_data[playerCarId].st.n.linearVelocity[0]);
vel.vy = -17;
vel.vz = FIXED(car_data[playerCarId].st.n.linearVelocity[2]);
SetSmashedCone(cone, &vel, id, 0);
gTrailblazerConeCount++;
gTrailblazerConeIndex += i + 1;
if (id == 0)
gPlayerScore.items++;
else
gPlayerScore.P2items++;
}
}
}
}
if (gTrailblazerConeIndex == 100)
MissionTargets[NumPlayers - 1].s.target_flags |= TARGET_FLAG_COMPLETED_ALLP;
}
}
if (Mission.timer[0].count < 0)
Mission.timer[0].count = 0;
if (Mission.timer[1].count < 0)
Mission.timer[1].count = 0;
gPlayerScore.time = Mission.timer[0].count;
gPlayerScore.P2time = Mission.timer[1].count;
}
// [D] [T]
void DrawDrivingGames(void)
{
int cone;
int i;
VECTOR wpos;
if (GameType != GAME_GATERACE && GameType != GAME_TRAILBLAZER ||
gTrailblazerConeModel == NULL || gTrailblazerData == NULL)
return;
SetFrustrumMatrix();
if (gTrailblazerConeIndex < 100)
{
for (i = 0; i < MAX_SMASHED_CONES; i++)
{
cone = gTrailblazerConeIndex + i;
if (gTrailblazerPrevConeDelay)
cone -= 1;
if (GameType == GAME_GATERACE)
{
GetConePos(cone, &wpos, 0);
DrawCone(&wpos, cone);
GetConePos(cone, &wpos, 1);
DrawCone(&wpos, cone);
}
else
{
GetConePos(cone, &wpos, -1);
DrawCone(&wpos, cone);
}
}
}
DrawSmashedCones();
}