Skip to content

Fix boulder chain reaction and mutant egg crash in The Hive - #540

Open
johnhsb wants to merge 2 commits into
XProger:masterfrom
johnhsb:fix/heavy-triggers-and-eggs
Open

johnhsb wants to merge 2 commits into
XProger:masterfrom
johnhsb:fix/heavy-triggers-and-eggs

Conversation

@johnhsb

@johnhsb johnhsb commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

This PR fixes two bugs in The Hive (TR1 Unfinished Business, END2.PHD). One of them also affects Atlantean Stronghold (END.PHD). The causes were found from the crash report and the level data (entities, floor data triggers and the model list).

1. Hanging boulders in the first room: almost all of them fall instead of 1–3

Room 18 with the hanging boulders

Room 18, right after the start room. The red lumps on the ceiling are the boulders.

Symptom

Room 18 has 25 TRAP_BOULDERs in a 5×5 grid, 2048 units above a flat floor (-4608). The floor has 30 PAD trigger sectors (mask 31, no timer, not one-shot), plus 3 more at the entrance of room 19. Each sector activates 1–3 boulders, usually not the one right above it. Stepping on a sector should drop only the boulders linked to it.

In OpenLara, almost all 25 boulders fall and roll at Lara after the first step.

Root cause

A boulder calls game->checkTrigger(this, true) every frame while it rolls. In Lara::checkTrigger():

  • With heavy = true, only the HEAVY case was guarded (if (!heavy) return; for non-heavy callers). Every other trigger type could still be tripped by a heavy object.
  • The PAD check is if (pos.y != info.floor) return;. Here info is read at the heavy object's sector, but pos is Lara's position, because this is a Lara member function. Room 18 has a flat floor, so the check passed whenever Lara stood anywhere on it.

So each rolling boulder tripped every PAD sector it rolled over. That dropped more boulders, which rolled over more PADs, and so on, until the room emptied.

The lava check at the top of the function has the same mix-up: a heavy object over a lava sector would kill Lara if her height matched that floor.

Fix

  • In Lara::checkTrigger(), return early when heavy is set and the trigger is not HEAVY. Heavy objects now trip only the HEAVY triggers meant for them.
  • Run the lava check only for non-heavy calls.

This affects every heavy caller: TrapBoulder, Block, MovingBlock, ThorHammer, GiantMutant, Doppelganger and ScionTarget. All of them now trip only HEAVY triggers.

2. Crash when Lara gets near some mutant eggs

The Hive egg room

The Hive: the area with the mutant eggs (rooms 9, 10 and 13).

Symptom

The game crashes when Lara gets close to some eggs:

EXC_BAD_ACCESS (SIGSEGV) KERN_INVALID_ADDRESS at 0x0000000000000006
0  Animation::initOverrides()          animation.h:64
1  Character::Character(IGame*, int, float)   character.h:68
2  Enemy::Enemy(...)                     enemy.h:79
3  GiantMutant::GiantMutant(IGame*, int) enemy.h:2135
4  Level::initController(int)            level.h:1177
5  Level::addEntity(...)                 level.h:781
6  MutantEgg::update()                   objects.h:1544

Root cause

MutantEgg picks its enemy from the entity code bits: 1 = mutant 2, 2 = centaur, 4 = giant mutant, 8 = mutant 3, anything else = winged mutant. When it hatches, it calls game->addEntity() without checking that the level has a model for that enemy.

Level Giant mutant model Eggs with code 4
The Hive (END2.PHD) missing 22 (rooms 9, 10, 13)
Atlantean Stronghold (END.PHD) missing 8 (room 18)

addEntity() then sets modelIndex = 0, and getModel() returns NULL. The GiantMutant constructor reaches Animation::initOverrides(), which reads model->mCount at offset 6 of a NULL pointer. That matches the faulting address 0x6.

Fix

In MutantEgg::update(), still shatter the egg, but call addEntity() only when level->getModelIndex(enemy) is non-zero. Eggs whose enemy has no model in the level now hatch empty instead of crashing.

Testing

  • macOS (OpenGL) build.
  • The Hive, room 18: each PAD step drops only the 1–3 boulders linked to it.
  • The Hive, rooms 9, 10 and 13: the giant mutant eggs hatch empty, and the other eggs still spawn their mutants. No crash.

🤖 Generated with Claude Code

johnhsb and others added 2 commits October 14, 2026 23:45
Lara::checkTrigger() let heavy objects (boulders, blocks, enemies) trip
any trigger type except the ones guarded explicitly. PAD triggers even
compared Lara's height with the floor of the sector under the object, so
a rolling boulder tripped every pad it passed while Lara stood on the
same floor. In The Hive (room 18) this chained until almost all 25
hanging boulders fell, instead of the 1-3 linked to the pad Lara stepped
on. The lava check had the same mix-up and could kill Lara when a heavy
object was over lava at her height.

As in the original, heavy objects now trip heavy triggers only, and the
lava check runs only for Lara.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MutantEgg spawned its enemy without checking that the level has a model
for it. The Hive has 22 eggs (and Atlantean Stronghold 8) coded to spawn
a giant mutant, which neither level contains, so the egg crashed the game
in Animation::initOverrides() on a NULL model. As in the original (and
TRX), the egg now still shatters but spawns nothing in that case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant