by Lars Skovlund
Version 0.1, 8. August 1999
This chapter deals with a rather complex subject within SCI. The subsystem described here is one of the "bad boys" in SCI, since it calls functions in user space, as well as changing the value of various selectors. This document is not necessarily complete. There are several things I have not covered - because they are better off in a separate document, or simply because I haven't yet figured that part out. IOW, this stuff is incomplete. Things may change.
After drawing a pic on the screen (which is DrawPic's job, that doesn't surprise now, does it?), some views have to be added to it. There are two ways of doing this; the AddToPic and the Animate call. While AddToPic is used for static views, Animate lets each animated view in the cast list perform an "animation cycle".
An animation cycle is done entirely in SCI code (with the aid of some kernel calls). It involves two other objects; the mover and the cycler. The mover is responsible for controlling the motion of an actor towards a specific point, while the cycler changes the image of the actor, making him appear to walk, for instance.
The behaviour of a view is controlled by its signal property. This property contains a bitfield which describes a lot of animation-related stuff. The bits can be roughly divided into two groups; the script and interpreter bits (I had called them Option and State bits at first, but that is not entirely accurate). The first group allows the script to influence the drawing pro- cess somewhat, the other are used internally by the interpreter. The two groups overlap a bit, though.
bit 0 - A view updating process has ended |
bit 1 - The view object is being updated |
bit 2 (noUpd) - Don't actually draw the view |
bit 3 - The view is hidden from sight. Often, if an actor is supposed to enter and exit a room (such as the guards in the plazas in QfG2), this bit is used. When he's supposed to enter the room, bit 3 in his signal is cleared. When he leaves, bit 3 is set, but his SCI object is not deleted. |
bit 4 (fixPriOn) - if this bit is set, the priority of the view never changes (if it isn't, the interpreter recalculates the priority automagically). |
bit 7 - The view should be removed from the screen (an interpreter bit - its corresponding script bit is bit 3). If bit 3 isn't set as well, the view reappears on the next frame. |
bit 8 - deactivates the mover object of the view (it is "frozen" - the view can still turn, however). |
bit 9 (isExtra) - ??? probably reserved for script use ??? |
bit 10 - the view hit an obstacle on the last animation cycle |
bit 11 - Meaningful for actors only. Means that the actor does not turn, even though he is walking the "wrong way". |
bit 12 - the view cycler is disabled. This makes ego float instead of walk. |
bit 13 (ignoreHorizon) - Meaningful for actors only. Moving the actor towards the edges of the screen doesn't cause a room switch. At least, that's what I thought it would do. It doesn't. Hmmm. :-( |
bit 14 (ignrAct) - Actors can walk in the rectangle occupied by the view. The behaviour of this bit is odd, and best expressed by example. The Guild Master in QfG1 has his bit 14 set. This means that ego (or someone else) can walk all the way to his chair (try sneaking in on him from behind). If we clear this bit, we can't sneak in on him. |
bit 15 - The view should be disposed |
Animate (see the section called Kernel function 0x0b: Animate([DblList], [word]) in Chapter 5) can be called in two ways:
Animate(DblList cast, bool cycle) |
Animate() |
The cast list is just a list of the views to draw. Animate creates a backup of this list for updating purposes. However, this backup cast list isn't just a normal copy. The interpreter copies some selectors from the view (view, loop, cel, nsRect) and places them in a special data structure. This indicates to me that there is a possibility that the view objects may be deleted even though an update is anticipated.
The general pseudocode for Animate goes as follows:
1. Kill the backup cast list. 2. If the cast pointer is NULL, just redraw the current map and exit. 3. For each non-frozen view (bit 8 clear), let it run an animation cycle (by calling View::doit) 6. For all views, perform steps 7-9. 7. If the loop or cel property has overflowed, it is reset to 0 8. Recalculate the priority of the view (only if signal bit 4 is clear). 9. If the signal property indicates that we need to, increase (not set) the PicNotValid flag (several bits are involved in this; the exact combinations are a mess to figure out, I'll do it on request). 10. If PicNotValid != 0, draw all the static views (PicViews). 11. Draw all non-PicViews, saving their rectangles first and storing a memory handle in the underBits selector. 12. Create a backup of the cast data. 13. Remove the appropriate views from screen. 14. Dispose the views which have their signal bit 15 set (calling View::delete) |
The algorithm for drawing PicViews is basically several loops: (repeat all of the steps for each view)
1. If signal bit 2 is clear, jump to 4 2. If bit 0 is set, clear it and set bit 2 instead. 3. Continue with the next view. 4. If signal bit 7 is set, jump to 8. 5. If PicNotValid == 1, jump to 7. 6. Restore the view rectangle using the memory handle stored in UnderBits (must be != 0, of course). 7. Free the memory used by underBits and zero out the selector afterwards. 8. Clear bit 6 of the signal 9. If bit 1 is set, clear it and bit 2. |
1. Load and draw the view 2. Clear signal bits 0, 1, 2, 6. 3. If signal bit 14 is set, skip to the next rectangle 4. Copy the view nsRect into a temporary variable. 5. Find the start of the priority band specified by the priority selector. 6. If it is greater than the nsRect top, set the top of our temp rectangle to the nsRect top. 7. If the top is now below the bottom, set the top = the bottom. 8. Draw the temp rectangle onto the control map using white color. |
![]() | The ReAnimate subfunction (0x0D) of the Graph kernel call redraws parts of the maps using the cast list created by Animate, whereas the ShowBits call (0x0C) copies parts of the active map to the physical screen. |
[1] | The bit names I have written come from some debug information I got from QfG2 - type "suck blue frog" then Ctrl-W to save the cast list! |