Fix pratcam null pointer dereference (#532)

* Add enum for pratcam events

* Force start of ambient pratcam when no current pratcam to avoid null dereference

This fixes a null pointer dereference when showing the pratcam after finishing the race for the first time.

Steps:
1. Start a race
2. Hide pratcam
3. Finish race
4. Start a new race
5. Finish race
6. Show pratcam.... CRASH
This commit is contained in:
Anonymous Maarten 2025-12-23 15:42:21 +01:00 committed by GitHub
parent fe7ff89322
commit 078232d7ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 126 additions and 53 deletions

View File

@ -4387,35 +4387,35 @@ void SetAmbientPratCam(tCar_spec* pCar) {
abs_omega_z = fabs(pCar->omega.v[2]);
if (abs_omega_x > 4.5f || abs_omega_z > 4.5f) {
ChangeAmbientPratcam(9);
ChangeAmbientPratcam(kPratcam_rolling_violent);
} else if (abs_omega_y > 4.5f) {
ChangeAmbientPratcam(12);
ChangeAmbientPratcam(kPratcam_spinning_violent);
} else if (abs_omega_x > 3.f || abs_omega_z > 3.f) {
ChangeAmbientPratcam(8);
ChangeAmbientPratcam(kPratcam_rolling_medium);
} else if (abs_omega_y > 3.f) {
ChangeAmbientPratcam(11);
ChangeAmbientPratcam(kPratcam_spinning_medium);
} else if (pCar->car_master_actor->t.t.mat.m[1][1] < 0.1f) {
ChangeAmbientPratcam(44);
ChangeAmbientPratcam(kPratcam_upside_down);
} else if (abs_vcs_y > abs_vcs_z && abs_vcs_y > abs_vcs_x && vcs_y < -.004f) {
ChangeAmbientPratcam(6);
ChangeAmbientPratcam(kPratcam_falling);
} else if (the_time - last_time_on_ground > 500) {
ChangeAmbientPratcam(5);
ChangeAmbientPratcam(kPratcam_flying);
} else if (abs_vcs_x > abs_vcs_z && vcs_x > .001f) {
ChangeAmbientPratcam(26);
ChangeAmbientPratcam(kPratcam_skidding_right);
} else if (abs_vcs_x > abs_vcs_z && vcs_x < -.001f) {
ChangeAmbientPratcam(25);
ChangeAmbientPratcam(kPratcam_skidding_left);
} else if (abs_omega_x > 1.5f || abs_omega_z > 1.5f) {
ChangeAmbientPratcam(7);
ChangeAmbientPratcam(kPratcam_rolling_gently);
} else if (abs_omega_y > 1.5f) {
ChangeAmbientPratcam(10);
ChangeAmbientPratcam(kPratcam_spinning_gently);
} else if (abs_vcs_z > .01f) {
ChangeAmbientPratcam(3);
ChangeAmbientPratcam(kPratcam_over_137mph);
} else if (abs_vcs_z > .004f) {
ChangeAmbientPratcam(2);
ChangeAmbientPratcam(kPratcam_between_67_and_167mph);
} else if (abs_vcs_z > .0015f) {
ChangeAmbientPratcam(1);
ChangeAmbientPratcam(kPratcam_between_25_and_67mph);
} else {
ChangeAmbientPratcam(0);
ChangeAmbientPratcam(kPratcam_stationary_or_below_25mph);
}
}

View File

@ -801,7 +801,7 @@ void LookLeft(void) {
if (gAusterity_mode) {
NewTextHeadupSlot(eHeadupSlot_misc, 0, 1000, -4, GetMiscString(kMiscString_NOT_ENOUGH_MEMORY));
} else {
PratcamEvent(27);
PratcamEvent(kPratcam_cockpit_head_left);
gProgram_state.old_view = gProgram_state.which_view;
if (gProgram_state.which_view == eView_left) {
LookForward();
@ -822,9 +822,9 @@ void LookLeft(void) {
void LookForward(void) {
if (gProgram_state.which_view == eView_right) {
PratcamEvent(27);
PratcamEvent(kPratcam_cockpit_head_left);
} else if (gProgram_state.which_view == eView_left) {
PratcamEvent(28);
PratcamEvent(kPratcam_cockpit_head_right);
}
if (gProgram_state.which_view != eView_forward) {
gProgram_state.old_view = gProgram_state.which_view;
@ -842,7 +842,7 @@ void LookRight(void) {
if (gAusterity_mode) {
NewTextHeadupSlot(eHeadupSlot_misc, 0, 1000, -4, GetMiscString(kMiscString_NOT_ENOUGH_MEMORY));
} else {
PratcamEvent(28);
PratcamEvent(kPratcam_cockpit_head_right);
gProgram_state.old_view = gProgram_state.which_view;
if (gProgram_state.which_view == eView_right) {
LookForward();
@ -1132,7 +1132,7 @@ void ConcussMe(void) {
SufferFromConcussion(1.f);
NewScreenWobble(IRandomPosNeg(15), IRandomPosNeg(10), IRandomBetween(10, 60));
PratcamEvent(3);
PratcamEvent(kPratcam_over_137mph);
}
// IDA: void __cdecl CheckHelp()
@ -1954,7 +1954,7 @@ void BrakeInstantly(void) {
gProgram_state.current_car.revs = 0.f;
if (gProgram_state.current_car.number_of_wheels_on_ground != 0 && BrVector3LengthSquared(&gProgram_state.current_car.v) > 0.0001f) {
PratcamEvent(41);
PratcamEvent(kPratcam_instant_handbrake);
for (i = 0; i < 5; i++) {
DRS3StartSound(gCar_outlet, 9000 + i);
}

View File

@ -689,15 +689,15 @@ void DoPratcamHit(br_vector3* pHit_vector) {
}
if (fabs(pHit_vector->v[2]) >= fabs(pHit_vector->v[0])) {
if (pHit_vector->v[2] >= 0.f) {
PratcamEvent(14 + strength_modifier);
PratcamEvent(kPratcam_small_hit_front + strength_modifier);
} else {
PratcamEvent(13 + strength_modifier);
PratcamEvent(kPratcam_small_hit_behind + strength_modifier);
}
} else {
if (pHit_vector->v[0] >= 0.f) {
PratcamEvent(15 + strength_modifier);
PratcamEvent(kPratcam_small_hit_left + strength_modifier);
} else {
PratcamEvent(16 + strength_modifier);
PratcamEvent(kPratcam_small_hit_right + strength_modifier);
}
}
}
@ -1187,7 +1187,7 @@ int DoCrashEarnings(tCar_spec* pCar1, tCar_spec* pCar2) {
NetGuaranteedSendMessageToEverybody(gCurrent_net_game, message, NULL);
NetEarnCredits(NetPlayerFromCar(culprit), credits);
} else {
PratcamEvent(32);
PratcamEvent(kPratcam_opponent_wasted);
DoFancyHeadup(kFancyHeadupYouWastedEm);
credits_squared = sqr(0.7f / victim->car_model_actors[victim->principal_car_actor].crush_data.softness_factor) * gWasted_creds[gProgram_state.skill_level] + 50.0f;
credits = 100 * (int)(credits_squared / 100.0);

View File

@ -1586,7 +1586,7 @@ void ReceivedGameplay(tNet_contents* pContents, tNet_message* pMessage, tU32 pRe
break;
case eNet_gameplay_suddenly_death:
DoFancyHeadup(kFancyHeadupNetworkRaceOverNetworkLoss);
ChangeAmbientPratcam(36);
ChangeAmbientPratcam(kPratcam_network_timeout);
gRace_finished = 1;
break;
default:

View File

@ -1724,7 +1724,7 @@ void ReceivedWasted(tNet_contents* pContents) {
last_culprit = culprit;
last_victim = victim;
if (pContents->data.wasted.culprit == gLocal_net_ID) {
PratcamEvent(32);
PratcamEvent(kPratcam_opponent_wasted);
last_wasted_em_time = PDGetTotalTime();
if (last_wasted_em_time - last_got_wasted_time > 1000) {
DoFancyHeadup(kFancyHeadupYouWastedEm);

View File

@ -2042,7 +2042,7 @@ void CheckPedestrianDeathScenario(tPedestrian_data* pPedestrian) {
BrVector3Set(&up, 0.f, 1.f, 0.f);
if (billiards_shot) {
credits_value *= 4;
PratcamEvent(30);
PratcamEvent(kPratcam_killed_lots_of_peds);
DoFancyHeadup(kFancyHeadupNiceShotSir);
} else if (fabs(the_car->omega.v[X]) <= 5.0f
&& fabs(the_car->omega.v[Z]) <= 5.0f
@ -2055,10 +2055,10 @@ void CheckPedestrianDeathScenario(tPedestrian_data* pPedestrian) {
if (gCurrent_ped_multiplier >= 2) {
DoFancyHeadup(gCurrent_ped_multiplier + kFancyHeadup2xComboBonus - 2);
} else {
PratcamEvent(30);
PratcamEvent(kPratcam_killed_lots_of_peds);
if (exploded) {
DoFancyHeadup(kFancyHeadupSplatterBonus);
PratcamEvent(30);
PratcamEvent(kPratcam_killed_lots_of_peds);
}
}
} else {
@ -2067,10 +2067,10 @@ void CheckPedestrianDeathScenario(tPedestrian_data* pPedestrian) {
}
} else {
credits_value *= 4;
PratcamEvent(30);
PratcamEvent(kPratcam_killed_lots_of_peds);
DoFancyHeadup(kFancyHeadupBonusForArtisticImpression);
}
PratcamEvent(29);
PratcamEvent(kPratcam_killed_one_ped);
EarnCredits(credits_value);
}
if (the_car->driver == eDriver_local_human && gProgram_state.cockpit_on) {

View File

@ -1123,7 +1123,7 @@ void ResetInstantHandbrake(tPowerup* pPowerup, tCar_spec* pCar) {
void DoBouncey(tPowerup* pPowerup, tU32 pPeriod) {
if (gProgram_state.current_car.bounce_rate <= GetTotalTime() - gProgram_state.current_car.last_bounce && gProgram_state.current_car.number_of_wheels_on_ground > 2) {
PratcamEvent(42);
PratcamEvent(kPratcam_bouncey_bouncey);
gProgram_state.current_car.last_bounce = GetTotalTime();
gProgram_state.current_car.v.v[1] += gProgram_state.current_car.bounce_amount;
DRS3StartSound(gCar_outlet, 9010);

View File

@ -13,6 +13,7 @@
#include "loading.h"
#include "pd/sys.h"
#include "sound.h"
#include "structur.h"
#include "utility.h"
#include <stdlib.h>
@ -513,6 +514,30 @@ void DoPratcam(tU32 pThe_time) {
DontLetFlicFuckWithPalettes();
DisableTranslationText();
for (i = 0; i < (old_last_time != 0 ? ((pThe_time - old_last_time) / gPrat_flic.frame_period) : 1); i++) {
#ifdef DETHRACE_FIX_BUGS
if (gPrat_flic.data == NULL) {
switch (gRace_over_reason) {
case eRace_over_laps:
case eRace_over_peds:
case eRace_over_opponents:
ChangeAmbientPratcamNow(kPratcam_race_complete, 0);
break;
case eRace_over_demo:
case eRace_over_out_of_time:
ChangeAmbientPratcamNow(kPratcam_out_of_time, 0);
break;
case eRace_over_abandoned:
case eRace_over_network_victory:
case eRace_over_network_loss:
ChangeAmbientPratcamNow(kPratcam_network_timeout, 0);
break;
default:
case eRace_not_over_yet:
ChangeAmbientPratcamNow(kPratcam_stationary_or_below_25mph, 0);
break;
}
}
#endif
if (PlayNextFlicFrame(&gPrat_flic)) {
NextPratcamChunk();
break;
@ -626,68 +651,68 @@ void TestPratCam(int pIndex) {
// FUNCTION: CARM95 0x0044e6c0
void PratCam0(void) {
TestPratCam(0);
TestPratCam(kPratcam_stationary_or_below_25mph);
}
// IDA: void __cdecl PratCam1()
// FUNCTION: CARM95 0x0044e72e
void PratCam1(void) {
TestPratCam(1);
TestPratCam(kPratcam_between_25_and_67mph);
}
// IDA: void __cdecl PratCam2()
// FUNCTION: CARM95 0x0044e743
void PratCam2(void) {
TestPratCam(2);
TestPratCam(kPratcam_between_67_and_167mph);
}
// IDA: void __cdecl PratCam3()
// FUNCTION: CARM95 0x0044e758
void PratCam3(void) {
TestPratCam(3);
TestPratCam(kPratcam_over_137mph);
}
// IDA: void __cdecl PratCam4()
// FUNCTION: CARM95 0x0044e76d
void PratCam4(void) {
TestPratCam(4);
TestPratCam(kPratcam_accelerating_unused_4);
}
// IDA: void __cdecl PratCam5()
// FUNCTION: CARM95 0x0044e782
void PratCam5(void) {
TestPratCam(5);
TestPratCam(kPratcam_flying);
}
// IDA: void __cdecl PratCam6()
// FUNCTION: CARM95 0x0044e797
void PratCam6(void) {
TestPratCam(6);
TestPratCam(kPratcam_falling);
}
// IDA: void __cdecl PratCam7()
// FUNCTION: CARM95 0x0044e7ac
void PratCam7(void) {
TestPratCam(7);
TestPratCam(kPratcam_rolling_gently);
}
// IDA: void __cdecl PratCam8()
// FUNCTION: CARM95 0x0044e7c1
void PratCam8(void) {
TestPratCam(8);
TestPratCam(kPratcam_rolling_medium);
}
// IDA: void __cdecl PratCam9()
// FUNCTION: CARM95 0x0044e7d6
void PratCam9(void) {
TestPratCam(9);
TestPratCam(kPratcam_rolling_violent);
}

View File

@ -90,9 +90,9 @@ void RaceCompleted(tRace_over_reason pReason) {
NetFinishRace(gCurrent_net_game, pReason);
}
if (pReason == eRace_over_out_of_time || pReason == eRace_over_demo) {
ChangeAmbientPratcam(35);
ChangeAmbientPratcam(kPratcam_out_of_time);
} else if (pReason < eRace_over_abandoned) {
ChangeAmbientPratcam(34);
ChangeAmbientPratcam(kPratcam_race_complete);
}
gRace_over_reason = pReason;
if (gMap_mode) {
@ -100,30 +100,30 @@ void RaceCompleted(tRace_over_reason pReason) {
}
switch (gRace_over_reason) {
case eRace_over_network_victory:
ChangeAmbientPratcam(34);
ChangeAmbientPratcam(kPratcam_race_complete);
DoFancyHeadup(kFancyHeadupNetworkVictory);
break;
case eRace_over_network_loss:
ChangeAmbientPratcam(36);
ChangeAmbientPratcam(kPratcam_network_timeout);
DoFancyHeadup(kFancyHeadupNetworkRaceOverNetworkLoss);
break;
case eRace_over_out_of_time:
ChangeAmbientPratcam(35);
ChangeAmbientPratcam(kPratcam_out_of_time);
DoFancyHeadup(kFancyHeadupOutOfTime);
DRS3StartSound(gPedestrians_outlet, 8010);
break;
case eRace_over_demo:
ChangeAmbientPratcam(35);
ChangeAmbientPratcam(kPratcam_out_of_time);
DoFancyHeadup(kFancyHeadupDemoTimeout);
break;
case eRace_over_laps:
case eRace_over_peds:
case eRace_over_opponents:
ChangeAmbientPratcam(34);
ChangeAmbientPratcam(kPratcam_race_complete);
DoFancyHeadup(kFancyHeadupRaceCompleted);
DRS3StartSound(gPedestrians_outlet, 8011);
break;
@ -150,7 +150,7 @@ void RaceCompleted(tRace_over_reason pReason) {
// FUNCTION: CARM95 0x004141ca
void Checkpoint(int pCheckpoint_index, int pDo_sound) {
PratcamEvent(33);
PratcamEvent(kPratcam_checkpoint);
DoFancyHeadup(kFancyHeadupCheckpoint);
if (pDo_sound) {
DRS3StartSound(gPedestrians_outlet, 8012);
@ -174,7 +174,7 @@ void IncrementCheckpoint(void) {
gCheckpoint = gCheckpoint_count;
RaceCompleted(eRace_over_laps);
} else if (gLap == gTotal_laps) {
PratcamEvent(33);
PratcamEvent(kPratcam_checkpoint);
NewTextHeadupSlot(eHeadupSlot_misc, 0, 1000, -4, GetMiscString(kMiscString_FinalLap));
DRS3StartSound(gPedestrians_outlet, 8014);
done_voice = 1;

View File

@ -764,6 +764,54 @@ enum {
kFont_DRKPLAQ1 = 20,
};
enum {
kPratcam_stationary_or_below_25mph = 0,
kPratcam_between_25_and_67mph = 1,
kPratcam_between_67_and_167mph = 2,
kPratcam_over_137mph = 3,
kPratcam_accelerating_unused_4 = 4,
kPratcam_flying = 5,
kPratcam_falling = 6,
kPratcam_rolling_gently = 7,
kPratcam_rolling_medium = 8,
kPratcam_rolling_violent = 9,
kPratcam_spinning_gently = 10,
kPratcam_spinning_medium = 11,
kPratcam_spinning_violent = 12,
kPratcam_small_hit_behind = 13,
kPratcam_small_hit_front = 14,
kPratcam_small_hit_left = 15,
kPratcam_small_hit_right = 16,
kPratcam_medium_hit_behind = 17,
kPratcam_medium_hit_front = 18,
kPratcam_medium_hit_left = 19,
kPratcam_medium_hit_right = 20,
kPratcam_big_hit_behind = 21,
kPratcam_big_hit_front = 22,
kPratcam_big_hit_left = 23,
kPratcam_big_hit_right = 24,
kPratcam_skidding_left = 25,
kPratcam_skidding_right = 26,
kPratcam_cockpit_head_left = 27,
kPratcam_cockpit_head_right = 28,
kPratcam_killed_one_ped = 29,
kPratcam_killed_lots_of_peds = 30,
kPratcam_apologise_for_ped_kill = 31,
kPratcam_opponent_wasted = 32,
kPratcam_checkpoint = 33,
kPratcam_race_complete = 34,
kPratcam_out_of_time = 35,
kPratcam_network_timeout = 36,
kPratcam_points_or_time = 37,
kPratcam_good_powerup = 38,
kPratcam_bad_powerup = 39,
kPratcam_weird_powerup = 40,
kPratcam_instant_handbrake = 41,
kPratcam_bouncey_bouncey = 42,
kPratcam_instant_bodywork_trash = 43,
kPratcam_upside_down = 44,
};
enum {
NETMSGID_SENDMEDETAILS = 0x00,
NETMSGID_DETAILS = 0x01,