Author Topic: Understanding later SCI code... SQ4  (Read 17013 times)

0 Members and 1 Guest are viewing this topic.

Offline Cloudee1

Understanding later SCI code... SQ4
« on: May 07, 2015, 11:10:50 PM »
So it's time to start seriously looking at this coding business and trying to sort it out. The latest decompilation that has been made available has been SQ4, so I am starting there. And not only starting there, but actually starting at the beginning... with the intro script.

I have been doing some tinkering with the code layout and whatnot to actually get it as recognizable to me as possible. I figured I would start throwing out some rudimentary questions as I come across things I am not sure about as well as some clarification just to make sure what I think is happening is actually what is happening. So I guess to start with, I will post the code that I am actually staring at. I commented the hell out of it so it might actually be easier to read if you copy it and paste it into our current version of sciCompanion just for the syntax highlighting.

Code: [Select]
//******************************************************************************
// SQ4 - Space Quest Splash Screen and initial Intro bit
//******************************************************************************
(include "sci.sh")(include "game.sh")                               (script 1)
//*****************************************************************************
(use "Main") // Good old main script, we are used to this one...
(use "SQRoom") // Seems to mainly handle ego motion
(use "n958")// Seems to be a small load / dispose script...
(use "User")// We are used to User
(use "Obj")// We are used to Obj

//*****************************************************************************
(local
    local0 // unused by this script so really could be omitted
    local1
)

//*****************************************************************************
(instance public rm001 of SQRoom
(properties picture 106) // picture 106 is the sierra splash screen...
  (method (init)
  (super:init())
  (self:setScript(RoomScript))
  (self:setRegions(707)) // actually the intro.txt file... holds the handleEvent for the intro screens
  Load(rsPIC 1)// Bah, who needs Load... no one ever uses it... anyway, loads pic 1 into memory
  proc958_0(135 68 69) // found in script 958... the small load / dispose script
  // So if I am halfway right, this will load param1 (resource type) and then
  // loop through the remaining paramaters representing the resource numbers
  // of that type... Loading each one in succession
  // looking at this in viewer, 135 must represent RSFONT, and would therefore load
  // fonts 68 and 69 (there aren't any other resource types which include 68 or 69)
  // so 135 must mean Font... we are used to this (define rsFONT   $87)
  )// end Method init
)// end Instance
//******************************************************
(instance RoomScript of Script
(properties)
  (method (doit)
  (super:doit())
  // So we know do it checks things every cycle...
  // so we are looking every cycle to see if the changestate is at state (or case) 1
  // and the music being played is throwing prevSignal 10... not sure what prevSignal 10
  // means but anyway, when those two conditions are met, then the RoomScript is supposed
  // to cue itself. Which I have never tried it but judging by this, it will bump the
  // changestate method on to the next state (case) as I am not seeing anything else here
  // that does do that.
  (if ((== state 1) and (== (send gLongSong:prevSignal) 10))(self:cue()))
  )// end Method Doit


    (method (changeState newState)
        (var temp0[3]) // unused by this method so really could be omitted
        (switch (= state newState)
            (case 0
                (send gLongSong:loop(-1)playBed()) // Starts the song that doit is keeping an eye on
                = cycles 2 // waits a couple of ticks then moves on to case 1
            )
            (case 1) // just hangs... This threw me until I noticed the cue() in the doit... thats what moves us on
            (case 2
                (send global2:drawPic(1))// Not sure what global2 is... gRoom maybe, we have always just used DrawPic(###) before
// anyway, this throws up the Space Quest Title Screen
                = register 200 // I see register is used in SQRoom.txt but in the context of newRoom... not sure what we are registering here.
// But judging from the next case, it looks like this is going to be used as a quick and dirty timer variable
                = cycles 2 // waits a couple of ticks then moves on to case 3
            )
            (case 3
                Animate((send gCast:elements) 0) // I am not sure what this actually does... do we have a cast?
                (while (--register and (== gTheGNumber gNumber))// so while register > 0 ?? I don't get what kicks us out of the while loop
                    (if (== register 150) // when the register variable is at 150... started in case 2 at 200
                        = local1 proc0_12(" 1991 Sierra On-Line, Inc." 67 1 177 70 316 28 proc0_18(global157 global156) 29 gColor 30 1 33 68)
// ok so not sure why this had to have a name, local1 is one of this scripts local variables defined at the top.
// local1 is set to proc0_12 which is pretty obvious is some sort of display command. as it throws the copyright
// line on to the screen... not sure why there are processes inside this display command though or what all of those parameters
// represent.
                    )
                    (User:doit()) // not sure why this is here....
                    Palette(6 160 191 -1) // or these
                    Palette(6 128 159 -1)
                )// end while
                (send global2:drawPic(803 30)) // Ok so this I can tell you, draws picture 803 on the screen. Again not sure about the send bit with DrawPic
                (if (== gNumber gTheGNumber) // hmm... so apparently if these two match
                    (send global2:newRoom(6))// then it is time to take this intro on to room 6... also, this confirms global2 = gRoom as we knew it previously
// (send gRoom:newRoom(###))
                )
            )
        )// end switch
    )//end method
)// end instance

