Opened 2 years ago

Closed 2 years ago

Last modified 2 years ago

#13367 closed defect (fixed)

SCUMM: Loom (EGA) - Bobbin as Rusty can exit the cell when the door is locked

Reported by: antoniou79 Owned by: eriktorbjorn
Priority: normal Component: Engine: SCUMM
Version: Keywords: glitch, blacksmiths
Cc: Game: Loom

Description

This in on Windows 10 x64, with a recent local build from HEAD master of 2.6.0git, testing with LOOM DOS EGA, using the orchestral audio feature.

For this I've applied the patch for the MT-32 upgrade to LOOM and set my Audio settings for the game to use "MT-32 emulator" as Music device. You may also need to do that for the attached save game to work.

How to reproduce:
At the Blacksmiths' Guild enter the room where Stokes waits Rusty to scold him, and watch the full cutscene until he puts Rusty/Bobbin into the prison cell. Then click on the door (Bobbin will comment that it's locked and he does not have a distaff). Keep clicking on the door -- maybe towards the bottom part of the door.

What happens:
Rusty/Bobbin will appear outside the cell. He can then walk around the Guild and go downstairs, listen to the conversation of the foreman with Bishop, but since he does not have his distaff there's nothing to do. He can go back into the cell, and this time the door will be locked and the glitch will no longer happen (as far as I've tested)

What should happen:
It should not be possible for Rusty/Bobbin to exit the cell while the door is locked.

Notes: If you skip the cutscene with Esc (cutscene skip key) then Bobbin seems to not be able to exit the cell (so the glitch does not happen). If you just skip lines of dialogue with the '.' key (dialogue line skip) the glitch will happen.

I'm including a save game at the point of entering the room with Stokes, and a screenshot showing Rusty/Bobbin outside the cell.

Attachments (5)

loom-ega.s62 (14.1 KB ) - added by antoniou79 2 years ago.
scummvm-loom-ega-00016.png (31.8 KB ) - added by antoniou79 2 years ago.
loom-ega.s07 (10.6 KB ) - added by eriktorbjorn 2 years ago.
loom-ega.s15 (14.4 KB ) - added by eriktorbjorn 2 years ago.
loom-saves.zip (59.1 KB ) - added by eriktorbjorn 2 years ago.

Download all attachments as: .zip

Change History (27)

by antoniou79, 2 years ago

Attachment: loom-ega.s62 added

by antoniou79, 2 years ago

Attachment: scummvm-loom-ega-00016.png added

comment:1 by athrxx, 2 years ago

This is very weird. It probably isn't an ordinary walk (box) bug, since it seems to depend on variables which get set or not. But I have yet to manage to reproduce this...

comment:2 by antoniou79, 2 years ago

Here's a short video I made quickly with the issue:
https://youtu.be/ImVAOR65fRQ

comment:3 by eriktorbjorn, 2 years ago

That seems to be the wrong savegame: When I load it, "Rusty" is already outside the cell, and Stoke is nowhere to be seen.

by eriktorbjorn, 2 years ago

Attachment: loom-ega.s07 added

comment:4 by eriktorbjorn, 2 years ago

I've attached my own savegame in the cell. I can reproduce the bug by clicking at the coordinates 90,125.

by eriktorbjorn, 2 years ago

Attachment: loom-ega.s15 added

comment:5 by eriktorbjorn, 2 years ago

I've also attached a savegame right before the confrontation with Stoke. Skipping the cutscene does indeed seem to make so the bug can't be reproduced.

comment:6 by antoniou79, 2 years ago

sorry about the mixup with the saved games. I have the one before the confrontation too, but since eriktorbjorn already posted one, there's probably no reason to post mine.

by eriktorbjorn, 2 years ago

Attachment: loom-saves.zip added

comment:7 by eriktorbjorn, 2 years ago

I don't know if it's of any use, but I've attached a set of savegames from the original interpreter. It doesn't cover the entire game, since I had only played up to the point where you encounter the shepherds. So I went from there and created a few more savegames up to the point where you're in the cell.

