Logo Pending


On SCI Windows – Part 3 – King’s Quest 5

Compared to a BorderWindow, the custom frame used in King’s Quest 5 looks pretty straightforward. Indeed, it’s a few lines and some decorative corner pieces, mostly.

 Here they are right now.

Normally, the color properties would be set on startup depending on the detected color depth. Let’s pretend otherwise. Other than that, the below code is effectively unchanged — all I did was add comments.

(class myWindow of SysWindow
  (properties
    ; SysWindow properties elided.
    back 23
    color 8
    lineColor 19
  )
 
  (method (open &tmp screens theTop theLeft theBottom theRight celHigh celWide)
    ; Determine the size of our corner pieces.
    (= celHigh (CelHigh 944 0 0))
    (= celWide (CelWide 944 0 0))
 
    ; Draw on the main screen.
    (SetPort 0)
 
    ; Make some room.
    (= theTop (- top 8))
    (= theLeft (- left 8))
    (= theBottom (+ bottom 8))
    (= theRight (+ right 8))
 
    (= screens VISUAL)
    (if (!= priority -1) (= screens (| screens PRIORITY)))
 
    ; Save what's underneath us.
    (= underBits (Graph grSAVE_BOX theTop theLeft (+ theBottom 2) (+ theRight 2) screens))
 
    ; Draw a drop shadow
    (Graph grFILL_BOX (+ theTop 2) (+ theLeft 2) (+ theBottom 2) (+ theRight 2) screens 0 priority)
 
    ; Draw our fill
    (Graph grFILL_BOX theTop theLeft theBottom theRight screens back priority)
 
    ; Draw the corner pieces
    (DrawCel 944 0 0 theLeft theTop -1)
    (DrawCel 944 0 1 theLeft (- theBottom celHigh) -1)
    (DrawCel 944 0 2 (- theRight celHigh) theTop -1)
    (DrawCel 944 0 3 (- theRight celHigh) (- theBottom celHigh) -1)
 
    ; Top edges...
    (Graph grDRAW_LINE theTop (+ theLeft celWide) theTop (- theRight celWide) lineColor -1 -1)
    (Graph grDRAW_LINE (+ theTop 2) (+ theLeft celWide) (+ theTop 2) (- theRight celWide) lineColor -1 -1)
    ; Bottom...
    (Graph grDRAW_LINE (- theBottom 1) (+ theLeft celWide) (- theBottom 1) (- theRight celWide) lineColor -1 -1)
    (Graph grDRAW_LINE (- theBottom 3) (+ theLeft celWide) (- theBottom 3) (- theRight celWide) lineColor -1 -1)
    ; Left...
    (Graph grDRAW_LINE (+ theTop celHigh) theLeft (- theBottom celHigh) theLeft lineColor -1 -1 )
    (Graph grDRAW_LINE (+ theTop celHigh) (+ theLeft 2) (- theBottom celHigh) (+ theLeft 2) lineColor -1 -1)
    ; and right.
    (Graph grDRAW_LINE (+ theTop celHigh) (- theRight 1) (- theBottom celHigh) (- theRight 1) lineColor -1 -1)
    (Graph grDRAW_LINE (+ theTop celHigh) (- theRight 3) (- theBottom celHigh) (- theRight 3) lineColor -1 -1)
 
    ; Show what we have wrought.
    (Graph grUPDATE_BOX theTop theLeft (+ theBottom 2) (+ theRight 2) 1)
 
    ; Only now do we change our window type to custom and open it.
    (= type 129)
    (super open:)
 
    (= top theTop)
    (= left theLeft)
    (= bottom (+ theBottom 2))
    (= right (+ theRight 2))
  )
)

Don’t let the math discourage you. Because the corner pieces are drawn before the edge lines, the latter have to be carefully drawn right up against the former. You’ll see in the next part how you can get away with doing the edges first and then drawing the corners.

[ , , ] Leave a Comment

On SCI Windows – Part 2 – BorderWindow

A popular style of window seen in SCI1 games like Police Quest and Space Quest is the BorderWindow. By default it’s thick and gray, but it can really have any thickness and set of five colors you want.