So what do you think, is this something we want to try and sort out together or no... I just figured we would take the game as it comes and look at the code and decipher what it is actually doing on screen.
« Last Edit: May 07, 2015, 11:37:27 PM by Cloudee1 »


Halloween Competition Brass Lantern Prop Competition Groundhog Day Competition

Offline troflip

Re: Understanding later SCI code... SQ4
« Reply #1 on: May 07, 2015, 11:36:24 PM »
A few notes:
- If I recall correctly, it's generally better to use gRoom:drawPic, and not the DrawPic kernel. If you use DrawPic, and the game is saved and restored, anything you drew with DrawPic will no longer be there.
- You're kicked out of the while loop after 200 iterations, when register reaches 0. I dunno what gNumber is, you'll have to follow it to see why it got named that.
- Palette(6 ...) is palette cycling. Looks like it's animating two separate regions of the palette (128-159 and 160-191).
Check out my website: http://icefallgames.com
Groundhog Day Competition

Offline MusicallyInspired

Re: Understanding later SCI code... SQ4
« Reply #2 on: May 08, 2015, 12:24:23 AM »
That would be the SQ4 logo which cycles the background and text separately. I posted an example of that a while back in the "Possible new version of SCI Companion" thread.
Brass Lantern Prop Competition

Offline Cloudee1

Re: Understanding later SCI code... SQ4
« Reply #3 on: May 08, 2015, 07:07:31 AM »
The only problem I have with that is that it is in the final case statement of the room. It is in this same case that the room moves on to room 6. Sierra Logo is long gone by then, It goes away in case 2. So if there is picture pallette cycling going on, shouldn't it be happening well before then.
Halloween Competition Brass Lantern Prop Competition Groundhog Day Competition

Offline troflip

