Camera — Follow, Pan & the Viewport

The presented frame is a fixed-width window into a room that can be wider than the screen. The camera's x is the centre of that window, not its left edge — every script opcode and every camera variable speaks in centre coordinates. setCameraAt(160) on a 320-wide screen shows the room from x=0.

1. Clamping

The centre is clamped so the window never shows past the room: it can't go below half a screen from the left edge or above half a screen from the right. A script can narrow this further with roomOps roomScroll, which sets VAR_CAMERA_MIN / VAR_CAMERA_MAX; when set, the scripted range overrides the default room bounds. Every camera movement — follow, pan, or a direct setCameraAt — lands inside the active range.

A room load is itself a clamp. SCUMM's cameraMoved reclamps the centre against the current room every frame, so crossing into a narrower room snaps a carried-over centre inward — and that corrected value is what the next room inherits. Clamping only at follow/pan/setCameraAt time leaves a gap: a centre can survive a plain loadRoom and sit outside the new room's bounds. The witness is the LeChuck-explosion ending, which uses no setCameraAt at all — it walks the 640-wide room 59 with the camera near ego's x≈297, through the 320-wide blimp room (whose bounds clamp the centre to 160), into the 640-wide credits room, which inherits 160 and frames the cliff at the left edge. Skip the room-load reclamp and 297 survives into the credits room, splitting it down the middle — the cliff stranded beside the LucasArts logo.

Every movement also publishes the new centre into VAR_CAMERA_POS_X. Scripts poll that variable constantly — escape-watchers, walk-past-camera gates (Meathook's payoff script loops on meathookX < cameraX − 175; Stan's arrival script waits for the centre to equal the clamp floor exactly) — so a camera that moves without writing it deadlocks them.

2. Follow mode

actorFollowCamera puts the camera in follow mode: it tracks the named actor with a dead zone of ±80 px around the centre. The actor walks freely inside that window; only when it leaves it does the camera move — and not by snapping to the edge: leaving the dead zone arms a pan to the actor's (clamped) x, stepped by the same 8-px-per-frame stepper as a scripted pan (§3) and latched until it lands, even if the actor stops back inside the dead zone meanwhile. wait forCamera covers a follow pan exactly like a scripted one — Stan's lot script waits for the centre to settle at the clamp floor while the ego stands well inside the dead zone, which only releases because the follow pan runs to the actor's clamped position, not the dead-zone edge. This is why walking around a one-screen room never scrolls, and why a long walk across a wide room scrolls only once the actor leads the camera by 80 px.

Pointing follow at an actor standing in another room is what triggers the room switch — MI1's boot script enters the lookout exactly this way: it places the ego in the lookout room and then issues actorFollowCamera, and the room change falls out of the follow.

3. Scripted pans

panCameraTo detaches follow and glides the centre toward a target at 8 px per game frame — one background strip per frame, since the room bitmap is stored in 8-px-wide strips (room 64's dig scene is the first to pan this way). Because a pan detaches follow, the two modes never fight over the camera within a frame.

wait forCamera blocks the calling script until the camera reaches its pan destination — not merely while a pan target is armed. The distinction is load-bearing: the SCUMM bar (room 28) runs a camera-controller script (#201) that re-issues panCameraTo every frame to whichever of the room's two fixed positions matches ego's side — including when the camera is already there. Scripts that wait on the camera in that room (the three-pirates conversation #220, the ambient chatter #207/#210) run later in slot order than #201, so an "armed-pan" check deadlocks them forever once they yield at the wait even once: the controller re-arms the target before every re-check, and the pan stepper only clears it at the end of the frame. A reached (or same-spot) destination must read as settled.

The pan target is transient state: a save taken mid-pan resumes with the camera at its saved position and no pending pan. Only the camera position itself persists.

4. Ordering within a game frame

The follow step runs once per game frame, after actors walk. Run it before the walk and the camera is always one frame behind the followed actor — the actor's screen position oscillates as it walks, a visible "two Guybrush" stutter. Walking first, then following, keeps actor and camera in lockstep.

5. Wide rooms and screen-space text

print … at (x, y) coordinates for system text are screen-space. In rooms no wider than the screen the two spaces coincide, but in wider rooms (MI1's 640-wide credits room) mapping screen text onto the room requires the camera position — the shell composes overlay text camera-relative, so the text stays put on screen while the room scrolls beneath it.