The default looks something like this. Your exact colors may vary as I use a custom palette instead of the standard SCI1 palette, and Space Quest 5 has somewhat tinted grays.
If one were to edit the BorderWindow script a little bit to enable title bars, and did it in a naive way, they’d get something like this. So let’s not do that.
The bevelWid and shadowWid properties can of course be changed on a per-window basis…
…as can the back and four edge colors, topBordColor et al.

But how does this work exactly? Let’s take the actual BorderWindow script code and walk through it.

(class BorderWindow of SysWindow
  (properties
    ; All other properties inherited from SysWindow
    back 5
    topBordColor 7
    lftBordColor 6
    rgtBordColor 4
    botBordColor 3
    bevelWid 3
    shadowWid 2
  )
 
  (method (dispose)
    (super dispose:)
    (SetPort 0)
  )
 
  (method (show)
    (Graph grUPDATE_BOX top left bottom right VISUAL)
  )
 
  (method (open &tmp oldPort screens)
    (SetPort 0) ; Use the entire screen.
 
    ; If we have a priority set, render to that screen too.
    (= screens VISUAL)
    (if (!= priority -1) (= screens (| screens PRIORITY)))
 
    ; Make some room in the "last seen" rect to fit the border.
    (= lsTop (- top bevelWid))
    (= lsLeft (- left bevelWid))
    (= lsRight (+ right bevelWid shadowWid))
    (= lsBottom (+ bottom bevelWid shadowWid))
 
    (= type 128) ; We are custom, as described in the
    ; previous post.
 
    (super open:) ; Let a SysWindow open itself.
    ; This actually just calls the NewWindow kernel call
    ; and saves the returned handle to our window property.
 
    (drawWindow top left bottom right back
      topBordColor lftBordColor botBordColor rgtBordColor
      bevelWid shadowWid
      priority screens
    )
 
    (= oldPort (GetPort)) ; Remember our current port.
    (SetPort 0) ; Use the whole screen again.
    ; Show what we have wrought.
    (Graph grUPDATE_BOX lsTop lsLeft lsBottom lsRight VISUAL)
    (SetPort oldPort)
  )
)

That’s not so bad. The meat of the dish is in drawWindow, obviously:

(procedure (drawWindow t l b r theColor topColor leftColor bottomColor rightColor theBevelWid theShadowWid thePri theMaps &tmp savePort i)
  ; Again, we remember the current port and use the whole screen.
  (= savePort (GetPort))
  (SetPort 0)
 
  ; Fill in the window background.
  (Graph grFILL_BOX t l (+ b 1) (+ r 1) theMaps theColor thePri)
 
  ; Extend our rect to include the bevel.
  (-= t theBevelWid)
  (-= l theBevelWid)
  (+= r theBevelWid)
  (+= b theBevelWid)
 
  ; Draw the top and bottom bevels as simple boxes.
  (Graph grFILL_BOX
    t l (+ t theBevelWid) r
    theMaps topColor thePri
  )
  (Graph grFILL_BOX
    (- b theBevelWid) l b r
    theMaps bottomColor thePri
  )
 
  ; Draw the left and right bevels line by line.
  (for ((= i 0)) (< i theBevelWid) ((++ i))
    (Graph grDRAW_LINE
      (+ t i) (+ l i) (- b (+ i 1)) (+ l i)
      leftColor thePri -1
    )
    (Graph grDRAW_LINE
      (+ t i) (- r (+ i 1)) (- b (+ i 1)) (- r (+ i 1))
      rightColor thePri -1
    )
  )
 
  ; Draw the shadow last. Unlike SysWindows,
  ; these are done as two boxes.
  (if theShadowWid
    (Graph grFILL_BOX
      (+ t theShadowWid) r
      (+ b theShadowWid) (+ r theShadowWid)
      theMaps 0 thePri
    )
    (Graph grFILL_BOX
      b (+ l theShadowWid)
      (+ b theShadowWid) r
      theMaps 0 thePri
    )
  )
 
  (SetPort savePort)
)

To visualize, a BorderWindow (sans shadow) renders like this:

Next time, we take a step back and look at King’s Quest.

[ , ] 1 Comment on On SCI Windows – Part 2 – BorderWindow