comment:8 by athrxx, 2 years ago

Thanks for attaching the correct savegame. Do you happen to know whether this is a regression? Or something we have been carrying around all the time?

comment:9 by eriktorbjorn, 2 years ago

If using the "room 37" debugger command is a realistic test, it seems to go back to at least ScummVM 1.3.0. (I wasn't able to compile 1.0.0, and I didn't try the versions in between.)

comment:10 by eriktorbjorn, 2 years ago

I think the problem is something it does to object 623.

If I watch the Stoke cutscene, it will call putClass(623, 24, 0).
If I skip the Stoke cutscene, it will call putClass(623, 24, 1).

If I force the last parameter to 1, I can no longer escape from the cell.

I guess object 623 represents the open door, and class 24 apparently tells whether or not the object is untouchable.

So it makes sense that the door is set to open as Stoke leads you into the cell, but surely it should be set to closed when he leaves?

comment:11 by eriktorbjorn, 2 years ago

It also seems like Var[216 Bit 3] is used to hold the door state, with 1 for open and 0 for closed. It does indeed set it to 0 when Stoke leaves (see script-86.dmp), but it doesn't set the object class there.

I'm not sure what's going on here.

comment:12 by eriktorbjorn, 2 years ago

Well, I'll be... It turns out that I can reproduce this with the original interpreter after all.

I can't reproduce it with the Mac version, though, and I can see at least one thing it does differently.

EGA DOS, roomobj-38-623:

Events:
  38 - 0016
[0016] (24) loadRoomWithEgo(602,37,124,77);
[001E] (00) stopObjectCode();
END

EGA Mac, roomobj-38-623 (note that here it's Var[223 Bit 2] that holds the door state)

Events:
  38 - 0016
[0016] (A8) if (Var[223 Bit 2]) {
[001B] (24)   loadRoomWithEgo(602,37,125,77);
[0023] (18) } else {
[0026] (0A)   startScript(204,[]);
[0029] (**) }
[0029] (00) stopObjectCode();
END

VGA DOS, roomobj-38-535 looks like it may be the corresponding script:

Events:
  38 - 0018
[0018] (A8) if (Bit[35]) {
[001D] (24)   loadRoomWithEgo(528,37,125,77);
[0025] (18) } else {
[0028] (0A)   startScript(204,[]);
[002B] (**) }
[002B] (00) stopObjectCode();
END

I'm not sure what the FM Towns and TurboGrafx-16 version do. I can never remember the correct descumm parameters. I don't have the Amiga or Atari ST versions.

Last edited 2 years ago by eriktorbjorn (previous) (diff)

comment:13 by eriktorbjorn, 2 years ago

Possible workaround, though I've only given it a quick test with the English DOS EGA version so it's merely proof-of-concept. Maybe there's some better way:

diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp
index ba5545ccd01..6ebdd1f7d52 100644
--- a/engines/scumm/script_v5.cpp
+++ b/engines/scumm/script_v5.cpp
@@ -1479,6 +1479,22 @@ void ScummEngine_v5::o5_loadRoomWithEgo() {
        obj = getVarOrDirectWord(PARAM_1);
        room = getVarOrDirectByte(PARAM_2);
 
+       // WORKAROUND: Bug #13367. In the EGA DOS version, it's possible to
+       // walk through the closed cell door, if you click on the ground just
+       // below it. This is because while the door is closd when Stoke leaves
+       // the room, the open door object is not set to untouchable.
+       //
+       // Later versions work around this by adding code to the object's
+       // script to check if the door is open or not. That's the fix we
+       // emulate here.
+
+       if (_game.id == GID_LOOM && _game.version == 3 && _game.platform == Common::kPlatformDOS && _currentRoom == 38 && vm.slot[_currentScript].number == 623 && !readVar(36339)) {
+               fetchScriptWordSigned();
+               fetchScriptWordSigned();
+               runScript(204, false, false, nullptr);
+               return;
+       }
+
        a = derefActor(VAR(VAR_EGO), "o5_loadRoomWithEgo");
 
        a->putActor(room);
Last edited 2 years ago by eriktorbjorn (previous) (diff)

comment:14 by eriktorbjorn, 2 years ago

Here's another possible workaround. This one won't fix old savegames, but on the other hand the behavior of clicking on the ground beneath the door is a bit more consistent, i.e. nothing happens while the door is closed.

diff --git a/engines/scumm/script_v3.cpp b/engines/scumm/script_v3.cpp
index f9473a7ee4a..e97b6b7c672 100644
--- a/engines/scumm/script_v3.cpp
+++ b/engines/scumm/script_v3.cpp
@@ -46,6 +46,18 @@ void ScummEngine_v3::o3_setBoxFlags() {
        a = getVarOrDirectByte(PARAM_1);
        b = fetchScriptByte();
        setBoxFlags(a, b);
+
+       // WORKAROUND: When Stoke leaves Bobbin in the cell, the door is closed
+       // but the open door object is not set as untouchable. That means you
+       // can walk straight through the door, if you click on the ground just
+       // below it.
+       //
+       // We work around this by making the object untouchable when the walk
+       // boxes are adjusted by the script.
+
+       if (_game.id == GID_LOOM && _game.version == 3 && _game.platform == Common::kPlatformDOS && vm.slot[_currentScript].number == 86 && a == 0 && b == 128) {
+               putClass(623, 24, 1);
+       }
 }
 
 void ScummEngine_v3::o3_waitForActor() {
Last edited 2 years ago by eriktorbjorn (previous) (diff)

comment:15 by eriktorbjorn, 2 years ago

To clarify, with the first workaround you can click on the ground below the door and Bobbin will say "Locked. And me without a distaff." This is what the Mac version does.

With the second workaround, Bobbin will walk to the door but he won't say anything. This is how the game works (even the Mac version!) after you've slept in the cell and wake up to find the distaff. (Probably because now the room's entry script will see that the door is closed, and make the door object untouchable.)

So it really depends on which, if any, of these two behaviors we want to emulate.

The case for the first one is that it emulates the behavior of an official LucasArts version of the game, albeit one that I'd guess almost no one plays nowadays.

The case for the second one is that it makes the behavior the same both before and after the sleeping cutscene.

comment:16 by eriktorbjorn, 2 years ago

Another clarification: The first workaround attaches itself to roomobj-38-623, which is quoted in its entirety in a comment above. It depends on knowing which variable holds the door state. Hopefully that's the same in all affected versions. (The Mac version, as noted, uses a different one.)

The second workaround attaches itself to this piece of script-86:

[04BB] (14) print(5,[Center(),Pos(160,152),Text("And I won't be alone.")]);
[04DA] (AE) WaitForMessage();
[04DC] (80) breakHere();
[04DD] (36) walkActorToObject(5,609);
[04E1] (AE) WaitForActor(5);
[04E4] (2D) putActorInRoom(5,0);
[04E7] (1A) Var[214 Bit 1] = 0;
[04EC] (1A) Var[216 Bit 3] = 0;
[04F1] (A8) if (VAR_OVERRIDE) {
[04F6] (11)   animateCostume(5,255);
[04F9] (11)   animateCostume(1,255);
[04FC] (11)   animateCostume(1,248);
[04FF] (2D)   putActorInRoom(1,38);
[0502] (01)   putActor(1,196,132);
[0508] (08)   if (VAR_ROOM != 38) {
[050F] (72)     loadRoom(38);
[0511] (32)     setCameraAt(160);
[0514] (**)   }
[0514] (**) }
[0514] (2D) putActorInRoom(5,0);
[0517] (07) setState(618,0);
[051B] (5D) setClass(616,[152]);
[0522] (5D) setClass(617,[24]);
[0529] (30) SetBoxUnknown00;
[052B] (80) breakHere();
[052C] (05) drawObject(614,255,255);
[0533] (80) breakHere();
[0534] (14) print(1,[Center(),Pos(160,Var[166]),Text()]);
[053E] (80) breakHere();
[053F] (C0) endCutscene();
[0540] (A0) stopObjectCode();
END

I'm a bit wary of tying the workaround to "SetBoxUnknown00". Maybe I should tie it to the script ending instead?

Last edited 2 years ago by eriktorbjorn (previous) (diff)

comment:17 by eriktorbjorn, 2 years ago

I could be wrong, but I get the impression that

  • The TurboGrafx-16 version seems to use the second workaround.
  • The FM Towns version may actually be using both, but the second takes precedence.
  • The VGA talkie version seems to use the first workaround.

comment:18 by eriktorbjorn, 2 years ago

It's been confirmed by einentei that the Amiga version has the same bug as the EGA DOS version.

Version 0, edited 2 years ago by eriktorbjorn (next)

comment:19 by eriktorbjorn, 2 years ago

Alternative version of workaround 1 that doesn't depend on knowing which variable holds the door state. On the other hand, you have to know two object numbers instead of one. But I think it's kind of elegant anyway:

diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp
index ba5545ccd01..aaa6a68a491 100644
--- a/engines/scumm/script_v5.cpp
+++ b/engines/scumm/script_v5.cpp
@@ -1056,7 +1056,34 @@ void ScummEngine_v5::o5_findObject() {
        getResultPos();
        int x = getVarOrDirectByte(PARAM_1);
        int y = getVarOrDirectByte(PARAM_2);
-       setResult(findObject(x, y));
+       int obj = findObject(x, y);
+
+       // WORKAROUND: In some versions of Loom, it's possible to walk right
+       // through the closed cell door if you allowed Stoke to lead you into
+       // the cell rather than skipping the cutscene. This is because the open
+       // door (object 623) is made touchable or untouchable by the entry
+       // script, and this flag is not updated when the cutscene latest closes
+       // the door.
+       //
+       // The FM Towns and TurboGrafx-16 versions fix this by making sure the
+       // object is untouchable at the end of the cutscene. The Macintosh and
+       // VGA talkie versions make sure the object script checks if the door
+       // is open. This makes the script identical to the script for the wall
+       // to the left of the door (object 609).
+       //
+       // The difference between these fixes is what happens if you click on
+       // the ground just below the closed door. Of course, once you've been
+       // through the sleep cutscene the entry script will make that object
+       // untouchable so you only have a small window in which to see the bug.
+       //
+       // Since the VGA talkie version (sadly) is the most common these days,
+       // let's go with that fix. But we do it by redirecting the click to the
+       // wall object instead.
+
+       if (_game.id == GID_LOOM && _game.version == 3 && _game.platform == Common::kPlatformDOS && _currentRoom == 38 && obj == 623)
+               obj = 609;
+
+       setResult(obj);

comment:20 by eriktorbjorn, 2 years ago

Owner: set to eriktorbjorn
Resolution: fixed
Status: newclosed

I've committed a slightly updated version of the last workaround. Could you please verify that this fixes the bug for you too in the next daily build?

comment:21 by antoniou79, 2 years ago

I can verify that the fix works for the LOOM EGA DOS. Rusty/Bobbin can no longer get out of the cell by clicking at the closed door.
The click and Bobbin's comment now applies to the whole left wall (and a bit below the door), but as I understand by the comments in the fix, this is intentional.
Looks good to me.

comment:22 by eriktorbjorn, 2 years ago

Yes, that's intentional: Before the sleep cutscene, you can click below the door. After the sleep cutscene, you can't.

It's a bit inconsistent, but it's what happens in the VGA talkie (and the 16 color Mac) version so I figured it made sense to use that behavior rather than that of the rarer FM Towns and TurboGrafx-16 behavior. (It's such a minor difference that it hardly matters anyway.)

Note: See TracTickets for help on using tickets.