Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inventory: limit max item quantities to prevent crashing #2554

Merged
merged 1 commit into from
Mar 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/tr1/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
- added support for custom levels to use `disable_floor` in the gameflow, similar to TR2's Floating Islands (#2541)
- changed the Controls screen to hide the reset and unbind texts when changing a key (#2103)
- 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)
Expand Down
1 change: 1 addition & 0 deletions docs/tr2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,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)
Expand Down
2 changes: 2 additions & 0 deletions src/libtrx/game/console/cmd/give_item.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "game/objects/vars.h"
#include "memory.h"
#include "strings.h"
#include "utils.h"

#include <stdio.h>
#include <string.h>
Expand Down Expand Up @@ -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++;
}

Expand Down
7 changes: 7 additions & 0 deletions src/libtrx/game/inventory.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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)) {
Expand Down
2 changes: 2 additions & 0 deletions src/libtrx/include/libtrx/game/inventory.h
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
4 changes: 3 additions & 1 deletion src/libtrx/include/libtrx/game/inventory_ring/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#include <stdint.h>

#define MAX_QTY 999999

typedef struct {
int16_t shape;
XYZ_16 pos;
Expand Down Expand Up @@ -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;

Expand Down
21 changes: 12 additions & 9 deletions src/tr1/game/inventory.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
}
}
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -69,17 +72,17 @@ 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;

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);
}
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand Down
8 changes: 4 additions & 4 deletions src/tr1/game/overlay.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
39 changes: 21 additions & 18 deletions src/tr2/game/inventory.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}
}
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -106,17 +109,17 @@ 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;

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);
}
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand Down
12 changes: 6 additions & 6 deletions src/tr2/game/overlay.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down