2019-08-25 04:46:40 +00:00
|
|
|
#include <ultra64.h>
|
|
|
|
|
|
|
|
#include "sm64.h"
|
2020-06-02 16:44:34 +00:00
|
|
|
#include "behavior_data.h"
|
2019-08-25 04:46:40 +00:00
|
|
|
#include "behavior_script.h"
|
2020-06-02 16:44:34 +00:00
|
|
|
#include "game/area.h"
|
|
|
|
#include "game/behavior_actions.h"
|
2020-04-03 18:57:26 +00:00
|
|
|
#include "game/game_init.h"
|
2020-06-02 16:44:34 +00:00
|
|
|
#include "game/mario.h"
|
|
|
|
#include "game/memory.h"
|
2019-08-25 04:46:40 +00:00
|
|
|
#include "game/obj_behaviors_2.h"
|
2020-06-02 16:44:34 +00:00
|
|
|
#include "game/object_helpers.h"
|
2019-08-25 04:46:40 +00:00
|
|
|
#include "game/object_list_processor.h"
|
2020-06-02 16:44:34 +00:00
|
|
|
#include "graph_node.h"
|
|
|
|
#include "surface_collision.h"
|
2020-08-08 04:13:07 +00:00
|
|
|
#include "pc/network/network.h"
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Macros for retrieving arguments from behavior scripts.
|
|
|
|
#define BHV_CMD_GET_1ST_U8(index) (u8)((gCurBhvCommand[index] >> 24) & 0xFF) // unused
|
|
|
|
#define BHV_CMD_GET_2ND_U8(index) (u8)((gCurBhvCommand[index] >> 16) & 0xFF)
|
|
|
|
#define BHV_CMD_GET_3RD_U8(index) (u8)((gCurBhvCommand[index] >> 8) & 0xFF)
|
|
|
|
#define BHV_CMD_GET_4TH_U8(index) (u8)((gCurBhvCommand[index]) & 0xFF)
|
|
|
|
|
|
|
|
#define BHV_CMD_GET_1ST_S16(index) (s16)(gCurBhvCommand[index] >> 16)
|
|
|
|
#define BHV_CMD_GET_2ND_S16(index) (s16)(gCurBhvCommand[index] & 0xFFFF)
|
|
|
|
|
|
|
|
#define BHV_CMD_GET_U32(index) (u32)(gCurBhvCommand[index])
|
|
|
|
#define BHV_CMD_GET_VPTR(index) (void *)(gCurBhvCommand[index])
|
|
|
|
|
|
|
|
#define BHV_CMD_GET_ADDR_OF_CMD(index) (uintptr_t)(&gCurBhvCommand[index])
|
|
|
|
|
2019-08-25 04:46:40 +00:00
|
|
|
static u16 gRandomSeed16;
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Unused function that directly jumps to a behavior command and resets the object's stack index.
|
|
|
|
static void goto_behavior_unused(const BehaviorScript *bhvAddr) {
|
|
|
|
gCurBhvCommand = segmented_to_virtual(bhvAddr);
|
|
|
|
gCurrentObject->bhvStackIndex = 0;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-08-08 01:01:58 +00:00
|
|
|
void force_replicable_seed(u8 always) {
|
|
|
|
// force the seed to consistent values
|
|
|
|
extern u16 gRandomSeed16;
|
|
|
|
extern u32 gGlobalTimer;
|
|
|
|
static u32 lastTimer = 0;
|
|
|
|
static f32 lastPos[3] = { 0 };
|
|
|
|
if (gGlobalTimer == lastTimer
|
|
|
|
&& lastPos[0] == gCurrentObject->oPosX / 10
|
|
|
|
&& lastPos[1] == gCurrentObject->oPosY / 10
|
|
|
|
&& lastPos[2] == gCurrentObject->oPosZ / 10
|
|
|
|
&& !always) {
|
|
|
|
return;
|
2020-08-03 01:21:43 +00:00
|
|
|
}
|
2020-08-08 01:01:58 +00:00
|
|
|
gRandomSeed16 = (u16)(gCurrentObject->oPosX / 1000.0f)
|
|
|
|
^ (u16)(gCurrentObject->oPosY / 1000.0f)
|
|
|
|
^ (u16)(gCurrentObject->oPosZ / 1000.0f);
|
|
|
|
if (!always) {
|
|
|
|
lastPos[0] = gCurrentObject->oPosX / 10;
|
|
|
|
lastPos[1] = gCurrentObject->oPosY / 10;
|
|
|
|
lastPos[2] = gCurrentObject->oPosZ / 10;
|
|
|
|
lastTimer = gGlobalTimer;
|
2020-08-03 01:21:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Generate a pseudorandom integer from 0 to 65535 from the random seed, and update the seed.
|
|
|
|
u16 random_u16(void) {
|
2020-08-03 01:21:43 +00:00
|
|
|
// override this function for synchronized entities
|
2020-08-08 04:13:07 +00:00
|
|
|
if (gCurrentObject->oSyncID != 0) {
|
|
|
|
struct SyncObject* so = &syncObjects[gCurrentObject->oSyncID];
|
|
|
|
if (so->o != NULL && !so->keepRandomSeed) {
|
|
|
|
force_replicable_seed(FALSE);
|
|
|
|
}
|
|
|
|
}
|
2020-08-03 01:21:43 +00:00
|
|
|
|
2019-08-25 04:46:40 +00:00
|
|
|
u16 temp1, temp2;
|
|
|
|
|
2019-09-01 19:50:50 +00:00
|
|
|
if (gRandomSeed16 == 22026) {
|
2019-08-25 04:46:40 +00:00
|
|
|
gRandomSeed16 = 0;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
|
|
|
temp1 = (gRandomSeed16 & 0x00FF) << 8;
|
|
|
|
temp1 = temp1 ^ gRandomSeed16;
|
|
|
|
|
|
|
|
gRandomSeed16 = ((temp1 & 0x00FF) << 8) + ((temp1 & 0xFF00) >> 8);
|
|
|
|
|
|
|
|
temp1 = ((temp1 & 0x00FF) << 1) ^ gRandomSeed16;
|
|
|
|
temp2 = (temp1 >> 1) ^ 0xFF80;
|
|
|
|
|
|
|
|
if ((temp1 & 1) == 0) {
|
2019-09-01 19:50:50 +00:00
|
|
|
if (temp2 == 43605) {
|
2019-08-25 04:46:40 +00:00
|
|
|
gRandomSeed16 = 0;
|
2019-09-01 19:50:50 +00:00
|
|
|
} else {
|
2019-08-25 04:46:40 +00:00
|
|
|
gRandomSeed16 = temp2 ^ 0x1FF4;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
} else {
|
|
|
|
gRandomSeed16 = temp2 ^ 0x8180;
|
|
|
|
}
|
|
|
|
|
|
|
|
return gRandomSeed16;
|
|
|
|
}
|
|
|
|
|
2020-06-02 16:44:34 +00:00
|
|
|
// Generate a pseudorandom float in the range [0, 1).
|
2020-04-03 18:57:26 +00:00
|
|
|
f32 random_float(void) {
|
|
|
|
f32 rnd = random_u16();
|
2019-08-25 04:46:40 +00:00
|
|
|
return rnd / (double) 0x10000;
|
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Return either -1 or 1 with a 50:50 chance.
|
|
|
|
s32 random_sign(void) {
|
|
|
|
if (random_u16() >= 0x7FFF) {
|
2019-08-25 04:46:40 +00:00
|
|
|
return 1;
|
2019-09-01 19:50:50 +00:00
|
|
|
} else {
|
2019-08-25 04:46:40 +00:00
|
|
|
return -1;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Update an object's graphical position and rotation to match its real position and rotation.
|
|
|
|
void obj_update_gfx_pos_and_angle(struct Object *obj) {
|
|
|
|
obj->header.gfx.pos[0] = obj->oPosX;
|
|
|
|
obj->header.gfx.pos[1] = obj->oPosY + obj->oGraphYOffset;
|
|
|
|
obj->header.gfx.pos[2] = obj->oPosZ;
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
obj->header.gfx.angle[0] = obj->oFaceAnglePitch & 0xFFFF;
|
|
|
|
obj->header.gfx.angle[1] = obj->oFaceAngleYaw & 0xFFFF;
|
|
|
|
obj->header.gfx.angle[2] = obj->oFaceAngleRoll & 0xFFFF;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Push the address of a behavior command to the object's behavior stack.
|
|
|
|
static void cur_obj_bhv_stack_push(uintptr_t bhvAddr) {
|
|
|
|
gCurrentObject->bhvStack[gCurrentObject->bhvStackIndex] = bhvAddr;
|
|
|
|
gCurrentObject->bhvStackIndex++;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Retrieve the last behavior command address from the object's behavior stack.
|
|
|
|
static uintptr_t cur_obj_bhv_stack_pop(void) {
|
|
|
|
uintptr_t bhvAddr;
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurrentObject->bhvStackIndex--;
|
|
|
|
bhvAddr = gCurrentObject->bhvStack[gCurrentObject->bhvStackIndex];
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
return bhvAddr;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
static void stub_behavior_script_1(void) {
|
2019-09-01 19:50:50 +00:00
|
|
|
for (;;) {
|
2019-08-25 04:46:40 +00:00
|
|
|
;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x22: Hides the current object.
|
|
|
|
// Usage: HIDE()
|
|
|
|
static s32 bhv_cmd_hide(void) {
|
2020-03-02 03:42:52 +00:00
|
|
|
cur_obj_hide();
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x35: Disables rendering for the object.
|
|
|
|
// Usage: DISABLE_RENDERING()
|
|
|
|
static s32 bhv_cmd_disable_rendering(void) {
|
2019-08-25 04:46:40 +00:00
|
|
|
gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x21: Billboards the current object, making it always face the camera.
|
|
|
|
// Usage: BILLBOARD()
|
|
|
|
static s32 bhv_cmd_billboard(void) {
|
2019-08-25 04:46:40 +00:00
|
|
|
gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_BILLBOARD;
|
2020-05-15 01:31:52 +00:00
|
|
|
|
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Command 0x
|
|
|
|
static s32 bhv_cmd_cylboard(void) {
|
|
|
|
gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_CYLBOARD;
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x1B: Sets the current model ID of the object.
|
|
|
|
// Usage: SET_MODEL(modelID)
|
|
|
|
static s32 bhv_cmd_set_model(void) {
|
|
|
|
s32 modelID = BHV_CMD_GET_2ND_S16(0);
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-01-03 15:38:57 +00:00
|
|
|
gCurrentObject->header.gfx.sharedChild = gLoadedGraphNodes[modelID];
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x1C: Spawns a child object with the specified model and behavior.
|
|
|
|
// Usage: SPAWN_CHILD(modelID, behavior)
|
|
|
|
static s32 bhv_cmd_spawn_child(void) {
|
|
|
|
u32 model = BHV_CMD_GET_U32(1);
|
|
|
|
const BehaviorScript *behavior = BHV_CMD_GET_VPTR(2);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-01-03 15:38:57 +00:00
|
|
|
struct Object *child = spawn_object_at_origin(gCurrentObject, 0, model, behavior);
|
2020-03-02 03:42:52 +00:00
|
|
|
obj_copy_pos_and_angle(child, gCurrentObject);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 3;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x2C: Spawns a new object with the specified model and behavior.
|
|
|
|
// Usage: SPAWN_OBJ(modelID, behavior)
|
|
|
|
static s32 bhv_cmd_spawn_obj(void) {
|
|
|
|
u32 model = BHV_CMD_GET_U32(1);
|
|
|
|
const BehaviorScript *behavior = BHV_CMD_GET_VPTR(2);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2019-11-03 19:36:27 +00:00
|
|
|
struct Object *object = spawn_object_at_origin(gCurrentObject, 0, model, behavior);
|
2020-03-02 03:42:52 +00:00
|
|
|
obj_copy_pos_and_angle(object, gCurrentObject);
|
2020-04-03 18:57:26 +00:00
|
|
|
// TODO: Does this cmd need renaming? This line is the only difference between this and the above func.
|
2019-08-25 04:46:40 +00:00
|
|
|
gCurrentObject->prevObj = object;
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 3;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x29: Spawns a child object with the specified model and behavior, plus a behavior param.
|
|
|
|
// Usage: SPAWN_CHILD_WITH_PARAM(bhvParam, modelID, behavior)
|
|
|
|
static s32 bhv_cmd_spawn_child_with_param(void) {
|
|
|
|
u32 bhvParam = BHV_CMD_GET_2ND_S16(0);
|
|
|
|
u32 modelID = BHV_CMD_GET_U32(1);
|
|
|
|
const BehaviorScript *behavior = BHV_CMD_GET_VPTR(2);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
struct Object *child = spawn_object_at_origin(gCurrentObject, 0, modelID, behavior);
|
2020-03-02 03:42:52 +00:00
|
|
|
obj_copy_pos_and_angle(child, gCurrentObject);
|
2020-04-03 18:57:26 +00:00
|
|
|
child->oBehParams2ndByte = bhvParam;
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 3;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x1D: Exits the behavior script and despawns the object.
|
|
|
|
// Usage: DEACTIVATE()
|
|
|
|
static s32 bhv_cmd_deactivate(void) {
|
2020-06-02 16:44:34 +00:00
|
|
|
gCurrentObject->activeFlags = ACTIVE_FLAG_DEACTIVATED;
|
2020-04-03 18:57:26 +00:00
|
|
|
return BHV_PROC_BREAK;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x0A: Exits the behavior script.
|
|
|
|
// Usage: BREAK()
|
|
|
|
static s32 bhv_cmd_break(void) {
|
|
|
|
return BHV_PROC_BREAK;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x0B: Exits the behavior script, unused.
|
|
|
|
// Usage: BREAK_UNUSED()
|
|
|
|
static s32 bhv_cmd_break_unused(void) {
|
|
|
|
return BHV_PROC_BREAK;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x02: Jumps to a new behavior command and stores the return address in the object's behavior stack.
|
|
|
|
// Usage: CALL(addr)
|
|
|
|
static s32 bhv_cmd_call(void) {
|
2019-11-03 19:36:27 +00:00
|
|
|
const BehaviorScript *jumpAddress;
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_bhv_stack_push(BHV_CMD_GET_ADDR_OF_CMD(1)); // Store address of the next bhv command in the stack.
|
|
|
|
jumpAddress = segmented_to_virtual(BHV_CMD_GET_VPTR(0));
|
|
|
|
gCurBhvCommand = jumpAddress; // Jump to the new address.
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x03: Jumps back to the behavior command stored in the object's behavior stack. Used after CALL.
|
|
|
|
// Usage: RETURN()
|
|
|
|
static s32 bhv_cmd_return(void) {
|
|
|
|
gCurBhvCommand = (const BehaviorScript *) cur_obj_bhv_stack_pop(); // Retrieve command address and jump to it.
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x01: Delays the behavior script for a certain number of frames.
|
|
|
|
// Usage: DELAY(num)
|
|
|
|
static s32 bhv_cmd_delay(void) {
|
|
|
|
s16 num = BHV_CMD_GET_2ND_S16(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
if (gCurrentObject->bhvDelayTimer < num - 1) {
|
|
|
|
gCurrentObject->bhvDelayTimer++; // Increment timer
|
2019-08-25 04:46:40 +00:00
|
|
|
} else {
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurrentObject->bhvDelayTimer = 0;
|
|
|
|
gCurBhvCommand++; // Delay ended, move to next bhv command (note: following commands will not execute until next frame)
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
return BHV_PROC_BREAK;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x25: Delays the behavior script for the number of frames given by the value of the specified field.
|
|
|
|
// Usage: DELAY_VAR(field)
|
|
|
|
static s32 bhv_cmd_delay_var(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
s32 num = cur_obj_get_int(field);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
if (gCurrentObject->bhvDelayTimer < num - 1) {
|
|
|
|
gCurrentObject->bhvDelayTimer++; // Increment timer
|
2019-08-25 04:46:40 +00:00
|
|
|
} else {
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurrentObject->bhvDelayTimer = 0;
|
|
|
|
gCurBhvCommand++; // Delay ended, move to next bhv command
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
return BHV_PROC_BREAK;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x04: Jumps to a new behavior script without saving anything.
|
|
|
|
// Usage: GOTO(addr)
|
|
|
|
static s32 bhv_cmd_goto(void) {
|
|
|
|
gCurBhvCommand++; // Useless
|
|
|
|
gCurBhvCommand = segmented_to_virtual(BHV_CMD_GET_VPTR(0)); // Jump directly to address
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x26: Unused. Marks the start of a loop that will repeat a certain number of times.
|
|
|
|
// Uses a u8 as the argument, instead of a s16 like the other version does.
|
|
|
|
// Usage: BEGIN_REPEAT_UNUSED(count)
|
|
|
|
static s32 bhv_cmd_begin_repeat_unused(void) {
|
|
|
|
s32 count = BHV_CMD_GET_2ND_U8(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_bhv_stack_push(BHV_CMD_GET_ADDR_OF_CMD(1)); // Store address of the first command of the loop in the stack
|
|
|
|
cur_obj_bhv_stack_push(count); // Store repeat count in the stack too
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x05: Marks the start of a loop that will repeat a certain number of times.
|
|
|
|
// Usage: BEGIN_REPEAT(count)
|
|
|
|
static s32 bhv_cmd_begin_repeat(void) {
|
|
|
|
s32 count = BHV_CMD_GET_2ND_S16(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_bhv_stack_push(BHV_CMD_GET_ADDR_OF_CMD(1)); // Store address of the first command of the loop in the stack
|
|
|
|
cur_obj_bhv_stack_push(count); // Store repeat count in the stack too
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x06: Marks the end of a repeating loop.
|
|
|
|
// Usage: END_REPEAT()
|
|
|
|
static s32 bhv_cmd_end_repeat(void) {
|
|
|
|
u32 count = cur_obj_bhv_stack_pop(); // Retrieve loop count from the stack.
|
2019-08-25 04:46:40 +00:00
|
|
|
count--;
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2019-08-25 04:46:40 +00:00
|
|
|
if (count != 0) {
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand = (const BehaviorScript *) cur_obj_bhv_stack_pop(); // Jump back to the first command in the loop
|
|
|
|
// Save address and count to the stack again
|
|
|
|
cur_obj_bhv_stack_push(BHV_CMD_GET_ADDR_OF_CMD(0));
|
|
|
|
cur_obj_bhv_stack_push(count);
|
|
|
|
} else { // Finished iterating over the loop
|
|
|
|
cur_obj_bhv_stack_pop(); // Necessary to remove address from the stack
|
|
|
|
gCurBhvCommand++;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Don't execute following commands until next frame
|
|
|
|
return BHV_PROC_BREAK;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x07: Also marks the end of a repeating loop, but continues executing commands following the loop on the same frame.
|
|
|
|
// Usage: END_REPEAT_CONTINUE()
|
|
|
|
static s32 bhv_cmd_end_repeat_continue(void) {
|
|
|
|
u32 count = cur_obj_bhv_stack_pop();
|
2019-08-25 04:46:40 +00:00
|
|
|
count--;
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2019-08-25 04:46:40 +00:00
|
|
|
if (count != 0) {
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand = (const BehaviorScript *) cur_obj_bhv_stack_pop(); // Jump back to the first command in the loop
|
|
|
|
// Save address and count to the stack again
|
|
|
|
cur_obj_bhv_stack_push(BHV_CMD_GET_ADDR_OF_CMD(0));
|
|
|
|
cur_obj_bhv_stack_push(count);
|
|
|
|
} else { // Finished iterating over the loop
|
|
|
|
cur_obj_bhv_stack_pop(); // Necessary to remove address from the stack
|
|
|
|
gCurBhvCommand++;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Start executing following commands immediately
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x08: Marks the beginning of an infinite loop.
|
|
|
|
// Usage: BEGIN_LOOP()
|
|
|
|
static s32 bhv_cmd_begin_loop(void) {
|
|
|
|
cur_obj_bhv_stack_push(BHV_CMD_GET_ADDR_OF_CMD(1)); // Store address of the first command of the loop in the stack
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x09: Marks the end of an infinite loop.
|
|
|
|
// Usage: END_LOOP()
|
|
|
|
static s32 bhv_cmd_end_loop(void) {
|
|
|
|
gCurBhvCommand = (const BehaviorScript *) cur_obj_bhv_stack_pop(); // Jump back to the first command in the loop
|
|
|
|
cur_obj_bhv_stack_push(BHV_CMD_GET_ADDR_OF_CMD(0)); // Save address to the stack again
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
return BHV_PROC_BREAK;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x0C: Executes a native game function. Function must not take or return any values.
|
|
|
|
// Usage: CALL_NATIVE(func)
|
|
|
|
typedef void (*NativeBhvFunc)(void);
|
|
|
|
static s32 bhv_cmd_call_native(void) {
|
|
|
|
NativeBhvFunc behaviorFunc = BHV_CMD_GET_VPTR(1);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
behaviorFunc();
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x0E: Sets the specified field to a float.
|
|
|
|
// Usage: SET_FLOAT(field, value)
|
|
|
|
static s32 bhv_cmd_set_float(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
f32 value = BHV_CMD_GET_2ND_S16(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_set_float(field, value);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x10: Sets the specified field to an integer.
|
|
|
|
// Usage: SET_INT(field, value)
|
|
|
|
static s32 bhv_cmd_set_int(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
s16 value = BHV_CMD_GET_2ND_S16(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_set_int(field, value);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x36: Unused. Sets the specified field to an integer. Wastes 4 bytes of space for no reason at all.
|
|
|
|
static s32 bhv_cmd_set_int_unused(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
s32 value = BHV_CMD_GET_2ND_S16(1); // Taken from 2nd word instead of 1st
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_set_int(field, value);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2; // Twice as long
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x14: Sets the specified field to a random float in the given range.
|
|
|
|
// Usage: SET_RANDOM_FLOAT(field, min, range)
|
|
|
|
static s32 bhv_cmd_set_random_float(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
f32 min = BHV_CMD_GET_2ND_S16(0);
|
|
|
|
f32 range = BHV_CMD_GET_1ST_S16(1);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_set_float(field, (range * random_float()) + min);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x15: Sets the specified field to a random integer in the given range.
|
|
|
|
// Usage: SET_RANDOM_INT(field, min, range)
|
|
|
|
static s32 bhv_cmd_set_random_int(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
s32 min = BHV_CMD_GET_2ND_S16(0);
|
|
|
|
s32 range = BHV_CMD_GET_1ST_S16(1);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_set_int(field, (s32)(range * random_float()) + min);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x13: Gets a random short, right shifts it the specified amount and adds min to it, then sets the specified field to that value.
|
|
|
|
// Usage: SET_INT_RAND_RSHIFT(field, min, rshift)
|
|
|
|
static s32 bhv_cmd_set_int_rand_rshift(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
s32 min = BHV_CMD_GET_2ND_S16(0);
|
|
|
|
s32 rshift = BHV_CMD_GET_1ST_S16(1);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_set_int(field, (random_u16() >> rshift) + min);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x16: Adds a random float in the given range to the specified field.
|
|
|
|
// Usage: ADD_RANDOM_FLOAT(field, min, range)
|
|
|
|
static s32 bhv_cmd_add_random_float(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
f32 min = BHV_CMD_GET_2ND_S16(0);
|
|
|
|
f32 range = BHV_CMD_GET_1ST_S16(1);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_set_float(field, cur_obj_get_float(field) + min + (range * random_float()));
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x17: Gets a random short, right shifts it the specified amount and adds min to it, then adds the value to the specified field. Unused.
|
|
|
|
// Usage: ADD_INT_RAND_RSHIFT(field, min, rshift)
|
|
|
|
static s32 bhv_cmd_add_int_rand_rshift(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
s32 min = BHV_CMD_GET_2ND_S16(0);
|
|
|
|
s32 rshift = BHV_CMD_GET_1ST_S16(1);
|
|
|
|
s32 rnd = random_u16();
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_set_int(field, (cur_obj_get_int(field) + min) + (rnd >> rshift));
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x0D: Adds a float to the specified field.
|
|
|
|
// Usage: ADD_FLOAT(field, value)
|
|
|
|
static s32 bhv_cmd_add_float(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
f32 value = BHV_CMD_GET_2ND_S16(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_add_float(field, value);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x0F: Adds an integer to the specified field.
|
|
|
|
// Usage: ADD_INT(field, value)
|
|
|
|
static s32 bhv_cmd_add_int(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
s16 value = BHV_CMD_GET_2ND_S16(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_add_int(field, value);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x11: Performs a bitwise OR with the specified field and the given integer.
|
|
|
|
// Usually used to set an object's flags.
|
|
|
|
// Usage: OR_INT(field, value)
|
|
|
|
static s32 bhv_cmd_or_int(void) {
|
|
|
|
u8 objectOffset = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
s32 value = BHV_CMD_GET_2ND_S16(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
|
|
|
value &= 0xFFFF;
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_or_int(objectOffset, value);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x12: Performs a bit clear with the specified short. Unused.
|
|
|
|
// Usage: BIT_CLEAR(field, value)
|
|
|
|
static s32 bhv_cmd_bit_clear(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
s32 value = BHV_CMD_GET_2ND_S16(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
|
|
|
value = (value & 0xFFFF) ^ 0xFFFF;
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_and_int(field, value);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x27: Loads the animations for the object. <field> is always set to oAnimations.
|
|
|
|
// Usage: LOAD_ANIMATIONS(field, anims)
|
|
|
|
static s32 bhv_cmd_load_animations(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_set_vptr(field, BHV_CMD_GET_VPTR(1));
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x28: Begins animation and sets the object's current animation index to the specified value.
|
|
|
|
// Usage: ANIMATE(animIndex)
|
|
|
|
static s32 bhv_cmd_animate(void) {
|
|
|
|
s32 animIndex = BHV_CMD_GET_2ND_U8(0);
|
2019-10-05 19:08:05 +00:00
|
|
|
struct Animation **animations = gCurrentObject->oAnimations;
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
geo_obj_init_animation(&gCurrentObject->header.gfx, &animations[animIndex]);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x1E: Finds the floor triangle directly under the object and moves the object down to it.
|
|
|
|
// Usage: DROP_TO_FLOOR()
|
|
|
|
static s32 bhv_cmd_drop_to_floor(void) {
|
2019-08-25 04:46:40 +00:00
|
|
|
f32 x = gCurrentObject->oPosX;
|
|
|
|
f32 y = gCurrentObject->oPosY;
|
|
|
|
f32 z = gCurrentObject->oPosZ;
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2019-08-25 04:46:40 +00:00
|
|
|
f32 floor = find_floor_height(x, y + 200.0f, z);
|
|
|
|
gCurrentObject->oPosY = floor;
|
|
|
|
gCurrentObject->oMoveFlags |= OBJ_MOVE_ON_GROUND;
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x18: No operation. Unused.
|
|
|
|
// Usage: CMD_NOP_1(field)
|
|
|
|
static s32 bhv_cmd_nop_1(void) {
|
|
|
|
UNUSED u8 field = BHV_CMD_GET_2ND_U8(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x1A: No operation. Unused.
|
|
|
|
// Usage: CMD_NOP_3(field)
|
|
|
|
static s32 bhv_cmd_nop_3(void) {
|
|
|
|
UNUSED u8 field = BHV_CMD_GET_2ND_U8(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x19: No operation. Unused.
|
|
|
|
// Usage: CMD_NOP_2(field)
|
|
|
|
static s32 bhv_cmd_nop_2(void) {
|
|
|
|
UNUSED u8 field = BHV_CMD_GET_2ND_U8(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x1F: Sets the destination float field to the sum of the values of the given float fields.
|
|
|
|
// Usage: SUM_FLOAT(fieldDst, fieldSrc1, fieldSrc2)
|
|
|
|
static s32 bhv_cmd_sum_float(void) {
|
|
|
|
u32 fieldDst = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
u32 fieldSrc1 = BHV_CMD_GET_3RD_U8(0);
|
|
|
|
u32 fieldSrc2 = BHV_CMD_GET_4TH_U8(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_set_float(fieldDst, cur_obj_get_float(fieldSrc1) + cur_obj_get_float(fieldSrc2));
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x20: Sets the destination integer field to the sum of the values of the given integer fields. Unused.
|
|
|
|
// Usage: SUM_INT(fieldDst, fieldSrc1, fieldSrc2)
|
|
|
|
static s32 bhv_cmd_sum_int(void) {
|
|
|
|
u32 fieldDst = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
u32 fieldSrc1 = BHV_CMD_GET_3RD_U8(0);
|
|
|
|
u32 fieldSrc2 = BHV_CMD_GET_4TH_U8(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_set_int(fieldDst, cur_obj_get_int(fieldSrc1) + cur_obj_get_int(fieldSrc2));
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x23: Sets the size of the object's cylindrical hitbox.
|
|
|
|
// Usage: SET_HITBOX(radius, height)
|
|
|
|
static s32 bhv_cmd_set_hitbox(void) {
|
|
|
|
s16 radius = BHV_CMD_GET_1ST_S16(1);
|
|
|
|
s16 height = BHV_CMD_GET_2ND_S16(1);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-01-03 15:38:57 +00:00
|
|
|
gCurrentObject->hitboxRadius = radius;
|
|
|
|
gCurrentObject->hitboxHeight = height;
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x2E: Sets the size of the object's cylindrical hurtbox.
|
|
|
|
// Usage: SET_HURTBOX(radius, height)
|
|
|
|
static s32 bhv_cmd_set_hurtbox(void) {
|
|
|
|
s16 radius = BHV_CMD_GET_1ST_S16(1);
|
|
|
|
s16 height = BHV_CMD_GET_2ND_S16(1);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-01-03 15:38:57 +00:00
|
|
|
gCurrentObject->hurtboxRadius = radius;
|
|
|
|
gCurrentObject->hurtboxHeight = height;
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x2B: Sets the size of the object's cylindrical hitbox, and applies a downwards offset.
|
|
|
|
// Usage: SET_HITBOX_WITH_OFFSET(radius, height, downOffset)
|
|
|
|
static s32 bhv_cmd_set_hitbox_with_offset(void) {
|
|
|
|
s16 radius = BHV_CMD_GET_1ST_S16(1);
|
|
|
|
s16 height = BHV_CMD_GET_2ND_S16(1);
|
|
|
|
s16 downOffset = BHV_CMD_GET_1ST_S16(2);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-01-03 15:38:57 +00:00
|
|
|
gCurrentObject->hitboxRadius = radius;
|
|
|
|
gCurrentObject->hitboxHeight = height;
|
|
|
|
gCurrentObject->hitboxDownOffset = downOffset;
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 3;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x24: No operation. Unused.
|
|
|
|
// Usage: CMD_NOP_4(field, value)
|
|
|
|
static s32 bhv_cmd_nop_4(void) {
|
|
|
|
UNUSED s16 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
UNUSED s16 value = BHV_CMD_GET_2ND_S16(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x00: Defines the start of the behavior script as well as the object list the object belongs to.
|
|
|
|
// Has some special behavior for certain objects.
|
|
|
|
// Usage: BEGIN(objList)
|
|
|
|
static s32 bhv_cmd_begin(void) {
|
|
|
|
// These objects were likely very early objects, which is why this code is here
|
|
|
|
// instead of in the respective behavior scripts.
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Initiate the room if the object is a haunted chair or the mad piano.
|
2020-03-02 03:42:52 +00:00
|
|
|
if (cur_obj_has_behavior(bhvHauntedChair)) {
|
2019-08-25 04:46:40 +00:00
|
|
|
bhv_init_room();
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2020-03-02 03:42:52 +00:00
|
|
|
if (cur_obj_has_behavior(bhvMadPiano)) {
|
2019-08-25 04:46:40 +00:00
|
|
|
bhv_init_room();
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2020-04-03 18:57:26 +00:00
|
|
|
// Set collision distance if the object is a message panel.
|
2020-03-02 03:42:52 +00:00
|
|
|
if (cur_obj_has_behavior(bhvMessagePanel)) {
|
2019-08-25 04:46:40 +00:00
|
|
|
gCurrentObject->oCollisionDistance = 150.0f;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// An unused, incomplete behavior command that does not have an entry in the lookup table, and so no command number.
|
|
|
|
// It cannot be simply re-added to the table, as unlike all other bhv commands it takes a parameter.
|
|
|
|
// Theoretically this command would have been of variable size.
|
|
|
|
// Included below is a modified/repaired version of this function that would work properly.
|
|
|
|
static void bhv_cmd_set_int_random_from_table(s32 tableSize) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
s32 table[16];
|
2019-08-25 04:46:40 +00:00
|
|
|
s32 i;
|
2020-04-03 18:57:26 +00:00
|
|
|
// This for loop would not work as intended at all...
|
|
|
|
for (i = 0; i <= tableSize / 2; i += 2) {
|
|
|
|
table[i] = BHV_CMD_GET_1ST_S16(i + 1);
|
|
|
|
table[i + 1] = BHV_CMD_GET_2ND_S16(i + 1);
|
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_set_int(field, table[(s32)(tableSize * random_float())]);
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Does not increment gCurBhvCommand or return a bhv status
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
// Command 0x??: Sets the specified field to a random entry in the given table, up to size 16.
|
|
|
|
// Bytes: ?? FF SS SS V1 V1 V2 V2 V3 V3 V4 V4... ...V15 V15 V16 V16 (no macro exists)
|
|
|
|
// F -> field, S -> table size, V1, V2, etc. -> table entries (up to 16)
|
|
|
|
static s32 bhv_cmd_set_int_random_from_table(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
// Retrieve tableSize from the bhv command instead of as a parameter.
|
|
|
|
s16 tableSize = BHV_CMD_GET_2ND_S16(0); // tableSize should not be greater than 16
|
|
|
|
s32 table[16];
|
|
|
|
s32 i;
|
|
|
|
|
|
|
|
// Construct the table from the behavior command.
|
|
|
|
for (i = 0; i <= tableSize; i += 2) {
|
|
|
|
table[i] = BHV_CMD_GET_1ST_S16((i / 2) + 1);
|
|
|
|
table[i + 1] = BHV_CMD_GET_2ND_S16((i / 2) + 1);
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Set the field to a random entry of the table.
|
|
|
|
cur_obj_set_int(field, table[(s32)(tableSize * random_float())]);
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += (tableSize / 2) + 1;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
2020-04-03 18:57:26 +00:00
|
|
|
**/
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x2A: Loads collision data for the object.
|
|
|
|
// Usage: LOAD_COLLISION_DATA(collisionData)
|
|
|
|
static s32 bhv_cmd_load_collision_data(void) {
|
|
|
|
u32 *collisionData = segmented_to_virtual(BHV_CMD_GET_VPTR(1));
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2019-08-25 04:46:40 +00:00
|
|
|
gCurrentObject->collisionData = collisionData;
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x2D: Sets the home position of the object to its current position.
|
|
|
|
// Usage: SET_HOME()
|
|
|
|
static s32 bhv_cmd_set_home(void) {
|
2019-08-25 04:46:40 +00:00
|
|
|
gCurrentObject->oHomeX = gCurrentObject->oPosX;
|
|
|
|
gCurrentObject->oHomeY = gCurrentObject->oPosY;
|
|
|
|
gCurrentObject->oHomeZ = gCurrentObject->oPosZ;
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x2F: Sets the object's interaction type.
|
|
|
|
// Usage: SET_INTERACT_TYPE(type)
|
|
|
|
static s32 bhv_cmd_set_interact_type(void) {
|
|
|
|
gCurrentObject->oInteractType = BHV_CMD_GET_U32(1);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x31: Sets the object's interaction subtype. Unused.
|
|
|
|
// Usage: SET_INTERACT_SUBTYPE(subtype)
|
|
|
|
static s32 bhv_cmd_set_interact_subtype(void) {
|
|
|
|
gCurrentObject->oInteractionSubtype = BHV_CMD_GET_U32(1);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x32: Sets the object's size to the specified percentage.
|
|
|
|
// Usage: SCALE(unusedField, percent)
|
|
|
|
static s32 bhv_cmd_scale(void) {
|
|
|
|
UNUSED u8 unusedField = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
s16 percent = BHV_CMD_GET_2ND_S16(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_scale(percent / 100.0f);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x30: Sets various parameters that the object uses for calculating physics.
|
|
|
|
// Usage: SET_OBJ_PHYSICS(wallHitboxRadius, gravity, bounciness, dragStrength, friction, buoyancy, unused1, unused2)
|
|
|
|
static s32 bhv_cmd_set_obj_physics(void) {
|
|
|
|
UNUSED f32 unused1, unused2;
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurrentObject->oWallHitboxRadius = BHV_CMD_GET_1ST_S16(1);
|
|
|
|
gCurrentObject->oGravity = BHV_CMD_GET_2ND_S16(1) / 100.0f;
|
|
|
|
gCurrentObject->oBounciness = BHV_CMD_GET_1ST_S16(2) / 100.0f;
|
|
|
|
gCurrentObject->oDragStrength = BHV_CMD_GET_2ND_S16(2) / 100.0f;
|
|
|
|
gCurrentObject->oFriction = BHV_CMD_GET_1ST_S16(3) / 100.0f;
|
|
|
|
gCurrentObject->oBuoyancy = BHV_CMD_GET_2ND_S16(3) / 100.0f;
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
unused1 = BHV_CMD_GET_1ST_S16(4) / 100.0f;
|
|
|
|
unused2 = BHV_CMD_GET_2ND_S16(4) / 100.0f;
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 5;
|
|
|
|
return BHV_PROC_CONTINUE;
|
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x33: Performs a bit clear on the object's parent's field with the specified value.
|
|
|
|
// Used for clearing active particle flags fron Mario's object.
|
|
|
|
// Usage: PARENT_BIT_CLEAR(field, value)
|
|
|
|
static s32 bhv_cmd_parent_bit_clear(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
s32 value = BHV_CMD_GET_U32(1);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
value = value ^ 0xFFFFFFFF;
|
|
|
|
obj_and_int(gCurrentObject->parentObj, field, value);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x37: Spawns a water droplet with the given parameters.
|
|
|
|
// Usage: SPAWN_WATER_DROPLET(dropletParams)
|
|
|
|
static s32 bhv_cmd_spawn_water_droplet(void) {
|
|
|
|
struct WaterDropletParams *dropletParams = BHV_CMD_GET_VPTR(1);
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-03-02 03:42:52 +00:00
|
|
|
spawn_water_droplet(gCurrentObject, dropletParams);
|
2020-05-15 01:31:52 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand += 2;
|
|
|
|
return BHV_PROC_CONTINUE;
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Command 0x34: Animates an object using texture animation. <field> is always set to oAnimState.
|
|
|
|
// Usage: ANIMATE_TEXTURE(field, rate)
|
|
|
|
static s32 bhv_cmd_animate_texture(void) {
|
|
|
|
u8 field = BHV_CMD_GET_2ND_U8(0);
|
|
|
|
s16 rate = BHV_CMD_GET_2ND_S16(0);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Increase the field (oAnimState) by 1 every <rate> frames.
|
2020-01-03 15:38:57 +00:00
|
|
|
if ((gGlobalTimer % rate) == 0) {
|
2020-04-03 18:57:26 +00:00
|
|
|
cur_obj_add_int(field, 1);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurBhvCommand++;
|
|
|
|
return BHV_PROC_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void stub_behavior_script_2(void) {
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef s32 (*BhvCommandProc)(void);
|
|
|
|
static BhvCommandProc BehaviorCmdTable[] = {
|
2020-05-15 01:31:52 +00:00
|
|
|
bhv_cmd_begin, //00
|
|
|
|
bhv_cmd_delay, //01
|
|
|
|
bhv_cmd_call, //02
|
|
|
|
bhv_cmd_return, //03
|
|
|
|
bhv_cmd_goto, //04
|
|
|
|
bhv_cmd_begin_repeat, //05
|
|
|
|
bhv_cmd_end_repeat, //06
|
|
|
|
bhv_cmd_end_repeat_continue, //07
|
|
|
|
bhv_cmd_begin_loop, //08
|
|
|
|
bhv_cmd_end_loop, //09
|
|
|
|
bhv_cmd_break, //0A
|
|
|
|
bhv_cmd_break_unused, //0B
|
|
|
|
bhv_cmd_call_native, //0C
|
|
|
|
bhv_cmd_add_float, //0D
|
|
|
|
bhv_cmd_set_float, //0E
|
|
|
|
bhv_cmd_add_int, //0F
|
|
|
|
bhv_cmd_set_int, //10
|
|
|
|
bhv_cmd_or_int, //11
|
|
|
|
bhv_cmd_bit_clear, //12
|
|
|
|
bhv_cmd_set_int_rand_rshift, //13
|
|
|
|
bhv_cmd_set_random_float, //14
|
|
|
|
bhv_cmd_set_random_int, //15
|
|
|
|
bhv_cmd_add_random_float, //16
|
|
|
|
bhv_cmd_add_int_rand_rshift, //17
|
|
|
|
bhv_cmd_nop_1, //18
|
|
|
|
bhv_cmd_nop_2, //19
|
|
|
|
bhv_cmd_nop_3, //1A
|
|
|
|
bhv_cmd_set_model, //1B
|
|
|
|
bhv_cmd_spawn_child, //1C
|
|
|
|
bhv_cmd_deactivate, //1D
|
|
|
|
bhv_cmd_drop_to_floor, //1E
|
|
|
|
bhv_cmd_sum_float, //1F
|
|
|
|
bhv_cmd_sum_int, //20
|
|
|
|
bhv_cmd_billboard, //21
|
|
|
|
bhv_cmd_hide, //22
|
|
|
|
bhv_cmd_set_hitbox, //23
|
|
|
|
bhv_cmd_nop_4, //24
|
|
|
|
bhv_cmd_delay_var, //25
|
|
|
|
bhv_cmd_begin_repeat_unused, //26
|
|
|
|
bhv_cmd_load_animations, //27
|
|
|
|
bhv_cmd_animate, //28
|
|
|
|
bhv_cmd_spawn_child_with_param, //29
|
|
|
|
bhv_cmd_load_collision_data, //2A
|
|
|
|
bhv_cmd_set_hitbox_with_offset, //2B
|
|
|
|
bhv_cmd_spawn_obj, //2C
|
|
|
|
bhv_cmd_set_home, //2D
|
|
|
|
bhv_cmd_set_hurtbox, //2E
|
|
|
|
bhv_cmd_set_interact_type, //2F
|
|
|
|
bhv_cmd_set_obj_physics, //30
|
|
|
|
bhv_cmd_set_interact_subtype, //31
|
|
|
|
bhv_cmd_scale, //32
|
|
|
|
bhv_cmd_parent_bit_clear, //33
|
|
|
|
bhv_cmd_animate_texture, //34
|
|
|
|
bhv_cmd_disable_rendering, //35
|
|
|
|
bhv_cmd_set_int_unused, //36
|
|
|
|
bhv_cmd_spawn_water_droplet, //37
|
|
|
|
bhv_cmd_cylboard //38
|
2019-08-25 04:46:40 +00:00
|
|
|
};
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Execute the behavior script of the current object, process the object flags, and other miscellaneous code for updating objects.
|
|
|
|
void cur_obj_update(void) {
|
2019-08-25 04:46:40 +00:00
|
|
|
UNUSED u32 unused;
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
s16 objFlags = gCurrentObject->oFlags;
|
2019-08-25 04:46:40 +00:00
|
|
|
f32 distanceFromMario;
|
2020-04-03 18:57:26 +00:00
|
|
|
BhvCommandProc bhvCmdProc;
|
|
|
|
s32 bhvProcResult;
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Calculate the distance from the object to Mario.
|
|
|
|
if (objFlags & OBJ_FLAG_COMPUTE_DIST_TO_MARIO) {
|
2019-08-25 04:46:40 +00:00
|
|
|
gCurrentObject->oDistanceToMario = dist_between_objects(gCurrentObject, gMarioObject);
|
|
|
|
distanceFromMario = gCurrentObject->oDistanceToMario;
|
|
|
|
} else {
|
|
|
|
distanceFromMario = 0.0f;
|
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Calculate the angle from the object to Mario.
|
|
|
|
if (objFlags & OBJ_FLAG_COMPUTE_ANGLE_TO_MARIO) {
|
2020-03-02 03:42:52 +00:00
|
|
|
gCurrentObject->oAngleToMario = obj_angle_to_object(gCurrentObject, gMarioObject);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// If the object's action has changed, reset the action timer.
|
2019-08-25 04:46:40 +00:00
|
|
|
if (gCurrentObject->oAction != gCurrentObject->oPrevAction) {
|
|
|
|
(void) (gCurrentObject->oTimer = 0, gCurrentObject->oSubAction = 0,
|
|
|
|
gCurrentObject->oPrevAction = gCurrentObject->oAction);
|
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Execute the behavior script.
|
|
|
|
gCurBhvCommand = gCurrentObject->curBhvCommand;
|
2019-08-25 04:46:40 +00:00
|
|
|
|
|
|
|
do {
|
2020-04-03 18:57:26 +00:00
|
|
|
bhvCmdProc = BehaviorCmdTable[*gCurBhvCommand >> 24];
|
|
|
|
bhvProcResult = bhvCmdProc();
|
|
|
|
} while (bhvProcResult == BHV_PROC_CONTINUE);
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
gCurrentObject->curBhvCommand = gCurBhvCommand;
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Increment the object's timer.
|
2019-09-01 19:50:50 +00:00
|
|
|
if (gCurrentObject->oTimer < 0x3FFFFFFF) {
|
2019-08-25 04:46:40 +00:00
|
|
|
gCurrentObject->oTimer++;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// If the object's action has changed, reset the action timer.
|
2019-08-25 04:46:40 +00:00
|
|
|
if (gCurrentObject->oAction != gCurrentObject->oPrevAction) {
|
|
|
|
(void) (gCurrentObject->oTimer = 0, gCurrentObject->oSubAction = 0,
|
|
|
|
gCurrentObject->oPrevAction = gCurrentObject->oAction);
|
|
|
|
}
|
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Execute various code based on object flags.
|
|
|
|
objFlags = (s16) gCurrentObject->oFlags;
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
if (objFlags & OBJ_FLAG_SET_FACE_ANGLE_TO_MOVE_ANGLE) {
|
2020-03-02 03:42:52 +00:00
|
|
|
obj_set_face_angle_to_move_angle(gCurrentObject);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
if (objFlags & OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW) {
|
2019-08-25 04:46:40 +00:00
|
|
|
gCurrentObject->oFaceAngleYaw = gCurrentObject->oMoveAngleYaw;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
if (objFlags & OBJ_FLAG_MOVE_XZ_USING_FVEL) {
|
2020-03-02 03:42:52 +00:00
|
|
|
cur_obj_move_xz_using_fvel_and_yaw();
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
if (objFlags & OBJ_FLAG_MOVE_Y_WITH_TERMINAL_VEL) {
|
2020-03-02 03:42:52 +00:00
|
|
|
cur_obj_move_y_with_terminal_vel();
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
if (objFlags & OBJ_FLAG_TRANSFORM_RELATIVE_TO_PARENT) {
|
2020-03-02 03:42:52 +00:00
|
|
|
obj_build_transform_relative_to_parent(gCurrentObject);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
if (objFlags & OBJ_FLAG_SET_THROW_MATRIX_FROM_TRANSFORM) {
|
2020-03-02 03:42:52 +00:00
|
|
|
obj_set_throw_matrix_from_transform(gCurrentObject);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
if (objFlags & OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE) {
|
|
|
|
obj_update_gfx_pos_and_angle(gCurrentObject);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
2020-04-03 18:57:26 +00:00
|
|
|
// Handle visibility of object
|
2019-08-25 04:46:40 +00:00
|
|
|
if (gCurrentObject->oRoom != -1) {
|
2020-04-03 18:57:26 +00:00
|
|
|
// If the object is in a room, only show it when Mario is in the room.
|
2020-03-02 03:42:52 +00:00
|
|
|
cur_obj_enable_rendering_if_mario_in_room();
|
2020-04-03 18:57:26 +00:00
|
|
|
} else if ((objFlags & OBJ_FLAG_COMPUTE_DIST_TO_MARIO) && gCurrentObject->collisionData == NULL) {
|
|
|
|
if (!(objFlags & OBJ_FLAG_ACTIVE_FROM_AFAR)) {
|
|
|
|
// If the object has a render distance, check if it should be shown.
|
2020-05-12 07:26:16 +00:00
|
|
|
#ifndef NODRAWINGDISTANCE
|
2019-08-25 04:46:40 +00:00
|
|
|
if (distanceFromMario > gCurrentObject->oDrawingDistance) {
|
2020-04-03 18:57:26 +00:00
|
|
|
// Out of render distance, hide the object.
|
2019-08-25 04:46:40 +00:00
|
|
|
gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
|
|
|
|
gCurrentObject->activeFlags |= ACTIVE_FLAG_FAR_AWAY;
|
|
|
|
} else if (gCurrentObject->oHeldState == HELD_FREE) {
|
2020-05-12 07:26:16 +00:00
|
|
|
#else
|
|
|
|
if (distanceFromMario <= gCurrentObject->oDrawingDistance && gCurrentObject->oHeldState == HELD_FREE) {
|
|
|
|
#endif
|
2020-04-03 18:57:26 +00:00
|
|
|
// In render distance (and not being held), show the object.
|
2019-08-25 04:46:40 +00:00
|
|
|
gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
|
|
|
|
gCurrentObject->activeFlags &= ~ACTIVE_FLAG_FAR_AWAY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|