Logo Pending


Text, Voice… Both?

“Interesting. I wonder if this is related to the “BOTH” button that got cut in SQ4.” — @ATMcashpoint

I don’t know about the both button that ScummVM adds to some SCI games, but there’s quite literally no way it could work by just adding a third button state. There’s a fair bit of script logic that’d need to be overhauled. Here’s why that is, and here’s how I did it in The Dating Pool.

could have used the SCI Companion template game to compare against and document, but to be honest it’s a bit of a mess, as you could expect from a decompilation. The leaked system scripts are much neater to work with, even though the actual script code is basically identical.

Original Messager.sc:

(method (sayNext theMod theNoun theVerb theCase theSeq &tmp aTalker [theBuf 200] msgkey)
  ; If we were called with arguments, grab the text for that entry.
  ; If not, grab the next entry in the sequence.
  (if argc
    (= aTalker (Message msgGET theMod theNoun theVerb theCase theSeq @theBuf))
  else
    (= aTalker (Message msgNEXT @theBuf))
  )
 
  ; If we have voice enabled, allocate space and grab the entry's tuple.
  ; This block is missing in SQ4CD.
  (if (& gMessageType CD_MSG)
    (= msgkey (Memory memALLOC_CRIT 12))
    (Message msgLAST_MESSAGE msgkey)
  )
 
  (if (and  aTalker
            (or  (not lastSequence)
                 (and  lastSequence
                       (<= curSequence lastSequence)
          )
        )
      )
    ; Look up the Talker (or Narrator) by number.
    ; aTalker was a number, but now it'll be an object pointer.
    (= aTalker (self findTalker: aTalker))
 
    (if (!= aTalker -1)
      (talkerSet add: aTalker)
 
      ; Now let our Talker handle the rest.
      (if (& gMessageType CD_MSG)
        (aTalker
          modNum: theMod,
          say:    msgkey self ;<-- pass ONLY the tuple
        )
      else
        (aTalker
          modNum: theMod,
          say:    @theBuf self ;<-- pass ONLY the string
        )
      )
      ; In SQ4, we just always pass only @theBuf. There's some major
      ; voodoo involved in getting it to work.
 
      (++ curSequence)
    )
    ; Cutting a bit of irrelevant fastcast voodoo
  )
  ; Dispose of the space we allocated for the voice tuple, if needed.
  (if (& gMessageType CD_MSG)
    (Memory memFREE msgkey)
  )
)

Catdate’s Messager.sc:

; Exactly the same as in the template BUT...
(if (!= aTalker -1)
  (talkerSet add: aTalker)
  ; Pass both the buffer AND the tuple, no matter our settings.
  ; That does mean that msgkey may be null, but say won't use it in
  ; that case anyway.
  (aTalker
    modNum: theMod
    say: @theBuf msgkey
  )
  (++ curSequence)
)

In SQ4CD, the Narrator has extra noun, verb, and sequence properties that get set to allow the text to work. It’s really quite a bit of a mess, and my hat’s off to whoever on the ScummVM team got that Both mode to work. I was going to document it but got lost trying, it’s that wild.

On to the Narrator and by extension Talker!

Original Talker.sc:

(method (say theBuf whoCares)
  (if theIconBar (theIconBar disable:))
  (if (not initialized) (self init:))
 
  (= caller
    (if (and (> argc 1) whoCares)
      whoCares
    else
      null
    )
  )
 
  ; Figure out what to do with the message.
  ; Note that in one case, theBuf is a string...
  (if (& gMessageType TEXT_MSG)
    ; (method (startText theBuf &tmp strLength)
    (self startText: theBuf)
  )
  ; ...but in the other it's a tuple!
  (if (& gMessageType CD_MSG)
    ; (method (startAudio theKeys &tmp m n v c s)
    (self startAudio: theBuf)
  )
 
  ; cut a bit...
 
  ; start___ will have set ticks to the length
  ; of the string or recording. We add one more
  ; second regardless.
  (= ticks (+ ticks 60 gameTime))
  (return true)
)

Catdate’s Talker.sc:

; much the same, but
  (method (say theText theAudio whoCares)
    ; ...
    (if (& gMessageType TEXT_MSG)
      (self startText: theText)
    )
    (if (& gMessageType CD_MSG)
      (self startAudio: theAudio)
    )
    ; ...
  )

Now, this works fine. If I record a quick bit of gibberish, then load up the game, switch to Both, and click, I get a perfectly readable message and hear my gibber. But if I were to revert my little change and use the original code…

That’s what we in the business call mistaking a bunch of numbers for a valid string. I specifically get this result because the first value in the tuple is the module number, which is 110 (0x6E ‘n‘) in this case, and all numbers in SCI are 16-bit so there’s a terminating null right after.

What’s funny is that after all this, I can’t see how SQ4 is supposed to support Both mode, and ScummVM only needs to add that third button state. There is no patch to adjust the script, and I can’t for the life of me figure out how this would work:

(method (say theVoodoo whoCares &tmp newEvent)
  ; ...
  (if (& gMessageType TEXT_MSG)
    ; Note: noun, tVerb, and tSequence are properties. theVoodoo is now "case".
    (self startText: modNum noun tVerb theVoodoo tSequence &rest)
  )
  (if (& gMessageType CD_MSG)
    (self startAudio: theVoodoo)
  )
  ; ..
)

The weird part is that I can’t find anywhere those properties are set.

…At least with the KQ6/LB2 patches they actually do overhaul quite a bit of the scripts’ logic, which are otherwise just the same system scripts as above. Not the way I did it for my game, but clearly in a way that works out.

[ , ] Leave a Comment

Palette Cycling in Larry 5

I distinctly recalled just before posting this that one particular room in Leisure Suit Larry 5 – Passionate Patti does Pittsburgh a Little Undercover Work had a palette cycling effect that bit into the 64 global colors of the palette. So I enabled the debug handler, loaded up ScummVM, and Alt-T’d my way over to room 700.

…It looks perfectly right. That’s not right.

Now, you’ll notice the Fast Forward icon isn’t grayed out. That’s what you get when you cheat, but that’s hardly relevant here.

Had I remembered wrong? Was this the wrong screen? No, surely my memory isn’t that bad? Besides, old adventure games are relevant to my interests. I don’t tend to forget things about those.

But then again, this is ScummVM. What does DOSBox have to say?

Thank you, DOSBox. I figure it must be because ScummVM draws it all in truecolor mode, manually applying the effect to the background, as opposed to the original actually changing the VGA color palette.

(Any political implications are entirely in the reader’s head.)

[ , , , ] Leave a Comment