LostArtefacts / TRX

Open source re-implementation of Tomb Raider I and Tomb Raider II, along with additional enhancements and bugfixes
https://lostartefacts.dev/
GNU General Public License v3.0
586 stars 38 forks source link

TR1: Exploding mummy kills Lara even when far away #1758

Open absolutelynothinghere opened 4 days ago

absolutelynothinghere commented 4 days ago

Hello again, sorry to bother you with all these issues.

In the TR1 level "Obelisk of Khamoon" there are mummies that explode when killed, dealing damage to Lara unless she is sufficiently far away. In TR1X these mummies always insta-kill Lara even when she is far away.

As you can see in the video below, Lara is standing on one end of a bridge while a mummy stands on the other end, just within her line of fire. When Lara shoots the mummy and it explodes, she immediately dies despite standing far away with full health.

The save file from the video: save_tr1_11.dat.gz

https://github.com/user-attachments/assets/3256a8db-b6a2-43fc-9525-a03ffc8c80db

Richard-L commented 4 days ago

Sadly the video is bugged for me. Mostly just shows black (?)

absolutelynothinghere commented 4 days ago

Ok do either of these videos work?

mummy_bomb_vp9+opus.webm

mummy_bomb_vp9+vorbis.webm

Richard-L commented 4 days ago

Yep, both work. Thanks for updating 👍

lahm86 commented 4 days ago

I can't replicate this with the provided save (or otherwise). Is it the latest build where this happens for you, and is it Windows, Linux or Mac?

Edit: I see it is 4.5.1 from your video.

absolutelynothinghere commented 4 days ago

It's version 4.5.1 on Linux, I compiled it myself using Zig CC. If you'd like the library versions used I can put together a list.

My executable is here: TR1X.gz

absolutelynothinghere commented 4 days ago

Update: I just recompiled version 4.5.1 with no optimizations (-O0) and the problem seems to have been fixed... I guess that helps?

yoqto commented 4 days ago

I threw your binary into a docker container and can confirm Lara dying with your binary. My local build with GCC 14.2.1 and -O3 does not kill Lara when the mummy goes down on your save. So it seems your compiler is messing up in some of its optimizations.

absolutelynothinghere commented 4 days ago

That makes sense, thank you. The problem persisted with -O2 and even -O1 so I suppose -O0 is the way to go...

rr- commented 4 days ago

Let's keep this open. We can't have platform-dependent arithmetic in our code.

yoqto commented 2 days ago

Beware, armchair debugging:

Declaring the distance parameter of Item_IsNearItem as uint32_t lets Lava live when built with any of the three compilers on my machine. Hope this helps?!

rr- commented 1 day ago

Thank you @yoqto that is really helpful! We'll aim to include a fix in the next release.

absolutelynothinghere commented 1 day ago

I tried the solution described by @yoqto and it indeed solves the problem!

Here's a patch for TR1X 4.5.1:

--- a/src/tr1/game/items.c
+++ b/src/tr1/game/items.c
@@ -314,7 +314,7 @@
     return changed;
 }

-bool Item_IsNearItem(const ITEM *item, const XYZ_32 *pos, int32_t distance)
+bool Item_IsNearItem(const ITEM *item, const XYZ_32 *pos, uint32_t distance)
 {
     int32_t x = pos->x - item->pos.x;
     int32_t y = pos->y - item->pos.y;
--- a/src/tr1/game/items.h
+++ b/src/tr1/game/items.h
@@ -25,7 +25,7 @@
 int32_t Item_GlobalReplace(
     GAME_OBJECT_ID src_object_id, GAME_OBJECT_ID dst_object_id);

-bool Item_IsNearItem(const ITEM *item, const XYZ_32 *pos, int32_t distance);
+bool Item_IsNearItem(const ITEM *item, const XYZ_32 *pos, uint32_t distance);
 bool Item_Test3DRange(int32_t x, int32_t y, int32_t z, int32_t range);
 bool Item_TestBoundsCollide(ITEM *src_item, ITEM *dst_item, int32_t radius);
 bool Item_TestPosition(
rr- commented 1 day ago

I tried the solution described by @yoqto and it indeed solves the problem!

Here's a patch for TR1X 4.5.1:

--- a/src/tr1/game/items.c
+++ b/src/tr1/game/items.c
@@ -314,7 +314,7 @@
     return changed;
 }

-bool Item_IsNearItem(const ITEM *item, const XYZ_32 *pos, int32_t distance)
+bool Item_IsNearItem(const ITEM *item, const XYZ_32 *pos, uint32_t distance)
 {
     int32_t x = pos->x - item->pos.x;
     int32_t y = pos->y - item->pos.y;
--- a/src/tr1/game/items.h
+++ b/src/tr1/game/items.h
@@ -25,7 +25,7 @@
 int32_t Item_GlobalReplace(
     GAME_OBJECT_ID src_object_id, GAME_OBJECT_ID dst_object_id);

-bool Item_IsNearItem(const ITEM *item, const XYZ_32 *pos, int32_t distance);
+bool Item_IsNearItem(const ITEM *item, const XYZ_32 *pos, uint32_t distance);
 bool Item_Test3DRange(int32_t x, int32_t y, int32_t z, int32_t range);
 bool Item_TestBoundsCollide(ITEM *src_item, ITEM *dst_item, int32_t radius);
 bool Item_TestPosition(

I'm glad to hear that the solution worked for you! We might explore a slightly different approach for the final solution, however; likely something akin to what we do in Math_GetVectorAngles, since an additional 1 bit of precision might still not be enough for larger level geometries.