Leaderboard
Popular Content
Showing content with the highest reputation on 07/02/23 in all areas
-
Nah, macros are gone (inlined into the script code) when the scripts are compiled - and currently, the decompiler doesn't reconstruct any macros, just leaves the inlined code as is. All the scripts in these very early games are global scripts (ETA: Outside the room definition - the verb scripts aren't global). Later, SCUMM would add local scripts which are automatically stopped when you exit a room. Any room can call a global script (you'll also see the example calling lots of scripts like give-package-to-weird-ed which aren't defined in this room). The guideline was (at least later) to define them in the room where they're most likely to be called (or which has also defined resources the script uses). Of course, you wouldn't want to place a single script in a room stored on disk 2 that's called from a room on disk 1. In this case, the room is "extra global" to the game - it's called from lots of places, depending on where a kid is when they die. But it does have the shared outcome of ending up outside the mansion, at the tombstones. This is a general principle in SCUMM, all the way up to CMI: There are global resources that are needed in many rooms, but they still "belong to" - and are stored - in (mostly) just one of them: The room itself, global scripts, costumes, sounds, character sets (in later games) - and to some extent objects. Although an object could only actually be visible in the room it belonged to - that's also why (when/if I get to releasing other scripts) you'd see that the hamster in Ted's cage is not actually the same hamster as in the microwave (so he really has no reason for getting so angry š). In the end, like almost everything else, the compiler just turns these globals into a number in the scripts that reference it. And then it stores the disk and room number for each resource - and their offset within the room - in an index on each disk. That's the "00.lfl" file, or, in later games e.g. "tentacle.000". When a script somewhere needs one of these resources, it's just looks up in the index and loads the resource from the room where it's stored. The rest of the room isn't loaded, so it doesn't add any overhead, and it could theoretically have been stored anywhere on the disk. Assigning it to a room just gives you a bit of control over where on disk it's stored - a bit of micro management to reduce seeking during disk access.2 points
-
Unfortunately not š - as far as I recall, there are two publicly available SPUTM executables that were compiled in debug mode and with Windex support (windex being SCUMM/SPUTM's debug mode which allows debugging the game on a second, monochrome, monitor): The MI2 non-interactive demo, and the MI2 talkie prototype. Both include a lot of extra info in the EXE - function names etc. - and the Windex debuggers obviously bring a lot of insight into internal terminologies and jargon - the talkie will even output a disassembly of the current script using the original command names, with somewhat accurate command syntax, but obviously more in assembly form than in actual script form. BG has a walkthrough and screenshot of Windex in this excellent article: https://mixnmojo.com/features/sitefeatures/LucasArts-First-Words/2 ETA: "Somewhat accurate command syntax": The Windex debugger just shows the current byte code formatted into strings that - for the convenience of the SCUMMlet - reads somewhat like the original lines. Without a symbol file, much like the decompiler, it doesn't display variable names, actor names, label names, etc. And by the time a SCUMM game had been compiled: loops and conditionals have been turned into jumps ("goto"s) cutscene blocks have been turned into start/end commands break-until has been turned into a loop - and, in turn, into conditional jumps. some commands have been "unrolled" - for example, break-here 17 would turn into simply 17 break-here's in a row if ([some arithmetic]) would have the arithmetic moved out before the if statement: If statements in the final byte code only check a single value in a variable or - from DOTT and on - a value on the stack that is calculated before the if. Those calculations are themselves stack-based, so you wouldn't see a nice if (actor-x guybrush >= actor-x elaine - 15). Some commands had multiple nice ways of being called, where parts could be left out (similar to overloaded functions in several languages) - the compiler - and Windex - would turn those into a single command with various constants indicating "default" added. Windex had no knowledge of macros, so e.g. all iMUSE commands would be listed as sound-kludge with a long list obscure numeric parameters. That's some of the stuff the decompiler "undoes".2 points
-
Just testing the waters, for now. The full MM decompile might show up at some point. Not sure when I'll have time to annotate the larger games with actor names, object names, room names etc. - or add the missing features that mostly have to do with "intelligently" figuring out what aliases to use - some aren't straightforward to figure out programmatically - like indirection for state-of, where it actually needs to follow the assignments in order to figure out if the object in question might be a door or a switch or another kind of object - and then pick e.g. "CLOSED" or "OFF" or "HERE" (or R-GONE) depending on context. Also want to add an easy way to define "reverse macros" - so that command sequences that are known to be a result of macro expansion are turned back into macro calls. Oh, the thing about HERE and R-GONE (and GONE and R-HERE). The objects' states also control whether (and later what) object images are displayed. Hence why "OFF" = "HERE": The convention in SCUMM was to draw objects onto the background, with the object image actually being an image of the object removed - i.e. the actual background behind the object. Hence, the default, "off", state (0) would be "HERE", and the "on" state would be "GONE". When artists didn't follow that convention, you used R-HERE and R-GONE - with R standing for "Reversed" - and e.g. R-GONE being = HERE. In order to have script readability without changing the art. But just to demonstrate how the syntax and commands changed relatively little until CMI (even though DOTT introduced a completely rewritten compiler and interpreter) - here's a bit from CMI. Without annotations naming all the variables, actors, costumes, objects etc., it becomes a fair bit less easy to read, though. It also shows a good example of macro expansion - the bits with "Too many ambient sounds" warnings messages were clearly originally a much shorter macro call, expanded on compilation: https://gist.github.com/Jither/fa3d05100e4106a125abffb3a6760249 ETA: The same thing goes for kludge commands inthere - although the decompiler could already give them their proper names, at the time the scripts were written, they were "commands in training" and were actually named by wrapping them inside a macro (so that's what it's intended that the decompiler eventually does too - use the "reverse macro expansion" to name them). iMUSE also had its own set of "sound kludge" commands wrapped in macros. It was never promoted to first class citizen in SCUMM. Heck, its macros even lived in a file named SOUNDCRP.SCU... š ETA 2: Other syntax-related tidbits that I didn't mention above (but there are so many that could be mentioned): start-script was mostly optional - you could just write play-cricket-sound rather than start-script play-cricket-sound, although the longer form was also allowed. is, are and == (and =) were all synonyms - as were is-not and != - the decompiler tries to choose the output form much like SCUMMlets would - if it's comparing to or assigning a number, use =, otherwise, is. The "intelligent alias" stuff would also eventually allow e.g. object names etc. to be annotated as plural, so that it can choose are when appropriate. a bit more technical: in case anyone with some parser knowledge is wondering about the infamously unconventional (for modern languages) use of the hyphen as both a valid identifier character and subtraction operator, the way it worked was simply that any hyphen between other identifier characters would be parsed as an identifier - spaces were required to make e.g. a - b a subtraction rather than an identifier (a-b). For the same reason, SCUMM only had prefix syntax for decrement (and increment) - --x - rather than x--, which would be parsed as an identifier. The hyphen wasn't valid as the first character of an identifier (e.g. -selected-number) - in that case, it would be parsed as a subtraction or negation. ETA3: Oh yes, I forgot (it's more than a year since I last actually worked on the decompiler) - automatic naming of rooms, objects etc. based on the info in the game files was off - the CMI example is a bit more readable now.2 points
-
Thought someone might find this interesting. The broader public finally got a proper view of actual SCUMM in the Video Game History Foundation's brilliant interview with Ron a couple of years ago. But for a bit of a wider glance, here's an example of what the script for a full room would look like. This is output from a project I started on a couple of years ago, which is currently in hiatus. Based on a lot of research and archaeology. First and foremost - this is not an original script (as should be somewhat evident, if you read it). I've never seen an original script from Maniac Mansion. This is reconstructed from the game files. It is, however, 100% actual SCUMM syntax. Possibly with some minor unknown differences compared to an actual 1987 SCUMM script - the syntax is accurate to SCUMM circa 1990-1991 - that is, the SCUMM compiler for MI1 or MI2 would accept it as proper SCUMM. The actual syntax never changed much between Maniac Mansion on C64 to CMI. And the commands, other than additions, rarely changed either, at least from Maniac Mansion for PC and on. Other than that, the script is from Maniac Mansion (obviously) - the PC version. Although my "decompiler" actually handles all games from MM C64 to CMI, there were some early hacks in C64 that it doesn't quite like yet, and which makes the MM C64 output slightly less readable - most notably that objects and actors shared references, meaning it has a harder time naming objects and actors where they overlap. Stuff worth noting: A few variables, objects, scripts, and defines haven't been named by me. Yes, those names are all mine, but based on how variables etc. would typically be named in actual game scripts. I've only done these "annotations" for Maniac Mansion so far. Even the way indentation was done is reconstructed by the tool - 3 spaces were used, but lines of dialog were mostly always indented to align perfectly. Obviously one of the most interesting things - comments - cannot be reconstructed from game files. š The decompiler doesn't yet handle cases where names have aliases. For example, "OFF", "CLOSED", "HERE" (yes) and "R-GONE" are all aliases for the same thing - SCUMMlets used whatever was appropriate in the context (or they'd be chastised by Ron or Tim š). Here, I've manually renamed most of those. And a few additional line breaks. There's no AI involved š, so the decompiler doesn't actually know where code could appropriately be split into sections. Some of the commands may actually be "expanded" code that was originally macros. Yes, the cases of "jump" commands jumping into different blocks were also actual common SCUMM practice. Other interesting things about this particular script: Around halfways down, the definition of the room starts. This is the standard (and required) layout in SCUMM - room scripts followed by the room definition - sounds, enter/exit scripts, and object definitions including their verb scripts. Since this is the PC version, while the play-cricket-sound script is still there, it doesn't actually do anything. The "userface" command is one of the few that I have no idea how actually looked. "wait-for-message" is one of the additions compared to the C64 version - where the equivalent SCUMM code would be "break-until (message-going is false)" - although it might already have been turned into a "wait-for-message" macro in the original game. Starting with the MM PC version, it turned into a native command. Enough talk... script play-cricket-sound { do { sleep-for 100 minutes } } script kill-a-kid { break-here cut-scene { if (cause-of-death is radioactive-steam) { say-line "Oh no! Radioactive steam! Ahheeeeeeee^" do { do-animation selected-actor turn-left break-here do-animation selected-actor turn-front break-here do-animation selected-actor turn-right break-here do-animation selected-actor turn-back break-here x = random 70 y = random 12 y += 56 walk selected-actor to x,y } until (message-going is false) who-dies is selected-actor } if (cause-of-death is drowning-in-pool) { current-room pool camera-at 41 sleep-for 2 seconds print-line "Glug! Glug! Glug! Glug!" wait-for-message sleep-for 3 seconds } if (cause-of-death is ed-seeing-hamster) { stop-script weird-ed-chases-kid wait-for-message say-line weird-ed "Wait! What IS that?" wait-for-message say-line weird-ed "It has bits of fur like my hamster's!" wait-for-message say-line weird-ed "Oh no!!! What did you do!!! Argh!!!" wait-for-message who-dies is selected-actor put-actor weird-ed at 10,52 in-room weird-eds-room } if (cause-of-death is flesh-eating-plant) { who-dies is selected-actor current-room plant-room camera-at 28 sleep-for 2 seconds print-line "YUM!!" sleep-for 3 seconds } if (cause-of-death is death-by-tentacle) { wait-for-message who-dies is selected-actor } actor who-dies costume costume-0 kid-is-busy[who-dies] = 1 foo = 253 do { if (owner-of foo is who-dies) { owner-of foo is nuked } foo -= 1 } until (foo == 0) ++number-of-dead-kids if (who-dies is dave) { dave-is-dead is true } if (number-of-dead-kids == 1) { state-of tombstone-1 is HERE class-of tombstone-1 is TOUCHABLE put-actor who-dies at 106,64 in-room mansion-exterior } if (number-of-dead-kids == 2) { state-of tombstone-2 is HERE class-of tombstone-2 is TOUCHABLE put-actor who-dies at 114,64 in-room mansion-exterior } if (number-of-dead-kids == 3) { state-of tombstone-3 is HERE class-of tombstone-3 is TOUCHABLE put-actor who-dies at 122,64 in-room mansion-exterior } foo = actor-x who-dies current-room mansion-exterior camera-at foo sleep-for 6 seconds } if (number-of-dead-kids == 3) { start-script game-over } userface 1 unfreeze-scripts cursor-on sentence inventory verbs } script open-film { if (develop-film-step is film-opened) { say-line "It's already opened." } if (develop-film-step is film-closed) { say-line "Ok, it's opened." wait-for-message do { foo is owner-of film if (foo == 0) { stop-script } bar is actor-room foo if (room-is-dark[bar] == 0) { if (state-of circuit-breakers is OFF) { if (selected-room is bar) { say-line "I think I just exposed the film." } develop-film-step is film-opened } } sleep-for 15 seconds } until (develop-film-step is-not film-closed) } } script deliver-envelope { sleep-for 1 minute do { sleep-for 30 seconds } until (selected-room is-not mansion-exterior) if (state-of envelope is OFF) { stop-script } state-of envelope is OFF class-of envelope is UNTOUCHABLE state-of mailbox-flag is OFF owner-of sealed-envelope-in-safe is nuked sleep-for 3 minutes cut-scene { current-room room-0 start-script marketeer-reacts-to-envelope-contents break-until (script-running marketeer-reacts-to-envelope-contents is false) } sleep-for 5 minutes if (contract-status > unsigned) { do { sleep-for 30 seconds } until (selected-room is-not mansion-exterior) state-of contract is R-HERE class-of contract is TOUCHABLE start-sound doorbell-sound } } script schedule-package-delivery { sleep-for 5 minutes do { sleep-for 5 seconds if (selected-room is-not mansion-exterior) { if (selected-room is-not weird-eds-room) { if (actor-room weird-ed is weird-eds-room) { jump deliver } } } } deliver: start-sound doorbell-sound state-of package is HERE class-of package is TOUCHABLE do { sleep-for 8 seconds } until (actor-room weird-ed is weird-eds-room) if (selected-room is-not mansion-exterior) { start-sound doorbell-sound } stop-script touch-stuff-in-weird-eds-room weird-ed-downstairs-reason is doorbell start-script send-weird-ed-downstairs } script read-contract { case contract-status { of signed-kid { case who-recorded-demo { of selected-actor { say-line "Wow! It's a recording contract for ME!" } of syd { say-line "It's a recording contract for Syd." } default { say-line "It's a recording contract for Razor." } } } of signed-green { say-line "It's a recording contract", "for Green Tentacle." } default { say-line "It's a book publishing contract,", "and it's worth MILLIONS!" } } } script meanwhile-in-lab-1 { sleep-for 1 minute cut-scene { override skip-meanwhile-1 state-of lab-door-right is OPEN put-actor dr-fred at 15,58 in-room lab put-actor sandy at 25,58 in-room lab do-animation dr-fred turn-right do-animation sandy turn-left current-room lab camera-at 20 sleep-for 1 second say-line dr-fred "Well, my dear. Hope you're having fun!": "Within minutes it'll all be over.": "You'll be hooked up to my machine", "getting your pretty brains sucked out." walk dr-fred to sandy within 5 break-until (chars-printed > 66) do-animation sandy turn-front do-animation sandy chore-12 wait-for-message say-line sandy "You'll never get away with this!": "Dave and his friends will rescue me!": "You and your meteor can eat slime!" break-until (chars-printed > 45) do-animation sandy turn-left wait-for-message foo = actor-x dr-fred walk dr-fred to foo,68 sleep-for 1 second say-line dr-fred "That's what she thinks!" wait-for-message walk dr-fred to lab-door-right say-line dr-fred "Heh, heh, heh." wait-for-actor dr-fred put-actor dr-fred in-the-void state-of lab-door-right is CLOSED start-sound close-door-sound walk sandy to lab-door-left wait-for-actor sandy do-animation sandy turn-back say-line sandy "Help, help, HELP!" wait-for-message sleep-for 1 second skip-meanwhile-1: print-line " " state-of lab-door-right is OFF } put-actor sandy in-the-void start-script schedule-meanwhile-in-lab-2 } script meanwhile-in-lab-2 { cut-scene { override skip-meanwhile-2 put-actor dr-fred at 50,62 in-room lab put-actor sandy at 30,62 in-room lab put-actor purple-tentacle at 40,62 in-room lab do-animation sandy turn-front current-room lab camera-at 20 sleep-for 1 second walk purple-tentacle to sandy within 3 wait-for-actor purple-tentacle do-animation sandy turn-left say-line sandy "Get away from me you purple slime geek." walk sandy to 5,50 break-here 2 walk purple-tentacle to 5,50 wait-for-actor sandy walk sandy to 25,45 say-line sandy "Don't touch me!" wait-for-actor purple-tentacle walk purple-tentacle to 21,50 wait-for-actor sandy walk dr-fred to 30,50 wait-for-actor dr-fred do-animation dr-fred turn-left say-line dr-fred "PURPLE TENTACLE!!": "Stop playing with the lab experiments.": "Bring her, the machine is ready.": "Heh, heh, heh." break-until (chars-printed > 90) walk dr-fred to 60,50 wait-for-message do-animation sandy turn-front say-line sandy "EEEEEEEEEK!!!!" do-animation sandy chore-12 wait-for-message sleep-for 1 second skip-meanwhile-2: print-line " " } put-actor sandy in-the-void } script schedule-meanwhile-in-lab-2 { sleep-for 45 minutes start-script meanwhile-in-lab-2 } room mansion-exterior { sounds { "sfx\unused-sound-5" unused-sound-5 "sfx\doorbell-sound" doorbell-sound } enter { lights is 2 stop-sound radiation-sound if (script-running win-game is false) { start-script play-cricket-sound } } exit { stop-script play-cricket-sound stop-sound cricket-sound if (state-of envelope is R-HERE) { if (envelope-stamped is true) { if (envelope-is-addressed is true) { if (state-of mailbox is CLOSED) { if (state-of mailbox-flag is R-HERE) { if (script-running deliver-envelope is false) { start-script deliver-envelope } } } } } } if (script-running script-12 is true) { start-sound radiation-sound } } object front-door-ext { name is "front door" class is LOCKED verb open { if (class-of current-noun1 is UNLOCKED) { start-script open-door state-of front-door-int-left is OPEN } else { start-script door-locked-response } } verb close { start-script close-door state-of front-door-int-left is CLOSED } verb unlock use { if (current-noun2 is key) { class-of current-noun1 is UNLOCKED do-sentence open front-door-ext } else { start-script cant-unlock-response } } verb lock { class-of current-noun1 is LOCKED do-sentence close front-door-ext } verb walk-to { if (state-of current-noun1 is OPEN) { if (entered-house is false) { entered-house is true start-script meanwhile-in-lab-1 put-actor nurse-edna at 62,56 in-room kitchen do-animation nurse-edna turn-back state-of refrigerator is OPEN start-script script-152 } come-out-door front-door-int-left in-room hall } } } object door-mat { name is "door mat" verb pull pick-up { if (state-of current-noun1 is GONE) { say-line "I'll leave it here." } else { state-of current-noun1 is GONE } } verb push { state-of current-noun1 is HERE } } object key { name is "key" class is PICKUPABLE dependent-on door-mat being GONE verb pick-up { pick-up-object current-noun1 } verb use { if (current-noun2 is front-door-ext) { class-of front-door-ext is UNLOCKED do-sentence open front-door-ext } else { say-line "It doesn't work." } } } object mailbox { name is "mailbox" verb open { state-of current-noun1 is OPEN } verb close { state-of current-noun1 is CLOSED } verb use { do-sentence use current-noun2 mailbox-open } } object mailbox-open { name is "mailbox" verb open { state-of mailbox is OPEN } verb close { state-of mailbox is CLOSED } verb use { if (current-noun2 is sealed-envelope-in-safe) { if (state-of mailbox is OPEN) { if (envelope-is-addressed is false) { say-line "There is no address on it." } else { if (envelope-stamped is false) { say-line "There's no stamp on it." } else { if (content-in-envelope == envelope-empty) { say-line "The envelope is empty." } else { owner-of sealed-envelope-in-safe is nobody class-of envelope is TOUCHABLE state-of envelope is R-HERE } } } } } } verb read { say-line "Solicitors will be eaten." } } object package { name is "package" state is GONE class is PICKUPABLE UNTOUCHABLE verb pick-up { pick-up-object current-noun1 if (got-stamps is false) { pick-up-object stamps owner-of stamps is nobody } } verb give { if (current-noun2 < end-kids) { owner-of current-noun1 is current-noun2 } if (current-noun2 is weird-ed) { start-script give-package-to-weird-ed } } verb read { say-line "To: Weird Ed" } verb open pull { if (got-stamps is false) { if (state-of current-noun1 is GONE) { owner-of stamps is selected-actor } else { pick-up-object stamps } say-line "Some uncanceled stamps came off!" got-stamps is true } else { say-line "That would be illegal." } } } object stamps { name is "stamps" class is PICKUPABLE dependent-on package being OFF verb pull pick-up { pick-up-object current-noun1 say-line "Hmm, they're uncanceled." got-stamps is true } verb use { if (current-noun2 is envelope-in-microwave or current-noun2 is sealed-envelope-in-safe) { if (envelope-unsealed == 1) { envelope-stamped is true say-line "They stick!" start-script update-envelope-name owner-of current-noun1 is nuked } else { jump wont-stick } } else { wont-stick: say-line "They won't stick." } } } object mailbox-flag { name is "flag" verb open { do-sentence open current-noun1 current-noun2 } verb close { do-sentence close current-noun1 current-noun2 } verb pull { state-of current-noun1 is GONE } verb push { state-of current-noun1 is HERE } verb use { if (state-of current-noun1 is GONE) { state-of current-noun1 is HERE } else { state-of current-noun1 is GONE } } } object bushes-left { name is "bushes" verb open pull pick-up { state-of current-noun1 is GONE } } object grating { name is "grating" class is LOCKED dependent-on bushes-left being GONE verb open { if (class-of current-noun1 is LOCKED) { if (used-hunk-o-matic[selected-actor] == 1) { say-line "Easy!" jump open-grating } else { say-line "I can't budge it. It's rusted shut." } } else { open-grating: state-of current-noun1 is OPEN state-of crawl-space-grate is OPEN start-sound open-door-sound } } verb close { state-of current-noun1 is CLOSED state-of crawl-space-grate is CLOSED } verb push pull { if (state-of current-noun1 is CLOSED) { do-sentence open grating } else { do-sentence close grating } } verb fix unlock use { if (current-noun2 is tools) { class-of current-noun1 is UNLOCKED do-sentence open grating } } verb walk-to { if (state-of current-noun1 is OPEN) { come-out-door crawl-space-grate in-room crawl-space } } } object film { name is "undeveloped film" state is R-HERE class is PICKUPABLE UNTOUCHABLE verb pick-up { pick-up-object current-noun1 } verb open { if (script-running open-film is false) { start-script open-film } } verb use { do-sentence use current-noun2 current-noun1 } verb read { if (develop-film-step < film-developed) { say-line "Kodak." } else { say-line "Looks like photographs of Ed's plans." } } verb give { if (current-noun2 < end-kids) { owner-of current-noun1 is current-noun2 } if (current-noun2 is weird-ed) { if (develop-film-step < film-developed) { say-line weird-ed "No! No! You have to develop it for me!" } else { start-script give-film-to-weird-ed } } } } object envelope { name is "envelope" class is UNTOUCHABLE dependent-on mailbox being OPEN verb read { if (envelope-is-addressed is false) { say-line "It's a blank envelope." } else { say-line "It's addressed to: 222 Skyscraper Way." } } verb pick-up { class-of envelope is UNTOUCHABLE state-of envelope is R-GONE owner-of sealed-envelope-in-safe is selected-actor } } object contract { name is "contract" class is PICKUPABLE UNTOUCHABLE dependent-on mailbox being OPEN verb pick-up { pick-up-object current-noun1 state-of current-noun1 is R-GONE } verb read { start-script read-contract } verb give { start-script give-contract } } object tombstone-1 { name is "tombstone" state is GONE class is UNTOUCHABLE verb read { say-line "And good riddance!" } } object tombstone-2 { name is "tombstone" state is GONE class is UNTOUCHABLE verb read { say-line "Another one bites the dust!" } } object tombstone-3 { name is "tombstone" state is GONE class is UNTOUCHABLE } object exit-mansion-ext-right { name is "" verb walk-to { come-out-door exit-mansion-gate-left in-room mansion-gate } } object bushes-right { name is "bushes" } object doorbell { name is "doorbell" verb push use { start-sound doorbell-sound if (var-92 == 0) { if (script-running send-weird-ed-downstairs is false) { if (actor-room weird-ed is weird-eds-room) { weird-ed-downstairs-reason is doorbell start-script send-weird-ed-downstairs } } else { start-script impatient-doorbell-ringing } } } verb read { say-line "This is the home of Dr. Fred,": "Nurse Edna, Weird Ed, Dead Cousin Ted,": "Green Tentacle and Purple Tentacle." } } }1 point
-
A few more notes on the CMI example: The scripts that have numbers from 2000 and up are actually local scripts. Whichi is why they're defined inside the room definition (defining a script inside the room definition is how you would signify that a script was local - again, MM didn't have local scripts). There aren't any global scripts in the "treasure" room - hence, the room definition starts at the very top of the file. The strings wouldn't actually start with (e.g.) "/TRNZ365/" while writing. That would likely be added by the compiler or another tool before compiling. We all know that CMI really only had three verbs - those are verb-5, verb-6 and verb-7. Already from the very early days there was a special "verb" defining the default action if a verb didn't have one. And a fallback script that would be called if there wasn't a default action on the object. E.g. having Guybrush say "That doesn't seem to do anything". There was also a special verb for the "quick action". That one had a macro so that rather than writing something like verb get-verb { double-verb = open } for a door, you could just write quick-verb is open. Assigning an icon to an object in the inventory was also done with a special verb, once again the actual verb code was hidden inside a macro - so, icon is bucket-icon, rather than verb get-icon { icon-number = bucket-icon }. Similarly, in the CMI example, you'll see verbs like verb-216 { var-630[0] = "/PU_M048/climb through" } ... which defines the name for the "use" verb. That would likely, once again, be shortened by a macro, something like use-name is "climb through" - with a similar macro for the look verb (verb-217) and talk/eat verb (verb-218). In other words, the verb scripts were really an object-oriented-programming-like way to have "methods" on an object - not just for the actual verb actions. start-script got two flags, also there relatively early in SCUMM's evolution: bak for "background scripts" - while scripts would generally run until they were stopped, in a multi tasking way (break-here, wait-for-* etc. would allow the engine to interpret all the other scripts currently running) - that didn't apply to cut-scenes. Whenever a cut-scene was entered, all other scripts were paused - except for scripts started with bak. That would be stuff like the most common script example: The grandfather clock going "tick tock" - don't want that to stop when a cutscene is running. The other flag is rec, which stands for "recursive" but doesn't actually mean that... It's for scripts that should be allowed to run multiple copies at the same time. Not recursively, but in parallel. If you started a non-rec script that was already running, the original script would stop, and a new version of it would be started instead.1 point
-
Yeah, you can also see the principle in e.g. SCUMMRev: Here, each global script ends up in "SCRP". The costumes and sounds that the room script declares are in SOUN and COST. The local scripts - which are only loaded when the room is - are in the LSCR chunks, and "entry" and "exit" scripts in EXCD and ENCD. Object definitions end up in OBCD along with their verb scripts. But note that SCRP, SOUN and COST are actually "outside" the ROOM (but inside LFLF) - they're not "really" part of the room, but associated with it.1 point
-
1 point
-
I spent a lot more of the review on Skull than I set out to because, having made the decision not to use spoilers, it became the most useful way to articulate my general response to Dial by contrast. Skull and Dial are kindred sequels, because theyāre both up against the same challenge: How do you tell a story about an aged Indy that necessarily puts the character outside of the era he was designed to operate in? How the two movies deal with this problem is highly revealing. The decisive difference is that Dial comes off as a movie that knows what it wants to be about. We can attack the screenplay, but it at least feels like it has one. Skull feels like they shot a story outline that happens to have dialog in it. I find it highly objectionable because it is in essence incomplete material. The truth is I can talk all day about individual things in Skull I admire, and individual things in Dial I consider defective, but thatās all just exercise. Thereās an aggregate effect with a movie, where it either works for you or it does not. I walked out of Dial satisfied, while I walked out of Skull deflated, and thatās going to color my whole perspective, as it ought to. I also decided that I needed to divulge where I was coming from walking into Dial to explain why I might have been prepared to forgive a lot, because where I was coming from is inescapably informed by the last installment. Though Iām negative on Skull, thereās a narrative around that movie based primarily on internet talking points (aliens, Shia LaBeouf, whatever) that I donāt want anything to do with. In short, the reasons youāre āsupposedā to dislike Skull are largely unrecognizable to me. I personally dislike Skull because I find it to be an inert, unshaped bore filmed by somebody who didnāt want to leave the country and desperately wanted you to know how addicted they are to Classic Softs and mist machines. Already weāre hearing how itās āillogicalā to tolerate Dialās zanier choices as some sort of hypocrisy due to common complaints against Skull. (Oh, if only outlandishness was Skullās problem!) The CGI āfakeryā I see in a similar light ā Iāll commiserate with anybody who thinks Dial is too VFX heavy. But the fact is that Skull looked fake even when it was real ā thatās how gratuitous the issue was. I just canāt overstate how lethal the aesthetic of that movie was for me, and how much of a rebound Dial managed to be on this score, even shot digitally and despite the fact that it features a goddamned machine-learned Indy (and obviously so at that) for twenty-five minutes. So in the end I gave a lot of ink to my actual problems with Skull (as opposed to what the received wisdom says) to try to orient the reader to the areas where I was going to be particularly susceptible to some redemption. Already itās looking like my perspective is one of the more generous ones, and hopefully all the knocking on Skull served the purpose of contextualizing that rather just reading as gratuitous.1 point
-
1 point
-
Well, didn't join you TODAY, but can't wait to watch this one in particular. One bit I randomly stumbled upon because I did skip around a bit to give myself a teaser... Aric not being able to answer how the dialogue trees worked is totally fair, because indeed, the SCUMM tools, compilers etc. knew nothing about it. All of it was implemented for Last Crusade mostly (almost exclusively) using functionality that was there already in Zak McKracken and Maniac Mansion on PC - a lot of it was even there in Maniac Mansion C64, before the tools and language really became portable. The short version is: Dialogue lines are just verbs repurposed - Maniac Mansion could already clear the verbs and replace them with entirely new verbs placed anywhere on the screen (as far as I recall, that was only added after the C64 version). The intricacies of doing the setup were hidden inside a few scripts and macros (like Aric mentions), which made it look like "not verbs at all" - macros which pushed the existing verbs on a stack, cleared them, created new custom verbs, placed them on screen based on their number, and set up the actions each verb would trigger. This combined with using the existing case ... of (similar to the typical switch ... case statement) for the choices. But since macros allow literally adding to the syntax of the language, this turned into something like (EDIT: using the real syntax, since that's already visible in the VGHF interview with Ron Gilbert): start-dialog set-dialog 1 "I want to be a pirate!" set-dialog 2 "I want to be a fireman!" set-dialog 3 "I mean to kill you all!" ; "wait-for-dialog" is what replaced the "case" keyword - in practice it worked like built-in "wait" commands - ; allowed other scripts to run while waiting for the player to pick a dialogue line. wait-for-dialog { of dialog-1 { jump dialogue-about-three-trials } of dialog-2 { jump beat-it-kid } of dialog-3 { jump beat-it-kid } } dialog-about-three-trials: ; SCUMM code for this discussion beat-it-kid: ; SCUMM code for this discussion The wait-for-dialog macro, as mentioned, would wait for the player to pick a line - allowing other scripts to run in the meantime. When a verb was chosen, its number would be stored in a variable, choice. So, the end of the macro would just be case choice, leading into the following of dialog-1... lines. dialog-1, 2, 3... being constants also defined within the SCUMM scripts. So, the entire "system" was all done in SCUMM without needing to change the tooling. After that, it's basically "goto's" all the way down - and to my knowledge there was never any tooling to make it easier to follow complex dialogue trees. ETA: Of course, the jumps here could be replaced with the actual response being inside the of... clauses (and in this particular case, they were) - that's up to the SCUMMlet. But jumps back to the choices within a branch after a response was finished, or back to the initial dialog choices in the conversation, etc. - would be done using jump.1 point
-
I did not like it at all. Full spoilers in the hidden section below. Where Crystal Skull was cartoonish to the point of stupidity, this is bland to the point of soulessness. There's no flair, no wit, no excitement, no sparkle. Crystal Skull may have been awful, but at least it was an awful Indiana Jones movie. This is just some charmless 2020s schedule-filler wearing an Indy mask.0 points
-
I blew my solo movie theatre venture on Asteroid City, so this will likely be a Blu Ray thing for me ... still nobody going with me.0 points
-
0 points
-
HAHA! It's dead, and my extreme JavaScript debugging skills tell me there were only 282 Heardles programmed in. What a time to make a thread. @Mintopia! WE WANT MODULO! WE WANT MODULO! Not the most catchy slogan, but hopefully effective.0 points