inventory: limit max item quantities to fix crashing (#2554)
Some checks are pending
Run code linters / Run code linters (push) Waiting to run
Publish a pre-release / Build TR1 (push) Has been skipped
Publish a pre-release / Build TR2 (push) Has been skipped
Publish a pre-release / Create a prerelease (push) Has been skipped

Resolves #2497.
This commit is contained in:
walkawayy 2025-02-28 19:58:51 -05:00 committed by GitHub
parent 3ece4b7b29
commit 3808fa7c28
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 59 additions and 38 deletions

View file

@ -3,6 +3,7 @@
- changed the Controls screen to hide the reset and unbind texts when changing a key (#2103)
- fixed several instances of the camera going out of bounds (#1034)
- fixed the bear AI fix option being applied in the Vilcabamba demo (#2559, regression from 4.8)
- fixed extremely large item quantities crashing the game (#2497, regression from 0.3)
## [4.8.3](https://github.com/LostArtefacts/TRX/compare/tr1-4.8.2...tr1-4.8.3) - 2025-02-17
- fixed some of Lara's speech in the gym not playing in response to player action (#2514, regression from 4.8)

View file

@ -6,6 +6,7 @@
- fixed a rare issue whereby Lara would be unable to move after disposing a flare (#2545, regression from 0.9)
- fixed flare pickups only adding one flare to Lara's inventory rather than six (#2551, regression from 0.9)
- fixed play any level causing the game to hang when no gym level is present (#2560, regression from 0.9)
- fixed extremely large item quantities crashing the game (#2497, regression from 0.3)
## [0.9.2](https://github.com/LostArtefacts/TRX/compare/tr2-0.9.1...tr2-0.9.2) - 2025-02-19
- fixed secret rewards not handed out after loading a save (#2528, regression from 0.8)

View file

@ -9,6 +9,7 @@
#include "game/objects/vars.h"
#include "memory.h"
#include "strings.h"
#include "utils.h"
#include <stdio.h>
#include <string.h>
@ -49,6 +50,7 @@ static COMMAND_RESULT M_Entrypoint(const COMMAND_CONTEXT *const ctx)
if (args == nullptr) {
return CR_BAD_INVOCATION;
}
CLAMPG(num, MAX_QTY);
args++;
}

View file

@ -2,6 +2,7 @@
#include "game/inventory_ring/vars.h"
#include "game/objects/vars.h"
#include "utils.h"
bool Inv_AddItemNTimes(const GAME_OBJECT_ID obj_id, const int32_t qty)
{
@ -12,6 +13,12 @@ bool Inv_AddItemNTimes(const GAME_OBJECT_ID obj_id, const int32_t qty)
return result;
}
void Inv_AddAmmo(AMMO_INFO *const weapon_ammo, int32_t qty)
{
weapon_ammo->ammo += qty;
CLAMPG(weapon_ammo->ammo, MAX_QTY);
}
GAME_OBJECT_ID Inv_GetItemOption(const GAME_OBJECT_ID obj_id)
{
if (Object_IsType(obj_id, g_InvObjects)) {

View file

@ -1,11 +1,13 @@
#pragma once
#include "inventory_ring/types.h"
#include "lara/types.h"
#include "objects/ids.h"
#include <stdint.h>
bool Inv_AddItemNTimes(GAME_OBJECT_ID obj_id, int32_t qty);
void Inv_AddAmmo(AMMO_INFO *weapon_ammo, int32_t qty);
GAME_OBJECT_ID Inv_GetItemOption(GAME_OBJECT_ID obj_id);
void Inv_InsertItem(INVENTORY_ITEM *inv_item);
bool Inv_RemoveItem(GAME_OBJECT_ID obj_id);

View file

@ -7,6 +7,8 @@
#include <stdint.h>
#define MAX_QTY 999999
typedef struct {
int16_t shape;
XYZ_16 pos;
@ -74,7 +76,7 @@ typedef struct {
typedef struct {
int16_t current;
int16_t count;
int16_t qtys[24];
int32_t qtys[24];
INVENTORY_ITEM *items[24];
} INV_RING_SOURCE;

View file

@ -9,6 +9,8 @@
#include "global/types.h"
#include "global/vars.h"
#include <libtrx/utils.h>
#include <stdint.h>
bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
@ -32,6 +34,7 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
for (int32_t i = 0; i < source->count; i++) {
if (source->items[i]->object_id == inv_obj_id) {
source->qtys[i]++;
CLAMPG(source->qtys[i], MAX_QTY);
return true;
}
}
@ -47,9 +50,9 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_SHOTGUN_OPTION:
for (int32_t i = Inv_RequestItem(O_SG_AMMO_ITEM); i > 0; i--) {
Inv_RemoveItem(O_SG_AMMO_ITEM);
g_Lara.shotgun.ammo += SHOTGUN_AMMO_QTY;
Inv_AddAmmo(&g_Lara.shotgun, SHOTGUN_AMMO_QTY);
}
g_Lara.shotgun.ammo += SHOTGUN_AMMO_QTY;
Inv_AddAmmo(&g_Lara.shotgun, SHOTGUN_AMMO_QTY);
Inv_InsertItem(&g_InvRing_Item_Shotgun);
Item_GlobalReplace(O_SHOTGUN_ITEM, O_SG_AMMO_ITEM);
return false;
@ -58,9 +61,9 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_MAGNUM_OPTION:
for (int32_t i = Inv_RequestItem(O_MAG_AMMO_ITEM); i > 0; i--) {
Inv_RemoveItem(O_MAG_AMMO_ITEM);
g_Lara.magnums.ammo += MAGNUM_AMMO_QTY;
Inv_AddAmmo(&g_Lara.magnums, MAGNUM_AMMO_QTY);
}
g_Lara.magnums.ammo += MAGNUM_AMMO_QTY;
Inv_AddAmmo(&g_Lara.magnums, MAGNUM_AMMO_QTY);
Inv_InsertItem(&g_InvRing_Item_Magnum);
Item_GlobalReplace(O_MAGNUM_ITEM, O_MAG_AMMO_ITEM);
return false;
@ -69,9 +72,9 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_UZI_OPTION:
for (int32_t i = Inv_RequestItem(O_UZI_AMMO_ITEM); i > 0; i--) {
Inv_RemoveItem(O_UZI_AMMO_ITEM);
g_Lara.uzis.ammo += UZI_AMMO_QTY;
Inv_AddAmmo(&g_Lara.uzis, UZI_AMMO_QTY);
}
g_Lara.uzis.ammo += UZI_AMMO_QTY;
Inv_AddAmmo(&g_Lara.uzis, UZI_AMMO_QTY);
Inv_InsertItem(&g_InvRing_Item_Uzi);
Item_GlobalReplace(O_UZI_ITEM, O_UZI_AMMO_ITEM);
return false;
@ -79,7 +82,7 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_SG_AMMO_ITEM:
case O_SG_AMMO_OPTION:
if (Inv_RequestItem(O_SHOTGUN_ITEM)) {
g_Lara.shotgun.ammo += SHOTGUN_AMMO_QTY;
Inv_AddAmmo(&g_Lara.shotgun, SHOTGUN_AMMO_QTY);
} else {
Inv_InsertItem(&g_InvRing_Item_ShotgunAmmo);
}
@ -88,7 +91,7 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_MAG_AMMO_ITEM:
case O_MAG_AMMO_OPTION:
if (Inv_RequestItem(O_MAGNUM_ITEM)) {
g_Lara.magnums.ammo += MAGNUM_AMMO_QTY;
Inv_AddAmmo(&g_Lara.magnums, MAGNUM_AMMO_QTY);
} else {
Inv_InsertItem(&g_InvRing_Item_MagnumAmmo);
}
@ -97,7 +100,7 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_UZI_AMMO_ITEM:
case O_UZI_AMMO_OPTION:
if (Inv_RequestItem(O_UZI_ITEM)) {
g_Lara.uzis.ammo += UZI_AMMO_QTY;
Inv_AddAmmo(&g_Lara.uzis, UZI_AMMO_QTY);
} else {
Inv_InsertItem(&g_InvRing_Item_UziAmmo);
}

View file

@ -622,18 +622,18 @@ static void M_DrawAmmoInfo(void)
return;
}
char ammo_string[80] = "";
char ammo_string[128] = "";
switch (g_Lara.gun_type) {
case LGT_PISTOLS:
return;
case LGT_SHOTGUN:
sprintf(ammo_string, "%5d A", g_Lara.shotgun.ammo / SHOTGUN_AMMO_CLIP);
sprintf(ammo_string, "%6d A", g_Lara.shotgun.ammo / SHOTGUN_AMMO_CLIP);
break;
case LGT_UZIS:
sprintf(ammo_string, "%5d C", g_Lara.uzis.ammo);
sprintf(ammo_string, "%6d C", g_Lara.uzis.ammo);
break;
case LGT_MAGNUMS:
sprintf(ammo_string, "%5d B", g_Lara.magnums.ammo);
sprintf(ammo_string, "%6d B", g_Lara.magnums.ammo);
break;
default:
return;

View file

@ -5,6 +5,8 @@
#include "game/objects/vars.h"
#include "global/vars.h"
#include <libtrx/utils.h>
bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
{
const GAME_OBJECT_ID inv_obj_id = Inv_GetItemOption(obj_id);
@ -21,6 +23,7 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
const int32_t qty =
obj_id == O_FLARES_ITEM ? FLARE_AMMO_QTY : 1;
source->qtys[i] += qty;
CLAMPG(source->qtys[i], MAX_QTY);
return true;
}
}
@ -45,9 +48,9 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_SHOTGUN_OPTION:
for (int32_t i = Inv_RequestItem(O_SHOTGUN_AMMO_ITEM); i > 0; i--) {
Inv_RemoveItem(O_SHOTGUN_AMMO_ITEM);
g_Lara.shotgun_ammo.ammo += SHOTGUN_AMMO_QTY;
Inv_AddAmmo(&g_Lara.shotgun_ammo, SHOTGUN_AMMO_QTY);
}
g_Lara.shotgun_ammo.ammo += SHOTGUN_AMMO_QTY;
Inv_AddAmmo(&g_Lara.shotgun_ammo, SHOTGUN_AMMO_QTY);
Inv_InsertItem(&g_InvRing_Item_Shotgun);
if (g_Lara.last_gun_type == LGT_UNARMED) {
g_Lara.last_gun_type = LGT_SHOTGUN;
@ -62,9 +65,9 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_MAGNUM_OPTION:
for (int32_t i = Inv_RequestItem(O_MAGNUM_AMMO_ITEM); i > 0; i--) {
Inv_RemoveItem(O_MAGNUM_AMMO_ITEM);
g_Lara.magnum_ammo.ammo += MAGNUM_AMMO_QTY;
Inv_AddAmmo(&g_Lara.magnum_ammo, MAGNUM_AMMO_QTY);
}
g_Lara.magnum_ammo.ammo += MAGNUM_AMMO_QTY;
Inv_AddAmmo(&g_Lara.magnum_ammo, MAGNUM_AMMO_QTY);
Inv_InsertItem(&g_InvRing_Item_Magnums);
Item_GlobalReplace(O_MAGNUM_ITEM, O_MAGNUM_AMMO_ITEM);
return false;
@ -73,9 +76,9 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_UZI_OPTION:
for (int32_t i = Inv_RequestItem(O_UZI_AMMO_ITEM); i > 0; i--) {
Inv_RemoveItem(O_UZI_AMMO_ITEM);
g_Lara.uzi_ammo.ammo += UZI_AMMO_QTY;
Inv_AddAmmo(&g_Lara.uzi_ammo, UZI_AMMO_QTY);
}
g_Lara.uzi_ammo.ammo += UZI_AMMO_QTY;
Inv_AddAmmo(&g_Lara.uzi_ammo, UZI_AMMO_QTY);
Inv_InsertItem(&g_InvRing_Item_Uzis);
Item_GlobalReplace(O_UZI_ITEM, O_UZI_AMMO_ITEM);
return false;
@ -84,9 +87,9 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_HARPOON_OPTION:
for (int32_t i = Inv_RequestItem(O_HARPOON_AMMO_ITEM); i > 0; i--) {
Inv_RemoveItem(O_HARPOON_AMMO_ITEM);
g_Lara.harpoon_ammo.ammo += HARPOON_AMMO_QTY;
Inv_AddAmmo(&g_Lara.harpoon_ammo, HARPOON_AMMO_QTY);
}
g_Lara.harpoon_ammo.ammo += HARPOON_AMMO_QTY;
Inv_AddAmmo(&g_Lara.harpoon_ammo, HARPOON_AMMO_QTY);
Inv_InsertItem(&g_InvRing_Item_Harpoon);
Item_GlobalReplace(O_HARPOON_ITEM, O_HARPOON_AMMO_ITEM);
return false;
@ -95,9 +98,9 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_M16_OPTION:
for (int32_t i = Inv_RequestItem(O_M16_AMMO_ITEM); i > 0; i--) {
Inv_RemoveItem(O_M16_AMMO_ITEM);
g_Lara.m16_ammo.ammo += M16_AMMO_QTY;
Inv_AddAmmo(&g_Lara.m16_ammo, M16_AMMO_QTY);
}
g_Lara.m16_ammo.ammo += M16_AMMO_QTY;
Inv_AddAmmo(&g_Lara.m16_ammo, M16_AMMO_QTY);
Inv_InsertItem(&g_InvRing_Item_M16);
Item_GlobalReplace(O_M16_ITEM, O_M16_AMMO_ITEM);
return false;
@ -106,9 +109,9 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_GRENADE_OPTION:
for (int32_t i = Inv_RequestItem(O_GRENADE_AMMO_ITEM); i > 0; i--) {
Inv_RemoveItem(O_GRENADE_AMMO_ITEM);
g_Lara.grenade_ammo.ammo += GRENADE_AMMO_QTY;
Inv_AddAmmo(&g_Lara.grenade_ammo, GRENADE_AMMO_QTY);
}
g_Lara.grenade_ammo.ammo += GRENADE_AMMO_QTY;
Inv_AddAmmo(&g_Lara.grenade_ammo, GRENADE_AMMO_QTY);
Inv_InsertItem(&g_InvRing_Item_Grenade);
Item_GlobalReplace(O_GRENADE_ITEM, O_GRENADE_AMMO_ITEM);
return false;
@ -116,7 +119,7 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_SHOTGUN_AMMO_ITEM:
case O_SHOTGUN_AMMO_OPTION:
if (Inv_RequestItem(O_SHOTGUN_ITEM)) {
g_Lara.shotgun_ammo.ammo += 12;
Inv_AddAmmo(&g_Lara.shotgun_ammo, SHOTGUN_AMMO_QTY);
} else {
Inv_InsertItem(&g_InvRing_Item_ShotgunAmmo);
}
@ -125,7 +128,7 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_MAGNUM_AMMO_ITEM:
case O_MAGNUM_AMMO_OPTION:
if (Inv_RequestItem(O_MAGNUM_ITEM)) {
g_Lara.magnum_ammo.ammo += 40;
Inv_AddAmmo(&g_Lara.magnum_ammo, MAGNUM_AMMO_QTY);
} else {
Inv_InsertItem(&g_InvRing_Item_MagnumAmmo);
}
@ -134,7 +137,7 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_UZI_AMMO_ITEM:
case O_UZI_AMMO_OPTION:
if (Inv_RequestItem(O_UZI_ITEM)) {
g_Lara.uzi_ammo.ammo += 80;
Inv_AddAmmo(&g_Lara.uzi_ammo, UZI_AMMO_QTY);
} else {
Inv_InsertItem(&g_InvRing_Item_UziAmmo);
}
@ -143,7 +146,7 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_HARPOON_AMMO_ITEM:
case O_HARPOON_AMMO_OPTION:
if (Inv_RequestItem(O_HARPOON_ITEM)) {
g_Lara.harpoon_ammo.ammo += 3;
Inv_AddAmmo(&g_Lara.harpoon_ammo, HARPOON_AMMO_CLIP);
} else {
Inv_InsertItem(&g_InvRing_Item_HarpoonAmmo);
}
@ -152,7 +155,7 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_M16_AMMO_ITEM:
case O_M16_AMMO_OPTION:
if (Inv_RequestItem(O_M16_ITEM)) {
g_Lara.m16_ammo.ammo += 40;
Inv_AddAmmo(&g_Lara.m16_ammo, M16_AMMO_QTY);
} else {
Inv_InsertItem(&g_InvRing_Item_M16Ammo);
}
@ -161,7 +164,7 @@ bool Inv_AddItem(const GAME_OBJECT_ID obj_id)
case O_GRENADE_AMMO_ITEM:
case O_GRENADE_AMMO_OPTION:
if (Inv_RequestItem(O_GRENADE_ITEM)) {
g_Lara.grenade_ammo.ammo += 2;
Inv_AddAmmo(&g_Lara.grenade_ammo, GRENADE_AMMO_QTY);
} else {
Inv_InsertItem(&g_InvRing_Item_GrenadeAmmo);
}

View file

@ -266,27 +266,27 @@ static void M_DrawAmmoInfo(void)
char buffer[128] = "";
switch (g_Lara.gun_type) {
case LGT_MAGNUMS:
sprintf(buffer, "%5d", g_Lara.magnum_ammo.ammo);
sprintf(buffer, "%6d", g_Lara.magnum_ammo.ammo);
break;
case LGT_UZIS:
sprintf(buffer, "%5d", g_Lara.uzi_ammo.ammo);
sprintf(buffer, "%6d", g_Lara.uzi_ammo.ammo);
break;
case LGT_SHOTGUN:
sprintf(buffer, "%5d", g_Lara.shotgun_ammo.ammo / 6);
sprintf(buffer, "%6d", g_Lara.shotgun_ammo.ammo / 6);
break;
case LGT_M16:
sprintf(buffer, "%5d", g_Lara.m16_ammo.ammo);
sprintf(buffer, "%6d", g_Lara.m16_ammo.ammo);
break;
case LGT_GRENADE:
sprintf(buffer, "%5d", g_Lara.grenade_ammo.ammo);
sprintf(buffer, "%6d", g_Lara.grenade_ammo.ammo);
break;
case LGT_HARPOON:
sprintf(buffer, "%5d", g_Lara.harpoon_ammo.ammo);
sprintf(buffer, "%6d", g_Lara.harpoon_ammo.ammo);
break;
default: