Community
SCI Programming => SCI Syntax Help => Topic started by: doomlazer on January 07, 2026, 06:27:37 PM
-
What's the purpose of the solitary vaules such as this from QfGIV rm340 (https://github.com/EricOakford/SCI-Decompilation-Archive/blob/36f8aeb4a2f6e5ec95eec91e12810bbef55357ba/qfg4cd/src/rm340.sc#L690):
(method (changeState newState)
(switch (= state newState)
(0
0 ; THE VALUE IN QUESTION
(theGame handsOff:)
(if (and (== (barrel x?) 116) (not (Btst 254)))
(self changeState: 6)
else
(= cycles 1)
)
)
...
I've looked at 'setScript' and some other possibilities and maybe it's setting the register value or something, but found nothing conclusive. Honestly, it just doesn't make sense to me.
They appear in both EO's and Sluice's decompile repos, so I don't think it's a mistake. Anyone know?
-
I have seen these in Longbow, which was apparently written by some interns. The compiler was lenient enough to allow it, and the final code worked. These interns were named (there are names in the credits you don't see anywhere else). So it's possibly an intern.
-
Ok, that's a satisfying enough explanation for me. TY
-
If I had to make a technical guess, having a bare expression like that might serve to set the PMachine's accumulator.
Now, we don't know what the original code looks like, whatever caused this code
0e69:35 00 ldi 0 //That's him, officer!
0e6b:38 0216 pushi 216 // $216 handsOff
0e6e:76 push0
0e6f:81 01 lag theGame
0e71:4a 0004 send 4but I can imagine why our decompilers would include that mystery value.
Still, all it does is set the accumulator, which is then replaced with a pointer to the game. However it got in there, it does nothing.
-
And the Longbow code I was thinking of is this:
(method (changeState newState &tmp temp0)
(switch (= state newState)
(0
(HandsOff)
(if (not (IsFlag 129))
(NormalEgo)
)
(switch register
(1
(cond
((== local0 220)
(cond
(21
36
37
38
50
56
67
75
98
99
103
115
119
135
167
(if
(and
(> (gEgo x:) 35)
(< (gEgo x:) 150)
)
(= global104 155)
)
)
(
(and
(> (gEgo x:) 170)
(< (gEgo x:) 285)
)
(= global104 165)
)
)
)
This should most likely have been (if (OneOf gForestRoom blah) blah) because there are numerous of those in the script. Typo, cut/paste error, or intern.
-
How the hell is that supposed to work?! I wouldn't know what that's supposed to do if you hadn't brought up the OneOf thing. There's no way that code works the way it supposedly should.
-
One more, from the same script:
(LoadMany
rsVIEW
805
792
764
763
230
231
232
233
234
235
236
237
238
(if (== gDay 2)
214
218
16
4
5
7
585
)
(switch gDisguiseNum
(0 ; outlaw
0
1
2
)
(1 ; beggar
36
37
38
)
(2 ; jewler (no rouge)
29
30
31
)
(3 ; jewler (rouge)
29
30
31
)
(4 ; yeoman
33
34
35
)
(5 ; abbey monk
23
24
27
)
(6 ; fens monk
16
17
18
)
)
)
Someone who knows the PMachine knows that that won't work.
-
Load all of these, and in this particular case also these? Forget the PMachine, that's a script-level mistake.
-
I'm more curious what the original source code looked like that ended up compiling to that. Do any of the games that have had the original code released (there are a few I think, like maybe one of the LSLs?) have logic like that?
-
All I have is Larry, and I'm pretty sure they don't.
The first instance with the same intent as the Longbow example would be LSL1 room 320, where the dancers or comedian and drummer are loaded along with the rest. But those are separate LoadMany calls with some distance between them. Same deal in rooms 350, 370, and 390. Then in LSL5 I see similar constructs all over.
If I were to ascribe to the "silly interns" theory, I'd say they misunderstood how sub-expressions (putting an if or switch in the middle of the argument list for OneOf or LoadMany) works. Clearly, Brian K. Hughes, Juan Carlos Escobar, and John Hartin knew what they were doing (except for BKH messing up the Hollywood sign feature in room 190 lol)
-
Omer hasn't been around, lately. I wonder if he has any of the original sources in question.
-
Just for fun, I replicated the basic premise in isolation:
Setup
(procedure (Test)
(TestHelper
1 2 3
(if (== gTest 2)
4 5 6
)
7 8 9
)
)(procedure Test
pushi 7 // argc
push1 // push the first three values to the stack
push2
pushi 3
lsg gTest // push gTest
ldi 2 // load 2 to acc
eq?
bnt nope
ldi 4 // load to acc, not push
ldi 5
ldi 6
nope:
push // push acc to stack
pushi 7 // push the rest
pushi 8
pushi 9
call TestHelper 14
)
Result from TestHelper
When the test fails:
0 = 1
1 = 2
2 = 3
3 = 0 <-- ?
4 = 7
5 = 8
6 = 9When the test succeeds:
0 = 1
1 = 2
2 = 3
3 = 6 <-- !
4 = 7
5 = 8
6 = 9
Takeaways:
1. We try to supply either six or nine items, but only ever push seven values. argc being 7 and the call looking back 14 bytes says as much.
2. If the test fails, we still push whatever is in acc! Values 4 and 5 are wasted.
3. This is not only Technically Valid code, but also even more hilariously broken at runtime than I expected!
-
If this is SCI Companion, the success case seems correct anyway. The value of a section of code is the last thing in that code, so 6 in this case. There should be 7 params, because the if statement resolves to a single param.
Not sure if it's "defined" what the value of a condition expression will be if there is no else, but it seems like it will always be the result of the last acc value that was branched on, 0.
-
I just tried it myself. A switch instead of an if gave the expected, similar results, just with the PMachine equivalent of a switch.
(ListAll
1 2 3
(switch gTest
(0
; Left blank for fun
)
(1
4 5 6
)
)
7 8 9
)Always seven values, and the fourth is either 6 or leftovers.
-
Great. This will be a pattern I use in my own fan mods from now on. :)
-
Of course, one could imagine a pushlist keyword that would actually do this properly. It would only work if the branches of the if/switch all had the same number of elements (as in the disguise part of the above), otherwise an enhancement to the PMachine would be needed. That would be an advanced usage, because it can potentially corrupt the stack.
-
I'm more curious what the original source code looked like that ended up compiling to that. Do any of the games that have had the original code released (there are a few I think, like maybe one of the LSLs?) have logic like that?
Probably used those long defines that Companion doesn't support. Sometimes Sierra had two versions of such defines which were subtly different. Maybe mistaking one for the other?
(or rather, I know that this is it. Some of the other OneOf calls have the exact same list of room numbers. Had to come from a define.)
-
Sluicebox managed to trackdown the cause, at least for the code I originally posted about. It's from using case values with switchTo.
SwitchTo (https://scicompanion.com/Documentation/Compiler/switchto.html) doesn't use case values; adding them compiles fine, but leaves behind the garbage. You can see switchTo was used in the LSL1VGA source with case values (https://github.com/historicalsource/leisure-suit-larry-1-vga/blob/13c82564d95c5253283b3dcf95715750a27af456/SRC/300.SC#L429), which results in the extra values when decompiled (https://github.com/sluicebox/sci-scripts/blob/12c1ab894c4bd5fbf4157eb18a9e86653ec15d1b/lsl1-dos-2.1/src/rm300.sc#L309).
switchTo is used quite a bit in lsl1vga, and not always incorrectly either!
edit: fixed link
-
That's a nice find. And switchto was a late addition to the SCI language, so it makes sense.