From bf1aa0bc3a6790d975a3b3182264329319f8d90a Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Wed, 27 Aug 2025 15:15:49 +0500 Subject: [PATCH 01/19] - fix brake light pool brightness values (thanks @Natsu235) --- src_rebuild/Game/C/cosmetic.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src_rebuild/Game/C/cosmetic.c b/src_rebuild/Game/C/cosmetic.c index 31131eba..cf6639aa 100644 --- a/src_rebuild/Game/C/cosmetic.c +++ b/src_rebuild/Game/C/cosmetic.c @@ -173,12 +173,11 @@ void AddIndicatorLight(CAR_DATA *cp, int Type) life2 = &cp->ap.life2; if (cp->ap.life < 0) - brightness = (0xff - (u_int)cp->ap.life) * 2; + brightness = (255 - (u_int)cp->ap.life) * 2 & 255; else - brightness = cp->ap.life << 1; - - col.r = brightness & 0xFF; + brightness = cp->ap.life << 1 & 255; + col.r = brightness; col.g = 0; col.b = 0; From c91805f08a13db368f2b9b8fef6a9df209dcd7c0 Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Wed, 27 Aug 2025 15:20:25 +0500 Subject: [PATCH 02/19] #209 overlay: fix multiplayer CTF misaligned flag counter + mdraw: match original behaviour of DrawMultiplayerTarget (thanks @Natsu235) --- src_rebuild/Game/C/mdraw.c | 13 +++++++++++++ src_rebuild/Game/C/overlay.c | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src_rebuild/Game/C/mdraw.c b/src_rebuild/Game/C/mdraw.c index 7b23e397..490ebab5 100644 --- a/src_rebuild/Game/C/mdraw.c +++ b/src_rebuild/Game/C/mdraw.c @@ -386,6 +386,19 @@ void DrawMultiplayerTarget(MS_TARGET *target) { tv.vx = player[gPlayerWithTheFlag].pos[0]; tv.vz = player[gPlayerWithTheFlag].pos[2]; + + if (gPlayerWithTheFlag == 0) + { + r = 128; + g = 0; + b = 0; + } + else if (gPlayerWithTheFlag == 1) + { + r = 0; + g = 128; + b = 0; + } } break; diff --git a/src_rebuild/Game/C/overlay.c b/src_rebuild/Game/C/overlay.c index 3fbfd6cd..0adf1d61 100644 --- a/src_rebuild/Game/C/overlay.c +++ b/src_rebuild/Game/C/overlay.c @@ -631,9 +631,9 @@ void DrawDrivingGameOverlays(void) sprintf(string, "%d", gPlayerScore.items); PrintString(string, x + 3, 16); - x = PrintString(G_LTXT(GTXT_Flags), gOverlayXPos, 132); + x = PrintString(G_LTXT(GTXT_Flags), gOverlayXPos, SCREEN_H / 2 + 12); sprintf(string, "%d", gPlayerScore.P2items); - PrintString(string, x + 3, SCREEN_H / 2 + 4); + PrintString(string, x + 3, SCREEN_H / 2 + 12); break; case GAME_SECRET: y = 36; From d44f77024d504d8b87669036b9d6ed1d8afba954 Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Fri, 12 Sep 2025 21:55:10 +0500 Subject: [PATCH 03/19] - add decompiled birds code from Driver 1, adjust so it works --- src_rebuild/Game/C/bcollide.c | 10 +- src_rebuild/Game/C/debris.c | 189 +++++++++++++++++++++++++++++++++- src_rebuild/Game/C/debris.h | 2 + src_rebuild/Game/C/texture.c | 9 +- src_rebuild/Game/C/texture.h | 2 +- src_rebuild/Game/dr2limits.h | 1 + 6 files changed, 205 insertions(+), 8 deletions(-) diff --git a/src_rebuild/Game/C/bcollide.c b/src_rebuild/Game/C/bcollide.c index 3ca46c5e..e2a4547b 100644 --- a/src_rebuild/Game/C/bcollide.c +++ b/src_rebuild/Game/C/bcollide.c @@ -895,12 +895,20 @@ int CarBuildingCollision(CAR_DATA *cp, BUILDING_BOX *building, CELL_OBJECT *cop, { if (model->flags2 & MODEL_FLAG_TREE) { + int rnd; VECTOR LeafPosition; LeafPosition.vx = collisionResult.hit.vx; - LeafPosition.vy = -((rand() & 0xfe) + 600) - collisionResult.hit.vy; + LeafPosition.vy = -((rand() & 254) + 600) - collisionResult.hit.vy; LeafPosition.vz = collisionResult.hit.vz; AddLeaf(&LeafPosition, 3, 1); + + rnd = rand(); + if ((rnd & 1) == 0) + { + LeafPosition.vy -= 1100; + CreateBirds(&LeafPosition, (rnd >> 8) & 7); + } } else { diff --git a/src_rebuild/Game/C/debris.c b/src_rebuild/Game/C/debris.c index 2c3833f1..fa1f324d 100644 --- a/src_rebuild/Game/C/debris.c +++ b/src_rebuild/Game/C/debris.c @@ -88,6 +88,14 @@ struct LEAF char sin_addition2; }; +struct BIRD +{ + VECTOR_NOPAD position; + SVECTOR_NOPAD direction; + short life; + short step; +}; + struct TRI_POINT { BVECTOR v0; @@ -389,6 +397,9 @@ LEAF leaf[MAX_LEAVES]; SVECTOR debris_rotvec; DEBRIS debris[MAX_DEBRIS]; +BIRD birds[MAX_BIRDS]; +int gNumBirds = 0; + int StreakCount1 = 0; int main_cop_light_pos = 0; int NextDamagedLamp = 0; @@ -755,6 +766,174 @@ void AddLeaf(VECTOR *Position, int num_leaves, int Type) } } +// [D] [T] +void CreateBirds(VECTOR* pos, int count) +{ + BIRD *bird; + int i; + + if (bird_texture1.tpageid == 0 || bird_texture2.tpageid == 0) + { + return; + } + + if (count >= MAX_BIRDS) + count = MAX_BIRDS-1; + + if (birds[0].life != 0) + { + return; + } + + gNumBirds = count; + for (i = 0; i < count; ++i) + { + bird = &birds[i]; + bird->position.vx = pos->vx - 32 + (rand() & 63); + bird->position.vy = pos->vy - 32 + (rand() & 63); + bird->position.vz = pos->vz - 32 + (rand() & 63); + bird->direction.vx = (rand() & 63) - 32; + bird->direction.vy = -10 - (rand() & 16); + bird->direction.vz = (rand() & 63) - 32; + bird->life = 120; + bird->step = rand() & 7; + } +} + +// [D] [T] +void HandleBirds() +{ + BIRD* bird; + POLY_FT4* primptr; + VECTOR pos; + SVECTOR vertPos[4]; + u_short clutid; + short sizeX; + short sizeY; + int i; + int z; + int bright; + + if (birds[0].life == 0 || gNumBirds == 0) + { + return; + } + + gte_SetRotMatrix(&identity); + + bright = 128; + if (gNight != 0) + bright = 64; + + for(i = 0; i < gNumBirds; ++i) + { + bird = &birds[i]; + if (bird->life <= 0) + { + continue; + } + + pos.vx = bird->position.vx - camera_position.vx; + pos.vy = bird->position.vy - camera_position.vy; + pos.vz = bird->position.vz - camera_position.vz; + Apply_Inv_CameraMatrix(&pos); + + gte_SetTransVector(&pos); + + if (pauseflag == 0 && pos.vz > 13500) + { + bird->life = 0; + return; + } + + sizeX = 40; + if (bird->step < 4) + { + sizeY = 19; + } + else + { + sizeX = 64; + sizeY = 24; + } + vertPos[0].vy = -sizeY; + vertPos[1].vy = -sizeY; + vertPos[0].vx = -sizeX; + vertPos[0].vz = 0; + vertPos[1].vx = sizeX; + vertPos[1].vz = 0; + vertPos[2].vx = -sizeX; + vertPos[2].vy = sizeY; + vertPos[2].vz = 0; + vertPos[3].vx = sizeX; + vertPos[3].vy = sizeY; + vertPos[3].vz = 0; + + gte_ldv3(&vertPos[0], &vertPos[1], &vertPos[2]); + gte_rtpt(); + + primptr = (POLY_FT4*)current->primptr; + if (bird->step < 4) + { + primptr->u0 = bird_texture2.coords.u0; + primptr->v0 = bird_texture2.coords.v0; + primptr->u1 = bird_texture2.coords.u1; + primptr->v1 = bird_texture2.coords.v1; + primptr->u2 = bird_texture2.coords.u2; + primptr->v2 = bird_texture2.coords.v2; + primptr->u3 = bird_texture2.coords.u3; + primptr->v3 = bird_texture2.coords.v3; + primptr->tpage = bird_texture2.tpageid; + clutid = bird_texture2.clutid; + } + else + { + primptr->u0 = bird_texture1.coords.u0; + primptr->v0 = bird_texture1.coords.v0; + primptr->u1 = bird_texture1.coords.u1; + primptr->v1 = bird_texture1.coords.v1; + primptr->u2 = bird_texture1.coords.u2; + primptr->v2 = bird_texture1.coords.v2; + primptr->u3 = bird_texture1.coords.u3; + primptr->v3 = bird_texture1.coords.v3; + primptr->tpage = bird_texture1.tpageid; + clutid = bird_texture1.clutid; + } + + primptr->clut = clutid; + setPolyFT4(primptr); + primptr->r0 = bright; + primptr->g0 = bright; + primptr->b0 = bright; + + gte_stsz(&z); + if (z < 150) + continue; + + gte_stsxy3(&primptr->x0, &primptr->x1, &primptr->x2); + + gte_ldv0(&vertPos[3]); + gte_rtps(); + + gte_stsxy(&primptr->x3); + + addPrim(current->ot + (z >> 3), primptr); + + current->primptr += sizeof(POLY_FT4); + + if (pauseflag == 0) + { + bird->position.vx += bird->direction.vx; + bird->position.vy += bird->direction.vy; + bird->position.vz = bird->position.vz + bird->direction.vz; + + if (--bird->step == -1) + bird->step = 8; + --bird->life; + } + } +} + // [D] [T] void SwirlLeaves(CAR_DATA *cp) { @@ -801,8 +980,8 @@ void InitDebrisNames(void) GetTextureDetails("SKID", &gTyreTexture); GetTextureDetails("FLARE", &flare_texture); GetTextureDetails("SPLASH", &sea_texture); - GetTextureDetails("SWBIRD1", &bird_texture1); - GetTextureDetails("SWBIRD2", &bird_texture2); + GetTextureDetails("SWBIRD1", &bird_texture1, 0); + GetTextureDetails("SWBIRD2", &bird_texture2, 0); GetTextureDetails("LENSFLR", &lensflare_texture); GetTextureDetails("SKYSUN", &sun_texture); GetTextureDetails("SKYMOON", &moon_texture); @@ -933,6 +1112,8 @@ void InitDebris(void) } } + birds[0].life = 0; + for (i = 0; i < MAX_SMOKE; i++) { smoke_alloc[i] = i; @@ -3135,7 +3316,7 @@ void HandleDebris(void) GetSmokeDrift(&Drift); MoveHubcap(); - + HandleBirds(); SetRotMatrix(&inv_camera_matrix); gte_SetTransVector(&dummy); @@ -3530,7 +3711,7 @@ void DrawRainDrops(void) bright = 50; if (gNight != 0) - bright -= -15; + bright -= 15; col = bright >> 1 | (bright >> 1) << 8; col |= col | col << 0x10; diff --git a/src_rebuild/Game/C/debris.h b/src_rebuild/Game/C/debris.h index 6a19fd43..8ff4ebf1 100644 --- a/src_rebuild/Game/C/debris.h +++ b/src_rebuild/Game/C/debris.h @@ -77,6 +77,8 @@ extern void InitFXPos(VECTOR* vec, SVECTOR* svec, CAR_DATA* cp); // 0x00039C90 extern void SwirlLeaves(CAR_DATA* cp); // 0x00039E54 extern void AddLeaf(VECTOR* Position, int num_leaves, int Type); // 0x00033574 +extern void CreateBirds(VECTOR* pos, int count); + extern void ShowCarlight(SVECTOR *v1, CAR_DATA *cp, CVECTOR *col, short size, short flare_size, TEXTURE_DETAILS *texture, int flag); // 0x000352CC extern void ShowLight1(VECTOR *v1, CVECTOR *col, short size, TEXTURE_DETAILS *texture); // 0x0003555C extern void ShowLight(VECTOR *v1, CVECTOR *col, short size, TEXTURE_DETAILS *texture); // 0x00035750 diff --git a/src_rebuild/Game/C/texture.c b/src_rebuild/Game/C/texture.c index 5101df2e..36c8a3fc 100644 --- a/src_rebuild/Game/C/texture.c +++ b/src_rebuild/Game/C/texture.c @@ -599,7 +599,7 @@ void ReloadIcons(void) } // [D] [T] -void GetTextureDetails(char *name, TEXTURE_DETAILS *info) +void GetTextureDetails(char *name, TEXTURE_DETAILS *info, int defaultToSea) { int i, j; int texamt; @@ -632,7 +632,12 @@ void GetTextureDetails(char *name, TEXTURE_DETAILS *info) } } - GetTextureDetails("SEA", info); // weird but ok, ok... + info->tpageid = 0; + info->clutid = 0; + info->texture_number = 0; + info->texture_page = 0; + if (defaultToSea) + GetTextureDetails("SEA", info); // weird but ok, ok... } diff --git a/src_rebuild/Game/C/texture.h b/src_rebuild/Game/C/texture.h index 9e1fde9c..9a485e65 100644 --- a/src_rebuild/Game/C/texture.h +++ b/src_rebuild/Game/C/texture.h @@ -40,7 +40,7 @@ extern int LoadTPageAndCluts(RECT16 *tpage, RECT16 *cluts, int tpage2send, char extern int Find_TexID(MODEL *model, int t_id); // 0x000805EC extern TEXINF* GetTEXINFName(char *name, int *tpagenum, int *texturenum); // 0x00080F3C extern TEXINF* GetTextureInfoName(char *name, TPAN *result); // 0x00080DA0 -extern void GetTextureDetails(char *name, TEXTURE_DETAILS *info); // 0x00080BB0 +extern void GetTextureDetails(char *name, TEXTURE_DETAILS *info, int defaultToSea = 1); // 0x00080BB0 extern void update_slotinfo(int tpage, int slot, RECT16 *pos); // 0x00081038 diff --git a/src_rebuild/Game/dr2limits.h b/src_rebuild/Game/dr2limits.h index c0361c40..339721aa 100644 --- a/src_rebuild/Game/dr2limits.h +++ b/src_rebuild/Game/dr2limits.h @@ -67,6 +67,7 @@ // debris limits #define MAX_SMOKE 80 #define MAX_LEAVES 50 +#define MAX_BIRDS 7 #define MAX_DEBRIS 60 #define MAX_GROUND_DEBRIS 16 #define MAX_DAMAGED_LAMPS 5 From ddfee61981c661dd67626c5a746b0d2ec2584138 Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Fri, 12 Sep 2025 22:51:33 +0500 Subject: [PATCH 04/19] - try fix CI build on Windows --- appveyor.yml | 8 ++++---- windows_dev_prepare.ps1 | 11 +++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 876327b5..fcefa0a2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -18,13 +18,13 @@ environment: # Dependency URLs windows_premake_url: 'https://github.com/premake/premake-core/releases/download/v5.0.0-beta1/premake-5.0.0-beta1-windows.zip' windows_jpeg_url: 'http://www.ijg.org/files/jpegsr9d.zip' - windows_openal_url: 'https://openal-soft.org/openal-binaries/openal-soft-1.21.1-bin.zip' - windows_sdl2_url: 'https://www.libsdl.org/release/SDL2-devel-2.0.20-VC.zip' + windows_openal_url: 'https://github.com/kcat/openal-soft/releases/download/1.23.1/openal-soft-1.23.1-bin.zip' + windows_sdl2_url: 'https://github.com/libsdl-org/SDL/releases/download/release-2.30.2/SDL2-devel-2.30.2-VC.zip' linux_premake_url: 'https://github.com/premake/premake-core/releases/download/v5.0.0-beta1/premake-5.0.0-beta1-linux.tar.gz' # Dependency Directories windows_jpeg_dir: '%dependency_folder%\jpeg-9d' - windows_openal_dir: '%dependency_folder%\openal-soft-1.21.1-bin' - windows_sdl2_dir: '%dependency_folder%\SDL2-2.0.20' + windows_openal_dir: '%dependency_folder%\openal-soft-1.23.1-bin' + windows_sdl2_dir: '%dependency_folder%\SDL2-2.30.2' install: diff --git a/windows_dev_prepare.ps1 b/windows_dev_prepare.ps1 index 25a675e0..abba82c4 100644 --- a/windows_dev_prepare.ps1 +++ b/windows_dev_prepare.ps1 @@ -1,7 +1,10 @@ +$openal_ver = '1.23.1' +$sdl2_ver = '2.30.2' + $windows_premake_url = 'https://github.com/premake/premake-core/releases/download/v5.0.0-beta1/premake-5.0.0-beta1-windows.zip' $windows_jpeg_url = 'http://www.ijg.org/files/jpegsr9d.zip' -$windows_openal_url = 'https://openal-soft.org/openal-binaries/openal-soft-1.21.1-bin.zip' -$windows_sdl2_url = 'https://www.libsdl.org/release/SDL2-devel-2.0.20-VC.zip' +$windows_openal_url = 'https://github.com/kcat/openal-soft/releases/download/' + $openal_ver + '/openal-soft-' + $openal_ver + '-bin.zip' +$windows_sdl2_url = 'https://github.com/libsdl-org/SDL/releases/download/release-' + $sdl2_ver + '/SDL2-devel-' + $sdl2_ver + '-VC.zip' $project_folder = '.\\src_rebuild' $dependency_folder = $project_folder + '\\dependencies' @@ -21,8 +24,8 @@ Expand-Archive JPEG.zip -DestinationPath $dependency_folder # Generate project files $windows_jpeg_dir = '.\\dependencies\\jpeg-9d' -$windows_openal_dir = '.\\dependencies\\openal-soft-1.21.1-bin' -$windows_sdl2_dir = '.\\dependencies\\SDL2-2.0.20' +$windows_openal_dir = '.\\dependencies\\openal-soft-' + $openal_ver + '-bin' +$windows_sdl2_dir = '.\\dependencies\\SDL2-' + $sdl2_ver $env:SDL2_DIR = $windows_sdl2_dir $env:OPENAL_DIR = $windows_openal_dir From 58e1f4061720cbf5c373c1e22207139a3e75ffce Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Fri, 3 Oct 2025 17:30:48 +0500 Subject: [PATCH 05/19] - remove comment --- src_rebuild/Game/C/dr2roads.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src_rebuild/Game/C/dr2roads.c b/src_rebuild/Game/C/dr2roads.c index bade3a62..0a32a044 100644 --- a/src_rebuild/Game/C/dr2roads.c +++ b/src_rebuild/Game/C/dr2roads.c @@ -346,9 +346,6 @@ sdPlane* sdGetCell(VECTOR *pos) buffer = RoadMapDataRegions[(cellPos.x >> 16 & 1) ^ (regions_across / 2 & 1) + (cellPos.y >> 15 & 2) ^ (regions_down & 2)]; - // Alpha 1.6 code, works too; not widely tested yet - //buffer = *(short**)((int)RoadMapDataRegions + (cellPos.x >> 14 & 4 ^ cellPos.y >> 13 & 8 ^ sdSelfModifyingCode)); - plane = GetSeaPlane(); if (*buffer != 2) From 3bdd6bba31b44c6e95242a4cc032557710891fd8 Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Fri, 3 Oct 2025 17:31:32 +0500 Subject: [PATCH 06/19] - spool: don't ping out secret cars in PrepareSecretCar --- src_rebuild/Game/C/spool.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src_rebuild/Game/C/spool.c b/src_rebuild/Game/C/spool.c index a075bc39..4e0c43f0 100644 --- a/src_rebuild/Game/C/spool.c +++ b/src_rebuild/Game/C/spool.c @@ -2162,7 +2162,7 @@ void CheckSpecialSpool(void) specialState == SpecSpool_None && GameType != GAME_PURSUIT && LoadedArea != -1 && - SpecialByRegion[GameLevel][LoadedArea] != MissionHeader->residentModels[4]-7) + SpecialByRegion[GameLevel][LoadedArea] != MissionHeader->residentModels[4] - 7) { lcp = car_data; @@ -2184,7 +2184,7 @@ void CheckSpecialSpool(void) gCarLowModelPtr[4] = NULL; specSpoolModelIndex = SpecialByRegion[GameLevel][LoadedArea]; - MissionHeader->residentModels[4] = SpecialByRegion[GameLevel][LoadedArea] + 7; + MissionHeader->residentModels[4] = specSpoolModelIndex + 7; SpecialStartNextBlock(); } @@ -2201,7 +2201,7 @@ void QuickSpoolSpecial(void) gCarDamModelPtr[4] = NULL; gCarLowModelPtr[4] = NULL; - specSpoolModelIndex = MissionHeader->residentModels[4]-7; + specSpoolModelIndex = MissionHeader->residentModels[4] - 7; do { SpoolSYNC(); @@ -2214,6 +2214,12 @@ void QuickSpoolSpecial(void) // [D] [T] void PrepareSecretCar(void) { + // [A] Don't do anything if model is already spooled + if (MissionHeader->residentModels[4] == 12) + { + return; + } + allowSpecSpooling = 0; PingOutAllSpecialCivCars(); @@ -2222,9 +2228,10 @@ void PrepareSecretCar(void) gCarLowModelPtr[4] = NULL; specSpoolModelIndex = 5; + MissionHeader->residentModels[4] = 12; + specModelValid = 0; startSpecSpool = CameraCnt; - MissionHeader->residentModels[4] = 12; specialState = SpecSpool_None; specBlocksToLoad = 0; SpecialStartNextBlock(); From c9b59e14513ef4f30a5eb943920b4dfcc8af28b5 Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Fri, 3 Oct 2025 17:32:38 +0500 Subject: [PATCH 07/19] - event: opening secret car gate in rio now triggers spool --- src_rebuild/Game/C/event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_rebuild/Game/C/event.c b/src_rebuild/Game/C/event.c index a063a284..d6c98648 100644 --- a/src_rebuild/Game/C/event.c +++ b/src_rebuild/Game/C/event.c @@ -3645,7 +3645,7 @@ VECTOR* TriggerEvent(int i) break; case 8: // open gate to secret car - PingOutAllSpecialCivCars(); + PrepareSecretCar(); TriggerDoor(&rioDoor[4], &stage[i], 0); TriggerDoor(&rioDoor[5], &stage[i], 0); From 07c1753e44edc71828d7cf90f7d57c6e0796b73a Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Fri, 3 Oct 2025 21:54:33 +0500 Subject: [PATCH 08/19] Load all base car models into memory (as permanent textures are already present) + Added MAX_CAR_RESIDENT_MODELS + use custom array for mission residentModels as new additional slot present --- src_rebuild/Game/C/cars.c | 16 ++--- src_rebuild/Game/C/cars.h | 10 ++-- src_rebuild/Game/C/civ_ai.c | 51 ++++++++-------- src_rebuild/Game/C/cosmetic.c | 20 +++---- src_rebuild/Game/C/cosmetic.h | 2 +- src_rebuild/Game/C/cutscene.c | 2 +- src_rebuild/Game/C/debris.c | 2 +- src_rebuild/Game/C/denting.c | 22 +++---- src_rebuild/Game/C/event.c | 2 +- src_rebuild/Game/C/gamesnd.c | 95 ++++++++++++++--------------- src_rebuild/Game/C/gamesnd.h | 2 +- src_rebuild/Game/C/handling.c | 2 +- src_rebuild/Game/C/main.c | 22 +++---- src_rebuild/Game/C/mgeneric.c | 4 +- src_rebuild/Game/C/mission.c | 37 +++++++++--- src_rebuild/Game/C/mission.h | 1 + src_rebuild/Game/C/models.c | 8 +-- src_rebuild/Game/C/pause.c | 4 +- src_rebuild/Game/C/players.c | 29 ++++----- src_rebuild/Game/C/spool.c | 103 ++++++++++++++++---------------- src_rebuild/Game/C/texture.c | 61 +++++++++++++++---- src_rebuild/Game/dr2limits.h | 7 ++- src_rebuild/redriver2_psxpc.cpp | 6 +- 23 files changed, 286 insertions(+), 222 deletions(-) diff --git a/src_rebuild/Game/C/cars.c b/src_rebuild/Game/C/cars.c index bd324f9d..ea90b9f5 100644 --- a/src_rebuild/Game/C/cars.c +++ b/src_rebuild/Game/C/cars.c @@ -79,20 +79,22 @@ DENTUVS *gTempCarUVPtr; DENTUVS gTempHDCarUVDump[MAX_CARS][MAX_DENTING_UVS]; DENTUVS gTempLDCarUVDump[MAX_CARS][MAX_DENTING_LOD_UVS]; -CAR_MODEL NewCarModel[MAX_CAR_MODELS]; -CAR_MODEL NewLowCarModel[MAX_CAR_MODELS]; +CAR_MODEL NewCarModel[MAX_CAR_RESIDENT_MODELS]; +CAR_MODEL NewLowCarModel[MAX_CAR_RESIDENT_MODELS]; -MODEL* gCarLowModelPtr[MAX_CAR_MODELS]; -MODEL* gCarDamModelPtr[MAX_CAR_MODELS]; -MODEL* gCarCleanModelPtr[MAX_CAR_MODELS]; +MODEL* gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS]; +MODEL* gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS]; +MODEL* gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS]; // pedestrian palette at 0 and next are cars // model_id, texture_number, palette u_short civ_clut[8][32][6]; +#define MAX_CAR_POLYS (200 * 2) * MAX_CAR_RESIDENT_MODELS + int whichCP = 0; int baseSpecCP = 0; -CAR_POLY carPolyBuffer[2001]; +CAR_POLY carPolyBuffer[MAX_CAR_POLYS + 1]; char LeftLight = 0; char RightLight = 0; @@ -1065,7 +1067,7 @@ void buildNewCarFromModel(int index, int detail, char* polySrc, MODEL* model) newNumPolys = whichCP; - for (i = 0; newNumPolys < 2000 && i < model->num_polys; i++) + for (i = 0; newNumPolys < MAX_CAR_POLYS && i < model->num_polys; i++) { ptype = *polyList; diff --git a/src_rebuild/Game/C/cars.h b/src_rebuild/Game/C/cars.h index 88902ddd..d60bc21d 100644 --- a/src_rebuild/Game/C/cars.h +++ b/src_rebuild/Game/C/cars.h @@ -13,12 +13,12 @@ extern CAR_DATA car_data[MAX_CARS + 2]; // all cars + Tanner cbox + Camera cbox extern CAR_DATA* active_car_list[MAX_CARS]; extern unsigned char lightsOnDelay[MAX_CARS]; -extern CAR_MODEL NewCarModel[MAX_CAR_MODELS]; -extern CAR_MODEL NewLowCarModel[MAX_CAR_MODELS]; +extern CAR_MODEL NewCarModel[MAX_CAR_RESIDENT_MODELS]; +extern CAR_MODEL NewLowCarModel[MAX_CAR_RESIDENT_MODELS]; -extern MODEL* gCarLowModelPtr[MAX_CAR_MODELS]; -extern MODEL* gCarDamModelPtr[MAX_CAR_MODELS]; -extern MODEL* gCarCleanModelPtr[MAX_CAR_MODELS]; +extern MODEL* gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS]; +extern MODEL* gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS]; +extern MODEL* gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS]; extern int whichCP; // car poly counter extern int baseSpecCP; // special car poly counter diff --git a/src_rebuild/Game/C/civ_ai.c b/src_rebuild/Game/C/civ_ai.c index fd6822f2..46315e5c 100644 --- a/src_rebuild/Game/C/civ_ai.c +++ b/src_rebuild/Game/C/civ_ai.c @@ -44,7 +44,7 @@ struct } civPingTest; #endif // DEBUG -char modelRandomList[] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 1, 0, 4 }; +char modelRandomList[16] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 1, 0, 4 }; u_char reservedSlots[MAX_CARS] = { 0 }; int distFurthestCivCarSq = 0; @@ -1595,7 +1595,7 @@ int PingOutAllSpecialCivCars(void) do { - if (lcp->controlType == CONTROL_TYPE_CIV_AI && MissionHeader->residentModels[lcp->ap.model] > 4) + if (lcp->controlType == CONTROL_TYPE_CIV_AI && missionResidentCarModels[lcp->ap.model] > 4) PingOutCar(lcp); lcp++; @@ -1786,22 +1786,19 @@ int CreateStationaryCivCar(int direction, int orientX, int orientZ, LONGVECTOR4* unsigned char* slot; CAR_DATA* newCar; CAR_DATA* carCnt; - int model; + int model, i; EXTRA_CIV_DATA civDat; LONGQUATERNION tmpQ; model = -1; - - if (MissionHeader->residentModels[0] == externalModel) - model = 0; - else if (MissionHeader->residentModels[1] == externalModel) - model = 1; - else if (MissionHeader->residentModels[2] == externalModel) - model = 2; - else if (MissionHeader->residentModels[3] == externalModel) - model = 3; - else if (MissionHeader->residentModels[4] == externalModel) - model = 4; + for(i = 0; i < MAX_CAR_RESIDENT_MODELS; ++i) + { + if (missionResidentCarModels[i] == externalModel) + { + model = i; + break; + } + } if (model != -1) { @@ -2172,18 +2169,27 @@ int PingInCivCar(int minPingInDist) } // check if special car is loaded and add it to random list - if (specModelValid == 0 || allowSpecSpooling == 0 || MissionHeader->residentModels[4] == 12) + if ((specModelValid == 0 || allowSpecSpooling == 0 || missionResidentCarModels[MAX_CAR_RESIDENT_MODELS-1] == 12) && missionResidentCarModels[MAX_CAR_RESIDENT_MODELS-1] >= 8) { +#if MAX_CAR_RESIDENT_MODELS == 6 + modelRandomList[15] = 4; +#else modelRandomList[15] = 0; +#endif modelRandomList[14] = 1; } else { modelRandomList[15] = 4; + +#if MAX_CAR_RESIDENT_MODELS == 6 + modelRandomList[14] = 4; +#else modelRandomList[14] = 1; +#endif if ((Random2(0) & 0x100) != 0) - modelRandomList[14] = 4; + modelRandomList[14] = MAX_CAR_RESIDENT_MODELS-1; } // another change for Caine's compound @@ -2211,7 +2217,7 @@ int PingInCivCar(int minPingInDist) } else { - model = modelRandomList[Random2(0) & 0xf]; + model = modelRandomList[Random2(0) & 15]; } // force spawn limo nearby in Caine's Cash @@ -2219,7 +2225,7 @@ int PingInCivCar(int minPingInDist) model = 4; // select car color palette - if (MissionHeader->residentModels[model] == 0 || MissionHeader->residentModels[model] > 4) + if (missionResidentCarModels[model] == 0 || missionResidentCarModels[model] > 4) { civDat.palette = 0; } @@ -2886,12 +2892,7 @@ void SetUpCivCollFlags(void) hornchanflag[i] = GetFreeChannel(); SpuSetVoiceAR(hornchanflag[i], 27); - if (cp0->ap.model == 4) - sample = ResidentModelsBodge(); - else if (cp0->ap.model < 3) - sample = cp0->ap.model; - else - sample = cp0->ap.model - 1; + sample = GetCarBankSample(cp0->ap.model); // [A] use tracking sound Start3DTrackingSound(hornchanflag[i], SOUND_BANK_CARS, sample * 3 + 2, @@ -3298,7 +3299,7 @@ void CreateRoadblock(void) noMoreCars = 0; distAlongSegment = -5; lbody = car_cosmetics[3].colBox.vz; - externalCopModel = MissionHeader->residentModels[3]; + externalCopModel = missionResidentCarModels[3]; // [A] use player instead of car dir = player[0].dir; diff --git a/src_rebuild/Game/C/cosmetic.c b/src_rebuild/Game/C/cosmetic.c index cf6639aa..2611c1e2 100644 --- a/src_rebuild/Game/C/cosmetic.c +++ b/src_rebuild/Game/C/cosmetic.c @@ -17,7 +17,7 @@ char* CosmeticFiles[] = { "LEVELS\\RIO.LCF", }; -CAR_COSMETICS car_cosmetics[MAX_CAR_MODELS]; +CAR_COSMETICS car_cosmetics[MAX_CAR_RESIDENT_MODELS]; #if ENABLE_GAME_FIXES // [A] storage for spooled models @@ -50,13 +50,13 @@ void ProcessCosmeticsLump(char *lump_ptr, int lump_size) int i; int offset; - for (i = 0; i < MAX_CAR_MODELS; i++) + for (i = 0; i < MAX_CAR_RESIDENT_MODELS; i++) { - model = MissionHeader->residentModels[i]; + model = missionResidentCarModels[i]; if (model == 13) { - model = 10 - (MissionHeader->residentModels[0] + MissionHeader->residentModels[1] + MissionHeader->residentModels[2]); + model = 10 - (missionResidentCarModels[0] + missionResidentCarModels[1] + missionResidentCarModels[2]); if (model < 1) model = 1; @@ -79,7 +79,7 @@ void ProcessCosmeticsLump(char *lump_ptr, int lump_size) // [A] cache all special vehicle cosmetics #if ENABLE_GAME_FIXES - for (i = 0; i < MAX_CAR_MODELS; i++) + for (i = 0; i < MAX_CAR_RESIDENT_MODELS; i++) { model = 8 + i; @@ -137,22 +137,22 @@ void AddReverseLight(CAR_DATA *cp) void SetupSpecCosmetics(char *loadbuffer) { int model; - model = MissionHeader->residentModels[4]; + model = missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; #if ENABLE_GAME_FIXES // [A] always use cached cosmetics - car_cosmetics[4] = levelSpecCosmetics[model - 8]; + car_cosmetics[MAX_CAR_RESIDENT_MODELS - 1] = levelSpecCosmetics[model - 8]; #else - car_cosmetics[4] = *(CAR_COSMETICS*)loadbuffer; + car_cosmetics[MAX_CAR_RESIDENT_MODELS - 1] = *(CAR_COSMETICS*)loadbuffer; #endif #if USE_PC_FILESYSTEM if (gContentOverride) - LoadCustomCarCosmetics(&car_cosmetics[4], model); + LoadCustomCarCosmetics(&car_cosmetics[MAX_CAR_RESIDENT_MODELS - 1], model); #endif // [A] don't forget - FixCarCos(&car_cosmetics[4], model); + FixCarCos(&car_cosmetics[MAX_CAR_RESIDENT_MODELS - 1], model); } // [D] [T] diff --git a/src_rebuild/Game/C/cosmetic.h b/src_rebuild/Game/C/cosmetic.h index 2e12158a..59d834dd 100644 --- a/src_rebuild/Game/C/cosmetic.h +++ b/src_rebuild/Game/C/cosmetic.h @@ -1,7 +1,7 @@ #ifndef COSMETIC_H #define COSMETIC_H -extern CAR_COSMETICS car_cosmetics[MAX_CAR_MODELS]; +extern CAR_COSMETICS car_cosmetics[MAX_CAR_RESIDENT_MODELS]; extern CAR_COSMETICS dummyCosmetics; extern int gcar_num; diff --git a/src_rebuild/Game/C/cutscene.c b/src_rebuild/Game/C/cutscene.c index 5828e9db..a500437f 100644 --- a/src_rebuild/Game/C/cutscene.c +++ b/src_rebuild/Game/C/cutscene.c @@ -609,7 +609,7 @@ int TriggerInGameCutsceneSystem(int cutscene) if (gCutsceneAtEnd != 0 && player[0].playerType == 1) { stream->SourceType.palette = car_data[player[0].playerCarId].ap.palette; - stream->SourceType.model = MissionHeader->residentModels[car_data[player[0].playerCarId].ap.model]; + stream->SourceType.model = missionResidentCarModels[car_data[player[0].playerCarId].ap.model]; bDamageOverride = 1; gCutsceneAtEnd = 0; diff --git a/src_rebuild/Game/C/debris.c b/src_rebuild/Game/C/debris.c index fa1f324d..09d3641f 100644 --- a/src_rebuild/Game/C/debris.c +++ b/src_rebuild/Game/C/debris.c @@ -4001,7 +4001,7 @@ int GetDebrisColour(CAR_DATA *cp) { int car_model; - car_model = MissionHeader->residentModels[cp->ap.model]; + car_model = missionResidentCarModels[cp->ap.model]; if (car_model == 0) return 1; diff --git a/src_rebuild/Game/C/denting.c b/src_rebuild/Game/C/denting.c index de95e292..48002c9f 100644 --- a/src_rebuild/Game/C/denting.c +++ b/src_rebuild/Game/C/denting.c @@ -49,9 +49,9 @@ char* DentingFiles[] = #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]; // the damage level (texture) count for polygons +u_char gCarDamageZoneVerts[MAX_CAR_RESIDENT_MODELS][NUM_DAMAGE_ZONES][MAX_DAMAGE_ZONE_VERTS]; +u_char gHDCarDamageZonePolys[MAX_CAR_RESIDENT_MODELS][NUM_DAMAGE_ZONES][MAX_DAMAGE_ZONE_POLYS]; +u_char gHDCarDamageLevels[MAX_CAR_RESIDENT_MODELS][MAX_DAMAGE_LEVELS]; // the damage level (texture) count for polygons // [D] [T] void InitialiseDenting(void) @@ -387,7 +387,7 @@ void MoveHubcap() if (gTimeOfDay == TIME_NIGHT) { - cmb = (combointensity & 0xffU) / 3; + cmb = (combointensity & 255) / 3; combointensity = cmb << 0x10 | cmb << 8 | cmb; } @@ -408,13 +408,13 @@ void ProcessDentLump(char *lump_ptr, int lump_size) int offset; u_char* mem; - for (i = 0; i < MAX_CAR_MODELS; i++) + for (i = 0; i < MAX_CAR_RESIDENT_MODELS; i++) { - model = MissionHeader->residentModels[i]; + model = missionResidentCarModels[i]; if (model == 13) { - model = 10 - (MissionHeader->residentModels[0] + MissionHeader->residentModels[1] + MissionHeader->residentModels[2]); + model = 10 - (missionResidentCarModels[0] + missionResidentCarModels[1] + missionResidentCarModels[2]); if (model < 1) model = 1; @@ -461,7 +461,7 @@ void SetupSpecDenting(char *loadbuffer) { char* newDenting; int model; - model = MissionHeader->residentModels[4]; + model = missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; newDenting = LoadCustomCarDentingFromFile(NULL, model); if (newDenting) @@ -471,13 +471,13 @@ void SetupSpecDenting(char *loadbuffer) #endif // [A] this is better - memcpy((u_char*)gCarDamageZoneVerts[4], (u_char*)loadbuffer, NUM_DAMAGE_ZONES * MAX_FILE_DAMAGE_ZONE_VERTS); + memcpy((u_char*)gCarDamageZoneVerts[MAX_CAR_RESIDENT_MODELS - 1], (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); + memcpy((u_char*)gHDCarDamageZonePolys[MAX_CAR_RESIDENT_MODELS - 1], (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); + memcpy((u_char*)gHDCarDamageLevels[MAX_CAR_RESIDENT_MODELS - 1], (u_char*)loadbuffer + offset, MAX_FILE_DAMAGE_LEVELS); } // [D] [T] diff --git a/src_rebuild/Game/C/event.c b/src_rebuild/Game/C/event.c index d6c98648..cbddcfed 100644 --- a/src_rebuild/Game/C/event.c +++ b/src_rebuild/Game/C/event.c @@ -1457,7 +1457,7 @@ void SetUpEvents(int full) firstMissionEvent = &event[cEvents]; cEvents += 3; } - else if (gCurrentMissionNumber - 39U < 2) + else if (gCurrentMissionNumber == 40) { // setup Lenny helicopter evt[cEvents].flags = 0xC0; diff --git a/src_rebuild/Game/C/gamesnd.c b/src_rebuild/Game/C/gamesnd.c index 707114e0..11dd625a 100644 --- a/src_rebuild/Game/C/gamesnd.c +++ b/src_rebuild/Game/C/gamesnd.c @@ -165,26 +165,26 @@ void LoadBankFromLump(int bank, int lump) // [D] [T] int CarHasSiren(int index) { - if (index == 4) + if (index == MAX_CAR_RESIDENT_MODELS - 1) { if (GameLevel == 0) { - if (MissionHeader->residentModels[4] == 8) + if (missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] == 8) return M_SHRT_2(SOUND_BANK_SFX, 12); } else if (GameLevel == 2) { - if (MissionHeader->residentModels[4] == 9) + if (missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] == 9) return M_SHRT_2(SOUND_BANK_SFX, 12); } else if (GameLevel == 3) { - if (MissionHeader->residentModels[4] == 10) + if (missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] == 10) return M_SHRT_2(SOUND_BANK_SFX, 12); } } - return M_SHRT_2((MissionHeader->residentModels[index] == 0) ? SOUND_BANK_VOICES : 0, 0); + return M_SHRT_2((missionResidentCarModels[index] == 0) ? SOUND_BANK_VOICES : 0, 0); } // [D] [T] @@ -206,7 +206,7 @@ int ResidentModelsBodge(void) int i; int j; - if (gCurrentMissionNumber == 24 || + if (gCurrentMissionNumber == 24 || gCurrentMissionNumber == 27 || gCurrentMissionNumber == 29 || gCurrentMissionNumber == 30 || @@ -215,7 +215,7 @@ int ResidentModelsBodge(void) return 3; } - j = MissionHeader->residentModels[4]; + j = missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; if (gCurrentMissionNumber - 50U < 16 && j == 12) { @@ -229,9 +229,9 @@ int ResidentModelsBodge(void) if (j != 9 && j != i) return 3; } - else if (GameLevel == 1) + else if (GameLevel == 1) { - if (j - 8U > 1) + if (j - 8U > 1) return 3; } else if (GameLevel == 2) @@ -254,6 +254,25 @@ int ResidentModelsBodge(void) return 4; } +// [A] +int GetCarBankSample(int model) +{ + int bankStartSample; + if (model == MAX_CAR_RESIDENT_MODELS - 1) + { +#if MAX_CAR_RESIDENT_MODELS > 5 + bankStartSample = ResidentModelsBodge() + 1; +#else + bankStartSample = ResidentModelsBodge(); +#endif + } + else if (model < 3) + bankStartSample = model; + else + bankStartSample = model - 1; + return bankStartSample; +} + // [D] [T] int MapCarIndexToBank(int index) { @@ -269,19 +288,19 @@ int MapCarIndexToBank(int index) int model; int ret; - RM = MissionHeader->residentModels; + RM = missionResidentCarModels; model = RM[index]; - if (gCurrentMissionNumber - 39U < 2 && RM[index] == 13) + if (gCurrentMissionNumber == 40 && RM[index] == 13) { model = 10 - (RM[0] + RM[1] + RM[2]); if (model < 1) model = 1; - if (model > 4) - model = 4; + if (model > 5) + model = 5; } ret = model - 1; @@ -316,6 +335,9 @@ void LoadLevelSFX(int missionNum) // load car banks for (i = 0; i < 3; i++) LoadBankFromLump(SOUND_BANK_CARS, MapCarIndexToBank(i)); +#if MAX_CAR_RESIDENT_MODELS > 5 + LoadBankFromLump(SOUND_BANK_CARS, MapCarIndexToBank(4)); +#endif ShowLoading(); @@ -475,8 +497,8 @@ void LoadLevelSFX(int missionNum) LoadSoundBankDynamic(NULL, 3, SOUND_BANK_CARS); // special vehicle 1 bank - if (missionNum - 39U < 2 || missionNum >= 400 && missionNum <= 404) - LoadBankFromLump(SOUND_BANK_CARS, MapCarIndexToBank(4)); + if (missionNum == 40 || missionNum >= 400 && missionNum <= 404) + LoadBankFromLump(SOUND_BANK_CARS, MapCarIndexToBank(MAX_CAR_RESIDENT_MODELS-1)); else LoadBankFromLump(SOUND_BANK_CARS, SpecialVehicleKludge(0)); @@ -505,7 +527,7 @@ void LoadLevelSFX(int missionNum) for (i = 0; i < 3; i++) { - if (MissionHeader->residentModels[i] == MissionHeader->residentModels[3]) + if (missionResidentCarModels[i] == missionResidentCarModels[3]) cop_model = i; } } @@ -524,13 +546,7 @@ void StartPlayerCarSounds(int playerId, int model, VECTOR* pos) int channel; int siren; - if (model == 4) - carSampleId = ResidentModelsBodge(); - else if (model < 3) - carSampleId = model; - else - carSampleId = model - 1; - + carSampleId = GetCarBankSample(model); siren = CarHasSiren(model); // rev sound @@ -1197,7 +1213,7 @@ void DoDopplerSFX(void) car = indexlist[i]; for (j = 0; j < MAX_CAR_NOISES; j++) { - int bank, model; + int bankStart, model; if (car_noise[j].in_use) continue; @@ -1218,17 +1234,12 @@ void DoDopplerSFX(void) model = cop_model; // get bank id - if (model == 4) - bank = ResidentModelsBodge(); - else if (model < 3) - bank = model; - else - bank = model - 1; + bankStart = GetCarBankSample(model); if (car_noise[j].idle) - sample = bank * 3 + 1; + sample = bankStart * 3 + 1; else - sample = bank * 3; + sample = bankStart * 3; car_noise[j].chan = Start3DTrackingSound(-1, SOUND_BANK_CARS, sample, (VECTOR*)car_data[car].hd.where.t, @@ -1263,7 +1274,7 @@ void DoDopplerSFX(void) // restart sound if it's changed if (old_idle != car_noise[j].idle) { - int bank, model; + int bankStart, model; StopChannel(car_noise[j].chan); UnlockChannel(car_noise[j].chan); @@ -1274,17 +1285,12 @@ void DoDopplerSFX(void) model = cop_model; // get bank id - if (model == 4) - bank = ResidentModelsBodge(); - else if (model < 3) - bank = model; - else - bank = model - 1; + bankStart = GetCarBankSample(model); if (car_noise[j].idle) - sample = bank * 3 + 1; + sample = bankStart * 3 + 1; else - sample = bank * 3; + sample = bankStart * 3; car_noise[j].chan = Start3DTrackingSound(-1, SOUND_BANK_CARS, sample, (VECTOR*)cp->hd.where.t, (LONGVECTOR3*)cp->st.n.linearVelocity); @@ -2569,12 +2575,7 @@ void LeadHorn(CAR_DATA* cp) if (horn_time == rnd) { - if (cp->ap.model == 4) - carBank = ResidentModelsBodge(); - else if (cp->ap.model < 3) - carBank = cp->ap.model; - else - carBank = cp->ap.model - 1; + carBank = GetCarBankSample(cp->ap.model); Start3DTrackingSound(-1, SOUND_BANK_CARS, carBank * 3 + 2, (VECTOR*)cp->hd.where.t, diff --git a/src_rebuild/Game/C/gamesnd.h b/src_rebuild/Game/C/gamesnd.h index 9c7915ea..ec2057e6 100644 --- a/src_rebuild/Game/C/gamesnd.h +++ b/src_rebuild/Game/C/gamesnd.h @@ -82,7 +82,7 @@ extern SPEECH_QUEUE gSpeechQueue; extern void LoadBankFromLump(int bank, int lump); // 0x00052460 extern int CarHasSiren(int index); // 0x000522EC -extern int ResidentModelsBodge(); // 0x0004D690 +extern int GetCarBankSample(int model); // 0x0004D690 extern void LoadLevelSFX(int missionNum); // 0x0004D784 diff --git a/src_rebuild/Game/C/handling.c b/src_rebuild/Game/C/handling.c index 538e0a79..80bfbe55 100644 --- a/src_rebuild/Game/C/handling.c +++ b/src_rebuild/Game/C/handling.c @@ -184,7 +184,7 @@ void FixCarCos(CAR_COSMETICS* carCos, int externalModelNumber) if (ActiveCheats.cheat10) // [A] cheat for secret car - Fireboyd78 { - if (carCos == &car_cosmetics[4] && externalModelNumber == 12) + if (carCos == &car_cosmetics[MAX_CAR_RESIDENT_MODELS - 1] && externalModelNumber == 12) { carCos->powerRatio += (carCos->powerRatio / 2); carCos->mass *= 3; diff --git a/src_rebuild/Game/C/main.c b/src_rebuild/Game/C/main.c index 6405104c..03b5f7b0 100644 --- a/src_rebuild/Game/C/main.c +++ b/src_rebuild/Game/C/main.c @@ -493,7 +493,7 @@ void State_GameInit(void* param) LoadMission(gCurrentMissionNumber); if (gCurrentMissionNumber == 38) - MissionHeader->residentModels[4] = 9; + missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = 9; if (GameType == GAME_MISSION) SetupFadePolys(); @@ -892,7 +892,7 @@ void StepSim(void) } else { - if (copsAreInPursuit != 0 && MissionHeader->residentModels[3] == 0 && gCurrentMissionNumber != 26) + if (copsAreInPursuit != 0 && missionResidentCarModels[3] == 0 && gCurrentMissionNumber != 26) requestRoadblock = 1; if (roadblockCount != 0) @@ -2294,9 +2294,9 @@ void RenderGame2(int view) for (i = 0; i < 2; i++) { - if (player[i].playerCarId >= 0 && - CarHasSiren(car_data[player[i].playerCarId].ap.model) != 0 && - player[i].horn.on != 0) + if (player[i].playerCarId >= 0 && + player[i].horn.on != 0 && + CarHasSiren(car_data[player[i].playerCarId].ap.model) != 0) { AddCopCarLight(&car_data[player[i].playerCarId]); } @@ -2484,7 +2484,7 @@ void InitGameVariables(void) void DealWithHorn(char* hr, int i) { int channel; - int modelId; + int sample; CAR_DATA* car; car = &car_data[player[i].playerCarId]; @@ -2499,16 +2499,10 @@ void DealWithHorn(char* hr, int i) } else if (*hr == 2) { - if (car->ap.model == 4) - modelId = ResidentModelsBodge(); - else if (car->ap.model < 3) - modelId = car->ap.model; - else - modelId = car->ap.model - 1; - + sample = GetCarBankSample(car->ap.model); channel = i != 0 ? 5 : 2; - Start3DSoundVolPitch(channel, SOUND_BANK_CARS, modelId * 3 + 2, + Start3DSoundVolPitch(channel, SOUND_BANK_CARS, sample * 3 + 2, car->hd.where.t[0], car->hd.where.t[1], car->hd.where.t[2], -10000, diff --git a/src_rebuild/Game/C/mgeneric.c b/src_rebuild/Game/C/mgeneric.c index 20b2d349..257e37cf 100644 --- a/src_rebuild/Game/C/mgeneric.c +++ b/src_rebuild/Game/C/mgeneric.c @@ -24,7 +24,7 @@ void StorePlayerPosition(SAVED_PLAYER_POS *data) cp = &car_data[slot]; - data->type = ((MissionHeader->residentModels[cp->ap.model] & 0xfff) << 4) | 1 | cp->ap.palette << 8; + data->type = ((missionResidentCarModels[cp->ap.model] & 0xfff) << 4) | 1 | cp->ap.palette << 8; data->totaldamage = cp->totalDamage; data->felony = cp->felonyRating; @@ -113,7 +113,7 @@ void StoreCarPosition(MS_TARGET *target, SAVED_CAR_POS *data) cp = &car_data[slot]; - data->model = MissionHeader->residentModels[cp->ap.model]; + data->model = missionResidentCarModels[cp->ap.model]; data->palette = cp->ap.palette; data->totaldamage = cp->totalDamage; diff --git a/src_rebuild/Game/C/mission.c b/src_rebuild/Game/C/mission.c index 4f419bd6..8ac68f13 100644 --- a/src_rebuild/Game/C/mission.c +++ b/src_rebuild/Game/C/mission.c @@ -148,6 +148,7 @@ STOPCOPS gStopCops; MS_MISSION* MissionLoadAddress; MS_MISSION* MissionHeader; +int missionResidentCarModels[MAX_CAR_RESIDENT_MODELS]; STREAM_SOURCE* PlayerStartInfo[8]; int numPlayersToCreate = 0; int gStartOnFoot = 0; @@ -324,7 +325,26 @@ void InitialiseMissionDefaults(void) void SetupResidentModels() { int i, j; - int takenSlots = 0; + int takenSlots; + + + takenSlots = 0; + for (i = 0; i < 5; ++i) + { + missionResidentCarModels[i] = MissionHeader->residentModels[i]; + takenSlots |= 1 << MissionHeader->residentModels[i]; + } +#if MAX_CAR_RESIDENT_MODELS > 5 + for (i = 1; i < 5; ++i) + { + if ((takenSlots & (1 << i)) == 0) + { + missionResidentCarModels[4] = i; + break; + } + } + missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = MissionHeader->residentModels[4]; +#endif // MAX_CAR_RESIDENT_MODELS > 5 // check if start data is required if (MissionHeader->type & 1) @@ -332,10 +352,11 @@ void SetupResidentModels() // check if start data is required RestoreStartData(); - if (PlayerStartInfo[0]->model > 4) - MissionHeader->residentModels[4] = PlayerStartInfo[0]->model; + if (PlayerStartInfo[0]->model > 5) + missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = PlayerStartInfo[0]->model; } + takenSlots = 0; for(i = 0; i < 2; i++) { if (wantedCar[i] != -1) @@ -343,9 +364,9 @@ void SetupResidentModels() int foundRM = -1; int singlePal; - for (j = 0; j < 5; j++) + for (j = 0; j < MAX_CAR_RESIDENT_MODELS; j++) { - if (MissionHeader->residentModels[j] == wantedCar[i]) + if (missionResidentCarModels[j] == wantedCar[i]) { foundRM = j; break; @@ -357,13 +378,13 @@ void SetupResidentModels() singlePal = (wantedCar[i] == 0 || wantedCar[i] > 4); // check if chosen cop car or special car - if (wantedCar[i] > 4)// && NumPlayers == 1) + if (wantedCar[i] > 5)// && NumPlayers == 1) { - MissionHeader->residentModels[4] = wantedCar[i]; + missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = wantedCar[i]; } else if(foundRM == -1) { - MissionHeader->residentModels[takenSlots++] = wantedCar[i]; + missionResidentCarModels[takenSlots++] = wantedCar[i]; } else { diff --git a/src_rebuild/Game/C/mission.h b/src_rebuild/Game/C/mission.h index 6a9d9df7..7e55e41e 100644 --- a/src_rebuild/Game/C/mission.h +++ b/src_rebuild/Game/C/mission.h @@ -14,6 +14,7 @@ extern GAMEMODE CurrentGameMode; extern GAMEMODE WantedGameMode; extern int gCurrentMissionNumber; extern MS_MISSION*MissionHeader; +extern int missionResidentCarModels[MAX_CAR_RESIDENT_MODELS]; extern STREAM_SOURCE* PlayerStartInfo[8]; extern int numPlayersToCreate; extern int gStartOnFoot; diff --git a/src_rebuild/Game/C/models.c b/src_rebuild/Game/C/models.c index 72cd576f..0286f392 100644 --- a/src_rebuild/Game/C/models.c +++ b/src_rebuild/Game/C/models.c @@ -251,23 +251,23 @@ int ProcessCarModelLump(char *lump_ptr, int lump_size) startBuildNewCars(0); - for (i = 0; i < MAX_CAR_MODELS; i++) + for (i = 0; i < MAX_CAR_RESIDENT_MODELS; i++) { gCarCleanModelPtr[i] = NULL; gCarDamModelPtr[i] = NULL; gCarLowModelPtr[i] = NULL; - if (i == MAX_CAR_MODELS-1) + if (i == MAX_CAR_RESIDENT_MODELS-1) { startBuildNewCars(1); specmallocptr = (char*)mallocptr; } - model_number = MissionHeader->residentModels[i]; + model_number = missionResidentCarModels[i]; if (model_number == 13) { - model_number = 10 - (MissionHeader->residentModels[0] + MissionHeader->residentModels[1] + MissionHeader->residentModels[2]); + model_number = 10 - (missionResidentCarModels[0] + missionResidentCarModels[1] + missionResidentCarModels[2]); if (model_number < 1) model_number = 1; diff --git a/src_rebuild/Game/C/pause.c b/src_rebuild/Game/C/pause.c index 9242a33e..ef4bdec2 100644 --- a/src_rebuild/Game/C/pause.c +++ b/src_rebuild/Game/C/pause.c @@ -148,7 +148,7 @@ int lastCar = -1; void ToggleSecretCarFun(int direction) { - extern CAR_COSMETICS car_cosmetics[5]; + extern CAR_COSMETICS car_cosmetics[MAX_CAR_RESIDENT_MODELS - 1]; extern int wantedCar[2]; int active = (ActiveCheats.cheat10 ^= 1); @@ -171,7 +171,7 @@ void ToggleSecretCarFun(int direction) } } - FixCarCos(&car_cosmetics[4], 12); + FixCarCos(&car_cosmetics[MAX_CAR_RESIDENT_MODELS - 1], 12); } void ToggleJerichoMode(int direction) diff --git a/src_rebuild/Game/C/players.c b/src_rebuild/Game/C/players.c index 1ef118c0..5ed2295d 100644 --- a/src_rebuild/Game/C/players.c +++ b/src_rebuild/Game/C/players.c @@ -20,30 +20,27 @@ PLAYER player[MAX_PLAYERS]; void InitPlayer(PLAYER *locPlayer, CAR_DATA *cp, char carCtrlType, int direction, LONGVECTOR4* startPos, int externModel, int palette, char *padid) { int playerId; - int model; + int model, i; u_int playerType; - playerType = externModel & 0xFF; + playerType = externModel & 255; ClearMem((char *)locPlayer, sizeof(PLAYER)); playerId = locPlayer - player; if (gStartOnFoot == 0 || carCtrlType == CONTROL_TYPE_LEAD_AI) { - model = 0xFF; - - if (MissionHeader->residentModels[0] == playerType) - model = 0; - else if(MissionHeader->residentModels[1] == playerType) - model = 1; - else if (MissionHeader->residentModels[2] == playerType) - model = 2; - else if (MissionHeader->residentModels[3] == playerType) - model = 3; - else if (MissionHeader->residentModels[4] == playerType) - model = 4; + model = -1; + for (i = 0; i < MAX_CAR_RESIDENT_MODELS; ++i) + { + if (missionResidentCarModels[i] == playerType) + { + model = i; + break; + } + } - InitCar(cp, direction, startPos, carCtrlType, model, palette & 0xff, &locPlayer->padid); + InitCar(cp, direction, startPos, carCtrlType, model, palette & 255, &locPlayer->padid); ResetTyreTracks(cp, playerId); @@ -215,7 +212,7 @@ void ChangePedPlayerToCar(int playerID, CAR_DATA *newCar) #endif ) { - if (gCurrentMissionNumber != 32 && MissionHeader->residentModels[newCar->ap.model] == 0) + if (gCurrentMissionNumber != 32 && missionResidentCarModels[newCar->ap.model] == 0) { NoteFelony(&felonyData, 11, 4096); } diff --git a/src_rebuild/Game/C/spool.c b/src_rebuild/Game/C/spool.c index 4e0c43f0..a577fb0b 100644 --- a/src_rebuild/Game/C/spool.c +++ b/src_rebuild/Game/C/spool.c @@ -1754,14 +1754,14 @@ void CleanModelSpooled(void) if (specBlocksToLoad == lastCleanBlock-1) { loadaddr = (int *)(specLoadBuffer + 12); - gCarCleanModelPtr[4] = (MODEL *)modelMemory; + gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS-1] = (MODEL *)modelMemory; } // memcpy while (loadaddr < (int*)(specLoadBuffer + CDSECTOR_SIZE)) *modelMemory++ = *loadaddr++; - polyBlock = GET_RELOC_MODEL_DATA(int, gCarCleanModelPtr[4], poly_block); + polyBlock = GET_RELOC_MODEL_DATA(int, gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS - 1], poly_block); if (specBlocksToLoad == 0 || modelMemory > polyBlock) { @@ -1769,14 +1769,14 @@ void CleanModelSpooled(void) modelMemory = polyBlock; #if MODEL_RELOCATE_POINTERS - gCarCleanModelPtr[4]->vertices += (int)gCarCleanModelPtr[4]; - gCarCleanModelPtr[4]->normals += (int)gCarCleanModelPtr[4]; - gCarCleanModelPtr[4]->point_normals += (int)gCarCleanModelPtr[4]; - gCarCleanModelPtr[4]->poly_block += (int)gCarCleanModelPtr[4]; + gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS-1]->vertices += (int)gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS - 1]; + gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS-1]->normals += (int)gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS - 1]; + gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS-1]->point_normals += (int)gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS - 1]; + gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS-1]->poly_block += (int)gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS - 1]; #endif - gCarCleanModelPtr[4]->instance_number = -1; - NewCarModel[4].nlist = GET_MODEL_DATA(SVECTOR, gCarCleanModelPtr[4], point_normals); - NewCarModel[4].vlist = GET_MODEL_DATA(SVECTOR, gCarCleanModelPtr[4], vertices); + gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS - 1]->instance_number = -1; + NewCarModel[MAX_CAR_RESIDENT_MODELS-1].nlist = GET_MODEL_DATA(SVECTOR, gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS-1], point_normals); + NewCarModel[MAX_CAR_RESIDENT_MODELS-1].vlist = GET_MODEL_DATA(SVECTOR, gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS-1], vertices); } if (quickSpool != 1) @@ -1796,14 +1796,14 @@ void DamagedModelSpooled(void) if (specBlocksToLoad == lengthDamBlock-1) { loadaddr = (int *)(specLoadBuffer + damOffset); - gCarDamModelPtr[4] = (MODEL *)modelMemory; + gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = (MODEL *)modelMemory; } // memcpy while (loadaddr < (int*)(specLoadBuffer + CDSECTOR_SIZE)) *modelMemory++ = *loadaddr++; - polyBlock = GET_RELOC_MODEL_DATA(int, gCarDamModelPtr[4], poly_block); + polyBlock = GET_RELOC_MODEL_DATA(int, gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS - 1], poly_block); if (specBlocksToLoad == 0 || modelMemory > polyBlock) { @@ -1811,12 +1811,12 @@ void DamagedModelSpooled(void) modelMemory = polyBlock; #if MODEL_RELOCATE_POINTERS - gCarDamModelPtr[4]->vertices += (int)gCarDamModelPtr[4]; - gCarDamModelPtr[4]->normals += (int)gCarDamModelPtr[4]; - gCarDamModelPtr[4]->poly_block += (int)gCarDamModelPtr[4]; - gCarDamModelPtr[4]->point_normals += (int)gCarDamModelPtr[4]; + gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS-1]->vertices += (int)gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS - 1]; + gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS-1]->normals += (int)gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS - 1]; + gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS-1]->poly_block += (int)gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS - 1]; + gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS-1]->point_normals += (int)gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS - 1]; #endif - gCarDamModelPtr[4]->instance_number = -1; + gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS - 1]->instance_number = -1; } if (quickSpool != 1) @@ -1836,14 +1836,14 @@ void LowModelSpooled(void) if (specBlocksToLoad == lengthLowBlock - 1) { loadaddr = (int *)(specLoadBuffer + lowOffset); - gCarLowModelPtr[4] = (MODEL *)modelMemory; + gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = (MODEL *)modelMemory; } // memcpy while (loadaddr < (int*)(specLoadBuffer + CDSECTOR_SIZE)) *modelMemory++ = *loadaddr++; - polyBlock = GET_RELOC_MODEL_DATA(int, gCarLowModelPtr[4], poly_block); + polyBlock = GET_RELOC_MODEL_DATA(int, gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS - 1], poly_block); if (specBlocksToLoad == 0 || modelMemory > polyBlock) { @@ -1851,14 +1851,14 @@ void LowModelSpooled(void) modelMemory = polyBlock; #if MODEL_RELOCATE_POINTERS - gCarLowModelPtr[4]->vertices += (int)gCarLowModelPtr[4]; - gCarLowModelPtr[4]->normals += (int)gCarLowModelPtr[4]; - gCarLowModelPtr[4]->poly_block += (int)gCarLowModelPtr[4]; - gCarLowModelPtr[4]->point_normals += (int)gCarLowModelPtr[4]; + gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS-1]->vertices += (int)gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS - 1]; + gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS-1]->normals += (int)gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS - 1]; + gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS-1]->poly_block += (int)gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS - 1]; + gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS-1]->point_normals += (int)gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS - 1]; #endif - gCarLowModelPtr[4]->instance_number = -1; - NewLowCarModel[4].nlist = GET_MODEL_DATA(SVECTOR, gCarLowModelPtr[4], point_normals); - NewLowCarModel[4].vlist = GET_MODEL_DATA(SVECTOR, gCarLowModelPtr[4], vertices); + gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS - 1]->instance_number = -1; + NewLowCarModel[MAX_CAR_RESIDENT_MODELS-1].nlist = GET_MODEL_DATA(SVECTOR, gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS-1], point_normals); + NewLowCarModel[MAX_CAR_RESIDENT_MODELS-1].vlist = GET_MODEL_DATA(SVECTOR, gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS-1], vertices); } if (quickSpool != 1) @@ -1912,33 +1912,33 @@ void CleanSpooled(void) { char* mem; - if (mem = LoadCarModelFromFile((char*)modelMemory, MissionHeader->residentModels[4], CAR_MODEL_CLEAN)) + if (mem = LoadCarModelFromFile((char*)modelMemory, missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1], CAR_MODEL_CLEAN)) { - gCarCleanModelPtr[4] = (MODEL*)modelMemory; + gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = (MODEL*)modelMemory; model = GetCarModel(mem, (char**)&modelMemory, 1); whichCP = baseSpecCP; - buildNewCarFromModel(4, 1, mem, model); + buildNewCarFromModel(MAX_CAR_RESIDENT_MODELS - 1, 1, mem, model); specBlocksToLoad = 0; specialState = SpecSpool_CleanModel; } - if (mem = LoadCarModelFromFile((char*)modelMemory, MissionHeader->residentModels[4], CAR_MODEL_DAMAGED)) + if (mem = LoadCarModelFromFile((char*)modelMemory, missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1], CAR_MODEL_DAMAGED)) { - gCarDamModelPtr[4] = (MODEL*)modelMemory; + gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = (MODEL*)modelMemory; model = GetCarModel(mem, (char**)&modelMemory, 0); specBlocksToLoad = 0; specialState = SpecSpool_DamagedModel; } - if (mem = LoadCarModelFromFile((char*)modelMemory, MissionHeader->residentModels[4], CAR_MODEL_LOWDETAIL)) + if (mem = LoadCarModelFromFile((char*)modelMemory, missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1], CAR_MODEL_LOWDETAIL)) { - gCarLowModelPtr[4] = (MODEL*)modelMemory; + gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = (MODEL*)modelMemory; model = GetCarModel(mem, (char**)&modelMemory, 1); - buildNewCarFromModel(4, 0, mem, model); + buildNewCarFromModel(MAX_CAR_RESIDENT_MODELS - 1, 0, mem, model); specBlocksToLoad = 0; specialState = SpecSpool_LowModel; @@ -1955,7 +1955,7 @@ void CleanSpooled(void) model = (MODEL*)(specmallocptr + sizeof(int) * 3); whichCP = baseSpecCP; - buildNewCarFromModel(4, 1, (char*)model, model); + buildNewCarFromModel(MAX_CAR_RESIDENT_MODELS - 1, 1, (char*)model, model); #if MODEL_RELOCATE_POINTERS model->vertices += (int)model; @@ -1978,7 +1978,7 @@ void LowSpooled(void) if (specBlocksToLoad == 0) { model = (MODEL *)(specmallocptr + lowOffset); - buildNewCarFromModel(4, 0, (char*)model, model); + buildNewCarFromModel(MAX_CAR_RESIDENT_MODELS - 1, 0, (char*)model, model); #if MODEL_RELOCATE_POINTERS model->vertices += (int)model; @@ -2162,14 +2162,14 @@ void CheckSpecialSpool(void) specialState == SpecSpool_None && GameType != GAME_PURSUIT && LoadedArea != -1 && - SpecialByRegion[GameLevel][LoadedArea] != MissionHeader->residentModels[4] - 7) + SpecialByRegion[GameLevel][LoadedArea] != missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] - 7) { lcp = car_data; // if there are cars that still using special models, deny spooling do // [A] { - if (MissionHeader->residentModels[lcp->ap.model] > 4) + if (missionResidentCarModels[lcp->ap.model] > 5) return; lcp++; @@ -2179,12 +2179,12 @@ void CheckSpecialSpool(void) specModelValid = 0; startSpecSpool = CameraCnt; - gCarDamModelPtr[4] = NULL; - gCarCleanModelPtr[4] = NULL; - gCarLowModelPtr[4] = NULL; + gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = NULL; + gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = NULL; + gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = NULL; specSpoolModelIndex = SpecialByRegion[GameLevel][LoadedArea]; - MissionHeader->residentModels[4] = specSpoolModelIndex + 7; + missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = specSpoolModelIndex + 7; SpecialStartNextBlock(); } @@ -2197,11 +2197,11 @@ void QuickSpoolSpecial(void) specialState = SpecSpool_None; specBlocksToLoad = 0; - gCarCleanModelPtr[4] = NULL; - gCarDamModelPtr[4] = NULL; - gCarLowModelPtr[4] = NULL; + gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = NULL; + gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS-1] = NULL; + gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS-1] = NULL; - specSpoolModelIndex = MissionHeader->residentModels[4] - 7; + specSpoolModelIndex = missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] - 7; do { SpoolSYNC(); @@ -2215,7 +2215,7 @@ void QuickSpoolSpecial(void) void PrepareSecretCar(void) { // [A] Don't do anything if model is already spooled - if (MissionHeader->residentModels[4] == 12) + if (missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] == 12) { return; } @@ -2223,12 +2223,12 @@ void PrepareSecretCar(void) allowSpecSpooling = 0; PingOutAllSpecialCivCars(); - gCarDamModelPtr[4] = NULL; - gCarCleanModelPtr[4] = NULL; - gCarLowModelPtr[4] = NULL; + gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = NULL; + gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = NULL; + gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = NULL; specSpoolModelIndex = 5; - MissionHeader->residentModels[4] = 12; + missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = 12; specModelValid = 0; startSpecSpool = CameraCnt; @@ -2328,6 +2328,9 @@ void InitSpecSpool(void) allowSpecSpooling = 0; #endif + if(missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] < 8) + allowSpecSpooling = 0; + specModelValid = 1; specialState = SpecSpool_None; specBlocksToLoad = 0; diff --git a/src_rebuild/Game/C/texture.c b/src_rebuild/Game/C/texture.c index 36c8a3fc..06880135 100644 --- a/src_rebuild/Game/C/texture.c +++ b/src_rebuild/Game/C/texture.c @@ -33,17 +33,57 @@ SXYPAIR tpagepos[20] = }; char specTpages[4][12] = { - { 54, 55, 66, 67, 56, 57, 68, 69, 61, 64, 61, 64 }, - { 38, 39, 38, 39, 42, 43, 44, 45, 48, 49, 48, 49 }, - { 18, 19, 65, 66, 67, 68, 11, 12, 63, 64, 63, 64 }, - { 66, 67, 77, 78, 73, 74, 75, 76, 69, 70, 71, 72 } + { + 54, 55, + 66, 67, + 56, 57, + 68, 69, + 61, 64, + 61, 64 + }, + { + 38, 39, + 38, 39, + 42, 43, + 44, 45, + 48, 49, + 48, 49 + }, + { + 18, 19, + 65, 66, + 67, 68, + 11, 12, + 63, 64, + 63, 64 + }, + { + 66, 67, + 77, 78, + 73, 74, + 75, 76, + 69, 70, + 71, 72 + } }; char carTpages[4][8] = { - { 01, 65, 62, 50, 63, 58, 54, 55 }, - { 10, 35, 20, 37, 51, 36, 38, 39 }, - { 41, 54, 62, 17, 32, 59, 18, 00 }, - { 55, 57, 68, 58, 60, 59, 66, 67 } + { + 01, 58, 65, 62, 50, 63, + 54, 55 + }, + { + 10, 36, 35, 20, 37, 51, + 38, 39 + }, + { + 41, 59, 54, 62, 17, 32, + 18, 19 + }, + { + 55, 59, 57, 68, 58, 60, + 66, 67 + } }; char *palette_lump; @@ -493,7 +533,6 @@ void LoadPermanentTPages(int *sector) int tp = permlist[i].x; update_slotinfo(tp, slotsused, &tpage); - LoadTPageAndCluts(&tpage, &clutpos, tp, tpagebuffer); slotsused++; @@ -506,7 +545,7 @@ void LoadPermanentTPages(int *sector) slot_clutpos[slotsused].vy = clutpos.y; // init special slot texture - specmodel = (MissionHeader->residentModels[4] - 8) * 2; + specmodel = (missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] - 8) * 2; specialSlot = (short)slotsused; // get special slot tpage @@ -554,9 +593,9 @@ void LoadPermanentTPages(int *sector) { update_slotinfo(tp, slotsused, &tpage); LoadTPageAndCluts(&tpage, &clutpos, tp, tpagebuffer); + slotsused++; clutsloaded += npalettes; - slotsused++; } tpagebuffer += (speclist[i].y + 2047) & -CDSECTOR_SIZE; diff --git a/src_rebuild/Game/dr2limits.h b/src_rebuild/Game/dr2limits.h index 339721aa..ee6dd567 100644 --- a/src_rebuild/Game/dr2limits.h +++ b/src_rebuild/Game/dr2limits.h @@ -19,7 +19,12 @@ #define MAX_MODEL_SLOTS 1536 // DO NOT CHANGE. No effect in upping it - limited by cell types #define MAX_CARS 20 -#define MAX_CAR_MODELS 5 +#ifndef PSX +#define MAX_CAR_RESIDENT_MODELS 6 // use all permanently loaded car models available +#else +#define MAX_CAR_RESIDENT_MODELS 5 +#endif + #define MAX_PEDESTRIANS 28 #define MAX_SEATED_PEDS 20 #define MAX_PLACED_PEDS 15 diff --git a/src_rebuild/redriver2_psxpc.cpp b/src_rebuild/redriver2_psxpc.cpp index bb0f5ca7..f55d300a 100644 --- a/src_rebuild/redriver2_psxpc.cpp +++ b/src_rebuild/redriver2_psxpc.cpp @@ -246,7 +246,7 @@ void GameDebugKeys(int nKey, char down) if (ShiftModifier) { // force a special car - model = MissionHeader->residentModels[4]; + model = missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; palette = 0; lastmodel = model; } @@ -255,7 +255,7 @@ void GameDebugKeys(int nKey, char down) for (int i = 0; i < 5; i++) { // horrible randomness - int newmodel = MissionHeader->residentModels[i]; + int newmodel = missionResidentCarModels[i]; if (newmodel == 0 || newmodel == lastmodel) continue; @@ -267,7 +267,7 @@ void GameDebugKeys(int nKey, char down) if (tmp & 4) { // rare chance of spawning special car - model = MissionHeader->residentModels[4]; + model = missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; palette = 0; lastmodel = model; break; From adc519f9c6e6165448c3bd1dd604e0b16d4e9fa3 Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Fri, 3 Oct 2025 22:00:04 +0500 Subject: [PATCH 09/19] - fix missing levelSpecCosmetics change --- src_rebuild/Game/C/cosmetic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_rebuild/Game/C/cosmetic.c b/src_rebuild/Game/C/cosmetic.c index 2611c1e2..94a527d6 100644 --- a/src_rebuild/Game/C/cosmetic.c +++ b/src_rebuild/Game/C/cosmetic.c @@ -22,7 +22,7 @@ CAR_COSMETICS car_cosmetics[MAX_CAR_RESIDENT_MODELS]; #if ENABLE_GAME_FIXES // [A] storage for spooled models // remember: we already have more than 1k of free memory with optimizations -CAR_COSMETICS levelSpecCosmetics[5]; +CAR_COSMETICS levelSpecCosmetics[MAX_CAR_RESIDENT_MODELS]; #endif #if USE_PC_FILESYSTEM From 8f39a42b1f43e7d2a2231472bcb4cc8e90ac3fd0 Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Fri, 3 Oct 2025 22:25:21 +0500 Subject: [PATCH 10/19] - fix Caine's cash missing limo --- src_rebuild/Game/C/civ_ai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_rebuild/Game/C/civ_ai.c b/src_rebuild/Game/C/civ_ai.c index 46315e5c..741c392f 100644 --- a/src_rebuild/Game/C/civ_ai.c +++ b/src_rebuild/Game/C/civ_ai.c @@ -2222,7 +2222,7 @@ int PingInCivCar(int minPingInDist) // force spawn limo nearby in Caine's Cash if (minPingInDist == 666) - model = 4; + model = MAX_CAR_RESIDENT_MODELS - 1; // select car color palette if (missionResidentCarModels[model] == 0 || missionResidentCarModels[model] > 4) From 7cc25af0dbd8676a45678589772423925673294f Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Fri, 3 Oct 2025 22:25:52 +0500 Subject: [PATCH 11/19] - if mission takes civ car as cop car, re-add it again as civ car --- src_rebuild/Game/C/mission.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src_rebuild/Game/C/mission.c b/src_rebuild/Game/C/mission.c index 8ac68f13..0eb77841 100644 --- a/src_rebuild/Game/C/mission.c +++ b/src_rebuild/Game/C/mission.c @@ -343,6 +343,9 @@ void SetupResidentModels() break; } } + if (missionResidentCarModels[3] != 0) + missionResidentCarModels[4] = missionResidentCarModels[3]; + missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = MissionHeader->residentModels[4]; #endif // MAX_CAR_RESIDENT_MODELS > 5 From 3c9b2d415b607a86182ca8035d41aafa869fcba8 Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Fri, 3 Oct 2025 22:36:29 +0500 Subject: [PATCH 12/19] - Caine's cash to have pickup truck instead of thunderbird on additional slot --- src_rebuild/Game/C/mission.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_rebuild/Game/C/mission.c b/src_rebuild/Game/C/mission.c index 0eb77841..c4dbada3 100644 --- a/src_rebuild/Game/C/mission.c +++ b/src_rebuild/Game/C/mission.c @@ -343,7 +343,7 @@ void SetupResidentModels() break; } } - if (missionResidentCarModels[3] != 0) + if (missionResidentCarModels[3] != 0 && gCurrentMissionNumber != 33) missionResidentCarModels[4] = missionResidentCarModels[3]; missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = MissionHeader->residentModels[4]; From 798238199471f7a6950ca3df618546249dd7359a Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Fri, 3 Oct 2025 23:49:56 +0500 Subject: [PATCH 13/19] - rename missionResidentCarModels -> residentCarModels --- src_rebuild/Game/C/civ_ai.c | 10 +++++----- src_rebuild/Game/C/cosmetic.c | 6 +++--- src_rebuild/Game/C/cutscene.c | 2 +- src_rebuild/Game/C/debris.c | 2 +- src_rebuild/Game/C/denting.c | 6 +++--- src_rebuild/Game/C/gamesnd.c | 14 +++++++------- src_rebuild/Game/C/main.c | 4 ++-- src_rebuild/Game/C/mgeneric.c | 4 ++-- src_rebuild/Game/C/mission.c | 20 ++++++++++---------- src_rebuild/Game/C/mission.h | 2 +- src_rebuild/Game/C/models.c | 4 ++-- src_rebuild/Game/C/players.c | 4 ++-- src_rebuild/Game/C/spool.c | 20 ++++++++++---------- src_rebuild/Game/C/texture.c | 2 +- src_rebuild/redriver2_psxpc.cpp | 6 +++--- 15 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src_rebuild/Game/C/civ_ai.c b/src_rebuild/Game/C/civ_ai.c index 741c392f..c4617fd1 100644 --- a/src_rebuild/Game/C/civ_ai.c +++ b/src_rebuild/Game/C/civ_ai.c @@ -1595,7 +1595,7 @@ int PingOutAllSpecialCivCars(void) do { - if (lcp->controlType == CONTROL_TYPE_CIV_AI && missionResidentCarModels[lcp->ap.model] > 4) + if (lcp->controlType == CONTROL_TYPE_CIV_AI && residentCarModels[lcp->ap.model] > 4) PingOutCar(lcp); lcp++; @@ -1793,7 +1793,7 @@ int CreateStationaryCivCar(int direction, int orientX, int orientZ, LONGVECTOR4* model = -1; for(i = 0; i < MAX_CAR_RESIDENT_MODELS; ++i) { - if (missionResidentCarModels[i] == externalModel) + if (residentCarModels[i] == externalModel) { model = i; break; @@ -2169,7 +2169,7 @@ int PingInCivCar(int minPingInDist) } // check if special car is loaded and add it to random list - if ((specModelValid == 0 || allowSpecSpooling == 0 || missionResidentCarModels[MAX_CAR_RESIDENT_MODELS-1] == 12) && missionResidentCarModels[MAX_CAR_RESIDENT_MODELS-1] >= 8) + if ((specModelValid == 0 || allowSpecSpooling == 0 || residentCarModels[MAX_CAR_RESIDENT_MODELS-1] == 12) && residentCarModels[MAX_CAR_RESIDENT_MODELS-1] >= 8) { #if MAX_CAR_RESIDENT_MODELS == 6 modelRandomList[15] = 4; @@ -2225,7 +2225,7 @@ int PingInCivCar(int minPingInDist) model = MAX_CAR_RESIDENT_MODELS - 1; // select car color palette - if (missionResidentCarModels[model] == 0 || missionResidentCarModels[model] > 4) + if (residentCarModels[model] == 0 || residentCarModels[model] > 4) { civDat.palette = 0; } @@ -3299,7 +3299,7 @@ void CreateRoadblock(void) noMoreCars = 0; distAlongSegment = -5; lbody = car_cosmetics[3].colBox.vz; - externalCopModel = missionResidentCarModels[3]; + externalCopModel = residentCarModels[3]; // [A] use player instead of car dir = player[0].dir; diff --git a/src_rebuild/Game/C/cosmetic.c b/src_rebuild/Game/C/cosmetic.c index 94a527d6..01cec4e4 100644 --- a/src_rebuild/Game/C/cosmetic.c +++ b/src_rebuild/Game/C/cosmetic.c @@ -52,11 +52,11 @@ void ProcessCosmeticsLump(char *lump_ptr, int lump_size) for (i = 0; i < MAX_CAR_RESIDENT_MODELS; i++) { - model = missionResidentCarModels[i]; + model = residentCarModels[i]; if (model == 13) { - model = 10 - (missionResidentCarModels[0] + missionResidentCarModels[1] + missionResidentCarModels[2]); + model = 10 - (residentCarModels[0] + residentCarModels[1] + residentCarModels[2]); if (model < 1) model = 1; @@ -137,7 +137,7 @@ void AddReverseLight(CAR_DATA *cp) void SetupSpecCosmetics(char *loadbuffer) { int model; - model = missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; + model = residentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; #if ENABLE_GAME_FIXES // [A] always use cached cosmetics diff --git a/src_rebuild/Game/C/cutscene.c b/src_rebuild/Game/C/cutscene.c index a500437f..e9278d3a 100644 --- a/src_rebuild/Game/C/cutscene.c +++ b/src_rebuild/Game/C/cutscene.c @@ -609,7 +609,7 @@ int TriggerInGameCutsceneSystem(int cutscene) if (gCutsceneAtEnd != 0 && player[0].playerType == 1) { stream->SourceType.palette = car_data[player[0].playerCarId].ap.palette; - stream->SourceType.model = missionResidentCarModels[car_data[player[0].playerCarId].ap.model]; + stream->SourceType.model = residentCarModels[car_data[player[0].playerCarId].ap.model]; bDamageOverride = 1; gCutsceneAtEnd = 0; diff --git a/src_rebuild/Game/C/debris.c b/src_rebuild/Game/C/debris.c index 09d3641f..8739a333 100644 --- a/src_rebuild/Game/C/debris.c +++ b/src_rebuild/Game/C/debris.c @@ -4001,7 +4001,7 @@ int GetDebrisColour(CAR_DATA *cp) { int car_model; - car_model = missionResidentCarModels[cp->ap.model]; + car_model = residentCarModels[cp->ap.model]; if (car_model == 0) return 1; diff --git a/src_rebuild/Game/C/denting.c b/src_rebuild/Game/C/denting.c index 48002c9f..01e7881a 100644 --- a/src_rebuild/Game/C/denting.c +++ b/src_rebuild/Game/C/denting.c @@ -410,11 +410,11 @@ void ProcessDentLump(char *lump_ptr, int lump_size) for (i = 0; i < MAX_CAR_RESIDENT_MODELS; i++) { - model = missionResidentCarModels[i]; + model = residentCarModels[i]; if (model == 13) { - model = 10 - (missionResidentCarModels[0] + missionResidentCarModels[1] + missionResidentCarModels[2]); + model = 10 - (residentCarModels[0] + residentCarModels[1] + residentCarModels[2]); if (model < 1) model = 1; @@ -461,7 +461,7 @@ void SetupSpecDenting(char *loadbuffer) { char* newDenting; int model; - model = missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; + model = residentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; newDenting = LoadCustomCarDentingFromFile(NULL, model); if (newDenting) diff --git a/src_rebuild/Game/C/gamesnd.c b/src_rebuild/Game/C/gamesnd.c index 11dd625a..2c7173cd 100644 --- a/src_rebuild/Game/C/gamesnd.c +++ b/src_rebuild/Game/C/gamesnd.c @@ -169,22 +169,22 @@ int CarHasSiren(int index) { if (GameLevel == 0) { - if (missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] == 8) + if (residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] == 8) return M_SHRT_2(SOUND_BANK_SFX, 12); } else if (GameLevel == 2) { - if (missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] == 9) + if (residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] == 9) return M_SHRT_2(SOUND_BANK_SFX, 12); } else if (GameLevel == 3) { - if (missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] == 10) + if (residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] == 10) return M_SHRT_2(SOUND_BANK_SFX, 12); } } - return M_SHRT_2((missionResidentCarModels[index] == 0) ? SOUND_BANK_VOICES : 0, 0); + return M_SHRT_2((residentCarModels[index] == 0) ? SOUND_BANK_VOICES : 0, 0); } // [D] [T] @@ -215,7 +215,7 @@ int ResidentModelsBodge(void) return 3; } - j = missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; + j = residentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; if (gCurrentMissionNumber - 50U < 16 && j == 12) { @@ -288,7 +288,7 @@ int MapCarIndexToBank(int index) int model; int ret; - RM = missionResidentCarModels; + RM = residentCarModels; model = RM[index]; @@ -527,7 +527,7 @@ void LoadLevelSFX(int missionNum) for (i = 0; i < 3; i++) { - if (missionResidentCarModels[i] == missionResidentCarModels[3]) + if (residentCarModels[i] == residentCarModels[3]) cop_model = i; } } diff --git a/src_rebuild/Game/C/main.c b/src_rebuild/Game/C/main.c index 03b5f7b0..9936e9f8 100644 --- a/src_rebuild/Game/C/main.c +++ b/src_rebuild/Game/C/main.c @@ -493,7 +493,7 @@ void State_GameInit(void* param) LoadMission(gCurrentMissionNumber); if (gCurrentMissionNumber == 38) - missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = 9; + residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = 9; if (GameType == GAME_MISSION) SetupFadePolys(); @@ -892,7 +892,7 @@ void StepSim(void) } else { - if (copsAreInPursuit != 0 && missionResidentCarModels[3] == 0 && gCurrentMissionNumber != 26) + if (copsAreInPursuit != 0 && residentCarModels[3] == 0 && gCurrentMissionNumber != 26) requestRoadblock = 1; if (roadblockCount != 0) diff --git a/src_rebuild/Game/C/mgeneric.c b/src_rebuild/Game/C/mgeneric.c index 257e37cf..8aaaf320 100644 --- a/src_rebuild/Game/C/mgeneric.c +++ b/src_rebuild/Game/C/mgeneric.c @@ -24,7 +24,7 @@ void StorePlayerPosition(SAVED_PLAYER_POS *data) cp = &car_data[slot]; - data->type = ((missionResidentCarModels[cp->ap.model] & 0xfff) << 4) | 1 | cp->ap.palette << 8; + data->type = ((residentCarModels[cp->ap.model] & 0xfff) << 4) | 1 | cp->ap.palette << 8; data->totaldamage = cp->totalDamage; data->felony = cp->felonyRating; @@ -113,7 +113,7 @@ void StoreCarPosition(MS_TARGET *target, SAVED_CAR_POS *data) cp = &car_data[slot]; - data->model = missionResidentCarModels[cp->ap.model]; + data->model = residentCarModels[cp->ap.model]; data->palette = cp->ap.palette; data->totaldamage = cp->totalDamage; diff --git a/src_rebuild/Game/C/mission.c b/src_rebuild/Game/C/mission.c index c4dbada3..75e3f4dc 100644 --- a/src_rebuild/Game/C/mission.c +++ b/src_rebuild/Game/C/mission.c @@ -148,7 +148,7 @@ STOPCOPS gStopCops; MS_MISSION* MissionLoadAddress; MS_MISSION* MissionHeader; -int missionResidentCarModels[MAX_CAR_RESIDENT_MODELS]; +int residentCarModels[MAX_CAR_RESIDENT_MODELS]; STREAM_SOURCE* PlayerStartInfo[8]; int numPlayersToCreate = 0; int gStartOnFoot = 0; @@ -331,7 +331,7 @@ void SetupResidentModels() takenSlots = 0; for (i = 0; i < 5; ++i) { - missionResidentCarModels[i] = MissionHeader->residentModels[i]; + residentCarModels[i] = MissionHeader->residentModels[i]; takenSlots |= 1 << MissionHeader->residentModels[i]; } #if MAX_CAR_RESIDENT_MODELS > 5 @@ -339,14 +339,14 @@ void SetupResidentModels() { if ((takenSlots & (1 << i)) == 0) { - missionResidentCarModels[4] = i; + residentCarModels[4] = i; break; } } - if (missionResidentCarModels[3] != 0 && gCurrentMissionNumber != 33) - missionResidentCarModels[4] = missionResidentCarModels[3]; + if (residentCarModels[3] != 0 && gCurrentMissionNumber != 33) + residentCarModels[4] = residentCarModels[3]; - missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = MissionHeader->residentModels[4]; + residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = MissionHeader->residentModels[4]; #endif // MAX_CAR_RESIDENT_MODELS > 5 // check if start data is required @@ -356,7 +356,7 @@ void SetupResidentModels() RestoreStartData(); if (PlayerStartInfo[0]->model > 5) - missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = PlayerStartInfo[0]->model; + residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = PlayerStartInfo[0]->model; } takenSlots = 0; @@ -369,7 +369,7 @@ void SetupResidentModels() for (j = 0; j < MAX_CAR_RESIDENT_MODELS; j++) { - if (missionResidentCarModels[j] == wantedCar[i]) + if (residentCarModels[j] == wantedCar[i]) { foundRM = j; break; @@ -383,11 +383,11 @@ void SetupResidentModels() // check if chosen cop car or special car if (wantedCar[i] > 5)// && NumPlayers == 1) { - missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = wantedCar[i]; + residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = wantedCar[i]; } else if(foundRM == -1) { - missionResidentCarModels[takenSlots++] = wantedCar[i]; + residentCarModels[takenSlots++] = wantedCar[i]; } else { diff --git a/src_rebuild/Game/C/mission.h b/src_rebuild/Game/C/mission.h index 7e55e41e..620586c7 100644 --- a/src_rebuild/Game/C/mission.h +++ b/src_rebuild/Game/C/mission.h @@ -14,7 +14,7 @@ extern GAMEMODE CurrentGameMode; extern GAMEMODE WantedGameMode; extern int gCurrentMissionNumber; extern MS_MISSION*MissionHeader; -extern int missionResidentCarModels[MAX_CAR_RESIDENT_MODELS]; +extern int residentCarModels[MAX_CAR_RESIDENT_MODELS]; extern STREAM_SOURCE* PlayerStartInfo[8]; extern int numPlayersToCreate; extern int gStartOnFoot; diff --git a/src_rebuild/Game/C/models.c b/src_rebuild/Game/C/models.c index 0286f392..fc1e6ee9 100644 --- a/src_rebuild/Game/C/models.c +++ b/src_rebuild/Game/C/models.c @@ -263,11 +263,11 @@ int ProcessCarModelLump(char *lump_ptr, int lump_size) specmallocptr = (char*)mallocptr; } - model_number = missionResidentCarModels[i]; + model_number = residentCarModels[i]; if (model_number == 13) { - model_number = 10 - (missionResidentCarModels[0] + missionResidentCarModels[1] + missionResidentCarModels[2]); + model_number = 10 - (residentCarModels[0] + residentCarModels[1] + residentCarModels[2]); if (model_number < 1) model_number = 1; diff --git a/src_rebuild/Game/C/players.c b/src_rebuild/Game/C/players.c index 5ed2295d..695cef26 100644 --- a/src_rebuild/Game/C/players.c +++ b/src_rebuild/Game/C/players.c @@ -33,7 +33,7 @@ void InitPlayer(PLAYER *locPlayer, CAR_DATA *cp, char carCtrlType, int direction model = -1; for (i = 0; i < MAX_CAR_RESIDENT_MODELS; ++i) { - if (missionResidentCarModels[i] == playerType) + if (residentCarModels[i] == playerType) { model = i; break; @@ -212,7 +212,7 @@ void ChangePedPlayerToCar(int playerID, CAR_DATA *newCar) #endif ) { - if (gCurrentMissionNumber != 32 && missionResidentCarModels[newCar->ap.model] == 0) + if (gCurrentMissionNumber != 32 && residentCarModels[newCar->ap.model] == 0) { NoteFelony(&felonyData, 11, 4096); } diff --git a/src_rebuild/Game/C/spool.c b/src_rebuild/Game/C/spool.c index a577fb0b..57b259b2 100644 --- a/src_rebuild/Game/C/spool.c +++ b/src_rebuild/Game/C/spool.c @@ -1912,7 +1912,7 @@ void CleanSpooled(void) { char* mem; - if (mem = LoadCarModelFromFile((char*)modelMemory, missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1], CAR_MODEL_CLEAN)) + if (mem = LoadCarModelFromFile((char*)modelMemory, residentCarModels[MAX_CAR_RESIDENT_MODELS - 1], CAR_MODEL_CLEAN)) { gCarCleanModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = (MODEL*)modelMemory; model = GetCarModel(mem, (char**)&modelMemory, 1); @@ -1924,7 +1924,7 @@ void CleanSpooled(void) specialState = SpecSpool_CleanModel; } - if (mem = LoadCarModelFromFile((char*)modelMemory, missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1], CAR_MODEL_DAMAGED)) + if (mem = LoadCarModelFromFile((char*)modelMemory, residentCarModels[MAX_CAR_RESIDENT_MODELS - 1], CAR_MODEL_DAMAGED)) { gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = (MODEL*)modelMemory; model = GetCarModel(mem, (char**)&modelMemory, 0); @@ -1933,7 +1933,7 @@ void CleanSpooled(void) specialState = SpecSpool_DamagedModel; } - if (mem = LoadCarModelFromFile((char*)modelMemory, missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1], CAR_MODEL_LOWDETAIL)) + if (mem = LoadCarModelFromFile((char*)modelMemory, residentCarModels[MAX_CAR_RESIDENT_MODELS - 1], CAR_MODEL_LOWDETAIL)) { gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = (MODEL*)modelMemory; model = GetCarModel(mem, (char**)&modelMemory, 1); @@ -2162,14 +2162,14 @@ void CheckSpecialSpool(void) specialState == SpecSpool_None && GameType != GAME_PURSUIT && LoadedArea != -1 && - SpecialByRegion[GameLevel][LoadedArea] != missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] - 7) + SpecialByRegion[GameLevel][LoadedArea] != residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] - 7) { lcp = car_data; // if there are cars that still using special models, deny spooling do // [A] { - if (missionResidentCarModels[lcp->ap.model] > 5) + if (residentCarModels[lcp->ap.model] > 5) return; lcp++; @@ -2184,7 +2184,7 @@ void CheckSpecialSpool(void) gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = NULL; specSpoolModelIndex = SpecialByRegion[GameLevel][LoadedArea]; - missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = specSpoolModelIndex + 7; + residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = specSpoolModelIndex + 7; SpecialStartNextBlock(); } @@ -2201,7 +2201,7 @@ void QuickSpoolSpecial(void) gCarDamModelPtr[MAX_CAR_RESIDENT_MODELS-1] = NULL; gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS-1] = NULL; - specSpoolModelIndex = missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] - 7; + specSpoolModelIndex = residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] - 7; do { SpoolSYNC(); @@ -2215,7 +2215,7 @@ void QuickSpoolSpecial(void) void PrepareSecretCar(void) { // [A] Don't do anything if model is already spooled - if (missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] == 12) + if (residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] == 12) { return; } @@ -2228,7 +2228,7 @@ void PrepareSecretCar(void) gCarLowModelPtr[MAX_CAR_RESIDENT_MODELS - 1] = NULL; specSpoolModelIndex = 5; - missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = 12; + residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] = 12; specModelValid = 0; startSpecSpool = CameraCnt; @@ -2328,7 +2328,7 @@ void InitSpecSpool(void) allowSpecSpooling = 0; #endif - if(missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] < 8) + if(residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] < 8) allowSpecSpooling = 0; specModelValid = 1; diff --git a/src_rebuild/Game/C/texture.c b/src_rebuild/Game/C/texture.c index 06880135..5eb6caf8 100644 --- a/src_rebuild/Game/C/texture.c +++ b/src_rebuild/Game/C/texture.c @@ -545,7 +545,7 @@ void LoadPermanentTPages(int *sector) slot_clutpos[slotsused].vy = clutpos.y; // init special slot texture - specmodel = (missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1] - 8) * 2; + specmodel = (residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] - 8) * 2; specialSlot = (short)slotsused; // get special slot tpage diff --git a/src_rebuild/redriver2_psxpc.cpp b/src_rebuild/redriver2_psxpc.cpp index f55d300a..6565cffb 100644 --- a/src_rebuild/redriver2_psxpc.cpp +++ b/src_rebuild/redriver2_psxpc.cpp @@ -246,7 +246,7 @@ void GameDebugKeys(int nKey, char down) if (ShiftModifier) { // force a special car - model = missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; + model = residentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; palette = 0; lastmodel = model; } @@ -255,7 +255,7 @@ void GameDebugKeys(int nKey, char down) for (int i = 0; i < 5; i++) { // horrible randomness - int newmodel = missionResidentCarModels[i]; + int newmodel = residentCarModels[i]; if (newmodel == 0 || newmodel == lastmodel) continue; @@ -267,7 +267,7 @@ void GameDebugKeys(int nKey, char down) if (tmp & 4) { // rare chance of spawning special car - model = missionResidentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; + model = residentCarModels[MAX_CAR_RESIDENT_MODELS - 1]; palette = 0; lastmodel = model; break; From a5f1e3a35b78a4b86c4bf4b56f38ec4a14887dbc Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Sat, 4 Oct 2025 17:32:48 +0500 Subject: [PATCH 14/19] - fix FEGetHiresBakedQuad buffer underflow --- src_rebuild/Game/Frontend/FEmain.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src_rebuild/Game/Frontend/FEmain.c b/src_rebuild/Game/Frontend/FEmain.c index 1e1b9e38..d6cd3aeb 100644 --- a/src_rebuild/Game/Frontend/FEmain.c +++ b/src_rebuild/Game/Frontend/FEmain.c @@ -92,12 +92,15 @@ void InitHiresFEFont() } } -void FEGetHiresBakedQuad(int char_index, float scale, float* xpos, float* ypos, FEFONT_QUAD* q) +int FEGetHiresBakedQuad(int char_index, float scale, float* xpos, float* ypos, FEFONT_QUAD* q) { float ipw = 1.0f / (float)HIRES_FONT_SIZE_W; float iph = 1.0f / (float)HIRES_FONT_SIZE_H; - const OUT_FN2INFO* b = gHiresFEFontCharData[0] + char_index - gHiresFEFontRanges[0].start; + const int idx = char_index - gHiresFEFontRanges[0].start; + if (idx < 0) + return 0; + const OUT_FN2INFO* b = gHiresFEFontCharData[0] + idx; float fscale = 0.5f * scale; @@ -117,6 +120,8 @@ void FEGetHiresBakedQuad(int char_index, float scale, float* xpos, float* ypos, q->y0 += 32.0f; *xpos += b->xadvance * fscale; + + return 1; } void SetHiresFEFontTexture(int enabled) @@ -149,7 +154,8 @@ int FEStringWidthHires(char* string) fx = 0; fy = 0; FEFONT_QUAD q; - FEGetHiresBakedQuad(c, 1.0f, &fx, &fy, &q); + if (!FEGetHiresBakedQuad(c, 1.0f, &fx, &fy, &q)) + continue; w += fx; } @@ -180,7 +186,8 @@ int FEPrintStringSizedHires(char* string, int x, int y, int scale, int transpare fx = x; fy = y; FEFONT_QUAD q; - FEGetHiresBakedQuad(let, scale / 4096.0f, &fx, &fy, &q); + if (!FEGetHiresBakedQuad(let, scale / 4096.0f, &fx, &fy, &q)) + continue; setPolyFT4(font); setSemiTrans(font, 1); From c09b639b2d9670986190676f6943fa8daaafc8fb Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Sat, 4 Oct 2025 17:35:39 +0500 Subject: [PATCH 15/19] - fix incorrect change causing buffer overflow --- src_rebuild/Game/C/cosmetic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_rebuild/Game/C/cosmetic.c b/src_rebuild/Game/C/cosmetic.c index 01cec4e4..7334402c 100644 --- a/src_rebuild/Game/C/cosmetic.c +++ b/src_rebuild/Game/C/cosmetic.c @@ -79,7 +79,7 @@ void ProcessCosmeticsLump(char *lump_ptr, int lump_size) // [A] cache all special vehicle cosmetics #if ENABLE_GAME_FIXES - for (i = 0; i < MAX_CAR_RESIDENT_MODELS; i++) + for (i = 0; i < 5; i++) { model = 8 + i; From 1b5565aca10dad6a58d91705c90f264b1f043c89 Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Sun, 5 Oct 2025 15:47:57 +0500 Subject: [PATCH 16/19] - fix out of bounds issue on Car bomb getaway --- src_rebuild/Game/C/cop_ai.c | 4 ++-- src_rebuild/Game/C/felony.c | 23 +++++++++++++++++------ src_rebuild/Game/C/felony.h | 5 +++-- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src_rebuild/Game/C/cop_ai.c b/src_rebuild/Game/C/cop_ai.c index 6e206848..7a5e4c20 100644 --- a/src_rebuild/Game/C/cop_ai.c +++ b/src_rebuild/Game/C/cop_ai.c @@ -943,7 +943,7 @@ void ControlCopDetection(void) if (player_position_known == 1 && first_offence == 0) { - heading = GetCarDirectionOfTravel(&car_data[player[0].playerCarId]); + heading = GetPlayerDirectionOfTravel(&player[0]); CopSay(Random2(2) % 2 + 10, heading); @@ -961,7 +961,7 @@ void ControlCopDetection(void) int rnd; rnd = Random2(2); - heading = GetCarDirectionOfTravel(&car_data[player[0].playerCarId]); + heading = GetPlayerDirectionOfTravel(&player[0]); if ((rnd == (rnd / 5) * 5) && (dx != LastHeading)) CopSay(rnd % 2 + 10, heading); diff --git a/src_rebuild/Game/C/felony.c b/src_rebuild/Game/C/felony.c index 13c38840..d6f64792 100644 --- a/src_rebuild/Game/C/felony.c +++ b/src_rebuild/Game/C/felony.c @@ -69,19 +69,30 @@ void InitFelonyData(FELONY_DATA *pFelonyData) } // [D] [T] -int GetCarHeading(int direction) +static int GetHeading(int direction) { - return (direction + 0x200U & 0xfff) >> 10; + return (direction + 512U & 4095) >> 10; } // [D] [T] -char GetCarDirectionOfTravel(CAR_DATA *cp) +char GetCarDirectionOfTravel(CAR_DATA* cp) { int direction; + direction = GetHeading(cp->hd.direction); - direction = GetCarHeading(cp->hd.direction);; + if (cp->hd.wheel_speed < 0) + direction = direction + 2 & 3; + + return direction; +} + +// [A] +char GetPlayerDirectionOfTravel(PLAYER* pl) +{ + int direction; + direction = GetHeading(pl->dir); - if (cp->hd.wheel_speed < 0) + if (pl->playerCarId >= 0 && car_data[pl->playerCarId].hd.wheel_speed < 0) direction = direction + 2 & 3; return direction; @@ -172,7 +183,7 @@ void NoteFelony(FELONY_DATA *pFelonyData, char type, short scale) { // say something.. rnd = Random2(1); - dir = GetCarDirectionOfTravel(&car_data[player[0].playerCarId]); + dir = GetPlayerDirectionOfTravel(&player[0]); switch (type) { diff --git a/src_rebuild/Game/C/felony.h b/src_rebuild/Game/C/felony.h index 5dd1c5d8..27d6c71b 100644 --- a/src_rebuild/Game/C/felony.h +++ b/src_rebuild/Game/C/felony.h @@ -14,9 +14,10 @@ extern FELONY_DATA felonyData; extern void InitFelonySystem(); // 0x0004D280 extern void CheckPlayerMiscFelonies(); // 0x0004CC28 -extern int GetCarHeading(int direction); // 0x0004D420 +extern int GetHeading(int direction); // 0x0004D420 -extern char GetCarDirectionOfTravel(CAR_DATA *cp); // 0x0004D430 +extern char GetCarDirectionOfTravel(CAR_DATA* cp); // 0x0004D430 +extern char GetPlayerDirectionOfTravel(PLAYER* pl); extern void CarHitByPlayer(CAR_DATA* victim, int howHard); // 0x0004D2B8 From 073ff66c30b3cc6ec5fd1d242563ba2f433bd35b Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Sun, 5 Oct 2025 16:15:04 +0500 Subject: [PATCH 17/19] - replace InitSpecSpool hardcoding with less hardcoding --- src_rebuild/Game/C/glaunch.c | 2 +- src_rebuild/Game/C/spool.c | 116 +++++++++++------------------------ 2 files changed, 36 insertions(+), 82 deletions(-) diff --git a/src_rebuild/Game/C/glaunch.c b/src_rebuild/Game/C/glaunch.c index f4dd417a..4aca8ae4 100644 --- a/src_rebuild/Game/C/glaunch.c +++ b/src_rebuild/Game/C/glaunch.c @@ -225,7 +225,7 @@ void State_GameStart(void* param) break; case GAME_TRAILBLAZER: - gCurrentMissionNumber = GameLevel * 8 + 260 + gWantNight * 4 + gSubGameNumber; + gCurrentMissionNumber = 260 + GameLevel * 8 + gWantNight * 4 + gSubGameNumber; SetState(STATE_GAMELAUNCH); break; diff --git a/src_rebuild/Game/C/spool.c b/src_rebuild/Game/C/spool.c index 57b259b2..e07bde93 100644 --- a/src_rebuild/Game/C/spool.c +++ b/src_rebuild/Game/C/spool.c @@ -2240,87 +2240,41 @@ void PrepareSecretCar(void) // [D] [T] void InitSpecSpool(void) { - switch (gCurrentMissionNumber) - { - case 2: - case 4: - case 6: - case 7: - case 10: - case 11: - case 12: - case 13: - case 16: - case 18: - case 19: - case 20: - case 24: - case 26: - case 27: - case 29: - case 30: - case 31: - case 33: - case 35: - case 38: - case 39: - case 40: - case 58: - case 59: - case 60: - case 61: - case 62: - case 63: - case 64: - case 65: - case 70: - case 78: - case 86: - case 94: - case 228: - case 229: - case 236: - case 237: - case 244: - case 245: - case 252: - case 253: - case 352: - case 353: - case 360: - case 169: - case 368: - case 369: - case 376: - case 377: - case 420: - case 421: - case 428: - case 429: - case 436: - case 437: - case 444: - case 445: - case 480: - case 481: - case 482: - case 483: - case 484: - case 485: - case 486: - case 487: - case 498: - case 499: - case 500: - case 501: - case 502: - case 503: - case 504: - case 505: - allowSpecSpooling = 0; - break; - default: - allowSpecSpooling = 1; + allowSpecSpooling = 1; + + if (GameType == GAME_SECRET) + allowSpecSpooling = 0; + else if (NumPlayers == 2) + allowSpecSpooling = 0; + else if (gCurrentMissionNumber == 40) // Chopper uses special texture slot + allowSpecSpooling = 0; + else if (gCurrentMissionNumber == 24) // Car bomb getaway is only exception + allowSpecSpooling = 1; + else + { + // disable special model spooling + // if special car is used as target + // or there is random chase present + MS_TARGET* target; + int i; + for (i = 0; i < MAX_MISSION_TARGETS; ++i) + { + target = &MissionTargets[i]; + if (target->type == Target_Car) + { + if (target->s.car.type == 3 && (target->s.car.flags & CARTARGET_FLAG_RANDOMCHASE)) + { + allowSpecSpooling = 0; + break; + } + + if (target->s.car.model == residentCarModels[MAX_CAR_RESIDENT_MODELS - 1]) + { + allowSpecSpooling = 0; + break; + } + } + } } #ifndef PSX From c1a9e29edb562e3cf35289d343bca105023fe13f Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Sun, 5 Oct 2025 16:15:24 +0500 Subject: [PATCH 18/19] - fix Lenny gets caught traffic vehicles --- src_rebuild/Game/C/civ_ai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_rebuild/Game/C/civ_ai.c b/src_rebuild/Game/C/civ_ai.c index c4617fd1..7473c32c 100644 --- a/src_rebuild/Game/C/civ_ai.c +++ b/src_rebuild/Game/C/civ_ai.c @@ -2169,7 +2169,7 @@ int PingInCivCar(int minPingInDist) } // check if special car is loaded and add it to random list - if ((specModelValid == 0 || allowSpecSpooling == 0 || residentCarModels[MAX_CAR_RESIDENT_MODELS-1] == 12) && residentCarModels[MAX_CAR_RESIDENT_MODELS-1] >= 8) + if ((specModelValid == 0 || allowSpecSpooling == 0 || residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] == 12) && residentCarModels[MAX_CAR_RESIDENT_MODELS - 1] != 13) { #if MAX_CAR_RESIDENT_MODELS == 6 modelRandomList[15] = 4; From 75ec6e98542e9e0d77ad212d3cf332b991291dad Mon Sep 17 00:00:00 2001 From: SoapyMan Date: Tue, 7 Oct 2025 16:39:27 +0500 Subject: [PATCH 19/19] - fix regression --- src_rebuild/Game/C/spool.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src_rebuild/Game/C/spool.c b/src_rebuild/Game/C/spool.c index e07bde93..4b232796 100644 --- a/src_rebuild/Game/C/spool.c +++ b/src_rebuild/Game/C/spool.c @@ -2246,7 +2246,9 @@ void InitSpecSpool(void) allowSpecSpooling = 0; else if (NumPlayers == 2) allowSpecSpooling = 0; - else if (gCurrentMissionNumber == 40) // Chopper uses special texture slot + else if ( + gCurrentMissionNumber == 7 || // Caine's Compound semi trucks + gCurrentMissionNumber == 40) // Chopper uses special texture slot allowSpecSpooling = 0; else if (gCurrentMissionNumber == 24) // Car bomb getaway is only exception allowSpecSpooling = 1;