sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

object_list_processor.c (21692B)


      1 #include <PR/ultratypes.h>
      2 
      3 #include "sm64.h"
      4 #include "area.h"
      5 #include "behavior_data.h"
      6 #include "camera.h"
      7 #include "debug.h"
      8 #include "engine/behavior_script.h"
      9 #include "engine/graph_node.h"
     10 #include "engine/surface_collision.h"
     11 #include "engine/surface_load.h"
     12 #include "interaction.h"
     13 #include "level_update.h"
     14 #include "mario.h"
     15 #include "memory.h"
     16 #include "object_collision.h"
     17 #include "object_helpers.h"
     18 #include "object_list_processor.h"
     19 #include "platform_displacement.h"
     20 #include "profiler.h"
     21 #include "spawn_object.h"
     22 
     23 
     24 /**
     25  * Flags controlling what debug info is displayed.
     26  */
     27 s32 gDebugInfoFlags;
     28 
     29 /**
     30  * The number of times per frame find_floor found no floor beneath an
     31  * object, and therefore either returned a dynamic floor or NULL.
     32  */
     33 s32 gNumFindFloorMisses;
     34 
     35 UNUSED s32 unused_8033BEF8;
     36 
     37 /**
     38  * An unused debug counter with the label "WALL".
     39  */
     40 s32 gUnknownWallCount;
     41 
     42 /**
     43  * Roughly the number of objects that have been processed this frame so far.
     44  * A bug in update_terrain_objects makes this count inaccurate.
     45  */
     46 u32 gObjectCounter;
     47 
     48 /**
     49  * The number of times find_floor, find_ceil, and find_wall_collisions have been called respectively.
     50  */
     51 struct NumTimesCalled gNumCalls;
     52 
     53 /**
     54  * An array of debug controls that could be used to tweak in-game parameters.
     55  * The only used rows are [4] and [5] (effectinfo and enemyinfo).
     56  */
     57 s16 gDebugInfo[16][8];
     58 s16 gDebugInfoOverwrite[16][8];
     59 
     60 /**
     61  * A set of flags to control which objects are updated on a given frame.
     62  * This is used during dialog and cutscenes to freeze most objects in place.
     63  */
     64 u32 gTimeStopState;
     65 
     66 /**
     67  * The pool that objects are allocated from.
     68  */
     69 struct Object gObjectPool[OBJECT_POOL_CAPACITY];
     70 
     71 /**
     72  * A special object whose purpose is to act as a parent for macro objects.
     73  */
     74 struct Object gMacroObjectDefaultParent;
     75 
     76 /**
     77  * A pointer to gObjectListArray.
     78  * Given an object list index idx, gObjectLists[idx] is the head of a doubly
     79  * linked list of all currently spawned objects in the list.
     80  */
     81 struct ObjectNode *gObjectLists;
     82 
     83 /**
     84  * A singly linked list of available slots in the object pool.
     85  */
     86 struct ObjectNode gFreeObjectList;
     87 
     88 /**
     89  * The object representing Mario.
     90  */
     91 struct Object *gMarioObject;
     92 
     93 /**
     94  * An object variable that may have been used to represent the planned
     95  * second player. This is speculation, based on its position and its usage in
     96  * shadow.c.
     97  */
     98 struct Object *gLuigiObject;
     99 
    100 /**
    101  * The object whose behavior script is currently being updated.
    102  * This object is used frequently in object behavior code, and so is often
    103  * aliased as "o".
    104  */
    105 struct Object *gCurrentObject;
    106 
    107 /**
    108  * The next object behavior command to be executed.
    109  */
    110 const BehaviorScript *gCurBhvCommand;
    111 
    112 /**
    113  * The number of objects that were processed last frame, which may miss some
    114  * objects that were spawned last frame and all objects that were spawned this
    115  * frame. It also includes objects that were unloaded last frame.
    116  * Besides this, a bug in update_terrain_objects makes this count inaccurate.
    117  */
    118 s16 gPrevFrameObjectCount;
    119 
    120 /**
    121  * The total number of surface nodes allocated (a node is allocated for each
    122  * spatial partition cell that a surface intersects).
    123  */
    124 s32 gSurfaceNodesAllocated;
    125 
    126 /**
    127  * The total number of surfaces allocated.
    128  */
    129 s32 gSurfacesAllocated;
    130 
    131 /**
    132  * The number of nodes that have been created for surfaces.
    133  */
    134 s32 gNumStaticSurfaceNodes;
    135 
    136 /**
    137  * The number of surfaces in the pool.
    138  */
    139 s32 gNumStaticSurfaces;
    140 
    141 /**
    142  * A pool used by chain chomp and wiggler to allocate their body parts.
    143  */
    144 struct MemoryPool *gObjectMemoryPool;
    145 
    146 
    147 s16 gCheckingSurfaceCollisionsForCamera;
    148 s16 gFindFloorIncludeSurfaceIntangible;
    149 TerrainData *gEnvironmentRegions;
    150 s32 gEnvironmentLevels[20];
    151 RoomData gDoorAdjacentRooms[60][2];
    152 s16 gMarioCurrentRoom;
    153 s16 D_8035FEE2;
    154 s16 D_8035FEE4;
    155 s16 gTHIWaterDrained;
    156 s16 gTTCSpeedSetting;
    157 s16 gMarioShotFromCannon;
    158 s16 gCCMEnteredSlide;
    159 s16 gNumRoomedObjectsInMarioRoom;
    160 s16 gNumRoomedObjectsNotInMarioRoom;
    161 s16 gWDWWaterLevelChanging;
    162 s16 gMarioOnMerryGoRound;
    163 
    164 /**
    165  * Nodes used to represent the doubly linked object lists.
    166  */
    167 struct ObjectNode gObjectListArray[16];
    168 
    169 /**
    170  * The order that object lists are processed in a frame.
    171  */
    172 s8 sObjectListUpdateOrder[] = { OBJ_LIST_SPAWNER,
    173                                 OBJ_LIST_SURFACE,
    174                                 OBJ_LIST_POLELIKE,
    175                                 OBJ_LIST_PLAYER,
    176                                 OBJ_LIST_PUSHABLE,
    177                                 OBJ_LIST_GENACTOR,
    178                                 OBJ_LIST_DESTRUCTIVE,
    179                                 OBJ_LIST_LEVEL,
    180                                 OBJ_LIST_DEFAULT,
    181                                 OBJ_LIST_UNIMPORTANT,
    182                                 -1 };
    183 
    184 /**
    185  * Info needed to spawn particles and keep track of which have been spawned for
    186  * an object.
    187  */
    188 struct ParticleProperties {
    189     u32 particleFlag;
    190     u32 activeParticleFlag;
    191     u8 model;
    192     const BehaviorScript *behavior;
    193 };
    194 
    195 /**
    196  * A table mapping particle flags to various properties use when spawning a particle.
    197  */
    198 struct ParticleProperties sParticleTypes[] = {
    199     { PARTICLE_DUST,                 ACTIVE_PARTICLE_DUST,                 MODEL_MIST,                 bhvMistParticleSpawner },
    200     { PARTICLE_VERTICAL_STAR,        ACTIVE_PARTICLE_V_STAR,               MODEL_NONE,                 bhvVertStarParticleSpawner },
    201     { PARTICLE_HORIZONTAL_STAR,      ACTIVE_PARTICLE_H_STAR,               MODEL_NONE,                 bhvHorStarParticleSpawner },
    202     { PARTICLE_SPARKLES,             ACTIVE_PARTICLE_SPARKLES,             MODEL_SPARKLES,             bhvSparkleParticleSpawner },
    203     { PARTICLE_BUBBLE,               ACTIVE_PARTICLE_BUBBLE,               MODEL_BUBBLE,               bhvBubbleParticleSpawner },
    204     { PARTICLE_WATER_SPLASH,         ACTIVE_PARTICLE_WATER_SPLASH,         MODEL_WATER_SPLASH,         bhvWaterSplash },
    205     { PARTICLE_IDLE_WATER_WAVE,      ACTIVE_PARTICLE_IDLE_WATER_WAVE,      MODEL_IDLE_WATER_WAVE,      bhvIdleWaterWave },
    206     { PARTICLE_PLUNGE_BUBBLE,        ACTIVE_PARTICLE_PLUNGE_BUBBLE,        MODEL_WHITE_PARTICLE_SMALL, bhvPlungeBubble },
    207     { PARTICLE_WAVE_TRAIL,           ACTIVE_PARTICLE_WAVE_TRAIL,           MODEL_WAVE_TRAIL,           bhvWaveTrail },
    208     { PARTICLE_FIRE,                 ACTIVE_PARTICLE_FIRE,                 MODEL_RED_FLAME,            bhvFireParticleSpawner },
    209     { PARTICLE_SHALLOW_WATER_WAVE,   ACTIVE_PARTICLE_SHALLOW_WATER_WAVE,   MODEL_NONE,                 bhvShallowWaterWave },
    210     { PARTICLE_SHALLOW_WATER_SPLASH, ACTIVE_PARTICLE_SHALLOW_WATER_SPLASH, MODEL_NONE,                 bhvShallowWaterSplash },
    211     { PARTICLE_LEAF,                 ACTIVE_PARTICLE_LEAF,                 MODEL_NONE,                 bhvLeafParticleSpawner },
    212     { PARTICLE_SNOW,                 ACTIVE_PARTICLE_SNOW,                 MODEL_NONE,                 bhvSnowParticleSpawner },
    213     { PARTICLE_BREATH,               ACTIVE_PARTICLE_BREATH,               MODEL_NONE,                 bhvBreathParticleSpawner },
    214     { PARTICLE_DIRT,                 ACTIVE_PARTICLE_DIRT,                 MODEL_NONE,                 bhvDirtParticleSpawner },
    215     { PARTICLE_MIST_CIRCLE,          ACTIVE_PARTICLE_MIST_CIRCLE,          MODEL_NONE,                 bhvMistCircParticleSpawner },
    216     { PARTICLE_TRIANGLE,             ACTIVE_PARTICLE_TRIANGLE,             MODEL_NONE,                 bhvTriangleParticleSpawner },
    217     { 0, 0, MODEL_NONE, NULL },
    218 };
    219 
    220 /**
    221  * Copy position, velocity, and angle variables from MarioState to the Mario
    222  * object.
    223  */
    224 void copy_mario_state_to_object(void) {
    225     s32 i = 0;
    226     // L is real
    227     if (gCurrentObject != gMarioObject) {
    228         i++;
    229     }
    230 
    231     gCurrentObject->oVelX = gMarioStates[i].vel[0];
    232     gCurrentObject->oVelY = gMarioStates[i].vel[1];
    233     gCurrentObject->oVelZ = gMarioStates[i].vel[2];
    234 
    235     gCurrentObject->oPosX = gMarioStates[i].pos[0];
    236     gCurrentObject->oPosY = gMarioStates[i].pos[1];
    237     gCurrentObject->oPosZ = gMarioStates[i].pos[2];
    238 
    239     gCurrentObject->oMoveAnglePitch = gCurrentObject->header.gfx.angle[0];
    240     gCurrentObject->oMoveAngleYaw = gCurrentObject->header.gfx.angle[1];
    241     gCurrentObject->oMoveAngleRoll = gCurrentObject->header.gfx.angle[2];
    242 
    243     gCurrentObject->oFaceAnglePitch = gCurrentObject->header.gfx.angle[0];
    244     gCurrentObject->oFaceAngleYaw = gCurrentObject->header.gfx.angle[1];
    245     gCurrentObject->oFaceAngleRoll = gCurrentObject->header.gfx.angle[2];
    246 
    247     gCurrentObject->oAngleVelPitch = gMarioStates[i].angleVel[0];
    248     gCurrentObject->oAngleVelYaw = gMarioStates[i].angleVel[1];
    249     gCurrentObject->oAngleVelRoll = gMarioStates[i].angleVel[2];
    250 }
    251 
    252 /**
    253  * Spawn a particle at gCurrentObject's location.
    254  */
    255 void spawn_particle(u32 activeParticleFlag, s16 model, const BehaviorScript *behavior) {
    256     if (!(gCurrentObject->oActiveParticleFlags & activeParticleFlag)) {
    257         struct Object *particle;
    258         gCurrentObject->oActiveParticleFlags |= activeParticleFlag;
    259         particle = spawn_object_at_origin(gCurrentObject, 0, model, behavior);
    260         obj_copy_pos_and_angle(particle, gCurrentObject);
    261     }
    262 }
    263 
    264 /**
    265  * Mario's primary behavior update function.
    266  */
    267 void bhv_mario_update(void) {
    268     u32 particleFlags = 0;
    269     s32 i;
    270 
    271     particleFlags = execute_mario_action(gCurrentObject);
    272     gCurrentObject->oMarioParticleFlags = particleFlags;
    273 
    274     // Mario code updates MarioState's versions of position etc, so we need
    275     // to sync it with the Mario object
    276     copy_mario_state_to_object();
    277 
    278     i = 0;
    279     while (sParticleTypes[i].particleFlag != 0) {
    280         if (particleFlags & sParticleTypes[i].particleFlag) {
    281             spawn_particle(sParticleTypes[i].activeParticleFlag, sParticleTypes[i].model,
    282                            sParticleTypes[i].behavior);
    283         }
    284 
    285         i++;
    286     }
    287 }
    288 
    289 /**
    290  * Update every object that occurs after firstObj in the given object list,
    291  * including firstObj itself. Return the number of objects that were updated.
    292  */
    293 s32 update_objects_starting_at(struct ObjectNode *objList, struct ObjectNode *firstObj) {
    294     s32 count = 0;
    295 
    296     while (objList != firstObj) {
    297         gCurrentObject = (struct Object *) firstObj;
    298 
    299         gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_HAS_ANIMATION;
    300         cur_obj_update();
    301 
    302         firstObj = firstObj->next;
    303         count++;
    304     }
    305 
    306     return count;
    307 }
    308 
    309 /**
    310  * Update objects in objList starting with firstObj while time stop is active.
    311  * This means that only certain select objects will be updated, such as Mario,
    312  * doors, unimportant objects, and the object that initiated time stop.
    313  * The exact set of objects that are updated depends on which flags are set
    314  * in gTimeStopState.
    315  * Return the total number of objects in the list (including those that weren't
    316  * updated)
    317  */
    318 s32 update_objects_during_time_stop(struct ObjectNode *objList, struct ObjectNode *firstObj) {
    319     s32 count = 0;
    320     s32 unfrozen;
    321 
    322     while (objList != firstObj) {
    323         gCurrentObject = (struct Object *) firstObj;
    324 
    325         unfrozen = FALSE;
    326 
    327         // Selectively unfreeze certain objects
    328         if (!(gTimeStopState & TIME_STOP_ALL_OBJECTS)) {
    329             if (gCurrentObject == gMarioObject && !(gTimeStopState & TIME_STOP_MARIO_AND_DOORS)) {
    330                 unfrozen = TRUE;
    331             }
    332 
    333             if ((gCurrentObject->oInteractType & (INTERACT_DOOR | INTERACT_WARP_DOOR))
    334                 && !(gTimeStopState & TIME_STOP_MARIO_AND_DOORS)) {
    335                 unfrozen = TRUE;
    336             }
    337 
    338             if (gCurrentObject->activeFlags
    339                 & (ACTIVE_FLAG_UNIMPORTANT | ACTIVE_FLAG_INITIATED_TIME_STOP)) {
    340                 unfrozen = TRUE;
    341             }
    342         }
    343 
    344         // Only update if unfrozen
    345         if (unfrozen) {
    346             gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_HAS_ANIMATION;
    347             cur_obj_update();
    348         } else {
    349             gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_HAS_ANIMATION;
    350         }
    351 
    352         firstObj = firstObj->next;
    353         count++;
    354     }
    355 
    356     return count;
    357 }
    358 
    359 /**
    360  * Update every object in the given list. Return the total number of objects in
    361  * the list.
    362  */
    363 s32 update_objects_in_list(struct ObjectNode *objList) {
    364     s32 count;
    365     struct ObjectNode *firstObj = objList->next;
    366 
    367     if (!(gTimeStopState & TIME_STOP_ACTIVE)) {
    368         count = update_objects_starting_at(objList, firstObj);
    369     } else {
    370         count = update_objects_during_time_stop(objList, firstObj);
    371     }
    372 
    373     return count;
    374 }
    375 
    376 /**
    377  * Unload any objects in the list that have been deactivated.
    378  */
    379 s32 unload_deactivated_objects_in_list(struct ObjectNode *objList) {
    380     struct ObjectNode *obj = objList->next;
    381 
    382     while (objList != obj) {
    383         gCurrentObject = (struct Object *) obj;
    384 
    385         obj = obj->next;
    386 
    387         if ((gCurrentObject->activeFlags & ACTIVE_FLAG_ACTIVE) != ACTIVE_FLAG_ACTIVE) {
    388             // Prevent object from respawning after exiting and re-entering the
    389             // area
    390             if (!(gCurrentObject->oFlags & OBJ_FLAG_PERSISTENT_RESPAWN)) {
    391                 set_object_respawn_info_bits(gCurrentObject, RESPAWN_INFO_DONT_RESPAWN);
    392             }
    393 
    394             unload_object(gCurrentObject);
    395         }
    396     }
    397 
    398     return 0;
    399 }
    400 
    401 /**
    402  * OR the object's respawn info with bits << 8. If bits = 0xFF, this prevents
    403  * the object from respawning after leaving and re-entering the area.
    404  * For macro objects, respawnInfo points to the 16 bit entry in the macro object
    405  * list. For other objects, it points to the 32 bit behaviorArg in the
    406  * SpawnInfo.
    407  */
    408 void set_object_respawn_info_bits(struct Object *obj, u8 bits) {
    409     u32 *info32;
    410     u16 *info16;
    411 
    412     switch (obj->respawnInfoType) {
    413         case RESPAWN_INFO_TYPE_32:
    414             info32 = (u32 *) obj->respawnInfo;
    415             *info32 |= bits << 8;
    416             break;
    417 
    418         case RESPAWN_INFO_TYPE_16:
    419             info16 = (u16 *) obj->respawnInfo;
    420             *info16 |= bits << 8;
    421             break;
    422     }
    423 }
    424 
    425 /**
    426  * Unload all objects whose activeAreaIndex is areaIndex.
    427  */
    428 void unload_objects_from_area(UNUSED s32 unused, s32 areaIndex) {
    429     struct Object *obj;
    430     struct ObjectNode *node;
    431     struct ObjectNode *list;
    432     s32 i;
    433     gObjectLists = gObjectListArray;
    434 
    435     for (i = 0; i < NUM_OBJ_LISTS; i++) {
    436         list = gObjectLists + i;
    437         node = list->next;
    438 
    439         while (node != list) {
    440             obj = (struct Object *) node;
    441             node = node->next;
    442 
    443             if (obj->header.gfx.activeAreaIndex == areaIndex) {
    444                 unload_object(obj);
    445             }
    446         }
    447     }
    448 }
    449 
    450 /**
    451  * Spawn objects given a list of SpawnInfos. Called when loading an area.
    452  */
    453 void spawn_objects_from_info(UNUSED s32 unused, struct SpawnInfo *spawnInfo) {
    454     gObjectLists = gObjectListArray;
    455     gTimeStopState = 0;
    456 
    457     gWDWWaterLevelChanging = FALSE;
    458     gMarioOnMerryGoRound = FALSE;
    459 
    460     //! (Spawning Displacement) On the Japanese version, Mario's platform object
    461     //  isn't cleared when transitioning between areas. This can cause Mario to
    462     //  receive displacement after spawning.
    463 #ifndef VERSION_JP
    464     clear_mario_platform();
    465 #endif
    466 
    467     if (gCurrAreaIndex == 2) {
    468         gCCMEnteredSlide |= 1;
    469     }
    470 
    471     while (spawnInfo != NULL) {
    472         struct Object *object;
    473         UNUSED u8 filler[4];
    474         const BehaviorScript *script;
    475         UNUSED s16 arg16 = (s16)(spawnInfo->behaviorArg & 0xFFFF);
    476 
    477         script = segmented_to_virtual(spawnInfo->behaviorScript);
    478 
    479         // If the object was previously killed/collected, don't respawn it
    480         if ((spawnInfo->behaviorArg & (RESPAWN_INFO_DONT_RESPAWN << 8))
    481             != (RESPAWN_INFO_DONT_RESPAWN << 8)) {
    482             object = create_object(script);
    483 
    484             // Behavior parameters are often treated as four separate bytes, but
    485             // are stored as an s32.
    486             object->oBhvParams = spawnInfo->behaviorArg;
    487             // The second byte of the behavior parameters is copied over to a special field
    488             // as it is the most frequently used by objects.
    489             object->oBhvParams2ndByte = ((spawnInfo->behaviorArg) >> 16) & 0xFF;
    490 
    491             object->behavior = script;
    492             object->unused1 = 0;
    493 
    494             // Record death/collection in the SpawnInfo
    495             object->respawnInfoType = RESPAWN_INFO_TYPE_32;
    496             object->respawnInfo = &spawnInfo->behaviorArg;
    497 
    498             if (spawnInfo->behaviorArg & 0x01) {
    499                 gMarioObject = object;
    500                 geo_make_first_child(&object->header.gfx.node);
    501             }
    502 
    503             geo_obj_init_spawninfo(&object->header.gfx, spawnInfo);
    504 
    505             object->oPosX = spawnInfo->startPos[0];
    506             object->oPosY = spawnInfo->startPos[1];
    507             object->oPosZ = spawnInfo->startPos[2];
    508 
    509             object->oFaceAnglePitch = spawnInfo->startAngle[0];
    510             object->oFaceAngleYaw = spawnInfo->startAngle[1];
    511             object->oFaceAngleRoll = spawnInfo->startAngle[2];
    512 
    513             object->oMoveAnglePitch = spawnInfo->startAngle[0];
    514             object->oMoveAngleYaw = spawnInfo->startAngle[1];
    515             object->oMoveAngleRoll = spawnInfo->startAngle[2];
    516         }
    517 
    518         spawnInfo = spawnInfo->next;
    519     }
    520 }
    521 
    522 void stub_obj_list_processor_1(void) {
    523 }
    524 
    525 /**
    526  * Clear objects, dynamic surfaces, and some miscellaneous level data used by objects.
    527  */
    528 void clear_objects(void) {
    529     s32 i;
    530 
    531     gTHIWaterDrained = 0;
    532     gTimeStopState = 0;
    533     gMarioObject = NULL;
    534     gMarioCurrentRoom = 0;
    535 
    536     for (i = 0; i < 60; i++) {
    537         gDoorAdjacentRooms[i][0] = 0;
    538         gDoorAdjacentRooms[i][1] = 0;
    539     }
    540 
    541     debug_unknown_level_select_check();
    542 
    543     init_free_object_list();
    544     clear_object_lists(gObjectListArray);
    545 
    546     stub_behavior_script_2();
    547     stub_obj_list_processor_1();
    548 
    549     for (i = 0; i < OBJECT_POOL_CAPACITY; i++) {
    550         gObjectPool[i].activeFlags = ACTIVE_FLAG_DEACTIVATED;
    551         geo_reset_object_node(&gObjectPool[i].header.gfx);
    552     }
    553 
    554     gObjectMemoryPool = mem_pool_init(0x800, MEMORY_POOL_LEFT);
    555     gObjectLists = gObjectListArray;
    556 
    557     clear_dynamic_surfaces();
    558 }
    559 
    560 /**
    561  * Update spawner and surface objects.
    562  */
    563 void update_terrain_objects(void) {
    564     gObjectCounter = update_objects_in_list(&gObjectLists[OBJ_LIST_SPAWNER]);
    565     //! This was meant to be +=
    566     gObjectCounter = update_objects_in_list(&gObjectLists[OBJ_LIST_SURFACE]);
    567 }
    568 
    569 /**
    570  * Update all other object lists besides spawner and surface objects, using
    571  * the order specified by sObjectListUpdateOrder.
    572  */
    573 void update_non_terrain_objects(void) {
    574     UNUSED u8 filler[4];
    575     s32 listIndex;
    576 
    577     s32 i = 2;
    578     while ((listIndex = sObjectListUpdateOrder[i]) != -1) {
    579         gObjectCounter += update_objects_in_list(&gObjectLists[listIndex]);
    580         i++;
    581     }
    582 }
    583 
    584 /**
    585  * Unload deactivated objects in any object list.
    586  */
    587 void unload_deactivated_objects(void) {
    588     UNUSED u8 filler[4];
    589     s32 listIndex;
    590 
    591     s32 i = 0;
    592     while ((listIndex = sObjectListUpdateOrder[i]) != -1) {
    593         unload_deactivated_objects_in_list(&gObjectLists[listIndex]);
    594         i++;
    595     }
    596 
    597     // TIME_STOP_UNKNOWN_0 was most likely intended to be used to track whether
    598     // any objects had been deactivated
    599     gTimeStopState &= ~TIME_STOP_UNKNOWN_0;
    600 }
    601 
    602 /**
    603  * Unused profiling function.
    604  */
    605 UNUSED static u16 unused_get_elapsed_time(u64 *cycleCounts, s32 index) {
    606     u16 time;
    607     f64 cycles;
    608 
    609     cycles = cycleCounts[index] - cycleCounts[index - 1];
    610     if (cycles < 0) {
    611         cycles = 0;
    612     }
    613 
    614     time = (u16)(((u64) cycles * 1000000 / osClockRate) / 16667.0 * 1000.0);
    615     if (time > 999) {
    616         time = 999;
    617     }
    618 
    619     return time;
    620 }
    621 
    622 /**
    623  * Update all objects. This includes script execution, object collision detection,
    624  * and object surface management.
    625  */
    626 void update_objects(UNUSED s32 unused) {
    627     s64 cycleCounts[30];
    628 
    629     cycleCounts[0] = get_current_clock();
    630 
    631     gTimeStopState &= ~TIME_STOP_MARIO_OPENED_DOOR;
    632 
    633     gNumRoomedObjectsInMarioRoom = 0;
    634     gNumRoomedObjectsNotInMarioRoom = 0;
    635     gCheckingSurfaceCollisionsForCamera = FALSE;
    636 
    637     reset_debug_objectinfo();
    638     stub_debug_5();
    639 
    640     gObjectLists = gObjectListArray;
    641 
    642     // If time stop is not active, unload object surfaces
    643     cycleCounts[1] = get_clock_difference(cycleCounts[0]);
    644     clear_dynamic_surfaces();
    645 
    646     // Update spawners and objects with surfaces
    647     cycleCounts[2] = get_clock_difference(cycleCounts[0]);
    648     update_terrain_objects();
    649 
    650     // If Mario was touching a moving platform at the end of last frame, apply
    651     // displacement now
    652     //! If the platform object unloaded and a different object took its place,
    653     //  displacement could be applied incorrectly
    654     apply_mario_platform_displacement();
    655 
    656     // Detect which objects are intersecting
    657     cycleCounts[3] = get_clock_difference(cycleCounts[0]);
    658     detect_object_collisions();
    659 
    660     // Update all other objects that haven't been updated yet
    661     cycleCounts[4] = get_clock_difference(cycleCounts[0]);
    662     update_non_terrain_objects();
    663 
    664     // Unload any objects that have been deactivated
    665     cycleCounts[5] = get_clock_difference(cycleCounts[0]);
    666     unload_deactivated_objects();
    667 
    668     // Check if Mario is on a platform object and save this object
    669     cycleCounts[6] = get_clock_difference(cycleCounts[0]);
    670     update_mario_platform();
    671 
    672     cycleCounts[7] = get_clock_difference(cycleCounts[0]);
    673 
    674     cycleCounts[0] = 0;
    675     try_print_debug_mario_object_info();
    676 
    677     // If time stop was enabled this frame, activate it now so that it will
    678     // take effect next frame
    679     if (gTimeStopState & TIME_STOP_ENABLED) {
    680         gTimeStopState |= TIME_STOP_ACTIVE;
    681     } else {
    682         gTimeStopState &= ~TIME_STOP_ACTIVE;
    683     }
    684 
    685     gPrevFrameObjectCount = gObjectCounter;
    686 }