Jump to content

Home

What SCUMM actually looked like


Serge

Recommended Posts

Yeah, but to manage expectations just a bit, Aric has been trying that for almost a decade. 🙂 But yeah, I hope he succeeds at it. There's a lot of historically important stuff in there, and - outside of Aric's archive, which I'm pretty damn sure is well maintained and cared for - it's not guaranteed to last forever.

 

A lot of stuff is still on backup tapes and floppy disks, and those get corrupted. And all of it is often very unstructured - random backups etc. Due to the various ways SCUMM built projects incrementally, and the way revisions were manually merged, developers may think they have a complete archive, although they're actually missing files or have old versions of them (of course, those old versions can, in themselves, be interesting from a history perspective). This new SCUMM Decompiler actually started with the goal of restoring a (thankfully) few corrupted and missing FLEM and BYLE files for one specific case.

 

Fingers crossed. 😁

  • Chef's Kiss 1
Link to comment
Share on other sites

10 minutes ago, Rolfe1 said:

SCUMM (Script Creation Utility for Maniac Mansion) was a game engine developed by Lucasfilm Games (later LucasArts) in the 1980s. Visually, SCUMM was a text-based scripting language with a command-line interface, allowing game designers to create and control interactive elements in classic point-and-click adventure games like Maniac Mansion and Monkey Island.

 

 

Wow, I didn't know we had a resident SCUMM expert that definitely isn't an AI in our midsts.

  • Haha 1
Link to comment
Share on other sites

Just another update of the Woodtick script: Script calls now use the proper types (i.e. room names rather than numbers when calling woodtick-music-control) - and inventory icons also got their proper names rather than numbers. ETA: Plus early work on sound-kludge/iMUSE

Edited by Serge
Link to comment
Share on other sites

Probably the last update for a while - but the decompiler now mostly does iMUSE properly. Which means the Woodtick script is dangerously close to the original script, other than:

  • Label and non-standard chore names
  • loc-0 in a single verb
  • No comments, obviously.
  • Some numeric constants (like break-here counts or x/y positions) that had defined names or short macros at the top rather than being written literally in the commands.
  • Generally, dialog trees - like Guybrush's dialogue with Largo - would be included from a separate script file.
  • Macros - i.e., some single line macro calls - like set-dialog - are inlined in their "full glory" here.

Here it is (same place as earlier versions): https://gist.github.com/Jither/077e9e90ad4d4f30127f2eddc3730fdb

 

But yes, this (particularly the code in woodtick-music-control) is what scripting iMUSE in MI2 looked like. There's one example of a macro in there:

 

start-sound woodtick-theme
flush-sound-q

 

... which had a shorter quick-start-sound woodtick-theme macro. Other than that, the iMUSE calls are identical to how they originally looked.

 

Very short iMUSE scripting primer

All iMUSE commands could either be called immediately, or queued to be called later. The latter was used for e.g. waiting for a cue marker (trigger) in the MIDI data before calling a command. So, e.g. q-sound-trigger woodtick 1 would block the queue until trigger 1 was reached in the music - then the next command in the queue (added with q-sound-command) would immediately be called.

 

Somewhat in the "reverse" direction, hooks were conditional commands stored within the MIDI data - calling set-hook from SCUMM would enable a specific hook, so that it would be triggered when the playback reached it, e.g. jumping to a different place in the music, enabling or disabling parts (instruments) or even transposing the music to a different key.

 

For a possibly slightly more intuitive (and full) view of the implementation of the music in Woodtick, here's the music-related parts (including scripting from other rooms in Woodtick) - rewritten in MUSK. MUSK is my own SCUMM-like language that makes iMUSE more of a first class citizen with some syntax constructs dedicated to it - for use in the iMUSE Sequencer. 🙂

 

https://github.com/Jither/iMUSE-Sequencer/blob/main/ImuseSequencer/Scripts/woodtick.musk

Edited by Serge
  • Like 1
  • Thanks 1
Link to comment
Share on other sites

  • 2 weeks later...

Ah well, one more update...

 

Early macro "compression" is implemented (along with a ton of other stuff - including label annotations). The macro "compression" restores those set-dialog calls that make things a whole lot more readable (it also restores a lot of other macro calls, although not all of them yet).

 

Also updated my SCUMM syntax highlighter and turned it into a small web app, which also makes for a much more enjoyable reading experience. 😉

 

So, here's an updated Woodtick script:

