OPAT
OPAT is the 10th subsystem in Crash 1. It concerns the allocation and initialization (and releasing) of all game objects. For this reason, a proposed name for its expansion is Object/Process Allocation Table.
Contents
Initialization routine
The OPAT initialization routine is located at the following addresses in each of the Crash games:
- Crash 1 NTSC-U: 0x1AAD8
- Crash 2 NTSC-U: 0x1EE64
Crash 1
Object Allocation
This routine begins by allocating a block of memory for 96 objects with the malloc function (96 objects * 604 bytes/object = 57984 bytes). A pointer to the newly allocated memory is stored in objects
of the GOOL subsystem namespace. objects
now refers to a dynamically allocated array of 96 objects.
The routine then allocates a separate section of memory for the 97th object-the player object. An extra 256 bytes in addition to the standard 608 byte structure size (608+256 = 860) is allocated for the player object. This is to account for the higher number of activation records created and local 'registers' used by its lengthier, more complex code. A pointer to the newly allocated memory is stored in player
of the GOOL subsystem namespace.
If either the memory for the objects or for the player object could not be allocated, the routine returns error code 0xFFFFFFF1.
Free List/Free Object Pool Initialization
At this point, all the necessary memory for objects has been allocated. The routine now initializes the freelist
[list handle] object, marking it as a list handle by setting its header
field to 2
. Note that a list handle object is not an actual object and only refers to a 'category' of objects, composed of its children.
Next the routine initializes and constructs a linked list of the 96 objects, marking each as a free object and assigning the first object as children
of the freelist
handle. This establishes a pool of free objects, initially consisting of all 96 objects. In detail, this is done by iterating through the first 95 objects, and for each object:
- setting its
header
field to0
. This marks the object a free object. - storing a pointer to the object that follows it [in the array] in its
sibling
field. (objects[n].sibling = &objects[n+1];
) This establishes the link between objects. The 96th object does not have a following object so its sibling field is set to0
. - setting its
parent
field to point to thefreelist
handle. Each object in the free list is a child of thefreelist
handle, and the left-child right-sibling representation requires that an object always points to its parent object. - setting its
children
field to0
. Presence of achildren
andsibling
field allow objects to have a left-child right-sibling k-ary tree of descendants, however this is irrelevant for free objects. Free objects do not have children and thus initialize theirchildren
field to0
.
The freelist
handle now refers to the category of free objects, and each of its children are an object in the pool.
Used Object List Initialization
Now the routine initializes 8 the used object list handles: usedlists
(array). When the game eventually creates or spawns an object, a free object is adopted from the pool to one of the 8 used object list handles; the game then marks that object as an existing object (i.e. 'in use') and continues to perform its remaining instantiation. Initially, however, no object is in use-all 96 objects are free objects. Consequently, none of the used object list handles should have children. Initializing the 8 handles is then accomplished by iterating through them, and for each handle:
- setting its
header
field to2
. This marks the handle [object] a list handle. - setting its
children
field to0
. The handle does not yet have children.
Eventually, the usedlists
are used not only to 'contain' spawned or created objects, but also to categorize them into 8 distinct categories.
Player Object Initialization
Finally the routine initializes the player object. This is done by
- setting its
header
field to0
. This marks the object a free object (**or rather, not in use) - setting its
parent
field to0
. The player object is treated separately from normal objects. Spawning the player does not require or involve adopting a free object from the pool; the player never belongs to and is never an object among the pool of free objects. Its data will always exist in the 860 byte region allocated for it, **in use or not. Thus it is not necessary for the player object to belong to any particular category and therefore have a parent at initialization. - setting its
sibling
field to0
. The player does not belong to a category and therefore does not have any sibling that could belong to a same category. - setting its
children
field to0
. The player object, though separate from the pool, is a free object and does not have children.
Return Success Code
At this point, the routine returns a success code (0xFFFFFF01).
Summary
- For the
freelist
handle:- set
type
field to2
(the object is a list handle) - set
children
field to point toobjects[0]
- set
- For the 96 allocated
objects
:- set
type
field to0
(the object is free/unused) - set
sibling
field to point to the following object if not the last object:
objects[n].process.sibling = &objects[n+1];
, else setsibling
field to0
- set
parent
field to point to thefreelist
handle - set
children
field to0
- set
- For the 8
usedlists
handles:- set
type
field to2
(the object is a list handle) - set
children
field to0
(no objects belong to it at init)
- set
- For the
player
object:- set
type
field to0
(the object is free/unused) - set
parent
field to0
(not part of a category) - set
sibling
field to0
(no sibling in its non-existent category) - set
children
field to0
- set
Deinitialization routine
This routine simply releases the object memory allocated by the initialization routine:
free(objects);
free(player);