sm64pc/src/game/macro_special_objects.c

376 lines
13 KiB
C

#include <ultra64.h>
#include "sm64.h"
#include "object_helpers.h"
#include "macro_special_objects.h"
#include "object_list_processor.h"
#include "behavior_data.h"
#include "macro_presets.h"
#include "special_presets.h"
/*
* Converts the rotation value supplied by macro objects into one
* that can be used by in-game objects.
*/
s16 convert_rotation(s16 inRotation) {
u16 rotation = ((u16)(inRotation & 0xFF));
rotation <<= 8;
if (rotation == 0x3F00) {
rotation = 0x4000;
}
if (rotation == 0x7F00) {
rotation = 0x8000;
}
if (rotation == 0xBF00) {
rotation = 0xC000;
}
if (rotation == 0xFF00) {
rotation = 0x0000;
}
return (s16) rotation;
}
/*
* Spawns an object at an absolute location with rotation around the y-axis and
* parameters filling up the upper 2 bytes of newObj->oBehParams.
* The object will not spawn if 'behavior' is NULL.
*/
void spawn_macro_abs_yrot_2params(u32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 params) {
if (behavior != NULL) {
struct Object *newObj = spawn_object_abs_with_rot(
&gMacroObjectDefaultParent, 0, model, behavior, x, y, z, 0, convert_rotation(ry), 0);
newObj->oBehParams = ((u32) params) << 16;
}
}
/*
* Spawns an object at an absolute location with rotation around the y-axis and
* a single parameter filling up the upper byte of newObj->oBehParams.
* The object will not spawn if 'behavior' is NULL.
*/
void spawn_macro_abs_yrot_param1(u32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 param) {
if (behavior != NULL) {
struct Object *newObj = spawn_object_abs_with_rot(
&gMacroObjectDefaultParent, 0, model, behavior, x, y, z, 0, convert_rotation(ry), 0);
newObj->oBehParams = ((u32) param) << 24;
}
}
/*
* Spawns an object at an absolute location with currently 3 unknown variables that get converted to
* floats. Oddly enough, this function doesn't care if 'behavior' is NULL or not.
*/
void spawn_macro_abs_special(u32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 unkA, s16 unkB,
s16 unkC) {
struct Object *newObj =
spawn_object_abs_with_rot(&gMacroObjectDefaultParent, 0, model, behavior, x, y, z, 0, 0, 0);
// Are all three of these values unused?
newObj->oMacroUnk108 = (f32) unkA;
newObj->oMacroUnk10C = (f32) unkB;
newObj->oMacroUnk110 = (f32) unkC;
}
static void spawn_macro_coin_unknown(const BehaviorScript *behavior, s16 a1[]) {
struct Object *sp3C;
s16 model;
model = bhvYellowCoin == behavior ? MODEL_YELLOW_COIN : MODEL_NONE;
sp3C = spawn_object_abs_with_rot(&gMacroObjectDefaultParent, 0, model, behavior,
a1[1], a1[2], a1[3], 0, convert_rotation(a1[0]), 0);
sp3C->oUnk1A8 = a1[4];
sp3C->oBehParams = (a1[4] & 0xFF) >> 16;
}
struct LoadedPreset {
/*0x00*/ const BehaviorScript *behavior;
/*0x04*/ s16 param; // huh? why does the below function swap these.. just use the struct..
/*0x06*/ s16 model;
};
#define MACRO_OBJ_Y_ROT 0
#define MACRO_OBJ_X 1
#define MACRO_OBJ_Y 2
#define MACRO_OBJ_Z 3
#define MACRO_OBJ_PARAMS 4
void spawn_macro_objects(s16 areaIndex, s16 *macroObjList) {
UNUSED u32 pad5C;
s32 presetID;
s16 macroObject[5]; // see the 5 #define statements above
struct Object *newObj;
struct LoadedPreset preset;
gMacroObjectDefaultParent.header.gfx.unk18 = areaIndex;
gMacroObjectDefaultParent.header.gfx.unk19 = areaIndex;
while (TRUE) {
if (*macroObjList == -1) { // An encountered value of -1 means the list has ended.
break;
}
presetID = (*macroObjList & 0x1FF) - 31; // Preset identifier for MacroObjectPresets array
if (presetID < 0) {
break;
}
// Set macro object properties from the list
macroObject[MACRO_OBJ_Y_ROT] = ((*macroObjList++ >> 9) & 0x7F) << 1; // Y-Rotation
macroObject[MACRO_OBJ_X] = *macroObjList++; // X position
macroObject[MACRO_OBJ_Y] = *macroObjList++; // Y position
macroObject[MACRO_OBJ_Z] = *macroObjList++; // Z position
macroObject[MACRO_OBJ_PARAMS] = *macroObjList++; // Behavior params
// Get the preset values from the MacroObjectPresets list.
preset.model = MacroObjectPresets[presetID].model;
preset.behavior = MacroObjectPresets[presetID].behavior;
preset.param = MacroObjectPresets[presetID].param;
if (preset.param != 0) {
macroObject[MACRO_OBJ_PARAMS] =
(macroObject[MACRO_OBJ_PARAMS] & 0xFF00) + (preset.param & 0x00FF);
}
// If object has been killed, prevent it from respawning
if (((macroObject[MACRO_OBJ_PARAMS] >> 8) & RESPAWN_INFO_DONT_RESPAWN)
!= RESPAWN_INFO_DONT_RESPAWN) {
// Spawn the new macro object.
newObj =
spawn_object_abs_with_rot(&gMacroObjectDefaultParent, // Parent object
0, // Unused
preset.model, // Model ID
preset.behavior, // Behavior address
macroObject[MACRO_OBJ_X], // X-position
macroObject[MACRO_OBJ_Y], // Y-position
macroObject[MACRO_OBJ_Z], // Z-position
0, // X-rotation
convert_rotation(macroObject[MACRO_OBJ_Y_ROT]), // Y-rotation
0 // Z-rotation
);
newObj->oUnk1A8 = macroObject[MACRO_OBJ_PARAMS];
newObj->oBehParams = ((macroObject[MACRO_OBJ_PARAMS] & 0x00FF) << 16)
+ (macroObject[MACRO_OBJ_PARAMS] & 0xFF00);
newObj->oBehParams2ndByte = macroObject[MACRO_OBJ_PARAMS] & 0x00FF;
newObj->respawnInfoType = RESPAWN_INFO_TYPE_16;
newObj->respawnInfo = macroObjList - 1;
newObj->parentObj = newObj;
}
}
}
void spawn_macro_objects_hardcoded(s16 areaIndex, s16 *macroObjList) {
UNUSED u8 pad[8];
// This version of macroObjList has the preset and Y-Rotation seperated,
// and lacks behavior params. Might be an early version of the macro object list?
s16 macroObjX;
s16 macroObjY;
s16 macroObjZ;
s16 macroObjPreset;
s16 macroObjRY; // Y Rotation
UNUSED u8 pad2[10];
gMacroObjectDefaultParent.header.gfx.unk18 = areaIndex;
gMacroObjectDefaultParent.header.gfx.unk19 = areaIndex;
while (TRUE) {
macroObjPreset = *macroObjList++;
if (macroObjPreset < 0) {
break;
}
macroObjX = *macroObjList++;
macroObjY = *macroObjList++;
macroObjZ = *macroObjList++;
macroObjRY = *macroObjList++;
// Spawn objects based on hardcoded presets, and most seem to be for Big Boo's Haunt.
// However, BBH doesn't use this function so this might just be an early test?
switch (macroObjPreset) {
case 0:
spawn_macro_abs_yrot_2params(MODEL_NONE, bhvBooBossSpawnedBridge, macroObjX, macroObjY,
macroObjZ, macroObjRY, 0);
break;
case 1:
spawn_macro_abs_yrot_2params(MODEL_BBH_TILTING_FLOOR_PLATFORM,
bhvBbhTiltingTrapPlatform, macroObjX, macroObjY, macroObjZ,
macroObjRY, 0);
break;
case 2:
spawn_macro_abs_yrot_2params(MODEL_BBH_TUMBLING_PLATFORM, bhvBbhTumblingBridge,
macroObjX, macroObjY, macroObjZ, macroObjRY, 0);
break;
case 3:
spawn_macro_abs_yrot_2params(MODEL_BBH_MOVING_BOOKSHELF, bhvHauntedBookshelf, macroObjX,
macroObjY, macroObjZ, macroObjRY, 0);
break;
case 4:
spawn_macro_abs_yrot_2params(MODEL_BBH_MESH_ELEVATOR, bhvMeshElevator, macroObjX,
macroObjY, macroObjZ, macroObjRY, 0);
break;
case 20:
spawn_macro_abs_yrot_2params(MODEL_YELLOW_COIN, bhvYellowCoin, macroObjX, macroObjY,
macroObjZ, macroObjRY, 0);
break;
case 21:
spawn_macro_abs_yrot_2params(MODEL_YELLOW_COIN, bhvYellowCoin, macroObjX, macroObjY,
macroObjZ, macroObjRY, 0);
break;
default:
break;
}
}
}
void spawn_special_objects(s16 areaIndex, s16 **specialObjList) {
s32 numOfSpecialObjects;
s32 i;
s32 offset;
s16 x;
s16 y;
s16 z;
s16 extraParams[4];
#ifdef VERSION_EU
s16 model;
#else
u8 model;
#endif
u8 type;
u8 presetID;
u8 defaultParam;
const BehaviorScript *behavior;
numOfSpecialObjects = **specialObjList;
(*specialObjList)++;
gMacroObjectDefaultParent.header.gfx.unk18 = areaIndex;
gMacroObjectDefaultParent.header.gfx.unk19 = areaIndex;
for (i = 0; i < numOfSpecialObjects; i++) {
presetID = (u8) * *specialObjList;
(*specialObjList)++;
x = **specialObjList;
(*specialObjList)++;
y = **specialObjList;
(*specialObjList)++;
z = **specialObjList;
(*specialObjList)++;
offset = 0;
while (TRUE) {
if (SpecialObjectPresets[offset].preset_id == presetID) {
break;
}
if (SpecialObjectPresets[offset].preset_id == 0xFF) {
}
offset++;
}
model = SpecialObjectPresets[offset].model;
behavior = SpecialObjectPresets[offset].behavior;
type = SpecialObjectPresets[offset].type;
defaultParam = SpecialObjectPresets[offset].defParam;
switch (type) {
case SPTYPE_NO_YROT_OR_PARAMS:
spawn_macro_abs_yrot_2params(model, behavior, x, y, z, 0, 0);
break;
case SPTYPE_YROT_NO_PARAMS:
extraParams[0] = **specialObjList; // Y-rotation
(*specialObjList)++;
spawn_macro_abs_yrot_2params(model, behavior, x, y, z, extraParams[0], 0);
break;
case SPTYPE_PARAMS_AND_YROT:
extraParams[0] = **specialObjList; // Y-rotation
(*specialObjList)++;
extraParams[1] = **specialObjList; // Params
(*specialObjList)++;
spawn_macro_abs_yrot_2params(model, behavior, x, y, z, extraParams[0], extraParams[1]);
break;
case SPTYPE_UNKNOWN:
extraParams[0] =
**specialObjList; // Unknown, gets put into obj->oMacroUnk108 as a float
(*specialObjList)++;
extraParams[1] =
**specialObjList; // Unknown, gets put into obj->oMacroUnk10C as a float
(*specialObjList)++;
extraParams[2] =
**specialObjList; // Unknown, gets put into obj->oMacroUnk110 as a float
(*specialObjList)++;
spawn_macro_abs_special(model, behavior, x, y, z, extraParams[0], extraParams[1],
extraParams[2]);
break;
case SPTYPE_DEF_PARAM_AND_YROT:
extraParams[0] = **specialObjList; // Y-rotation
(*specialObjList)++;
spawn_macro_abs_yrot_param1(model, behavior, x, y, z, extraParams[0], defaultParam);
break;
default:
break;
}
}
}
#ifndef TARGET_N64
u32 get_special_objects_size(s16 *data) {
s16 *startPos = data;
s32 numOfSpecialObjects;
s32 i;
u8 presetID;
s32 offset;
numOfSpecialObjects = *data++;
for (i = 0; i < numOfSpecialObjects; i++) {
presetID = (u8) *data++;
data += 3;
offset = 0;
while (TRUE) {
if (SpecialObjectPresets[offset].preset_id == presetID) {
break;
}
offset++;
}
switch (SpecialObjectPresets[offset].type) {
case SPTYPE_NO_YROT_OR_PARAMS:
break;
case SPTYPE_YROT_NO_PARAMS:
data++;
break;
case SPTYPE_PARAMS_AND_YROT:
data += 2;
break;
case SPTYPE_UNKNOWN:
data += 3;
break;
case SPTYPE_DEF_PARAM_AND_YROT:
data++;
break;
default:
break;
}
}
return data - startPos;
}
#endif