Logo Pending


Unusual arrow keys and cursor behavior

Most players of SCI games would naturally gravitate to using the mouse if it’s an SCI1 game or later. With SCI0 using a text parser and no pathfinding it strikes me personally as more efficient to just use the arrow keys in those games. But that’s just me. The important part here is that some SCI11 games don’t respond to the arrow keys the same way as others do.

SCI0 being effectively stateless in a way, pressing the arrow keys will cause your character to start walking in that direction. Clicking somewhere causes them to walk there in a straight line until something gets in the way. In SCI1 the icon bar introduced a kind of state in that you have several active cursors. In all but a few adventure games, pressing the arrow keys will cause your character to move if the current cursor is Walk. Otherwise, the cursor itself moves around. So if the current cursor is, let’s say, Look, the little eye moves instead of the main character. Unless of course you’d already set them on their way. And of course (unless you’re playing the original KQ5) clicking somewhere with the Walk cursor makes your character find their way around obstacles towards that point.

Two exceptions to this rule that I know of are Space Quest 5 and King’s Quest 6. It turns out if you press the arrow keys with the Walk cursor out, the cursor itself moves. Why is that?

Obviously, there’s something in the game scripts that causes both the usual and specific behavior. Let’s look at both.

The usual behavior is enabled by the Ego class and its handleEvent method. Called from User, this method checks for direction and walk events. If it’s the former, an arrow key was pressed or a joystick was nudged. If it’s the latter, we clicked the Walk cursor somewhere. How do we know it’s Walk? Because User only calls this method if it was. Any other cursor, it runs further down and ends up calling another script that handles moving the cursor around if you press an arrow key.

(method (handleEvent pEvent &tmp eType dir)
  (= eType (pEvent type?))
  (cond
    ; First, see if we have a script that wants the event.
    ((and script (script handleEvent: pEvent)) true)
 
    ; See if it's a direction event
    ((& eType evJOYSTICK)
      (= dir (pEvent message?))
 
      ; don't claim dirStop/CENTER
      (if (and (== dir CENTER) (& eType evKEYBOARD))
        (return (pEvent claimed?))
      )
 
      ; Pressing the same key that started a motion again should stop
      (if (and (& eType evKEYBOARD) ; it's a key
               (== dir (gUser prevDir?)) ; same dir as before
               (IsObject mover)) ; ego is moving
        (= dir CENTER)
      )
 
      ; In the case of a keyDown event, keep the previous direction,
      ; so we know what key stops ego.
      (gUser prevDir: dir)
 
      ; Actor::setDirection sets ego off to walk.
      (self setDirection: dir)
      (pEvent claimed: true)
    )
 
    ((& eType evVERB)
      (if (& eType evMOVE)
        (switch gEgoUseObstacles
          (0 (self setMotion: MoveTo (pEvent x?) (+ (pEvent y?) z)))
          (1 (self setMotion: PolyPath (pEvent x?) (+ (pEvent y?) z)))
          (2 (self setMotion: PolyPath (pEvent x?) (+ (pEvent y?) z) null false))
        )
        (gUser prevDir: 0)
        (pEvent claimed: true)
      else
        (super handleEvent: pEvent)
      )
    )
    (else (super handleEvent: pEvent))
  )
  (return (pEvent claimed?))
)

You might notice the bit about gEgoUseObstacles.  Setting that to zero effectively makes clicks act like in SCI0. At least to the player — the script code is somewhat different.

Now that just leaves the question of why these two games don’t react like that. And it’s really very simple. KQ6 and SQ5 do it each in their own slightly different way, but the basic trick is the same. Because KQ6 seems a bit neater to me, I’ll show that one first:

(instance ego of Ego
  ; Irrelevancies elided
 
  (method (handleEvent pEvent)
    (return
      (if (& (pEvent type?) evJOYSTICK)
        ; Refuse to handle any directional inputs
        (return false)
      else
        ; Let the original Ego class figure it out
        (super handleEvent: pEvent &rest)
      )
    )
  )
)

Simple, huh? Because this returns false for any direction events, User will always end up percolating the event down to PseudoMouse and as such the Walk cursor is moved by the keyboard or joystick instead of the player character. Now let’s see how this compares to Space Quest 5.

(class SQEgo of Ego
  ; Irrelevancies elided
 
  (method (handleEvent pEvent &tmp eType eMsg)
    (= eType (pEvent type?))
    (= eMsg (pEvent message?)) ; woo wasted effort!
    (return
      (cond 
        ((and script (script handleEvent: pEvent)) true)
        ((& eType evJOYSTICK) (return false))
        (else (super handleEvent: pEvent &rest))
      )
    )
  )
)

Seems pretty clear considering what we already know. So much so I won’t bother documenting it much.

The SCI Companion SCI11 template game is based on SQ5 so by default this too applies to any game you make with it. The obvious way to remove this then is to remove GameEgo::handleEvent. I did, and I haven’t looked back since.

Like
[ ]

Leave a Reply

Your email address will not be published. Required fields are marked *