[✓][BUG][PL] Zombie levels can soft-lock after using the nuke

Started by Armani, August 25, 2026, 06:17:16 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Armani

This bug, although I don't intentionally try to reproduce it, pops up regularly by accident. I went ahead and fixed it myself for my copy, but I thought I'd better report it since it happens quite often in levels featuring zombies.

Setup:
Activate the nuke while the next lemming still queued to spawn is a pre-assigned zombie.

Expected outcome:
Once all lemmings die, the level ends and transitions to the postview screen.

What actually happens:
You get soft-locked even after all lemmings have died.

Reason:
StateIsUnplayable(basically the level-end check) treats a nuked level as still playable if UserSetNuking and CheckIfZombiesRemain are true, which is fine. However, CheckIfZombiesRemain(which only ever gets evaluated when UserSetNuking is already true) also checks the next lemming still queued to spawn and whether it was a pre-assigned zombie. It then keeps checking whether that permanently frozen queue slot(due to the nuke) happens to be a zombie, and reports that "a zombie remains" for a lemming that can no longer exist, causing StateIsUnplayable to remain permanently false.

Fix:
Just remove the spawn-queue-peek block so that it only considers zombies that are actually alive in the level at that moment. Its sole consumer is StateIsUnplayable, which in turn only determines whether the level should end, so there should be no physics side effects.
My upcoming NeoLemmix level pack: In-development topic 8-)

My NeoLemmix level packs(in chronological order):
  Lemmings Uncharted
  Xmas Lemmings 2021
  Lemmings Halloween 2023
  Holiday Lemmings 2024 - a collaboration pack with Mobiethian :D

WillLem

Thanks for the heads up and the suggested fix.

Just to double check, you are referring to the second block in CheckIfZombiesRemain?

function TLemmingGame.CheckIfZombiesRemain: Boolean;
var
  i: Integer;
  ReleaseOffset: Integer;
begin
  Result := True;

  for i := 0 to LemmingList.Count-1 do
    if LemmingList[i].LemIsZombie and not LemmingList[i].LemRemoved then
      Exit;

=============== FROM HERE =================

  ReleaseOffset := 0;
  if (LemmingsToRelease - ReleaseOffset > 0) then
  begin
    i := Level.Info.SpawnOrder[Level.Info.LemmingsCount - Level.PreplacedLemmings.Count - LemmingsToRelease + ReleaseOffset];
    if i >= 0 then
      if Gadgets[i].IsPreassignedZombie then
        Exit;
  end;

============== TO HERE ==============

  Result := False;
end;

Removing the second block fixes the bug, but just wanted to make sure that's exactly what you meant.

WillLem

Added a Nuke status check to the second block. This fixes the bug but keeps the pre-assigned check available should it prove to be necessary for any reason.

Fixed in NLCEPlayer commit 636fdeb.