Re: Understanding later SCI code... SQ4
« Reply #4 on: May 08, 2015, 09:14:05 AM »
The Sierra logo (which doesn't cycle) is gone, but it is replaced by the "SPACE QUEST IV" title logo, which is the one that cycles. Seems to match what happens in the room exactly.
Check out my website: http://icefallgames.com
Groundhog Day Competition

Offline Cloudee1

Re: Understanding later SCI code... SQ4
« Reply #5 on: May 08, 2015, 09:52:25 AM »
That is so weird... I would have sworn last night that the Sierra Logo was cycling too... I think I might just be losing it lol  :o
Halloween Competition Brass Lantern Prop Competition Groundhog Day Competition

Offline troflip

Re: Understanding later SCI code... SQ4
« Reply #6 on: May 08, 2015, 09:56:24 AM »
It cycles in SQ5!
Check out my website: http://icefallgames.com
Groundhog Day Competition

Offline Cloudee1

Re: Understanding later SCI code... SQ4
« Reply #7 on: May 08, 2015, 11:15:49 AM »
Ok, so now that I am over that...

On to this prevSignal value in the doit check... (== (send gLongSong:prevSignal) 10)

I have thrown some values into scicompanion to see if I can replicate and I am not finding anywhere that prevSignal is ever actually changed... or reached by the normal playing of the sound.

So in the titlescreen, I have included a changestate and thrown this into case 0
Code: [Select]
(case 0
           (send gTheMusic:
prevSignal(0)
stop()
number(900)
loop(-1)
play()
   )
           = cycles 2 // waits a couple of ticks then moves on to case 1
     )

and then I have changed the doit method
Code: [Select]
  (method (doit)
  (super:doit())
   (if(== state 1)
  (if(== (send gTheMusic:prevSignal) 10)// Doesn't ever seem to occur...
  (self:cue())
  )
   )
  )// end Method

If I comment out the check for prevSignal 10, then the changestate does move on past state 1, but with the line included it does not. What, where and how does prevSignal get set I have scoured both our current template and the sq4 decompile and I am simply not finding anything. This would actually come in handy for my own splash screen and the falling bag trigger.

*Edit
So I got a little peeved at this and decided to try something. I made a quick little timer that printed out the value of the prevSignal every so often. It apparently never changes on its own. A little more desperate I went ahead and decided to force it to change.

I added a couple of local variables
Code: [Select]
temp0
showMe = 50

and then in the doit method I changed it to this.
Code: [Select]
(if(== state 1)
    // Fake it to see what it does...
    (if(> showMe 0) --showMe)
   
    (if(== showMe 0) // when it reaches 0
      = temp0 (send gTheMusic:prevSignal) // set our temp0 variable
         FormatPrint("prevSignal %3d" temp0)  // and show it to me
      = showMe 50 // reset the timer
      (send gTheMusic:prevSignal(+ (send gTheMusic:prevSignal) 1)) // and force change prevSignal
    )
   
  (if(== (send gTheMusic:prevSignal) 10)// Doesn't ever seem to occur on it's own...
  (self:cue())
  )
   )
« Last Edit: May 08, 2015, 11:37:47 AM by Cloudee1 »
Halloween Competition Brass Lantern Prop Competition Groundhog Day Competition

Offline MusicallyInspired

Re: Understanding later SCI code... SQ4
« Reply #8 on: May 08, 2015, 04:46:48 PM »
It's probably triggered via MIDI from the sound resource itself. MIDI files (and by extension, sound resources) have various CC controllers that various MIDI devices can read and understand as various things such as an instrument change, tempo change, pitch shift, pan change, volume change, etc. SCI also recognizes a specific CC to cue a script event. I believe Ken Allen said in one podcast that it was CC controller 127. That's used for things like cuing the next sequence in a cutscene for instance once a song reaches a certain point. Like in the SQ4 intro where the logo "Roger Wilco and the Time Rippers" won't appear until the full theme starts playing. If you swap the intro theme for another song resource that has no scipt-cuing CC controller in it, the intro will just sit there at the Sierra logo and never go beyond it.
Brass Lantern Prop Competition

Offline lskovlun

Re: Understanding later SCI code... SQ4
« Reply #9 on: May 08, 2015, 05:16:41 PM »
It's probably triggered via MIDI from the sound resource itself. MIDI files (and by extension, sound resources) have various CC controllers that various MIDI devices can read and understand as various things such as an instrument change, tempo change, pitch shift, pan change, volume change, etc. SCI also recognizes a specific CC to cue a script event. I believe Ken Allen said in one podcast that it was CC controller 127. That's used for things like cuing the next sequence in a cutscene for instance once a song reaches a certain point. Like in the SQ4 intro where the logo "Roger Wilco and the Time Rippers" won't appear until the full theme starts playing. If you swap the intro theme for another song resource that has no scipt-cuing CC controller in it, the intro will just sit there at the Sierra logo and never go beyond it.
This is true in concept, with the addition that the exact mechanics changed throughout the SCI timeline.

Offline MusicallyInspired

Re: Understanding later SCI code... SQ4
« Reply #10 on: May 08, 2015, 05:36:24 PM »
Yeah. I imagined it would have.
Brass Lantern Prop Competition

Offline Cloudee1

Re: Understanding later SCI code... SQ4
« Reply #11 on: May 08, 2015, 09:10:30 PM »
Ah, so if I were to open up one of my midi sounds in soundbox and actually set some cue points, then I might be able to see this in action... Gonna have to see what I can get to happen.


Holy shit, that kicks ass.  ;D How have I never known about this before.

So... now theoretically, I can create a silent midi. Then play that sound whenever I want while simultaneously kicking off some mp3's via sciaudio and still halfway be able to trigger musically timed events regardless of cycles or seconds... hell, timed events in general, regardless of sciaudio

and yes, I am still talking about SCI0 here.

« Last Edit: May 08, 2015, 09:20:58 PM by Cloudee1 »
Halloween Competition Brass Lantern Prop Competition Groundhog Day Competition

Offline Cloudee1

Re: Understanding later SCI code... SQ4
« Reply #12 on: May 08, 2015, 10:02:55 PM »
Ok... so I guess that takes care of the major questions concerning the first room of SQ4 intro. On to the second room of the intro room 6.

Now this screen shows us a space scene with a ship that flies across it, the game's subtitle, and then a handful of credits before moving on to room 9.

I have managed to get as far as getting the ship to fly across the screen, but I haven't been able to stop getting the ship to fly across the screen.

In the use section, it calls for a script called MCyc. Now for the most part I got this class into the template game and have been able to call it. Currently in my set up, it is script 970. There was a public procedure that it called, so I just went ahead and copied it out of the main script and stuck it straight into the script. Also, I went ahead and added global37 to the main script. That was pretty much all I had to do to get this script in the sci0 template and compiled.
 
Code: [Select]
/******************************************************************************/
(include "sci.sh")
(include "game.sh")
/******************************************************************************/
(script 970)
/******************************************************************************/
(use "Main")
(use "Cycle")
(use "Obj")
//*****************************************************************************
(local

)
/******************************************************************************/
(procedure public (proc999_6 param1 param2)
    return | StrAt(param1 (* 2 param2)) (<< StrAt(param1 (+ 1 (* 2 param2))) $0008)
)
//******************************************************************************
(class MCyc of Cycle
    (properties
        client 0
        caller 0
        cycleDir 1
        cycleCnt 0
        completed 0
        value 0
        points 0
        size 0
    )

    (method (init theClient thePoints theCaller theCycleDir)
        (var temp0[2])
        = client theClient
        = points thePoints
        (if (>= paramTotal 3)
            (if (>= paramTotal 4)
                = cycleDir theCycleDir
                = caller theCaller
            )(else
                (if (IsObject(theCaller))
                    = caller theCaller
                )(else
                    = cycleDir theCaller
                )
            )
        )
        = size 0
        (while (<> proc999_6(points size) 32768)
            ++size
        )
        (if (== cycleDir 1)
            = value 0
        )(else
            = value (- size 4)
        )
        (super:init())
    )


    (method (doit)
        (if (> ++cycleCnt (send client:cycleSpeed))
            = cycleCnt 0
            (self:nextCel())
        )
    )


    (method (nextCel)
        (send client:
            loop(proc999_6(points value))
            cel(proc999_6(points + value 1))
            x(proc999_6(points + value 2))
            y(proc999_6(points + value 3))
        )
        = value (+ value (* cycleDir 4))
        (if (((== cycleDir 1) and (>= value size)) or ((== cycleDir -1) and (< value 0)))
            (self:cycleDone())
        )
    )


    (method (cycleDone)
        = completed 1
        = value 0
        (if (caller)
            = global37 1 // added to main script
        )(else
            (self:motionCue())
        )
    )

)

Now in room 6, there is a local variable which is one long ass array. This array gets sent to this motion class. It was all on one line, I went ahead and added some line breaks to try and make it a little easier to follow. Assuming I have it right, we end up with this.
Code: [Select]
// cycle Dir, Cel, x, y
falconLocations[50] = (1 0 114 70
                   1 0 116 70
                   1 0 118 70
                   1 1 119 70
                   1 1 123 70
                   1 2 133 70
                   1 2 142 70
                   1 3 162 71
                   1 4 197 71
                   1 5 239 71
                   1 6 314 72
                   0 0 65436 65436 32768 )

Then of course, there is our view. In this case they have it set up as a prop which I thought was pretty interesting
Code: [Select]
(instance falcon of Prop(properties view 901))
And then finally in the changeState, our prop uses this new motion class as well as the local variable we talked about.
Code: [Select]
(case 6
  (falcon:
                    setPri(8)
                    z(0)
                    setCycle(MCyc @falconLocations self)
                )
  )
(case 7
                 Print("Hi")
  (falcon:dispose())
  )

So in theory, this prop should run through the motion class MCyc based off the variable points defined, and when complete, cue itself to the next state in which it gets promptly thrown away. I am again missing something here, As I can not get it to recognize that it has completed the cycle through the variable points. Instead, the view reaches the last point (presumably) and then jumps back to the first point and cycles through them again. Similar to setting setCycle(Fwd) instead of End.
« Last Edit: May 08, 2015, 10:05:13 PM by Cloudee1 »
Halloween Competition Brass Lantern Prop Competition Groundhog Day Competition

Offline MusicallyInspired

Re: Understanding later SCI code... SQ4
« Reply #13 on: May 08, 2015, 10:30:54 PM »
Ah I was thinking that cued CC controllers wouldn't be possible with sciAudio. That's neat. :)

I really wanted to delve heavily in what could be done with this method of cuing scripts and vice versa to sound resources, but music always comes at the end of a project's development and I never reached the end of KQ2SCI. All this is exciting me and making me want to get back to it. However, I have a fairly busy touring schedule coming up starting next month.
Brass Lantern Prop Competition

Offline troflip

Re: Understanding later SCI code... SQ4
« Reply #14 on: May 09, 2015, 01:11:34 AM »
fyi, the new version of SCI Companion I have on github has midi import support for sounds, and you can add cue points and the loop point (I don't think the old version of SCI Companion had this, did it? I forget). It's only SCI0 though. The sound format changed in SCI1 and I haven't written support for that yet. And Lars mentioned the way cue points worked has changed throughout SCI, so that's not fun :-(.

Check out my website: http://icefallgames.com
Groundhog Day Competition


SMF 2.0.19 | SMF © 2021, Simple Machines
Simple Audio Video Embedder

Page created in 0.063 seconds with 19 queries.