sm64

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

macro_special_objects.c (13428B)


      1 #include <PR/ultratypes.h>
      2 
      3 #include "sm64.h"
      4 #include "object_helpers.h"
      5 #include "macro_special_objects.h"
      6 #include "object_list_processor.h"
      7 #include "behavior_data.h"
      8 
      9 #include "macro_presets.inc.c"
     10 #include "special_presets.inc.c"
     11 
     12 /*
     13  * Converts the rotation value supplied by macro objects into one
     14  * that can be used by in-game objects.
     15  */
     16 s16 convert_rotation(s16 inRotation) {
     17     u16 rotation = ((u16)(inRotation & 0xFF));
     18     rotation <<= 8;
     19 
     20     if (rotation == 0x3F00) {
     21         rotation = 0x4000;
     22     }
     23 
     24     if (rotation == 0x7F00) {
     25         rotation = 0x8000;
     26     }
     27 
     28     if (rotation == 0xBF00) {
     29         rotation = 0xC000;
     30     }
     31 
     32     if (rotation == 0xFF00) {
     33         rotation = 0x0000;
     34     }
     35 
     36     return (s16) rotation;
     37 }
     38 
     39 /*
     40  * Spawns an object at an absolute location with rotation around the y-axis and
     41  * parameters filling up the upper 2 bytes of newObj->oBhvParams.
     42  * The object will not spawn if 'behavior' is NULL.
     43  */
     44 void spawn_macro_abs_yrot_2params(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 params) {
     45     if (behavior != NULL) {
     46         struct Object *newObj = spawn_object_abs_with_rot(
     47             &gMacroObjectDefaultParent, 0, model, behavior, x, y, z, 0, convert_rotation(ry), 0);
     48         newObj->oBhvParams = ((u32) params) << 16;
     49     }
     50 }
     51 
     52 /*
     53  * Spawns an object at an absolute location with rotation around the y-axis and
     54  * a single parameter filling up the upper byte of newObj->oBhvParams.
     55  * The object will not spawn if 'behavior' is NULL.
     56  */
     57 void spawn_macro_abs_yrot_param1(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 param) {
     58     if (behavior != NULL) {
     59         struct Object *newObj = spawn_object_abs_with_rot(
     60             &gMacroObjectDefaultParent, 0, model, behavior, x, y, z, 0, convert_rotation(ry), 0);
     61         newObj->oBhvParams = ((u32) param) << 24;
     62     }
     63 }
     64 
     65 /*
     66  * Spawns an object at an absolute location with currently 3 unknown variables that get converted to
     67  * floats. Oddly enough, this function doesn't care if 'behavior' is NULL or not.
     68  */
     69 void spawn_macro_abs_special(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 unkA, s16 unkB,
     70                              s16 unkC) {
     71     struct Object *newObj =
     72         spawn_object_abs_with_rot(&gMacroObjectDefaultParent, 0, model, behavior, x, y, z, 0, 0, 0);
     73 
     74     // Are all three of these values unused?
     75     newObj->oMacroUnk108 = (f32) unkA;
     76     newObj->oMacroUnk10C = (f32) unkB;
     77     newObj->oMacroUnk110 = (f32) unkC;
     78 }
     79 
     80 #define MACRO_OBJ_Y_ROT 0
     81 #define MACRO_OBJ_X 1
     82 #define MACRO_OBJ_Y 2
     83 #define MACRO_OBJ_Z 3
     84 #define MACRO_OBJ_PARAMS 4
     85 
     86 UNUSED static void spawn_macro_coin_unknown(const BehaviorScript *behavior, s16 objInfo[]) {
     87     struct Object *coin;
     88     s16 model = bhvYellowCoin == behavior ? MODEL_YELLOW_COIN : MODEL_NONE;
     89 
     90     coin = spawn_object_abs_with_rot(&gMacroObjectDefaultParent, 0, model, behavior,
     91                                      objInfo[MACRO_OBJ_X], objInfo[MACRO_OBJ_Y], objInfo[MACRO_OBJ_Z],
     92                                      0, convert_rotation(objInfo[MACRO_OBJ_Y_ROT]), 0);
     93     coin->oUnusedBhvParams = objInfo[MACRO_OBJ_PARAMS];
     94     coin->oBhvParams = (objInfo[MACRO_OBJ_PARAMS] & 0xFF) >> 16;
     95 }
     96 
     97 struct LoadedPreset {
     98     /* 0x00 */ const BehaviorScript *behavior;
     99     /* 0x04 */ s16 param; // huh? why does the below function swap these.. just use the struct..
    100     /* 0x06 */ s16 model;
    101 };
    102 
    103 void spawn_macro_objects(s16 areaIndex, s16 *macroObjList) {
    104     UNUSED u8 filler[4];
    105     s32 presetID;
    106 
    107     s16 macroObject[5]; // see the 5 #define statements above
    108     struct Object *newObj;
    109     struct LoadedPreset preset;
    110 
    111     gMacroObjectDefaultParent.header.gfx.areaIndex = areaIndex;
    112     gMacroObjectDefaultParent.header.gfx.activeAreaIndex = areaIndex;
    113 
    114     while (TRUE) {
    115         if (*macroObjList == -1) { // An encountered value of -1 means the list has ended.
    116             break;
    117         }
    118 
    119         presetID = (*macroObjList & 0x1FF) - 31; // Preset identifier for sMacroObjectPresets array
    120 
    121         if (presetID < 0) {
    122             break;
    123         }
    124 
    125         // Set macro object properties from the list
    126         macroObject[MACRO_OBJ_Y_ROT] = ((*macroObjList++ >> 9) & 0x7F) << 1; // Y-Rotation
    127         macroObject[MACRO_OBJ_X] = *macroObjList++;                          // X position
    128         macroObject[MACRO_OBJ_Y] = *macroObjList++;                          // Y position
    129         macroObject[MACRO_OBJ_Z] = *macroObjList++;                          // Z position
    130         macroObject[MACRO_OBJ_PARAMS] = *macroObjList++;                     // Behavior params
    131 
    132         // Get the preset values from the sMacroObjectPresets list.
    133         preset.model = sMacroObjectPresets[presetID].model;
    134         preset.behavior = sMacroObjectPresets[presetID].behavior;
    135         preset.param = sMacroObjectPresets[presetID].param;
    136 
    137         if (preset.param != 0) {
    138             macroObject[MACRO_OBJ_PARAMS] =
    139                 (macroObject[MACRO_OBJ_PARAMS] & 0xFF00) + (preset.param & 0x00FF);
    140         }
    141 
    142         // If object has been killed, prevent it from respawning
    143         if (((macroObject[MACRO_OBJ_PARAMS] >> 8) & RESPAWN_INFO_DONT_RESPAWN)
    144             != RESPAWN_INFO_DONT_RESPAWN) {
    145             // Spawn the new macro object.
    146             newObj = spawn_object_abs_with_rot(
    147                          &gMacroObjectDefaultParent, // Parent object
    148                          0,                          // Unused
    149                          preset.model,               // Model ID
    150                          preset.behavior,            // Behavior address
    151                          macroObject[MACRO_OBJ_X],   // X-position
    152                          macroObject[MACRO_OBJ_Y],   // Y-position
    153                          macroObject[MACRO_OBJ_Z],   // Z-position
    154                          0,                          // X-rotation
    155                          convert_rotation(macroObject[MACRO_OBJ_Y_ROT]), // Y-rotation
    156                          0                                               // Z-rotation
    157                      );
    158 
    159             newObj->oUnusedBhvParams = macroObject[MACRO_OBJ_PARAMS];
    160             newObj->oBhvParams = ((macroObject[MACRO_OBJ_PARAMS] & 0x00FF) << 16)
    161                                  + (macroObject[MACRO_OBJ_PARAMS] & 0xFF00);
    162             newObj->oBhvParams2ndByte = macroObject[MACRO_OBJ_PARAMS] & 0x00FF;
    163             newObj->respawnInfoType = RESPAWN_INFO_TYPE_16;
    164             newObj->respawnInfo = macroObjList - 1;
    165             newObj->parentObj = newObj;
    166         }
    167     }
    168 }
    169 
    170 void spawn_macro_objects_hardcoded(s16 areaIndex, s16 *macroObjList) {
    171     UNUSED u8 filler1[8];
    172 
    173     // This version of macroObjList has the preset and Y-Rotation separated,
    174     // and lacks behavior params. Might be an early version of the macro object list?
    175     s16 macroObjX;
    176     s16 macroObjY;
    177     s16 macroObjZ;
    178     s16 macroObjPreset;
    179     s16 macroObjRY; // Y Rotation
    180 
    181     UNUSED u8 filler2[10];
    182 
    183     gMacroObjectDefaultParent.header.gfx.areaIndex = areaIndex;
    184     gMacroObjectDefaultParent.header.gfx.activeAreaIndex = areaIndex;
    185 
    186     while (TRUE) {
    187         macroObjPreset = *macroObjList++;
    188 
    189         if (macroObjPreset < 0) {
    190             break;
    191         }
    192 
    193         macroObjX = *macroObjList++;
    194         macroObjY = *macroObjList++;
    195         macroObjZ = *macroObjList++;
    196         macroObjRY = *macroObjList++;
    197 
    198         // Spawn objects based on hardcoded presets, and most seem to be for Big Boo's Haunt.
    199         // However, BBH doesn't use this function so this might just be an early test?
    200         switch (macroObjPreset) {
    201             case 0:
    202                 spawn_macro_abs_yrot_2params(MODEL_NONE, bhvBooStaircase, macroObjX, macroObjY,
    203                                              macroObjZ, macroObjRY, 0);
    204                 break;
    205             case 1:
    206                 spawn_macro_abs_yrot_2params(MODEL_BBH_TILTING_FLOOR_PLATFORM,
    207                                              bhvBBHTiltingTrapPlatform, macroObjX, macroObjY, macroObjZ,
    208                                              macroObjRY, 0);
    209                 break;
    210             case 2:
    211                 spawn_macro_abs_yrot_2params(MODEL_BBH_TUMBLING_PLATFORM, bhvBBHTumblingBridge,
    212                                              macroObjX, macroObjY, macroObjZ, macroObjRY, 0);
    213                 break;
    214             case 3:
    215                 spawn_macro_abs_yrot_2params(MODEL_BBH_MOVING_BOOKSHELF, bhvHauntedBookshelf, macroObjX,
    216                                              macroObjY, macroObjZ, macroObjRY, 0);
    217                 break;
    218             case 4:
    219                 spawn_macro_abs_yrot_2params(MODEL_BBH_MESH_ELEVATOR, bhvMeshElevator, macroObjX,
    220                                              macroObjY, macroObjZ, macroObjRY, 0);
    221                 break;
    222             case 20:
    223                 spawn_macro_abs_yrot_2params(MODEL_YELLOW_COIN, bhvYellowCoin, macroObjX, macroObjY,
    224                                              macroObjZ, macroObjRY, 0);
    225                 break;
    226             case 21:
    227                 spawn_macro_abs_yrot_2params(MODEL_YELLOW_COIN, bhvYellowCoin, macroObjX, macroObjY,
    228                                              macroObjZ, macroObjRY, 0);
    229                 break;
    230             default:
    231                 break;
    232         }
    233     }
    234 }
    235 
    236 void spawn_special_objects(s16 areaIndex, TerrainData **specialObjList) {
    237     s32 numOfSpecialObjects;
    238     s32 i;
    239     s32 offset;
    240     s16 x;
    241     s16 y;
    242     s16 z;
    243     s16 extraParams[4];
    244     u8 model;
    245     u8 type;
    246     u8 presetID;
    247     u8 defaultParam;
    248     const BehaviorScript *behavior;
    249 
    250     numOfSpecialObjects = **specialObjList;
    251     (*specialObjList)++;
    252 
    253     gMacroObjectDefaultParent.header.gfx.areaIndex = areaIndex;
    254     gMacroObjectDefaultParent.header.gfx.activeAreaIndex = areaIndex;
    255 
    256     for (i = 0; i < numOfSpecialObjects; i++) {
    257         presetID = (u8) **specialObjList;
    258         (*specialObjList)++;
    259         x = **specialObjList;
    260         (*specialObjList)++;
    261         y = **specialObjList;
    262         (*specialObjList)++;
    263         z = **specialObjList;
    264         (*specialObjList)++;
    265 
    266         offset = 0;
    267         while (TRUE) {
    268             if (sSpecialObjectPresets[offset].presetID == presetID) {
    269                 break;
    270             }
    271 
    272             if (sSpecialObjectPresets[offset].presetID == special_null_end) {
    273             }
    274 
    275             offset++;
    276         }
    277 
    278         model = sSpecialObjectPresets[offset].model;
    279         behavior = sSpecialObjectPresets[offset].behavior;
    280         type = sSpecialObjectPresets[offset].type;
    281         defaultParam = sSpecialObjectPresets[offset].defParam;
    282 
    283         switch (type) {
    284             case SPTYPE_NO_YROT_OR_PARAMS:
    285                 spawn_macro_abs_yrot_2params(model, behavior, x, y, z, 0, 0);
    286                 break;
    287             case SPTYPE_YROT_NO_PARAMS:
    288                 extraParams[0] = **specialObjList; // Y-rotation
    289                 (*specialObjList)++;
    290                 spawn_macro_abs_yrot_2params(model, behavior, x, y, z, extraParams[0], 0);
    291                 break;
    292             case SPTYPE_PARAMS_AND_YROT:
    293                 extraParams[0] = **specialObjList; // Y-rotation
    294                 (*specialObjList)++;
    295                 extraParams[1] = **specialObjList; // Params
    296                 (*specialObjList)++;
    297                 spawn_macro_abs_yrot_2params(model, behavior, x, y, z, extraParams[0], extraParams[1]);
    298                 break;
    299             case SPTYPE_UNKNOWN:
    300                 extraParams[0] =
    301                     **specialObjList; // Unknown, gets put into obj->oMacroUnk108 as a float
    302                 (*specialObjList)++;
    303                 extraParams[1] =
    304                     **specialObjList; // Unknown, gets put into obj->oMacroUnk10C as a float
    305                 (*specialObjList)++;
    306                 extraParams[2] =
    307                     **specialObjList; // Unknown, gets put into obj->oMacroUnk110 as a float
    308                 (*specialObjList)++;
    309                 spawn_macro_abs_special(model, behavior, x, y, z, extraParams[0], extraParams[1],
    310                                         extraParams[2]);
    311                 break;
    312             case SPTYPE_DEF_PARAM_AND_YROT:
    313                 extraParams[0] = **specialObjList; // Y-rotation
    314                 (*specialObjList)++;
    315                 spawn_macro_abs_yrot_param1(model, behavior, x, y, z, extraParams[0], defaultParam);
    316                 break;
    317             default:
    318                 break;
    319         }
    320     }
    321 }
    322 
    323 #ifdef NO_SEGMENTED_MEMORY
    324 u32 get_special_objects_size(s16 *data) {
    325     s16 *startPos = data;
    326     s32 numOfSpecialObjects;
    327     s32 i;
    328     u8 presetID;
    329     s32 offset;
    330 
    331     numOfSpecialObjects = *data++;
    332 
    333     for (i = 0; i < numOfSpecialObjects; i++) {
    334         presetID = (u8) *data++;
    335         data += 3;
    336         offset = 0;
    337 
    338         while (TRUE) {
    339             if (sSpecialObjectPresets[offset].presetID == presetID) {
    340                 break;
    341             }
    342             offset++;
    343         }
    344 
    345         switch (sSpecialObjectPresets[offset].type) {
    346             case SPTYPE_NO_YROT_OR_PARAMS:
    347                 break;
    348             case SPTYPE_YROT_NO_PARAMS:
    349                 data++;
    350                 break;
    351             case SPTYPE_PARAMS_AND_YROT:
    352                 data += 2;
    353                 break;
    354             case SPTYPE_UNKNOWN:
    355                 data += 3;
    356                 break;
    357             case SPTYPE_DEF_PARAM_AND_YROT:
    358                 data++;
    359                 break;
    360             default:
    361                 break;
    362         }
    363     }
    364 
    365     return data - startPos;
    366 }
    367 #endif