https://scumm.jither.net/?Jither/077e9e90ad4d4f30127f2eddc3730fdb

 

And as a bonus, a half-done script from my "complete Fate of Atlantis annotations" project. It looks a bit scary towards the top, because this particular room also includes the entire scripting for fighting in FOA. And although all that kind of "low level" stuff can also be done in SCUMM, it's sometimes a bit verbose about it... Also, haven't quite grogged how the crate moving works, so that part (and other parts toward the bottom of this very long script) are a bit rough in terms of naming, still...

 

Fate of Atlantis - New York Street

https://scumm.jither.net/?Jither/4f98f905073d408deb89ed8b8b42fe0f

 

 

  • Like 1
  • Thanks 2
  • Chef's Kiss 1
Link to comment
Share on other sites

On 7/3/2023 at 6:20 PM, rzil said:

Also, I haven't managed to figure out how the instructions for using colon, plus and comma in say-line until your example, so thanks again.

 

Just remembered this one. Note that there are a few places where you might see multiple of those line-concatenators in a row - e.g. in the MI2 end credits. My decompiler currently output them like this:

 

https://scumm.jither.net/?Jither/5c3c0dfe9484834ca1ec91c2898da759


Comma followed by plus. That's perfectly serviceable for reading - and makes sense - but I'm relatively sure it wouldn't be compilable. The actual scripts were written with a literal 0xfe 0x01 at the end of the string, and only the + outside of it. Just mentioning it for completeness sake, because I was just looking at the end credits again. 🙂 Also worth noting that these characters wouldn't be backslash-escaped in the source file - they'd be written in verbatim. In Borland Brief and codepage 437, that wouldn't look like total garbage, but rather something along the lines of a filled square followed by a smiley (minus the colors here 😉😞

 

"Additional Art■☺️"+

 

The SCUMM5 compiler only supported escaping double-quotes - \" - even if actual double quotes for output in the games were usually written using the backtick `. As far as I recall (but never looked closely), it didn't support escaping the backslash itself either.

 

Another somewhat related thing I never mentioned above - and which is still missing from the decompiled scripts: There's (clearly) no statement separator in SCUMM, other than new-line. Splitting a long statement over multiple lines actually requires "escaping the newline" - i.e. a \ at the end of the line.

Edited by Serge
Link to comment
Share on other sites

The Fate of Atlantis and Woodtick scripts have been updated with a couple of new decompiler features:

 

The macro restoration has become more robust, meaning it can restore more of the macro calls correctly. So, even closer to the original readability. That includes turning:

 

start-sound largo-theme
flush-sound-q

 

... into the original macro call:

 

quick-start-sound largo-theme

 

But more substantially, turning:

 

for foo = 120 to 128 ++ {
   verb foo off
}

verb dialog-up-arrow off
verb dialog-down-arrow off
screen-escape-array = 0, 0, 0, 0, 0, 0, 0, 0, 0
say-screen-escape is 0, 0, 0, 0, 0, 0, 0, 0, 0
cursor off
userput off

 

... which disables the dialog interface when a dialog ends - into the "slightly" more concise original call:

 

cancel-dialog

 

The FOA script also shows quite a few examples of a commonly used macro (although it happens to not be used at all in the Woodtick script) - run-script - which would start a script and then wait for it to finish running before continuing the current script. If you compare to the previous version of the decompiled FOA script, you'll see that the macro just calls start-script and then loops over a call to break-here until the script that was started has stopped running.

 

The other major change in the decompiler is adding declaration of room local variables.

 

A "bit" of an explanation of that one, since it's not actually documented in any (publicly available or otherwise) official documentation of SCUMM:

 

Room local variables

SCUMM (obviously) had support for global variables from the start. The first 50-100 (circa) of these were system variables declared and understood by the compiler and engine - for things like the selected actor, the soundcard, the machine speed, the cursor position, etc. The rest were game specific and declared in SCUMM scripts.

 

Mostly each of these variables had a specific relatively local purpose and were named as such - e.g. something like visited-iceland. A few, however, were reused for all kinds of purposes across scripts - this helped reduce the amount of memory allocated for global variables. The first couple of these - which were already there in Maniac Mansion - were named foo and bar (the latter was renamed around MI1 for possibly obvious reasons - hint: MI1 and MI2 both have a room named bar 😉).

 

Global variables could be integer numbers or arrays (or bits or strings - which had their own dedicated space. In SCUMM 6 - from DOTT - nibble, byte, and word variables were also added).

 

When scripts local to a room were added for Last Crusade, local variables - local to the scripts - were also introduced.

 

However, sometimes (quite often) you need variables that can be shared between all the scripts in a single room, but are still local to that room. Unlike script-local variables, this wasn't implemented as a compiler and engine feature, but rather, was implemented by a bit of (ab)use of functionality provided by the two:

 

Global variables were declared in a dedicated SCUMM script, defining the name of each variable, and the "slot" (just a relative pointer to its location in memory). Using one of two syntaxes:

 

variable selected-actor       @ 1

 

Which would declare that the variable selected-actor would be in slot 1. (This was the typical way the system variables were declared in the script).

 

Or:

 

start-variables 100
variable foo
variable bar
variable some-array[10]
variable visited-iceland

 

Which would place foo in slot 100, bar in slot 101 etc. some-array would simply take up the next 10 slots, 102-111, with visited-iceland being in slot 112.

 

So, in order to add "room local variables", you'd do this:

  1. Add an array to your global variables, named, say, room-local, with, say, 14 items (this was the typical number)
  2. At the top of each room needing room local variables, simply use the above syntax:
    start-variables room-local
    
    variable time-to-nuke-largo
    variable looked-at-money
    variable out-of-money-lines

    ... which would place time-to-nuke-largo at the same slot as room-local - in other words, it would be at the same location in memory as room-local[0]. In a different room, you could then have another set of variables, pointing to the same array.

 

This is exactly what can be seen in the woodtick script (and similarly in the new-york-street script). So, you could have up to 14 variables that were specific to a room, but only took up 14 variable slots of memory across the game.

 

To make it a bit cleaner, another feature was used: Every room in SCUMM can have an enter and exit script, which defines a script to be executed when you enter/exit that room. However, there was also two global enter scripts - and two global exit scripts - assigned during the boot script. Which would be run respectively before and after the individual room's enter/exit scripts - for every room. In one of these, you could place a for loop, which would iterate over the room-local array and set each item to 0. That way, whenever the player entered a new room, the room local variables would start out with a clean, default, 0 value.

 

Just another example - much like the dialog system - of the kind of flexibility SCUMM allowed without actually needing changes to the compiler or interpreter. 🤓

Edited by Serge
  • Like 1
  • Chef's Kiss 3
Link to comment
Share on other sites

  • 3 weeks later...

Another quick example today - not 100% annotated, some scripts and verbs are still unnamed.

 

But to show the flexibility of SCUMM, here's the "logo" room from Last Crusade. This room, like in many of the other games, also contains the boot script as well as the global scripts that handle input, default responses, global scripts for room entry/exit etc. (And yeah, the script from the intro cutscene is also there, even if it takes place in the college halls). It's these scripts that allow a game like Loom to have a completely different interface. The SCUMM sentence building interface with verbs and inventory isn't a SCUMM feature as such - it's implemented *in* SCUMM. The setup concepts in this boot script would pretty much be the same all the way up to CMI.

 

The scripts ending in "build-sentence" are the ones that handle key presses, clicking on verbs or the rest of the screen etc. - in different contexts.

 

The term "verb" in SCUMM has two different meanings, and both meanings are not necessarily what you'd think:

  • In their "visual" meaning, verbs are just text or graphics on screen that can (mostly) be clicked. This means that the inventory items are also "verbs" - as are the arrows to scroll through the inventory, and the sentence line itself. And - as discussed earlier - the dialog choices.
  • In their "non-visual" meaning, verbs are scripts that are owned by a specific game object. They may (and often do) contain scripts that respond to a specific verb used on an object ("open door"). But they can be anything relating to that object. Which is why the choice of inventory icon for objects in later games is also chosen by implementing a verb on the object. Another "verb" sets the "quick-verb" - the verb that's used when right-clicking an object. Verb scripts are also used to define the response when the actor cannot reach an object. Etc. In a way, they allow simple "object oriented programming". The important thing is that they're not restricted to being responses to open/close/talk etc.

 

https://scumm.jither.net/?Jither/036e506282f14a7932d85808e13c7fcc

 

Note that the boot script has a few "special" string assignments for the save/load dialog and error messages. These use string format tokens (%c etc.) that don't follow the standard SCUMM syntax of %token%. I've finally updated the syntax highlighting to support this special case. So if much of the script just displays grey text (because it thinks a string token never ends), clear your cache and reload it. 🙂

Edited by Serge
  • Like 2
  • Thanks 1
Link to comment
Share on other sites

On 8/14/2023 at 11:33 AM, Serge said:

Another quick example today - not 100% annotated, some scripts and verbs are still unnamed.

 

But to show the flexibility of SCUMM, here's the "logo" room from Last Crusade. This room, like in many of the other games, also contains the boot script as well as the global scripts that handle input, default responses, global scripts for room entry/exit etc. (And yeah, the script from the intro cutscene is also there, even if it takes place in the college halls). It's these scripts that allow a game like Loom to have a completely different interface. The SCUMM sentence building interface with verbs and inventory isn't a SCUMM feature as such - it's implemented *in* SCUMM. The setup concepts in this boot script would pretty much be the same all the way up to CMI.

 

The scripts ending in "build-sentence" are the ones that handle key presses, clicking on verbs or the rest of the screen etc. - in different contexts.

 

The term "verb" in SCUMM has two different meanings, and both meanings are not necessarily what you'd think:

  • In their "visual" meaning, verbs are just text or graphics on screen that can (mostly) be clicked. This means that the inventory items are also "verbs" - as are the arrows to scroll through the inventory, and the sentence line itself. And - as discussed earlier - the dialog choices.
  • In their "non-visual" meaning, verbs are scripts that are owned by a specific game object. They may (and often do) contain scripts that respond to a specific verb used on an object ("open door"). But they can be anything relating to that object. Which is why the choice of inventory icon for objects in later games is also chosen by implementing a verb on the object. Another "verb" sets the "quick-verb" - the verb that's used when right-clicking an object. Verb scripts are also used to define the response when the actor cannot reach an object. Etc. In a way, they allow simple "object oriented programming". The important thing is that they're not restricted to being responses to open/close/talk etc.

 

https://scumm.jither.net/?Jither/036e506282f14a7932d85808e13c7fcc

 

Note that the boot script has a few "special" string assignments for the save/load dialog and error messages. These use string format tokens (%c etc.) that don't follow the standard SCUMM syntax of %token%. I've finally updated the syntax highlighting to support this special case. So if much of the script just displays grey text (because it thinks a string token never ends), clear your cache and reload it. 🙂

 

I knew this, but reading about it in more detail is really quite interesting. I've always thought that Last Crusade's interface was one of the major barriers to the game's general enjoyment (that and the random dialogue puzzles). The idea that it could be made to behave like Monkey Island EGA's vastly superior interface is intriguing.

Edited by ThunderPeel2001
Link to comment
Share on other sites

  • 2 months later...
On 7/5/2023 at 4:27 AM, AndywinXp said:

 

Looking forward to that! :D 

Better yet, it'd be great if an IDE for SCUMM games got made. Something similar to SCICompanion and WinAGI. I've been wanting to make basic SCUMM templates for a long time now.

Link to comment
Share on other sites

  • 2 weeks later...

I've managed to put together a list of defines relating to Fate of Atlantis, based on what Serge has provided. Check it out. The decompilation is of the playable demo of the game, which actually has the whole fight and death code present. Crucially, some versions of the demo do not have this code (since it's usually in room 10, which was removed), which results in the game crashing when Indy drowns in room 82. The version which does have this code is Version A (according to DREAMM). Get it here. It's available on ScummVM's site as well, but I've got the precise version here.

Edited by EOakford
Link to comment
Share on other sites

6 minutes ago, EOakford said:

I've managed to put together a list of defines relating to Fate of Atlantis, based on what Serge has provided. Check it out. The decompilation is of the playable demo of the game, which actually has the whole fight and death code present. Crucially, some versions of the demo do not have this code (since it's usually in room 10, which was removed), which results in the game crashing when Indy drowns in room 82. The version which does have this code is Version A (according to DREAMM), and is identified as  Get it here. It's available on ScummVM's site as well, but I've got the precise version here.

 

I'm not in SCUMM Decompiler mode at the moment, but here's its symbols for FOA as they look at the moment, in SCUMM Decompiler's symbol syntax. Still far from complete, but might have some you're missing. Do note that some (like variables and classes) will be missing, simply because this file inherits from symbol files shared between games (see the top "include" directives) - those define common variables, classes, states, verbs, etc.

 

Also note that some of them may not actually be correct, since the first FOA symbols were gathered when the decompiler didn't have a concept of e.g. room local variables.

 

https://gist.github.com/Jither/7ed7b65fb77acc0f3cd2bd28ec4c5a9f

 

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...