From 1ee3fd1d1302f4b46ce6ae3f7eeec361e80e6f60 Mon Sep 17 00:00:00 2001 From: MysterD Date: Fri, 5 May 2023 23:59:58 -0700 Subject: [PATCH] Fixed ~240 possible crashes --- autogen/lua_definitions/constants.lua | 4 +- autogen/lua_definitions/functions.lua | 11 ++- data/dynos_level.cpp | 10 +-- docs/lua/functions-4.md | 20 ++++++ docs/lua/functions-5.md | 5 +- docs/lua/functions.md | 1 + src/engine/behavior_script.c | 7 +- src/engine/graph_node.c | 2 +- src/engine/level_script.c | 11 ++- src/game/behavior_actions.h | 3 + src/game/behaviors/beta_boo_key.inc.c | 12 ++-- src/game/behaviors/bird.inc.c | 2 +- src/game/behaviors/blue_coin.inc.c | 8 ++- src/game/behaviors/blue_fish.inc.c | 2 +- src/game/behaviors/bowling_ball.inc.c | 2 +- src/game/behaviors/bowser.inc.c | 40 +++++++---- src/game/behaviors/bub.inc.c | 3 +- src/game/behaviors/cannon.inc.c | 12 ++-- src/game/behaviors/capswitch.inc.c | 4 +- src/game/behaviors/castle_floor_trap.inc.c | 9 ++- src/game/behaviors/celebration_star.inc.c | 12 ++-- src/game/behaviors/chain_chomp.inc.c | 24 +++++-- .../behaviors/checkerboard_platform.inc.c | 2 +- src/game/behaviors/cloud.inc.c | 7 +- src/game/behaviors/coffin.inc.c | 2 +- src/game/behaviors/coin.inc.c | 5 +- .../behaviors/controllable_platform.inc.c | 15 +++-- src/game/behaviors/elevator.inc.c | 8 +-- src/game/behaviors/exclamation_box.inc.c | 6 +- src/game/behaviors/eyerok.inc.c | 26 +++++-- src/game/behaviors/falling_pillar.inc.c | 1 + src/game/behaviors/ferris_wheel.inc.c | 6 ++ src/game/behaviors/fish.inc.c | 10 +-- src/game/behaviors/flamethrower.inc.c | 4 +- .../behaviors/flying_bookend_switch.inc.c | 1 + src/game/behaviors/goomba.inc.c | 11 ++- src/game/behaviors/grill_door.inc.c | 28 ++++---- src/game/behaviors/ground_particles.inc.c | 4 +- src/game/behaviors/heave_ho.inc.c | 38 ++++++----- src/game/behaviors/king_bobomb.inc.c | 2 +- src/game/behaviors/koopa.inc.c | 9 +-- .../behaviors/lll_floating_wood_piece.inc.c | 2 +- .../lll_octagonal_rotating_mesh.inc.c | 7 +- .../behaviors/lll_rotating_hex_flame.inc.c | 11 ++- src/game/behaviors/mips.inc.c | 8 ++- src/game/behaviors/moat_drainer.inc.c | 20 +++--- src/game/behaviors/moneybag.inc.c | 4 +- src/game/behaviors/monty_mole.inc.c | 3 + src/game/behaviors/mr_blizzard.inc.c | 4 +- src/game/behaviors/mr_i.inc.c | 4 ++ src/game/behaviors/platform_on_track.inc.c | 14 ++-- src/game/behaviors/pyramid_top.inc.c | 4 +- src/game/behaviors/racing_penguin.inc.c | 24 ++++--- .../behaviors/rotating_octagonal_plat.inc.c | 6 +- src/game/behaviors/rotating_platform.inc.c | 2 +- src/game/behaviors/scuttlebug.inc.c | 2 +- src/game/behaviors/seesaw_platform.inc.c | 4 +- src/game/behaviors/sl_walking_penguin.inc.c | 67 ++++++++++--------- src/game/behaviors/snowman.inc.c | 4 ++ src/game/behaviors/sparkle_spawn_star.inc.c | 3 +- src/game/behaviors/thi_top.inc.c | 7 +- src/game/behaviors/tower_platform.inc.c | 29 ++++---- src/game/behaviors/tox_box.inc.c | 1 + src/game/behaviors/treasure_chest.inc.c | 5 ++ src/game/behaviors/triplet_butterfly.inc.c | 17 ++--- src/game/behaviors/ttc_2d_rotator.inc.c | 7 +- src/game/behaviors/ttc_pit_block.inc.c | 18 +++-- src/game/behaviors/ttc_rotating_solid.inc.c | 9 ++- src/game/behaviors/tumbling_bridge.inc.c | 7 +- src/game/behaviors/tuxie.inc.c | 6 +- src/game/behaviors/ukiki.inc.c | 2 +- src/game/behaviors/ukiki_cage.inc.c | 2 +- src/game/behaviors/unagi.inc.c | 10 +-- src/game/behaviors/water_bomb.inc.c | 10 +-- src/game/behaviors/water_bomb_cannon.inc.c | 2 +- src/game/behaviors/water_pillar.inc.c | 6 +- src/game/behaviors/water_ring.inc.c | 7 +- src/game/behaviors/wdw_water_level.inc.c | 5 +- src/game/behaviors/wiggler.inc.c | 28 +++++--- src/game/camera.c | 4 ++ src/game/ingame_menu.c | 6 +- src/game/interaction.c | 2 +- src/game/level_update.c | 1 + src/game/mario_actions_cutscene.c | 10 +-- src/game/memory.c | 4 ++ src/game/moving_texture.c | 6 +- src/game/obj_behaviors_2.c | 1 + src/game/object_helpers.c | 32 +++++++-- src/game/object_helpers.h | 1 + src/game/object_list_processor.c | 2 + src/game/spawn_object.c | 7 +- src/game/spawn_sound.c | 3 +- src/game/spawn_sound.h | 2 +- src/menu/file_select.c | 37 +++++----- src/menu/star_select.c | 13 ++-- src/pc/lua/smlua_constants_autogen.c | 4 +- src/pc/lua/smlua_functions_autogen.c | 29 ++++++-- src/pc/lua/utils/smlua_model_utils.c | 5 ++ src/pc/lua/utils/smlua_obj_utils.c | 20 ++++++ src/pc/network/packets/packet_area.c | 2 +- 100 files changed, 620 insertions(+), 331 deletions(-) diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index edd0f98d..968e20a1 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -11543,13 +11543,13 @@ MAX_LOCAL_VERSION_LENGTH = 36 MAX_VERSION_LENGTH = 32 --- @type integer -MINOR_VERSION_NUMBER = 1 +MINOR_VERSION_NUMBER = 0 --- @type integer PATCH_VERSION_NUMBER = 0 --- @type integer -VERSION_NUMBER = 34 +VERSION_NUMBER = 35 --- @type string VERSION_REGION = "JP" diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 3c0fb7c2..dd0d6c4e 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -7187,6 +7187,12 @@ function get_object_list_from_behavior(behavior) -- ... end +--- @param trajectory Pointer_Trajectory +--- @return integer +function get_trajectory_length(trajectory) + -- ... +end + --- @param value number --- @param center number --- @param zeroThreshold number @@ -9000,8 +9006,9 @@ function cur_obj_play_sound_2(soundMagic) end --- @param soundStates SoundState +--- @param maxSoundStates integer --- @return nil -function exec_anim_sound_state(soundStates) +function exec_anim_sound_state(soundStates, maxSoundStates) -- ... end @@ -9076,5 +9083,5 @@ end --- @class Pointer_number --- @class Pointer_Vec4s --- @class Pointer_Mtx ---- @class Pointer_Collision --- @class Pointer_Trajectory +--- @class Pointer_Collision diff --git a/data/dynos_level.cpp b/data/dynos_level.cpp index f69fa488..6dfd7167 100644 --- a/data/dynos_level.cpp +++ b/data/dynos_level.cpp @@ -908,10 +908,12 @@ s16 *DynOS_Level_GetWarp(s32 aLevel, s32 aArea, u8 aWarpId) { } DynOS_Level_Init(); - for (const auto &_Warp : sDynosLevelWarps[aLevel]) { - if (_Warp.mArea == aArea) { - if (_Warp.mId == aWarpId) { - return (s16 *) &_Warp; + if (aLevel < LEVEL_COUNT) { + for (const auto &_Warp : sDynosLevelWarps[aLevel]) { + if (_Warp.mArea == aArea) { + if (_Warp.mId == aWarpId) { + return (s16 *) &_Warp; + } } } } diff --git a/docs/lua/functions-4.md b/docs/lua/functions-4.md index 4be078f6..ff4d6bd7 100644 --- a/docs/lua/functions-4.md +++ b/docs/lua/functions-4.md @@ -4650,6 +4650,26 @@
+## [get_trajectory_length](#get_trajectory_length) + +### Lua Example +`local integerValue = get_trajectory_length(trajectory)` + +### Parameters +| Field | Type | +| ----- | ---- | +| trajectory | `Pointer` <`Trajectory`> | + +### Returns +- `integer` + +### C Prototype +`s32 get_trajectory_length(Trajectory* trajectory);` + +[:arrow_up_small:](#) + +
+ ## [increment_velocity_toward_range](#increment_velocity_toward_range) ### Lua Example diff --git a/docs/lua/functions-5.md b/docs/lua/functions-5.md index 6910d378..f3343be0 100644 --- a/docs/lua/functions-5.md +++ b/docs/lua/functions-5.md @@ -2569,18 +2569,19 @@ ## [exec_anim_sound_state](#exec_anim_sound_state) ### Lua Example -`exec_anim_sound_state(soundStates)` +`exec_anim_sound_state(soundStates, maxSoundStates)` ### Parameters | Field | Type | | ----- | ---- | | soundStates | [SoundState](structs.md#SoundState) | +| maxSoundStates | `integer` | ### Returns - None ### C Prototype -`void exec_anim_sound_state(struct SoundState *soundStates);` +`void exec_anim_sound_state(struct SoundState *soundStates, u16 maxSoundStates);` [:arrow_up_small:](#) diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 5262ae27..bddc69a4 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -1348,6 +1348,7 @@ - [find_unimportant_object](functions-4.md#find_unimportant_object) - [geo_offset_klepto_debug](functions-4.md#geo_offset_klepto_debug) - [get_object_list_from_behavior](functions-4.md#get_object_list_from_behavior) + - [get_trajectory_length](functions-4.md#get_trajectory_length) - [increment_velocity_toward_range](functions-4.md#increment_velocity_toward_range) - [is_item_in_array](functions-4.md#is_item_in_array) - [is_mario_moving_fast_or_in_air](functions-4.md#is_mario_moving_fast_or_in_air) diff --git a/src/engine/behavior_script.c b/src/engine/behavior_script.c index a7649a32..2363bf70 100644 --- a/src/engine/behavior_script.c +++ b/src/engine/behavior_script.c @@ -130,6 +130,7 @@ void obj_update_gfx_pos_and_angle(struct Object *obj) { static void cur_obj_bhv_stack_push(uintptr_t bhvAddr) { gCurrentObject->bhvStack[gCurrentObject->bhvStackIndex] = bhvAddr; gCurrentObject->bhvStackIndex++; + if (gCurrentObject->bhvStackIndex >= 8) { gCurrentObject->bhvStackIndex = 8 - 1; } } // Retrieve the last behavior command address from the object's behavior stack. @@ -137,6 +138,7 @@ static uintptr_t cur_obj_bhv_stack_pop(void) { uintptr_t bhvAddr; gCurrentObject->bhvStackIndex--; + if (gCurrentObject->bhvStackIndex >= 8) { gCurrentObject->bhvStackIndex = 0; } bhvAddr = gCurrentObject->bhvStack[gCurrentObject->bhvStackIndex]; return bhvAddr; @@ -858,7 +860,9 @@ static s32 bhv_cmd_parent_bit_clear(void) { s32 value = BHV_CMD_GET_U32(1); value = value ^ 0xFFFFFFFF; - obj_and_int(gCurrentObject->parentObj, field, value); + if (gCurrentObject->parentObj) { + obj_and_int(gCurrentObject->parentObj, field, value); + } gCurBhvCommand += 2; return BHV_PROC_CONTINUE; @@ -1337,6 +1341,7 @@ cur_obj_update_begin:; if (!skipBehavior) { do { + if (!gCurBhvCommand) { break; } bhvCmdProc = BehaviorCmdTable[*gCurBhvCommand >> 24]; bhvProcResult = bhvCmdProc(); } while (bhvProcResult == BHV_PROC_CONTINUE); diff --git a/src/engine/graph_node.c b/src/engine/graph_node.c index c6426d62..36570463 100644 --- a/src/engine/graph_node.c +++ b/src/engine/graph_node.c @@ -488,7 +488,7 @@ struct GraphNodeBackground *init_graph_node_background(struct AllocOnlyPool *poo if (graphNode != NULL) { init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_BACKGROUND); - if (background > BACKGROUND_CUSTOM) { + if (backgroundFunc && background > BACKGROUND_CUSTOM) { LOG_ERROR("invalid background id"); background = BACKGROUND_OCEAN_SKY; } diff --git a/src/engine/level_script.c b/src/engine/level_script.c index 2cace6b5..c9bda5e0 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -66,6 +66,7 @@ static s32 sRegister; static struct LevelCommand *sCurrentCmd; static u8 sLevelOwnedGraphNodes[MAX_LOADED_GRAPH_NODES] = { 0 }; +static u8 sFinishedLoadingPerm = false; static s32 eval_script_area(s32 arg) { return (sWarpDest.areaIdx == arg); @@ -389,6 +390,7 @@ static void level_cmd_alloc_level_pool(void) { // reset level graph node ownership for (s32 i = 0; i < MAX_LOADED_GRAPH_NODES; i++) { if (sLevelOwnedGraphNodes[i]) { + gLoadedGraphNodes[i] = NULL; sLevelOwnedGraphNodes[i] = false; } } @@ -455,7 +457,7 @@ static void level_cmd_load_model_from_dl(void) { if (val1 < MAX_LOADED_GRAPH_NODES) { gLoadedGraphNodes[val1] = (struct GraphNode *) init_graph_node_display_list(sLevelPool, 0, val2, val3); - sLevelOwnedGraphNodes[val1] = true; + if (sFinishedLoadingPerm) { sLevelOwnedGraphNodes[val1] = true; } smlua_model_util_remember(val1, val2, val3, 1); } @@ -468,8 +470,11 @@ static void level_cmd_load_model_from_geo(void) { if (arg0 < MAX_LOADED_GRAPH_NODES) { gLoadedGraphNodes[arg0] = process_geo_layout(sLevelPool, arg1); - sLevelOwnedGraphNodes[arg0] = true; + if (sFinishedLoadingPerm) { sLevelOwnedGraphNodes[arg0] = true; } smlua_model_util_remember(arg0, LAYER_OPAQUE, arg1, 0); + if (arg0 == MODEL_ERROR_MODEL) { + sFinishedLoadingPerm = true; + } } sCurrentCmd = CMD_NEXT; @@ -491,7 +496,7 @@ static void level_cmd_23(void) { // GraphNodeScale has a GraphNode at the top. This // is being stored to the array, so cast the pointer. gLoadedGraphNodes[model] = (struct GraphNode *) init_graph_node_scale(sLevelPool, 0, arg0H, arg1, arg2.f); - sLevelOwnedGraphNodes[model] = true; + if (sFinishedLoadingPerm) { sLevelOwnedGraphNodes[model] = true; } smlua_model_util_remember(model, arg0H, arg1, 1); } diff --git a/src/game/behavior_actions.h b/src/game/behavior_actions.h index d5356944..5e79ef4a 100644 --- a/src/game/behavior_actions.h +++ b/src/game/behavior_actions.h @@ -1,6 +1,9 @@ #ifndef BEHAVIOR_ACTIONS_H #define BEHAVIOR_ACTIONS_H +#define BHV_ARR_CHECK(_arr, _idx, _arritem) (((size_t)_idx) < (sizeof(_arr) / sizeof(_arritem))) +#define BHV_ARR(_arr, _idx, _arritem) (BHV_ARR_CHECK(_arr, _idx, _arritem) ? _arr[_idx] : 0) + void spawn_mist_particles_variable(s32 count, s32 offsetY, f32 size); void bhv_spawn_star_no_level_exit(struct Object* object, u32 params, u8 networkSendEvent); void bhv_star_door_loop_2(void); diff --git a/src/game/behaviors/beta_boo_key.inc.c b/src/game/behaviors/beta_boo_key.inc.c index 2e81c7f0..bdf33ac1 100644 --- a/src/game/behaviors/beta_boo_key.inc.c +++ b/src/game/behaviors/beta_boo_key.inc.c @@ -35,7 +35,9 @@ void bhv_alpha_boo_key_loop(void) { // Another theory is that the boo key was intended to be spawned by a // spawner that used object field 0x00 for something else. This // is elaborated on more in beta_boo_key_dropped_loop. - o->parentObj->oBooDeathStatus = BOO_DEATH_STATUS_DYING; + if (o->parentObj) { + o->parentObj->oBooDeathStatus = BOO_DEATH_STATUS_DYING; + } // Delete the object and spawn sparkles obj_mark_for_deletion(o); @@ -94,7 +96,7 @@ static void beta_boo_key_dropped_loop(void) { // One theory about this code is that there was a boo spawner, which // spawned "false" boos and one "true" boo with the key, and the player // was intended to find the one with the key to progress. - o->parentObj->oInteractStatus = INT_STATUS_HOOT_GRABBED_BY_MARIO; + if (o->parentObj) { o->parentObj->oInteractStatus = INT_STATUS_HOOT_GRABBED_BY_MARIO; } // Delete the object and spawn sparkles obj_mark_for_deletion(o); @@ -120,7 +122,9 @@ static void beta_boo_key_drop(void) { // which stops this function from running again. if (o->oTimer == 0) { // Separate from the parent boo - o->parentObj = parent->parentObj; + if (parent) { + o->parentObj = parent->parentObj; + } o->oAction = BETA_BOO_KEY_ACT_DROPPED; @@ -154,7 +158,7 @@ static void beta_boo_key_inside_boo_loop(void) { o->oPosY += 40.0f; // If the boo is dying/dead, set the action to BETA_BOO_KEY_ACT_DROPPING. - if (parent->oBooDeathStatus != BOO_DEATH_STATUS_ALIVE) { + if (parent && parent->oBooDeathStatus != BOO_DEATH_STATUS_ALIVE) { o->oAction = BETA_BOO_KEY_ACT_DROPPING; } diff --git a/src/game/behaviors/bird.inc.c b/src/game/behaviors/bird.inc.c index 33550460..700657a6 100644 --- a/src/game/behaviors/bird.inc.c +++ b/src/game/behaviors/bird.inc.c @@ -63,7 +63,7 @@ static void bird_act_fly(void) { // A spawned bird's parent is its spawner bird. A spawner bird's parent // is itself. In other words, when a group of birds has its spawner bird // fly past Y=8000, they will all despawn simultaneously. Otherwise, fly. - if (o->parentObj->oPosY > 8000.0f) { + if (!o->parentObj || o->parentObj->oPosY > 8000.0f) { obj_mark_for_deletion(o); } else { // If the bird is a spawner bird, fly towards its home; otherwise, diff --git a/src/game/behaviors/blue_coin.inc.c b/src/game/behaviors/blue_coin.inc.c index ea6cf1c9..93f9ddd4 100644 --- a/src/game/behaviors/blue_coin.inc.c +++ b/src/game/behaviors/blue_coin.inc.c @@ -28,7 +28,7 @@ void bhv_hidden_blue_coin_loop(void) { // Wait until the blue coin switch starts ticking to activate. blueCoinSwitch = o->oHiddenBlueCoinSwitch; - if (blueCoinSwitch->oAction == BLUE_COIN_SWITCH_ACT_TICKING) { + if (blueCoinSwitch && blueCoinSwitch->oAction == BLUE_COIN_SWITCH_ACT_TICKING) { o->oAction++; // Set to HIDDEN_BLUE_COIN_ACT_ACTIVE } @@ -107,8 +107,10 @@ void bhv_blue_coin_number_loop(void) { */ void bhv_blue_coin_switch_init(void) { struct Object *blueCoinNumber = spawn_object(o, MODEL_NUMBER, bhvBlueCoinNumber); - blueCoinNumber->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; // to make sure it's updated even during time stop - blueCoinNumber->oHiddenBlueCoinSwitch = o; + if (blueCoinNumber) { + blueCoinNumber->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; // to make sure it's updated even during time stop + blueCoinNumber->oHiddenBlueCoinSwitch = o; + } o->oHomeY = o->oPosY; } diff --git a/src/game/behaviors/blue_fish.inc.c b/src/game/behaviors/blue_fish.inc.c index efc69804..7e815804 100644 --- a/src/game/behaviors/blue_fish.inc.c +++ b/src/game/behaviors/blue_fish.inc.c @@ -85,7 +85,7 @@ void bhv_blue_fish_movement_loop(void) { cur_obj_move_using_fvel_and_gravity(); // Deletes object if the parent has oAction set to BLUE_FISH_ACT_DUPLICATE. - if (o->parentObj->oAction == BLUE_FISH_ACT_DUPLICATE) { + if (!o->parentObj || o->parentObj->oAction == BLUE_FISH_ACT_DUPLICATE) { obj_mark_for_deletion(o); } } diff --git a/src/game/behaviors/bowling_ball.inc.c b/src/game/behaviors/bowling_ball.inc.c index b0b7dc30..d8e85d99 100644 --- a/src/game/behaviors/bowling_ball.inc.c +++ b/src/game/behaviors/bowling_ball.inc.c @@ -266,7 +266,7 @@ void bhv_bob_pit_bowling_ball_loop(void) { UNUSED s16 collisionFlags = object_step(); find_floor_height_and_data(o->oPosX, o->oPosY, o->oPosZ, &sp1c); - if ((sp1c->normalX == 0) && (sp1c->normalZ == 0)) + if (sp1c && (sp1c->normalX == 0) && (sp1c->normalZ == 0)) o->oForwardVel = 28.0f; bowling_ball_set_hitbox(); diff --git a/src/game/behaviors/bowser.inc.c b/src/game/behaviors/bowser.inc.c index 8cf90add..bb4901ff 100644 --- a/src/game/behaviors/bowser.inc.c +++ b/src/game/behaviors/bowser.inc.c @@ -48,6 +48,7 @@ s16 D_8032F520[][3] = { { 1, 10, 40 }, { 0, 0, 74 }, { -1, -10, 114 }, { 1 { -1, 80, 184 }, { 1, 160, 186 }, { -1, -160, 186 }, { 1, 0, 0 }, }; void bhv_bowser_tail_anchor_init(void) { + if (!o->parentObj) { mark_obj_for_deletion(o); return; } sync_object_init_field(o->parentObj, &o->oAction); sync_object_init_field(o->parentObj, &o->oPrevAction); sync_object_init_field(o->parentObj, &o->oTimer); @@ -59,6 +60,7 @@ void bhv_bowser_tail_anchor_init(void) { } void bhv_bowser_tail_anchor_loop(void) { + if (!o->parentObj) { return; } CUR_OBJ_CALL_ACTION_FUNCTION(sBowserTailAnchorActions); o->oParentRelativePosX = 90.0f; if (o->parentObj->oAction == 4) @@ -71,6 +73,7 @@ void bhv_bowser_flame_spawn_loop(void) { sync_object_init(o, SYNC_DISTANCE_ONLY_EVENTS); } struct Object *bowser = o->parentObj; + if (!bowser) { return; } s32 sp30; f32 sp2C; f32 sp28; @@ -79,8 +82,9 @@ void bhv_bowser_flame_spawn_loop(void) { s16 *sp1C = segmented_to_virtual(bowser_seg6_unkmoveshorts_060576FC); if (bowser->oSoundStateID == 6) { sp30 = bowser->header.gfx.animInfo.animFrame + 1.0f; - if (bowser->header.gfx.animInfo.curAnim->loopEnd == sp30) + if (bowser->header.gfx.animInfo.curAnim && bowser->header.gfx.animInfo.curAnim->loopEnd == sp30) { sp30 = 0; + } if (sp30 > 45 && sp30 < 85) { cur_obj_play_sound_1(SOUND_AIR_BOWSER_SPIT_FIRE); sp2C = sp1C[5 * sp30]; @@ -106,6 +110,7 @@ void bhv_bowser_flame_spawn_loop(void) { } void bhv_bowser_body_anchor_init(void) { + if (!o->parentObj) { mark_obj_for_deletion(o); return; } sync_object_init_field(o->parentObj, &o->oInteractType); sync_object_init_field(o->parentObj, &o->oInteractStatus); sync_object_init_field(o->parentObj, &o->oIntangibleTimer); @@ -113,6 +118,7 @@ void bhv_bowser_body_anchor_init(void) { } void bhv_bowser_body_anchor_loop(void) { + if (!o->parentObj) { return; } obj_copy_pos_and_angle(o, o->parentObj); if (o->parentObj->oAction == 4) { #ifndef VERSION_JP @@ -1213,7 +1219,7 @@ void bowser_free_update(void) { o->platform = floor->object; else o->platform = NULL; - exec_anim_sound_state(D_8032F5B8); + exec_anim_sound_state(D_8032F5B8, sizeof(D_8032F5B8) / sizeof(struct SoundState)); } void bowser_held_update(void) { @@ -1262,9 +1268,11 @@ void bowser_thrown_dropped_update(void) { o->oForwardVel = coss(o->oBowserHeldAnglePitch) * sp1C; o->oVelY = -sins(o->oBowserHeldAnglePitch) * sp1C; cur_obj_become_intangible(); - o->prevObj->oAction = 1; // not sure what prevObj is - o->prevObj->oTimer = 0; - o->prevObj->oSubAction = 0; + if (o->prevObj) { + o->prevObj->oAction = 1; // not sure what prevObj is + o->prevObj->oTimer = 0; + o->prevObj->oSubAction = 0; + } o->oTimer = 0; o->oSubAction = 0; @@ -1549,7 +1557,9 @@ Gfx *geo_bits_bowser_coloring(s32 run, struct GraphNode *node, UNUSED s32 a2) { void falling_bowser_plat_act_0(void) { o->oPlatformUnkF8 = cur_obj_nearest_object_with_behavior(bhvBowser); - obj_set_collision_data(o, D_8032F698[o->oBehParams2ndByte].unk0); + if (BHV_ARR_CHECK(D_8032F698, o->oBehParams2ndByte, struct Struct8032F698)) { + obj_set_collision_data(o, D_8032F698[o->oBehParams2ndByte].unk0); + } if (o->oPlatformUnkF8 != 0) o->oAction = 1; } @@ -1558,13 +1568,13 @@ void falling_bowser_plat_act_1(void) { u8 doSend = FALSE; UNUSED s32 unused; struct Object *sp0 = o->oPlatformUnkF8; - if (sp0->platform == o) { + if (sp0 && sp0->platform == o) { if (sp0->oAction == 13 && sp0->oBowserUnkF4 & 0x10000) { o->oAction = 2; doSend = TRUE; } } - if (sp0->oHealth == 1 && (sp0->oAction == 3 || sp0->oHeldState != HELD_FREE)) + if (sp0 && sp0->oHealth == 1 && (sp0->oAction == 3 || sp0->oHeldState != HELD_FREE)) o->oSubAction = 1; if (o->oSubAction == 0) o->oPlatformUnkFC = 0; @@ -1594,7 +1604,7 @@ void falling_bowser_plat_act_2(void) { o->oGravity = 0.0f; } else o->oGravity = -4.0f; - if ((o->oTimer & 1) == 0 && o->oTimer < 14) { + if ((o->oTimer & 1) == 0 && o->oTimer < 14 && BHV_ARR_CHECK(D_8032F698, o->oBehParams2ndByte, struct Struct8032F698)) { sp22 = D_8032F698[o->oBehParams2ndByte].unk3 + (gDebugInfo[4][1] << 8); sp1C = -(o->oTimer / 2) * 290 + 1740; vec3f_copy_2(sp24, &o->oPosX); @@ -1779,10 +1789,16 @@ void bhv_flame_floating_landing_loop(void) { cur_obj_update_floor_and_walls(); cur_obj_move_standard(0x4e); bowser_flame_move(); - if (bowser_flame_should_despawn(900)) + if (bowser_flame_should_despawn(900)) { obj_mark_for_deletion(o); - if (o->oVelY < D_8032F748[o->oBehParams2ndByte]) - o->oVelY = D_8032F748[o->oBehParams2ndByte]; + } + + if (BHV_ARR_CHECK(D_8032F748, o->oBehParams2ndByte, f32)) { + if (o->oVelY < D_8032F748[o->oBehParams2ndByte]) { + o->oVelY = D_8032F748[o->oBehParams2ndByte]; + } + } + if (o->oMoveFlags & OBJ_MOVE_LANDED) { if (o->oBehParams2ndByte == 0) spawn_object(o, MODEL_RED_FLAME, bhvFlameLargeBurningOut); diff --git a/src/game/behaviors/bub.inc.c b/src/game/behaviors/bub.inc.c index 831b2916..5e165e53 100644 --- a/src/game/behaviors/bub.inc.c +++ b/src/game/behaviors/bub.inc.c @@ -8,6 +8,7 @@ void bub_spawner_act_0(void) { s32 i; s32 sp18 = o->oBirdChirpChirpUnkF4; + if (sp18 > 20) { sp18 = 20; } for (i = 0; i < sp18; i++) spawn_object(o, MODEL_BUB, bhvBub); o->oAction = 1; @@ -138,6 +139,6 @@ void bhv_bub_loop(void) { cur_obj_update_floor_and_walls(); CUR_OBJ_CALL_ACTION_FUNCTION(sCheepCheepActions); cur_obj_move_using_fvel_and_gravity(); - if (o->parentObj->oAction == 2) + if (!o->parentObj || o->parentObj->oAction == 2) obj_mark_for_deletion(o); } diff --git a/src/game/behaviors/cannon.inc.c b/src/game/behaviors/cannon.inc.c index c5d7bc6d..dae4bf1e 100644 --- a/src/game/behaviors/cannon.inc.c +++ b/src/game/behaviors/cannon.inc.c @@ -53,9 +53,9 @@ void opened_cannon_act_4(void) { o->oPosZ += (f32)((o->oTimer / 2 & 1) - 0.5) * 4; o->oAction = 6; } - if (o->oCannonPlayerIndex != 0) { + if (o->oCannonPlayerIndex != 0 && o->oCannonPlayerIndex < MAX_PLAYERS) { struct MarioState* controlledBy = &gMarioStates[o->oCannonPlayerIndex]; - if (controlledBy->marioObj != NULL) { + if (controlledBy && controlledBy->marioObj != NULL) { controlledBy->marioObj->oMarioCannonObjectYaw = o->oMoveAngleYaw; controlledBy->marioObj->oMarioCannonInputYaw = 0; } @@ -75,9 +75,9 @@ void opened_cannon_act_6(void) { o->oMoveAngleYaw = sins(o->oCannonUnkF4) * 0x4000 + ((s16)(o->oBehParams2ndByte << 8)); o->oCannonUnkF4 += 0x400; } else if (o->oTimer < 26) { - } else { + } else if (o->oCannonPlayerIndex < MAX_PLAYERS) { struct MarioState* controlledBy = &gMarioStates[o->oCannonPlayerIndex]; - if (controlledBy->marioObj != NULL) { + if (controlledBy && controlledBy->marioObj != NULL) { controlledBy->marioObj->oMarioCannonObjectYaw = o->oMoveAngleYaw; controlledBy->marioObj->oMarioCannonInputYaw = 0; } @@ -110,7 +110,7 @@ void opened_cannon_act_1(void) { if (o->oCannonPlayerIndex == 0) { cur_obj_become_intangible(); cur_obj_disable_rendering(); - } else { + } else if (o->oCannonPlayerIndex < MAX_PLAYERS) { struct MarioState* controlledBy = &gMarioStates[o->oCannonPlayerIndex]; o->oMoveAnglePitch = 14563 + controlledBy->faceAngle[0] * -0.5f; if (controlledBy->marioObj != NULL) { @@ -245,7 +245,7 @@ void bhv_cannon_base_loop(void) { void bhv_cannon_barrel_loop(void) { struct Object *parent = o->parentObj; - if (parent->header.gfx.node.flags & GRAPH_RENDER_ACTIVE) { + if (parent && parent->header.gfx.node.flags & GRAPH_RENDER_ACTIVE) { cur_obj_enable_rendering(); obj_copy_pos(o, o->parentObj); o->oMoveAngleYaw = o->parentObj->oMoveAngleYaw; diff --git a/src/game/behaviors/capswitch.inc.c b/src/game/behaviors/capswitch.inc.c index dab3e6ad..ead66868 100644 --- a/src/game/behaviors/capswitch.inc.c +++ b/src/game/behaviors/capswitch.inc.c @@ -8,7 +8,7 @@ void cap_switch_act_0(void) { o->oPosY += 71.0f; spawn_object_relative_with_scale(0, 0, -71, 0, 0.5f, o, MODEL_CAP_SWITCH_BASE, bhvCapSwitchBase); if (gCurrLevelNum != LEVEL_UNKNOWN_32) { - if (save_file_get_flags() & D_8032F0C0[o->oBehParams2ndByte]) { + if (save_file_get_flags() & BHV_ARR(D_8032F0C0, o->oBehParams2ndByte, s32)) { o->oAction = 3; o->header.gfx.scale[1] = 0.1f; } else @@ -19,7 +19,7 @@ void cap_switch_act_0(void) { void cap_switch_act_1(void) { if (capSwitchForcePress || cur_obj_is_mario_on_platform()) { - save_file_set_flags(D_8032F0C0[o->oBehParams2ndByte]); + save_file_set_flags(BHV_ARR(D_8032F0C0, o->oBehParams2ndByte, s32)); o->oAction = 2; cur_obj_play_sound_2(SOUND_GENERAL_ACTIVATE_CAP_SWITCH); if (!capSwitchForcePress) { diff --git a/src/game/behaviors/castle_floor_trap.inc.c b/src/game/behaviors/castle_floor_trap.inc.c index 19cec9c5..bda06b09 100644 --- a/src/game/behaviors/castle_floor_trap.inc.c +++ b/src/game/behaviors/castle_floor_trap.inc.c @@ -6,9 +6,12 @@ void bhv_floor_trap_in_castle_loop(void) { if (!is_player_active(&gMarioStates[i])) { continue; } onPlatform = onPlatform || (gMarioStates[i].marioObj->platform == o); } - if (onPlatform) - o->parentObj->oInteractStatus |= INT_STATUS_TRAP_TURN; - o->oFaceAngleRoll = o->parentObj->oFaceAngleRoll; + if (o->parentObj) { + if (onPlatform) { + o->parentObj->oInteractStatus |= INT_STATUS_TRAP_TURN; + } + o->oFaceAngleRoll = o->parentObj->oFaceAngleRoll; + } } void bhv_castle_floor_trap_init(void) { diff --git a/src/game/behaviors/celebration_star.inc.c b/src/game/behaviors/celebration_star.inc.c index 3e57aed6..3efd9824 100644 --- a/src/game/behaviors/celebration_star.inc.c +++ b/src/game/behaviors/celebration_star.inc.c @@ -1,10 +1,12 @@ // celebration_star.c.inc void bhv_celebration_star_init(void) { - o->oHomeX = o->parentObj->header.gfx.pos[0]; - o->oPosY = o->parentObj->header.gfx.pos[1] + 30.0f; - o->oHomeZ = o->parentObj->header.gfx.pos[2]; - o->oMoveAngleYaw = o->parentObj->header.gfx.angle[1] + 0x8000; + if (o->parentObj) { + o->oHomeX = o->parentObj->header.gfx.pos[0]; + o->oPosY = o->parentObj->header.gfx.pos[1] + 30.0f; + o->oHomeZ = o->parentObj->header.gfx.pos[2]; + o->oMoveAngleYaw = o->parentObj->header.gfx.angle[1] + 0x8000; + } o->oCelebStarDiameterOfRotation = 100; #if BUGFIX_STAR_BOWSER_KEY if (gCurrLevelNum == LEVEL_BOWSER_1 || gCurrLevelNum == LEVEL_BOWSER_2) { @@ -57,7 +59,7 @@ void celeb_star_act_face_camera(void) { cur_obj_scale((f32) o->oTimer / 10.0); #endif o->oFaceAngleYaw += 0x1000; - } else { + } else if (o->parentObj) { o->oFaceAngleYaw = o->parentObj->header.gfx.angle[1]; } diff --git a/src/game/behaviors/chain_chomp.inc.c b/src/game/behaviors/chain_chomp.inc.c index 9fb582b6..757745bf 100644 --- a/src/game/behaviors/chain_chomp.inc.c +++ b/src/game/behaviors/chain_chomp.inc.c @@ -38,13 +38,17 @@ void bhv_chain_chomp_chain_part_update(void) { obj_mark_for_deletion(o); network_send_object(o); } else if (o->oBehParams2ndByte != CHAIN_CHOMP_CHAIN_PART_BP_PIVOT) { - struct ChainSegment *segment = &o->parentObj->oChainChompSegments[o->oBehParams2ndByte]; + struct ChainSegment *segment = (o->oBehParams2ndByte <= 4 && o->parentObj) + ? &o->parentObj->oChainChompSegments[o->oBehParams2ndByte] + : NULL; // Set position relative to the pivot - if (segment) { - o->oPosX = o->parentObj->parentObj->oPosX + segment->posX; - o->oPosY = o->parentObj->parentObj->oPosY + segment->posY; - o->oPosZ = o->parentObj->parentObj->oPosZ + segment->posZ; + if (segment && o->parentObj && o->parentObj->parentObj) { + if (o->parentObj->oChainChompSegments) { + o->oPosX = o->parentObj->parentObj->oPosX + segment->posX; + o->oPosY = o->parentObj->parentObj->oPosY + segment->posY; + o->oPosZ = o->parentObj->parentObj->oPosZ + segment->posZ; + } } } else if (o->parentObj->oChainChompReleaseStatus != CHAIN_CHOMP_NOT_RELEASED) { cur_obj_update_floor_and_walls(); @@ -379,6 +383,10 @@ static void chain_chomp_act_move(void) { chain_chomp_act_uninitialized(); } + if (!o->parentObj) { + return; + } + // Segment 0 connects the pivot to the chain chomp itself o->oChainChompSegments[0].posX = o->oPosX - o->parentObj->oPosX; o->oChainChompSegments[0].posY = o->oPosY - o->parentObj->oPosY; @@ -447,8 +455,10 @@ static void chain_chomp_act_unload_chain(void) { o->oAction = CHAIN_CHOMP_ACT_UNINITIALIZED; if (o->oChainChompReleaseStatus != CHAIN_CHOMP_NOT_RELEASED) { - for (u8 i = 0; i < 5; i++) { - obj_mark_for_deletion((struct Object*)&o->oChainChompSegments[i]); + if (o->oChainChompSegments) { + for (u8 i = 0; i < 5; i++) { + obj_mark_for_deletion((struct Object*)&o->oChainChompSegments[i]); + } } obj_mark_for_deletion(o); obj_mark_for_deletion(o->parentObj); diff --git a/src/game/behaviors/checkerboard_platform.inc.c b/src/game/behaviors/checkerboard_platform.inc.c index 125213e7..ab0f6f11 100644 --- a/src/game/behaviors/checkerboard_platform.inc.c +++ b/src/game/behaviors/checkerboard_platform.inc.c @@ -57,7 +57,7 @@ static void bhv_checkerboard_platform_run_once(void) { } void bhv_checkerboard_platform_init(void) { - o->oCheckerBoardPlatformUnkFC = o->parentObj->oBehParams2ndByte; + o->oCheckerBoardPlatformUnkFC = o->parentObj ? o->parentObj->oBehParams2ndByte : 0; o->areaTimerType = AREA_TIMER_TYPE_LOOP; o->areaTimer = 0; o->areaTimerDuration = 132 + o->oCheckerBoardPlatformUnkFC * 2; diff --git a/src/game/behaviors/cloud.inc.c b/src/game/behaviors/cloud.inc.c index afbef216..fb31ca3e 100644 --- a/src/game/behaviors/cloud.inc.c +++ b/src/game/behaviors/cloud.inc.c @@ -115,7 +115,7 @@ static void cloud_act_main(void) { localOffsetPhase = 0x800 * gGlobalTimer; - if (o->parentObj != o) { + if (o->parentObj && o->parentObj != o) { // Despawn if the parent lakitu does if (o->parentObj->activeFlags == ACTIVE_FLAG_DEACTIVATED) { o->oAction = CLOUD_ACT_UNLOAD; @@ -180,7 +180,7 @@ void bhv_cloud_update(void) { * Update function for bhvCloudPart. Follow the parent cloud with some oscillation. */ void bhv_cloud_part_update(void) { - if (o->parentObj->oAction == CLOUD_ACT_UNLOAD) { + if (!o->parentObj || o->parentObj->oAction == CLOUD_ACT_UNLOAD) { obj_mark_for_deletion(o); } else { f32 size = 2.0f / 3.0f * o->parentObj->header.gfx.scale[0]; @@ -206,8 +206,7 @@ void bhv_cloud_part_update(void) { o->oPosX = o->parentObj->oCloudCenterX + cloudRadius * sins(angleFromCenter) + localOffset; - o->oPosY = - o->parentObj->oCloudCenterY + localOffset + size * sCloudPartHeights[o->oBehParams2ndByte]; + o->oPosY = o->parentObj->oCloudCenterY + localOffset + size * BHV_ARR(sCloudPartHeights, o->oBehParams2ndByte, s8); o->oPosZ = o->parentObj->oPosZ + cloudRadius * coss(angleFromCenter) + localOffset; diff --git a/src/game/behaviors/coffin.inc.c b/src/game/behaviors/coffin.inc.c index 02fda7c3..6691e1d0 100644 --- a/src/game/behaviors/coffin.inc.c +++ b/src/game/behaviors/coffin.inc.c @@ -156,7 +156,7 @@ void coffin_act_stand_up(void) { */ void bhv_coffin_loop(void) { // Gotta save those 6 object slots - if (o->parentObj->oAction == COFFIN_SPAWNER_ACT_COFFINS_UNLOADED) { + if (o->parentObj && o->parentObj->oAction == COFFIN_SPAWNER_ACT_COFFINS_UNLOADED) { obj_mark_for_deletion(o); } else { // Scale the coffin vertically? Must have thought it was too short? diff --git a/src/game/behaviors/coin.inc.c b/src/game/behaviors/coin.inc.c index b44835da..aa3f40ce 100644 --- a/src/game/behaviors/coin.inc.c +++ b/src/game/behaviors/coin.inc.c @@ -133,11 +133,12 @@ void bhv_coin_formation_spawn_loop(void) { cur_obj_set_model(smlua_model_util_load(E_MODEL_YELLOW_COIN_NO_SHADOW)); } } else { - if (bhv_coin_sparkles_init()) + if (o->parentObj && bhv_coin_sparkles_init()) { o->parentObj->oCoinUnkF4 |= bit_shift_left(o->oBehParams2ndByte); + } o->oAnimState++; } - if (o->parentObj->oAction == 2) + if (!o->parentObj || o->parentObj->oAction == 2) obj_mark_for_deletion(o); } diff --git a/src/game/behaviors/controllable_platform.inc.c b/src/game/behaviors/controllable_platform.inc.c index 891efa30..11fcc00a 100644 --- a/src/game/behaviors/controllable_platform.inc.c +++ b/src/game/behaviors/controllable_platform.inc.c @@ -31,11 +31,11 @@ void bhv_controllable_platform_sub_loop(void) { if (gMarioStates[0].marioObj->platform == o) { D_80331694 = o->oBehParams2ndByte; #ifdef VERSION_SH - o->parentObj->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; + if (o->parentObj) { o->parentObj->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; } #endif o->oAction = 1; cur_obj_play_sound_2(SOUND_GENERAL_MOVING_PLATFORM_SWITCH); - network_send_object(o->parentObj); + if (o->parentObj) { network_send_object(o->parentObj); } } break; @@ -48,11 +48,13 @@ void bhv_controllable_platform_sub_loop(void) { break; } - o->oVelX = o->parentObj->oVelX; - o->oVelZ = o->parentObj->oVelZ; + if (o->parentObj) { + o->oVelX = o->parentObj->oVelX; + o->oVelZ = o->parentObj->oVelZ; - if (o->parentObj->activeFlags == ACTIVE_FLAG_DEACTIVATED) - o->activeFlags = ACTIVE_FLAG_DEACTIVATED; + if (o->parentObj->activeFlags == ACTIVE_FLAG_DEACTIVATED) + o->activeFlags = ACTIVE_FLAG_DEACTIVATED; + } } static void bhv_controllable_platform_on_received_post(UNUSED u8 localIndex) { @@ -279,6 +281,7 @@ void bhv_controllable_platform_loop(void) { D_80331694 = 0; o->oTimer = 0; for (s32 i = 0; i < 4; i++) { + if (!controllablePlatformSubs[i]) { continue; } controllablePlatformSubs[i]->oParentRelativePosY = 51.0f; controllablePlatformSubs[i]->oAction = 0; controllablePlatformSubs[i]->oTimer = 0; diff --git a/src/game/behaviors/elevator.inc.c b/src/game/behaviors/elevator.inc.c index a0c02815..b0302e6b 100644 --- a/src/game/behaviors/elevator.inc.c +++ b/src/game/behaviors/elevator.inc.c @@ -122,15 +122,15 @@ void elevator_act_3(void) // nearly identical to action 2 } void bhv_elevator_init(void) { - s32 sp1C = D_8032F38C[o->oBehParams2ndByte * 3 + 2]; + s32 sp1C = BHV_ARR(D_8032F38C, o->oBehParams2ndByte * 3 + 2, s16); if (sp1C == 0) { - o->oElevatorUnkF4 = D_8032F38C[o->oBehParams2ndByte * 3]; + o->oElevatorUnkF4 = BHV_ARR(D_8032F38C, o->oBehParams2ndByte * 3, s16); o->oElevatorUnkF8 = o->oHomeY; o->oElevatorUnkFC = (o->oElevatorUnkF4 + o->oElevatorUnkF8) / 2; o->oElevatorUnk100 = cur_obj_has_behavior(bhvRrElevatorPlatform); } else { - o->oElevatorUnkF4 = D_8032F38C[o->oBehParams2ndByte * 3]; - o->oElevatorUnkF8 = D_8032F38C[o->oBehParams2ndByte * 3 + 1]; + o->oElevatorUnkF4 = BHV_ARR(D_8032F38C, o->oBehParams2ndByte * 3, s16); + o->oElevatorUnkF8 = BHV_ARR(D_8032F38C, o->oBehParams2ndByte * 3 + 1, s16); o->oElevatorUnkFC = (o->oElevatorUnkF4 + o->oElevatorUnkF8) / 2; o->oElevatorUnk100 = 2; } diff --git a/src/game/behaviors/exclamation_box.inc.c b/src/game/behaviors/exclamation_box.inc.c index 01a2e758..8a10a6af 100644 --- a/src/game/behaviors/exclamation_box.inc.c +++ b/src/game/behaviors/exclamation_box.inc.c @@ -31,7 +31,7 @@ struct Struct802C0DF0 sExclamationBoxContents[] = { { 0, 0, 0, MODEL_MARIOS_WING { 99, 0, 0, 0, NULL } }; void bhv_rotating_exclamation_box_loop(void) { - if (o->parentObj->oAction != 1) + if (!o->parentObj || o->parentObj->oAction != 1) obj_mark_for_deletion(o); } @@ -39,7 +39,7 @@ void exclamation_box_act_0(void) { o->oExclamationBoxForce = FALSE; if (o->oBehParams2ndByte < 3) { o->oAnimState = o->oBehParams2ndByte; - if ((save_file_get_flags() & D_8032F0C0[o->oBehParams2ndByte]) + if ((save_file_get_flags() & BHV_ARR(D_8032F0C0, o->oBehParams2ndByte, s32)) || ((o->oBehParams >> 24) & 0xFF) != 0) o->oAction = 2; else @@ -56,7 +56,7 @@ void exclamation_box_act_1(void) { spawn_object(o, smlua_model_util_load(E_MODEL_EXCLAMATION_POINT), bhvRotatingExclamationMark); cur_obj_set_model(smlua_model_util_load(E_MODEL_EXCLAMATION_BOX_OUTLINE)); } - if ((save_file_get_flags() & D_8032F0C0[o->oBehParams2ndByte]) + if ((save_file_get_flags() & BHV_ARR(D_8032F0C0, o->oBehParams2ndByte, s32)) || ((o->oBehParams >> 24) & 0xFF) != 0) { o->oAction = 2; cur_obj_set_model(smlua_model_util_load(E_MODEL_EXCLAMATION_BOX)); diff --git a/src/game/behaviors/eyerok.inc.c b/src/game/behaviors/eyerok.inc.c index ebb5709b..3fc52a5f 100644 --- a/src/game/behaviors/eyerok.inc.c +++ b/src/game/behaviors/eyerok.inc.c @@ -208,6 +208,7 @@ static void eyerok_boss_act_die(void) { } void bhv_eyerok_boss_loop(void) { + if (!o->parentObj) { return; } if (o->oAction == EYEROK_BOSS_ACT_DEAD) { return; } @@ -232,7 +233,7 @@ void bhv_eyerok_boss_loop(void) { } if (o->oAction != oldAction) { - if (sync_object_is_owned_locally(o->parentObj->oSyncID)) { + if (o->parentObj && sync_object_is_owned_locally(o->parentObj->oSyncID)) { eyerokBossImmediateUpdate = TRUE; } else { o->oAction = EYEROK_BOSS_ACT_PAUSE; @@ -246,6 +247,7 @@ void bhv_eyerok_boss_loop(void) { } static s32 eyerok_hand_check_attacked(void) { + if (!o->parentObj) { return FALSE; } struct Object* player = nearest_player_to_object(o); s32 angleToPlayer = player ? obj_angle_to_object(o, player) : 0; if (o->oEyerokReceivedAttack != 0 && abs_angle_diff(angleToPlayer, o->oFaceAngleYaw) < 0x3000) { @@ -279,7 +281,8 @@ static void eyerok_hand_pound_ground(void) { } static void eyerok_hand_act_sleep(void) { - if (o->parentObj->oAction != EYEROK_BOSS_ACT_SLEEP + if (!o->parentObj) { return; } + if (o->parentObj && o->parentObj->oAction != EYEROK_BOSS_ACT_SLEEP && ++o->oEyerokHandWakeUpTimer > -3 * o->oBehParams2ndByte) { if (cur_obj_check_if_near_animation_end()) { o->parentObj->oEyerokBossNumHands += 1; @@ -305,6 +308,7 @@ static void eyerok_hand_act_sleep(void) { } static void eyerok_hand_act_idle(void) { + if (!o->parentObj) { return; } struct Object* player = nearest_player_to_object(o); s32 angleToPlayer = player ? obj_angle_to_object(o, player) : 0; cur_obj_init_animation_with_sound(2); @@ -342,6 +346,7 @@ static void eyerok_hand_act_idle(void) { } static void eyerok_hand_act_open(void) { + if (!o->parentObj) { return; } struct Object* player = nearest_player_to_object(o); s32 angleToPlayer = player ? obj_angle_to_object(o, player) : 0; o->parentObj->oEyerokBossUnk1AC = o->oBehParams2ndByte; @@ -365,6 +370,7 @@ static void eyerok_hand_act_open(void) { } static void eyerok_hand_act_show_eye(void) { + if (!o->parentObj) { return; } struct Object* player = nearest_player_to_object(o); s32 angleToPlayer = player ? obj_angle_to_object(o, player) : 0; UNUSED s16 val06; @@ -373,7 +379,7 @@ static void eyerok_hand_act_show_eye(void) { cur_obj_play_sound_at_anim_range(0, 0, SOUND_OBJ_EYEROK_SHOW_EYE); if (!eyerok_hand_check_attacked()) { - if (o->parentObj->oEyerokBossActiveHand == 0) { + if (o->parentObj && o->parentObj->oEyerokBossActiveHand == 0) { if (o->oAnimState < 3) { o->oAnimState += 1; } else if (cur_obj_check_if_near_animation_end()) { @@ -385,13 +391,13 @@ static void eyerok_hand_act_show_eye(void) { if (o->oEyerokHandUnkFC != 0) { o->oEyerokHandUnkFC -= 1; } - o->oAnimState = D_80331BA4[o->oEyerokHandUnkFC]; + o->oAnimState = BHV_ARR(D_80331BA4, o->oEyerokHandUnkFC, s8); } else { o->oEyerokHandUnkFC = 5; o->oEyerokHandUnk100 = random_linear_offset(20, 50); } - if (o->parentObj->oEyerokBossNumHands != 2) { + if (o->parentObj && o->parentObj->oEyerokBossNumHands != 2) { obj_face_yaw_approach(o->oMoveAngleYaw, 0x800); if (o->oTimer > 10 && ((player && o->oPosZ - player->oPosZ > 0.0f) || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE))) { @@ -404,6 +410,7 @@ static void eyerok_hand_act_show_eye(void) { } static void eyerok_hand_act_close(void) { + if (!o->parentObj) { return; } if (cur_obj_init_anim_check_frame(7, 1)) { o->collisionData = segmented_to_virtual(ssl_seg7_collision_07028274); @@ -435,6 +442,7 @@ static void eyerok_hand_act_recover(void) { } static void eyerok_hand_act_become_active(void) { + if (!o->parentObj) { return; } if (o->parentObj->oEyerokBossActiveHand == 0 || o->parentObj->oEyerokBossNumHands != 2) { o->oAction = EYEROK_HAND_ACT_RETREAT; o->parentObj->oEyerokBossActiveHand = o->oBehParams2ndByte; @@ -454,6 +462,7 @@ static void eyerok_hand_act_die_event(void) { } static void eyerok_hand_act_die(void) { + if (!o->parentObj) { return; } if (cur_obj_init_anim_and_check_if_end(1)) { o->parentObj->oEyerokBossUnk1AC = 0; eyerok_hand_act_die_event(); @@ -490,6 +499,7 @@ static void eyerok_hand_act_retreat(void) { } static void eyerok_hand_act_target_mario(void) { + if (!o->parentObj) { return; } struct Object* player = nearest_player_to_object(o); s32 angleToPlayer = player ? obj_angle_to_object(o, player) : 0; if (eyerok_check_mario_relative_z(400) != 0 || (player && o->oPosZ - player->oPosZ > 0.0f) @@ -553,6 +563,7 @@ static void eyerok_hand_act_fist_push(void) { } static void eyerok_hand_act_fist_sweep(void) { + if (!o->parentObj) { return; } if (o->oPosZ - o->parentObj->oPosZ < 1000.0f || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE)) { o->oAction = EYEROK_HAND_ACT_RETREAT; o->oForwardVel = 0.0f; @@ -564,6 +575,7 @@ static void eyerok_hand_act_fist_sweep(void) { } static void eyerok_hand_act_begin_double_pound(void) { + if (!o->parentObj) { return; } f32 sp4; if (o->parentObj->oEyerokBossUnk104 < 0 @@ -582,6 +594,7 @@ static void eyerok_hand_act_begin_double_pound(void) { } static void eyerok_hand_act_double_pound(void) { + if (!o->parentObj) { return; } if (o->parentObj->oEyerokBossNumHands != 2) { o->parentObj->oEyerokBossActiveHand = o->oBehParams2ndByte; } @@ -608,6 +621,7 @@ static void eyerok_hand_act_double_pound(void) { } void bhv_eyerok_hand_loop(void) { + if (!o->parentObj) { return; } if (o->oAction == EYEROK_HAND_ACT_DEAD) { eyerok_hand_act_die_event(); return; @@ -679,7 +693,7 @@ void bhv_eyerok_hand_loop(void) { o->header.gfx.scale[0] = 1.5f * o->oBehParams2ndByte; if (o->oAction != oldAction) { - if (sync_object_is_owned_locally(o->parentObj->oSyncID)) { + if (o->parentObj && sync_object_is_owned_locally(o->parentObj->oSyncID)) { eyerokBossImmediateUpdate = TRUE; } else { o->oAction = EYEROK_HAND_ACT_PAUSE; diff --git a/src/game/behaviors/falling_pillar.inc.c b/src/game/behaviors/falling_pillar.inc.c index 2ca09df1..fb8f9eca 100644 --- a/src/game/behaviors/falling_pillar.inc.c +++ b/src/game/behaviors/falling_pillar.inc.c @@ -129,6 +129,7 @@ void bhv_falling_pillar_loop(void) { * Main loop for the invisible hitboxes. */ void bhv_falling_pillar_hitbox_loop(void) { + if (!o->parentObj) { return; } // Get the state of the pillar. s32 pitch = o->parentObj->oFaceAnglePitch; s32 yaw = o->parentObj->oFaceAngleYaw; diff --git a/src/game/behaviors/ferris_wheel.inc.c b/src/game/behaviors/ferris_wheel.inc.c index 7594eefb..375a9a73 100644 --- a/src/game/behaviors/ferris_wheel.inc.c +++ b/src/game/behaviors/ferris_wheel.inc.c @@ -31,6 +31,10 @@ void bhv_ferris_wheel_axle_init(void) { struct Object *platform; s32 i; + if (!BHV_ARR_CHECK(sFerrisWheelProperties, o->oBehParams2ndByte, struct FerrisWheelProperties)) { + return; + } + o->collisionData = segmented_to_virtual(sFerrisWheelProperties[o->oBehParams2ndByte].axleCollision); for (i = 0; i < 4; i++) { @@ -60,6 +64,8 @@ void bhv_ferris_wheel_platform_update(void) { f32 offsetXZ; s16 offsetAngle; + if (!o->parentObj) { return; } + obj_perform_position_op(POS_OP_SAVE_POSITION); offsetAngle = o->parentObj->oFaceAngleRoll + o->oBehParams2ndByte * 0x4000; diff --git a/src/game/behaviors/fish.inc.c b/src/game/behaviors/fish.inc.c index 330758f6..889f07a9 100644 --- a/src/game/behaviors/fish.inc.c +++ b/src/game/behaviors/fish.inc.c @@ -8,10 +8,10 @@ * These settings are animations, colour, and spawn quantity. */ static void fish_spawner_act_spawn(void) { - s32 i; - s32 schoolQuantity; - s16 model; - const struct Animation * const *fishAnimation; + s32 i = 0; + s32 schoolQuantity = 0; + s16 model = MODEL_ERROR_MODEL; + const struct Animation * const *fishAnimation = NULL; struct Object *fishObject; switch (o->oBehParams2ndByte) { @@ -280,7 +280,7 @@ void bhv_fish_loop(void) cur_obj_move_using_fvel_and_gravity(); // If the parent object has action set to two, then delete the fish object. - if (o->parentObj->oAction == FISH_SPAWNER_ACT_RESPAWN) { + if (!o->parentObj || o->parentObj->oAction == FISH_SPAWNER_ACT_RESPAWN) { obj_mark_for_deletion(o); } } diff --git a/src/game/behaviors/flamethrower.inc.c b/src/game/behaviors/flamethrower.inc.c index a01dc7f4..7dd48aa5 100644 --- a/src/game/behaviors/flamethrower.inc.c +++ b/src/game/behaviors/flamethrower.inc.c @@ -20,9 +20,9 @@ void bhv_flamethrower_flame_loop(void) { o->oVelY = 0; o->oPosY = o->oFloorHeight + 25.0f * size; } - sp18 = o->parentObj->oFlameThowerFlameUnk110 / 1.2; + sp18 = o->parentObj ? o->parentObj->oFlameThowerFlameUnk110 / 1.2 : 0; } else - sp18 = o->parentObj->oFlameThowerFlameUnk110; + sp18 = o->parentObj ? o->parentObj->oFlameThowerFlameUnk110 : 0; cur_obj_scale(size); if (o->oBehParams2ndByte == 4) o->oPosY += o->oForwardVel; // weird? diff --git a/src/game/behaviors/flying_bookend_switch.inc.c b/src/game/behaviors/flying_bookend_switch.inc.c index 9984ccad..8edf9552 100644 --- a/src/game/behaviors/flying_bookend_switch.inc.c +++ b/src/game/behaviors/flying_bookend_switch.inc.c @@ -336,6 +336,7 @@ void bhv_book_switch_loop(void) { o->header.gfx.scale[0] = 2.0f; o->header.gfx.scale[1] = 0.9f; + if (!o->parentObj) { return; } if (o->parentObj->oAction == 4) { obj_mark_for_deletion(o); diff --git a/src/game/behaviors/goomba.inc.c b/src/game/behaviors/goomba.inc.c index 4a717938..6711b008 100644 --- a/src/game/behaviors/goomba.inc.c +++ b/src/game/behaviors/goomba.inc.c @@ -138,12 +138,9 @@ static void goomba_begin_jump(void) { * comes back. */ void mark_goomba_as_dead(void) { - if (o->parentObj != o) { - set_object_respawn_info_bits(o->parentObj, - (o->oBehParams2ndByte & GOOMBA_BP_TRIPLET_FLAG_MASK) >> 2); - - o->parentObj->oBehParams = - o->parentObj->oBehParams | (o->oBehParams2ndByte & GOOMBA_BP_TRIPLET_FLAG_MASK) << 6; + if (o->parentObj && o->parentObj != o) { + set_object_respawn_info_bits(o->parentObj, (o->oBehParams2ndByte & GOOMBA_BP_TRIPLET_FLAG_MASK) >> 2); + o->parentObj->oBehParams = o->parentObj->oBehParams | (o->oBehParams2ndByte & GOOMBA_BP_TRIPLET_FLAG_MASK) << 6; } } @@ -282,7 +279,7 @@ void bhv_goomba_update(void) { if (obj_update_standard_actions(o->oGoombaScale)) { // If this goomba has a spawner and mario moved away from the spawner, // unload - if (o->parentObj != o) { + if (o->parentObj && o->parentObj != o) { if (o->parentObj->oAction == GOOMBA_TRIPLET_SPAWNER_ACT_UNLOADED) { obj_mark_for_deletion(o); } diff --git a/src/game/behaviors/grill_door.inc.c b/src/game/behaviors/grill_door.inc.c index b8f8e13e..76c1596e 100644 --- a/src/game/behaviors/grill_door.inc.c +++ b/src/game/behaviors/grill_door.inc.c @@ -5,7 +5,7 @@ struct OpenableGrill gOpenableGrills[] = { { 320, MODEL_BOB_BARS_GRILLS, bob_seg void bhv_openable_cage_door_loop(void) { if (gCurrentObject->oAction == 0) { - if (gCurrentObject->parentObj->oOpenableGrillUnk88 != 0) + if (gCurrentObject->parentObj && gCurrentObject->parentObj->oOpenableGrillUnk88 != 0) gCurrentObject->oAction++; } else if (gCurrentObject->oAction == 1) { if (gCurrentObject->oTimer < 64) @@ -21,18 +21,20 @@ void bhv_openable_grill_loop(void) { switch (o->oAction) { case 0: grillIdx = o->oBehParams2ndByte; - grillObj = spawn_object_relative(-1, gOpenableGrills[grillIdx].halfWidth, 0, 0, o, gOpenableGrills[grillIdx].modelID, - bhvOpenableCageDoor); - if (grillObj != NULL) { - grillObj->oMoveAngleYaw += 0x8000; - obj_set_collision_data(grillObj, gOpenableGrills[grillIdx].collision); + if (BHV_ARR_CHECK(gOpenableGrills, grillIdx, struct OpenableGrill)) { + grillObj = spawn_object_relative(-1, gOpenableGrills[grillIdx].halfWidth, 0, 0, o, gOpenableGrills[grillIdx].modelID, + bhvOpenableCageDoor); + if (grillObj != NULL) { + grillObj->oMoveAngleYaw += 0x8000; + obj_set_collision_data(grillObj, gOpenableGrills[grillIdx].collision); + } + grillObj = spawn_object_relative(1, -gOpenableGrills[grillIdx].halfWidth, 0, 0, o, gOpenableGrills[grillIdx].modelID, + bhvOpenableCageDoor); + if (grillObj != NULL) { + obj_set_collision_data(grillObj, gOpenableGrills[grillIdx].collision); + } + o->oAction++; } - grillObj = spawn_object_relative(1, -gOpenableGrills[grillIdx].halfWidth, 0, 0, o, gOpenableGrills[grillIdx].modelID, - bhvOpenableCageDoor); - if (grillObj != NULL) { - obj_set_collision_data(grillObj, gOpenableGrills[grillIdx].collision); - } - o->oAction++; break; case 1: if ((o->oOpenableGrillUnkF4 = cur_obj_nearest_object_with_behavior(bhvFloorSwitchGrills)) @@ -41,7 +43,7 @@ void bhv_openable_grill_loop(void) { break; case 2: grillObj = o->oOpenableGrillUnkF4; - if (grillObj->oAction == 2) { + if (grillObj && grillObj->oAction == 2) { o->oOpenableGrillUnk88 = 2; cur_obj_play_sound_2(SOUND_GENERAL_CAGE_OPEN); o->oAction++; diff --git a/src/game/behaviors/ground_particles.inc.c b/src/game/behaviors/ground_particles.inc.c index d673ff66..76c517fb 100644 --- a/src/game/behaviors/ground_particles.inc.c +++ b/src/game/behaviors/ground_particles.inc.c @@ -25,7 +25,9 @@ void spawn_smoke_with_velocity(void) { // TODO Fix name void clear_particle_flags(u32 flags) { - o->parentObj->oActiveParticleFlags &= flags ^ -1; // Clear the flags given (could just be ~flags) + if (o->parentObj) { + o->parentObj->oActiveParticleFlags &= flags ^ -1; // Clear the flags given (could just be ~flags) + } } void bhv_ground_snow_init(void) { diff --git a/src/game/behaviors/heave_ho.inc.c b/src/game/behaviors/heave_ho.inc.c index 8e86f057..94f8be6a 100644 --- a/src/game/behaviors/heave_ho.inc.c +++ b/src/game/behaviors/heave_ho.inc.c @@ -11,24 +11,26 @@ void bhv_heave_ho_throw_mario_loop(void) { o->oParentRelativePosX = 200.0f; o->oParentRelativePosY = -50.0f; o->oParentRelativePosZ = 0.0f; - o->oMoveAngleYaw = o->parentObj->oMoveAngleYaw; - switch (o->parentObj->oHeaveHoUnk88) { - case 0: - break; - case 1: - break; - case 2: - cur_obj_play_sound_2(SOUND_OBJ_HEAVEHO_TOSSED); - if (player) { - player->oInteractStatus |= INT_STATUS_MARIO_UNK2; - } - if (marioState) { - marioState->forwardVel = -45.0f; - marioState->vel[1] = 95.0f; - } - o->parentObj->oHeaveHoUnk88 = 0; - o->parentObj->usingObj = NULL; - break; + if (o->parentObj) { + o->oMoveAngleYaw = o->parentObj->oMoveAngleYaw; + switch (o->parentObj->oHeaveHoUnk88) { + case 0: + break; + case 1: + break; + case 2: + cur_obj_play_sound_2(SOUND_OBJ_HEAVEHO_TOSSED); + if (player) { + player->oInteractStatus |= INT_STATUS_MARIO_UNK2; + } + if (marioState) { + marioState->forwardVel = -45.0f; + marioState->vel[1] = 95.0f; + } + o->parentObj->oHeaveHoUnk88 = 0; + o->parentObj->usingObj = NULL; + break; + } } } diff --git a/src/game/behaviors/king_bobomb.inc.c b/src/game/behaviors/king_bobomb.inc.c index ffc786e1..b187567f 100644 --- a/src/game/behaviors/king_bobomb.inc.c +++ b/src/game/behaviors/king_bobomb.inc.c @@ -366,7 +366,7 @@ void king_bobomb_move(void) { else cur_obj_move_using_fvel_and_gravity(); CUR_OBJ_CALL_ACTION_FUNCTION(sKingBobombActions); - exec_anim_sound_state(sKingBobombSoundStates); + exec_anim_sound_state(sKingBobombSoundStates, sizeof(sKingBobombSoundStates) / sizeof(struct SoundState)); s32 distanceToPlayer = dist_between_objects(o, gMarioStates[0].marioObj); if (distanceToPlayer < 5000.0f * draw_distance_scalar()) cur_obj_enable_rendering(); diff --git a/src/game/behaviors/koopa.inc.c b/src/game/behaviors/koopa.inc.c index 208f8127..c0590db8 100644 --- a/src/game/behaviors/koopa.inc.c +++ b/src/game/behaviors/koopa.inc.c @@ -587,7 +587,7 @@ s32 obj_begin_race(s32 noTimer) { level_control_timer(TIMER_CONTROL_SHOW); level_control_timer(TIMER_CONTROL_START); - o->parentObj->oKoopaRaceEndpointRaceBegun = TRUE; + if (o->parentObj) { o->parentObj->oKoopaRaceEndpointRaceBegun = TRUE; } } // Unfreeze mario and disable time stop to begin the race @@ -630,7 +630,7 @@ u8 koopa_the_quick_act_show_init_text_continue_dialog(void) { return o->oAction static void koopa_the_quick_act_show_init_text(void) { struct MarioState* marioState = nearest_mario_state_to_object(o); s32 response = 0; - if (marioState && should_start_or_continue_dialog(marioState, o)) { + if (marioState && should_start_or_continue_dialog(marioState, o) && BHV_ARR_CHECK(sKoopaTheQuickProperties, o->oKoopaTheQuickRaceIndex, struct KoopaTheQuickProperties)) { response = obj_update_race_proposition_dialog(&gMarioStates[0], *sKoopaTheQuickProperties[o->oKoopaTheQuickRaceIndex].initText, koopa_the_quick_act_show_init_text_continue_dialog); } @@ -738,7 +738,7 @@ static void koopa_the_quick_act_race(void) { struct Object* player = nearest_player_to_object(o); s32 distanceToPlayer = player ? dist_between_objects(o, player) : 10000; - if (o->parentObj->oKoopaRaceEndpointRaceStatus != 0 && distanceToPlayer > 1500.0f + if (o->parentObj && o->parentObj->oKoopaRaceEndpointRaceStatus != 0 && distanceToPlayer > 1500.0f && (o->oPathedPrevWaypointFlags & WAYPOINT_MASK_00FF) < 28) { // Move faster if mario has already finished the race or // cheated by shooting from cannon @@ -840,6 +840,7 @@ static void koopa_the_quick_act_after_race(void) { cur_obj_init_animation_with_sound(7); struct MarioState* marioState = nearest_mario_state_to_object(o); + if (!o->parentObj) { return; } if (o->parentObj->oKoopaRaceEndpointUnk100 == 0) { if (marioState == &gMarioStates[0] && cur_obj_can_mario_activate_textbox_2(&gMarioStates[0], 400.0f, 400.0f)) { @@ -913,7 +914,7 @@ static void koopa_the_quick_update(void) { break; } - if (o->parentObj != o) { + if (o->parentObj != o && o->parentObj) { if (dist_between_objects(o, o->parentObj) < 400.0f) { o->parentObj->oKoopaRaceEndpointKoopaFinished = TRUE; } diff --git a/src/game/behaviors/lll_floating_wood_piece.inc.c b/src/game/behaviors/lll_floating_wood_piece.inc.c index 710b251a..95aa742e 100644 --- a/src/game/behaviors/lll_floating_wood_piece.inc.c +++ b/src/game/behaviors/lll_floating_wood_piece.inc.c @@ -10,7 +10,7 @@ void bhv_lll_wood_piece_loop(void) { o->oPosY -= 100.0f; o->oPosY += sins(o->oLllWoodPieceOscillationTimer) * 3.0f; o->oLllWoodPieceOscillationTimer += 0x400; - if (o->parentObj->oAction == 2) + if (o->parentObj && o->parentObj->oAction == 2) obj_mark_for_deletion(o); } diff --git a/src/game/behaviors/lll_octagonal_rotating_mesh.inc.c b/src/game/behaviors/lll_octagonal_rotating_mesh.inc.c index 87f995ec..58afca1d 100644 --- a/src/game/behaviors/lll_octagonal_rotating_mesh.inc.c +++ b/src/game/behaviors/lll_octagonal_rotating_mesh.inc.c @@ -8,6 +8,7 @@ s16 *D_8032F8C8[] = { D_8032F860, D_8032F894 }; s32 lll_octagonal_mesh_move(s16 *a0, s32 a1) { + if (!BHV_ARR_CHECK(D_8032F860, a1, s16)) { return 0; } switch (a0[a1]) { case 4: o->oMoveAngleYaw = a0[a1 + 2]; @@ -70,9 +71,9 @@ void bhv_lll_moving_octagonal_mesh_platform_loop(void) { if (o->oAction == 0) { o->oHorizontalMovementUnkF8 = 0; o->oAction++; - } else - o->oHorizontalMovementUnkF8 = - lll_octagonal_mesh_move(D_8032F8C8[o->oBehParams2ndByte], o->oHorizontalMovementUnkF8); + } else if (BHV_ARR_CHECK(D_8032F8C8, o->oBehParams2ndByte, s16*)) { + o->oHorizontalMovementUnkF8 = lll_octagonal_mesh_move(D_8032F8C8[o->oBehParams2ndByte], o->oHorizontalMovementUnkF8); + } print_debug_top_down_objectinfo("number %d\n", o->oHorizontalMovementUnkF8); cur_obj_move_using_fvel_and_gravity(); if (lll_octagonal_mesh_find_y_offset(&o->oHorizontalMovementUnk104, &o->oHorizontalMovementUnk108, 0x400, -80)) { diff --git a/src/game/behaviors/lll_rotating_hex_flame.inc.c b/src/game/behaviors/lll_rotating_hex_flame.inc.c index 02c55cd2..41c103a8 100644 --- a/src/game/behaviors/lll_rotating_hex_flame.inc.c +++ b/src/game/behaviors/lll_rotating_hex_flame.inc.c @@ -4,10 +4,15 @@ void bhv_lll_rotating_hex_flame_loop(void) { f32 sp24 = o->oLllRotatingHexFlameUnkF4; f32 sp20 = o->oLllRotatingHexFlameUnkF8; f32 sp1C = o->oLllRotatingHexFlameUnkFC; - cur_obj_set_pos_relative(o->parentObj, sp24, sp20, sp1C); - o->oPosY = o->parentObj->oPosY + 100.0f; - if (o->parentObj->oAction == 3) + + if (o->parentObj) { + cur_obj_set_pos_relative(o->parentObj, sp24, sp20, sp1C); + o->oPosY = o->parentObj->oPosY + 100.0f; + if (o->parentObj->oAction == 3) + obj_mark_for_deletion(o); + } else { obj_mark_for_deletion(o); + } } void fire_bar_spawn_flames(s16 a0) { diff --git a/src/game/behaviors/mips.inc.c b/src/game/behaviors/mips.inc.c index b8f704fc..54f0aa28 100644 --- a/src/game/behaviors/mips.inc.c +++ b/src/game/behaviors/mips.inc.c @@ -146,12 +146,14 @@ void bhv_mips_act_wait_for_nearby_mario(void) { void bhv_mips_act_follow_path(void) { s16 collisionFlags = 0; s32 followStatus = 0; - struct Waypoint ***pathBase; + struct Waypoint **pathBase; struct Waypoint *waypoint; // Retrieve current waypoint. - pathBase = segmented_to_virtual(sMipsPaths); - waypoint = segmented_to_virtual(*(*pathBase + o->oMipsStartWaypointIndex)); + pathBase = segmented_to_virtual(sMipsPaths[0]); + s32 length = get_trajectory_length((Trajectory*)pathBase); + if (o->oMipsStartWaypointIndex >= length) { return; } + waypoint = segmented_to_virtual(pathBase[o->oMipsStartWaypointIndex]); // Set start waypoint and follow the path from there. o->oPathedStartWaypoint = waypoint; diff --git a/src/game/behaviors/moat_drainer.inc.c b/src/game/behaviors/moat_drainer.inc.c index bc774f34..8b2353df 100644 --- a/src/game/behaviors/moat_drainer.inc.c +++ b/src/game/behaviors/moat_drainer.inc.c @@ -2,8 +2,10 @@ void bhv_invisible_objects_under_bridge_init(void) { if (save_file_get_flags() & SAVE_FLAG_MOAT_DRAINED) { - gEnvironmentRegions[6] = -800; - gEnvironmentRegions[12] = -800; + if (gEnvironmentRegions) { + gEnvironmentRegions[6] = -800; + gEnvironmentRegions[12] = -800; + } o->oAction = 2; } else { o->oAction = 0; @@ -18,12 +20,14 @@ void bhv_invisible_objects_under_bridge_loop(void) { break; case 1: // approach -800 - gEnvironmentRegions[6] = (s16)approach_f32_symmetric(gEnvironmentRegions[6], -800, 5.0f); - gEnvironmentRegions[12] = (s16)approach_f32_symmetric(gEnvironmentRegions[12], -800, 5.0f); - if (gEnvironmentRegions[6] <= -795 && gEnvironmentRegions[12] <= -795) { - gEnvironmentRegions[6] = -800; - gEnvironmentRegions[12] = -800; - o->oAction = 2; + if (gEnvironmentRegions) { + gEnvironmentRegions[6] = (s16)approach_f32_symmetric(gEnvironmentRegions[6], -800, 5.0f); + gEnvironmentRegions[12] = (s16)approach_f32_symmetric(gEnvironmentRegions[12], -800, 5.0f); + if (gEnvironmentRegions[6] <= -795 && gEnvironmentRegions[12] <= -795) { + gEnvironmentRegions[6] = -800; + gEnvironmentRegions[12] = -800; + o->oAction = 2; + } } break; case 2: diff --git a/src/game/behaviors/moneybag.inc.c b/src/game/behaviors/moneybag.inc.c index e1afa68e..98aeb97f 100644 --- a/src/game/behaviors/moneybag.inc.c +++ b/src/game/behaviors/moneybag.inc.c @@ -196,7 +196,9 @@ void bhv_moneybag_loop(void) { o->oOpacity += 12; if (o->oOpacity >= 256) { o->oOpacity = 255; - o->parentObj->activeFlags = ACTIVE_FLAG_DEACTIVATED; + if (o->parentObj) { + o->parentObj->activeFlags = ACTIVE_FLAG_DEACTIVATED; + } o->oAction = MONEYBAG_ACT_MOVE_AROUND; } break; diff --git a/src/game/behaviors/monty_mole.inc.c b/src/game/behaviors/monty_mole.inc.c index 399b4f51..c1ee19ce 100644 --- a/src/game/behaviors/monty_mole.inc.c +++ b/src/game/behaviors/monty_mole.inc.c @@ -64,6 +64,7 @@ static struct Object *monty_mole_select_available_hole(f32 minDistToMario) { struct Object *hole = sMontyMoleHoleList; s32 numAvailableHoles = 0; + s32 sanity = 0; while (hole != NULL) { player = nearest_player_to_object(hole); @@ -74,6 +75,8 @@ static struct Object *monty_mole_select_available_hole(f32 minDistToMario) { } } + if (sanity++ > 100) { break; } + if (hole == hole->parentObj) { break; } hole = hole->parentObj; } diff --git a/src/game/behaviors/mr_blizzard.inc.c b/src/game/behaviors/mr_blizzard.inc.c index e5b8c210..1d0e0343 100644 --- a/src/game/behaviors/mr_blizzard.inc.c +++ b/src/game/behaviors/mr_blizzard.inc.c @@ -436,7 +436,7 @@ void bhv_mr_blizzard_update(void) { static void mr_blizzard_snowball_act_0(void) { cur_obj_move_using_fvel_and_gravity(); - if (o->parentObj->prevObj == o) { + if (o->parentObj && o->parentObj->prevObj == o) { o->oAction = 1; o->oParentRelativePosX = 190.0f; o->oParentRelativePosY = o->oParentRelativePosZ = -38.0f; @@ -453,7 +453,7 @@ static void mr_blizzard_snowball_act_1(void) { f32 marioDist; - if (o->parentObj->prevObj == NULL) { + if (o->parentObj && o->parentObj->prevObj == NULL) { if (o->parentObj->oAction == MR_BLIZZARD_ACT_THROW_SNOWBALL) { marioDist = distanceToPlayer; if (marioDist > 800.0f) { diff --git a/src/game/behaviors/mr_i.inc.c b/src/game/behaviors/mr_i.inc.c index 3033d717..cf507303 100644 --- a/src/game/behaviors/mr_i.inc.c +++ b/src/game/behaviors/mr_i.inc.c @@ -54,6 +54,10 @@ void spawn_mr_i_particle(void) { } void bhv_mr_i_body_loop(void) { + if (!o->parentObj) { + obj_mark_for_deletion(o); + return; + } obj_copy_pos_and_angle(o, o->parentObj); if (!(o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM)) { obj_copy_scale(o, o->parentObj); diff --git a/src/game/behaviors/platform_on_track.inc.c b/src/game/behaviors/platform_on_track.inc.c index 7413c102..3816cf2e 100644 --- a/src/game/behaviors/platform_on_track.inc.c +++ b/src/game/behaviors/platform_on_track.inc.c @@ -93,10 +93,13 @@ void bhv_platform_on_track_init(void) { o->oPlatformOnTrackIsNotSkiLift = o->oPlatformOnTrackType - PLATFORM_ON_TRACK_TYPE_SKI_LIFT; - o->collisionData = - segmented_to_virtual(sPlatformOnTrackCollisionModels[o->oPlatformOnTrackType]); + if (BHV_ARR_CHECK(sPlatformOnTrackCollisionModels, o->oPlatformOnTrackType, void const *)) { + o->collisionData = segmented_to_virtual(sPlatformOnTrackCollisionModels[o->oPlatformOnTrackType]); + } - o->oPlatformOnTrackStartWaypoint = segmented_to_virtual(*sPlatformOnTrackPaths[pathIndex]); + if (BHV_ARR_CHECK(sPlatformOnTrackPaths, pathIndex, Trajectory**)) { + o->oPlatformOnTrackStartWaypoint = segmented_to_virtual(*sPlatformOnTrackPaths[pathIndex]); + } o->oPlatformOnTrackIsNotHMC = pathIndex - 4; @@ -353,8 +356,9 @@ void bhv_platform_on_track_update(void) { */ void bhv_track_ball_update(void) { // Despawn after the elevator passes this ball - s16 relativeIndex = - (s16) o->oBehParams2ndByte - (s16) o->parentObj->oPlatformOnTrackBaseBallIndex - 1; + s16 relativeIndex = o->parentObj ? + ((s16) o->oBehParams2ndByte - (s16) o->parentObj->oPlatformOnTrackBaseBallIndex - 1) + : 0; if (relativeIndex < 1 || relativeIndex > 5) { obj_mark_for_deletion(o); } diff --git a/src/game/behaviors/pyramid_top.inc.c b/src/game/behaviors/pyramid_top.inc.c index 99313fef..2a464447 100644 --- a/src/game/behaviors/pyramid_top.inc.c +++ b/src/game/behaviors/pyramid_top.inc.c @@ -157,7 +157,9 @@ void bhv_pyramid_pillar_touch_detector_loop(void) { cur_obj_become_tangible(); if ((o->oInteractStatus & INT_STATUS_INTERACTED) || obj_check_if_collided_with_object(o, gMarioStates[0].marioObj) == 1) { // Increase the pyramid top's count of pillars touched. - o->parentObj->oPyramidTopPillarsTouched++; + if (o->parentObj) { + o->parentObj->oPyramidTopPillarsTouched++; + } o->activeFlags = ACTIVE_FLAG_DEACTIVATED; if (!(o->oInteractStatus & INT_STATUS_INTERACTED)) { network_send_collect_item(o); diff --git a/src/game/behaviors/racing_penguin.inc.c b/src/game/behaviors/racing_penguin.inc.c index 8052016f..fd8d9cfa 100644 --- a/src/game/behaviors/racing_penguin.inc.c +++ b/src/game/behaviors/racing_penguin.inc.c @@ -31,9 +31,11 @@ void bhv_racing_penguin_the_quick_override_ownership(u8* shouldOverride, u8* sho void bhv_racing_penguin_run_once(void) { cur_obj_align_gfx_with_floor(); - cur_obj_push_mario_away_from_cylinder( - *sRacingPenguinData[o->oBehParams2ndByte].radius, - *sRacingPenguinData[o->oBehParams2ndByte].height); + if (BHV_ARR_CHECK(sRacingPenguinData, o->oBehParams2ndByte, struct RacingPenguinData)) { + cur_obj_push_mario_away_from_cylinder( + *sRacingPenguinData[o->oBehParams2ndByte].radius, + *sRacingPenguinData[o->oBehParams2ndByte].height); + } } void bhv_racing_penguin_init(void) { @@ -44,10 +46,10 @@ void bhv_racing_penguin_init(void) { } struct Object* objFinishLine = cur_obj_nearest_object_with_behavior(bhvPenguinRaceFinishLine); - objFinishLine->parentObj = o; + if (objFinishLine) { objFinishLine->parentObj = o; } struct Object* objShortcutCheck = cur_obj_nearest_object_with_behavior(bhvPenguinRaceShortcutCheck); - objShortcutCheck->parentObj = o; + if (objShortcutCheck) { objShortcutCheck->parentObj = o; } struct SyncObject* so = sync_object_init(o, SYNC_DISTANCE_ONLY_EVENTS); if (so) { @@ -95,6 +97,7 @@ u8 racing_penguin_act_show_init_text_continue_dialog(void) { return o->oAction = static void racing_penguin_act_show_init_text(void) { if (!gMarioStates[0].visibleToEnemies) { return; } + if (!BHV_ARR_CHECK(sRacingPenguinData, o->oBehParams2ndByte, struct RacingPenguinData)) { return; } s32 response = obj_update_race_proposition_dialog(&gMarioStates[0], *sRacingPenguinData[o->oBehParams2ndByte].text, racing_penguin_act_show_init_text_continue_dialog); if (response == 1) { @@ -136,12 +139,12 @@ static void racing_penguin_act_race(void) { // prevent segfault / error state if (o->oPathedStartWaypoint == NULL) { - struct Object* child; + struct Object* child = NULL; child = cur_obj_nearest_object_with_behavior(bhvPenguinRaceFinishLine); - child->parentObj = o; + if (child) { child->parentObj = o; } child = cur_obj_nearest_object_with_behavior(bhvPenguinRaceShortcutCheck); - child->parentObj = o; + if (child) { child->parentObj = o; } o->oPathedStartWaypoint = o->oPathedPrevWaypoint = segmented_to_virtual(gBehaviorValues.trajectories.RacingPenguinTrajectory); o->oPathedPrevWaypointFlags = 0; @@ -295,6 +298,9 @@ void bhv_racing_penguin_update(void) { void bhv_penguin_race_finish_line_update(void) { struct Object* player = nearest_player_to_object(o); s32 distanceToPlayer = player ? dist_between_objects(o, player) : 10000; + if (!o->parentObj) { + return; + } if (o->parentObj->oRacingPenguinReachedBottom || (player && distanceToPlayer < 1000.0f && player->oPosZ - o->oPosZ < 0.0f)) { @@ -308,7 +314,7 @@ void bhv_penguin_race_finish_line_update(void) { void bhv_penguin_race_shortcut_check_update(void) { struct Object* player = nearest_player_to_object(o); s32 distanceToPlayer = player ? dist_between_objects(o, player) : 10000; - if (distanceToPlayer < 500.0f && !o->parentObj->oRacingPenguinMarioCheated) { + if (distanceToPlayer < 500.0f && o->parentObj && !o->parentObj->oRacingPenguinMarioCheated) { o->parentObj->oRacingPenguinMarioCheated = TRUE; network_send_object(o->parentObj); } diff --git a/src/game/behaviors/rotating_octagonal_plat.inc.c b/src/game/behaviors/rotating_octagonal_plat.inc.c index 86d758c8..98fcc974 100644 --- a/src/game/behaviors/rotating_octagonal_plat.inc.c +++ b/src/game/behaviors/rotating_octagonal_plat.inc.c @@ -8,8 +8,10 @@ void const *D_80331A44[] = { s16 D_80331A4C[] = { 300, -300, 600, -600 }; void bhv_rotating_octagonal_plat_init(void) { - o->collisionData = segmented_to_virtual(D_80331A44[(u8)(o->oBehParams >> 16)]); - o->oAngleVelYaw = D_80331A4C[(u8)(o->oBehParams >> 24)]; + if (BHV_ARR_CHECK(D_80331A44, (u8)(o->oBehParams >> 16), void const*)) { + o->collisionData = segmented_to_virtual(D_80331A44[(u8)(o->oBehParams >> 16)]); + } + o->oAngleVelYaw = BHV_ARR(D_80331A4C, (u8)(o->oBehParams >> 24), s16); } void bhv_rotating_octagonal_plat_loop(void) { diff --git a/src/game/behaviors/rotating_platform.inc.c b/src/game/behaviors/rotating_platform.inc.c index 921e55ad..9fe04591 100644 --- a/src/game/behaviors/rotating_platform.inc.c +++ b/src/game/behaviors/rotating_platform.inc.c @@ -39,7 +39,7 @@ void bhv_wf_rotating_wooden_platform_loop(void) { void bhv_rotating_platform_loop(void) { s8 sp1F = o->oBehParams >> 24; - if (o->oTimer == 0) { + if (o->oTimer == 0 && BHV_ARR_CHECK(sWFRotatingPlatformData, o->oBehParams2ndByte, struct WFRotatingPlatformData)) { obj_set_collision_data(o, sWFRotatingPlatformData[o->oBehParams2ndByte].collisionData); o->oCollisionDistance = sWFRotatingPlatformData[o->oBehParams2ndByte].collisionDistance; cur_obj_scale(sWFRotatingPlatformData[o->oBehParams2ndByte].scale * 0.01f); diff --git a/src/game/behaviors/scuttlebug.inc.c b/src/game/behaviors/scuttlebug.inc.c index ddaa69cc..85f615b1 100644 --- a/src/game/behaviors/scuttlebug.inc.c +++ b/src/game/behaviors/scuttlebug.inc.c @@ -129,7 +129,7 @@ void bhv_scuttlebug_loop(void) { if (o->parentObj != o) { if (obj_is_hidden(o)) obj_mark_for_deletion(o); - if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) { + if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED && o->parentObj) { o->parentObj->oScuttlebugSpawnerUnk88 = 1; network_send_object(o->parentObj); } diff --git a/src/game/behaviors/seesaw_platform.inc.c b/src/game/behaviors/seesaw_platform.inc.c index 5387ec57..85c807b5 100644 --- a/src/game/behaviors/seesaw_platform.inc.c +++ b/src/game/behaviors/seesaw_platform.inc.c @@ -16,7 +16,9 @@ static void const *sSeesawPlatformCollisionModels[] = { * Init function for bhvSeesawPlatform. */ void bhv_seesaw_platform_init(void) { - o->collisionData = segmented_to_virtual(sSeesawPlatformCollisionModels[o->oBehParams2ndByte]); + if (BHV_ARR_CHECK(sSeesawPlatformCollisionModels, o->oBehParams2ndByte, void const*)) { + o->collisionData = segmented_to_virtual(sSeesawPlatformCollisionModels[o->oBehParams2ndByte]); + } // The S-shaped seesaw platform in BitS is large, so increase its collision // distance diff --git a/src/game/behaviors/sl_walking_penguin.inc.c b/src/game/behaviors/sl_walking_penguin.inc.c index b7c485d4..d23a030c 100644 --- a/src/game/behaviors/sl_walking_penguin.inc.c +++ b/src/game/behaviors/sl_walking_penguin.inc.c @@ -22,11 +22,11 @@ static s32 sl_walking_penguin_turn(void) { // Stay still and use walking animation for the turn. o->oForwardVel = 0.0f; cur_obj_init_animation_with_accel_and_sound(PENGUIN_ANIM_WALK, 1.0f); - + // Turn around. o->oAngleVelYaw = 0x400; o->oMoveAngleYaw += o->oAngleVelYaw; - + if (o->oTimer == 31) return TRUE; // Finished turning else @@ -52,7 +52,7 @@ void bhv_sl_walking_penguin_loop(void) { o->oAngleVelYaw = 0; cur_obj_update_floor_and_walls(); - + switch (o->oAction) { // Walk erratically across the ice bridge using preset steps. case SL_WALKING_PENGUIN_ACT_MOVING_FORWARDS: @@ -61,68 +61,69 @@ void bhv_sl_walking_penguin_loop(void) { o->oSLWalkingPenguinCurStep = 0; o->oSLWalkingPenguinCurStepTimer = 0; } - - if (o->oSLWalkingPenguinCurStepTimer < sSLWalkingPenguinErraticSteps[o->oSLWalkingPenguinCurStep].stepLength) - o->oSLWalkingPenguinCurStepTimer++; - else { - // Move to next step - o->oSLWalkingPenguinCurStepTimer = 0; - o->oSLWalkingPenguinCurStep++; - if (sSLWalkingPenguinErraticSteps[o->oSLWalkingPenguinCurStep].stepLength < 0) - // Reached the end of the list, go back to the start - o->oSLWalkingPenguinCurStep = 0; - } - - if (o->oPosX < 300.0f) - o->oAction++; // If reached the end of the bridge, turn around and head back. - else { - // Move and animate the penguin - o->oForwardVel = sSLWalkingPenguinErraticSteps[o->oSLWalkingPenguinCurStep].speed; - - cur_obj_init_animation_with_accel_and_sound( - sSLWalkingPenguinErraticSteps[o->oSLWalkingPenguinCurStep].anim, - sSLWalkingPenguinErraticSteps[o->oSLWalkingPenguinCurStep].animSpeed - ); + if (BHV_ARR_CHECK(sSLWalkingPenguinErraticSteps, o->oSLWalkingPenguinCurStep, struct SLWalkingPenguinStep)) { + if (o->oSLWalkingPenguinCurStepTimer < sSLWalkingPenguinErraticSteps[o->oSLWalkingPenguinCurStep].stepLength) + o->oSLWalkingPenguinCurStepTimer++; + else { + // Move to next step + o->oSLWalkingPenguinCurStepTimer = 0; + o->oSLWalkingPenguinCurStep++; + if (sSLWalkingPenguinErraticSteps[o->oSLWalkingPenguinCurStep].stepLength < 0) + // Reached the end of the list, go back to the start + o->oSLWalkingPenguinCurStep = 0; + } + + if (o->oPosX < 300.0f) + o->oAction++; // If reached the end of the bridge, turn around and head back. + else { + // Move and animate the penguin + o->oForwardVel = sSLWalkingPenguinErraticSteps[o->oSLWalkingPenguinCurStep].speed; + + cur_obj_init_animation_with_accel_and_sound( + sSLWalkingPenguinErraticSteps[o->oSLWalkingPenguinCurStep].anim, + sSLWalkingPenguinErraticSteps[o->oSLWalkingPenguinCurStep].animSpeed + ); + } } break; - + // At the end, turn around and prepare to head back across the bridge. case SL_WALKING_PENGUIN_ACT_TURNING_BACK: if (sl_walking_penguin_turn()) o->oAction++; // Finished turning break; - + // Walk back across the bridge at a constant speed. case SL_WALKING_PENGUIN_ACT_RETURNING: // Move and animate the penguin o->oForwardVel = 12.0f; cur_obj_init_animation_with_accel_and_sound(PENGUIN_ANIM_WALK, 2.0f); - + if (o->oPosX > 1700.0f) o->oAction++; // If reached the start of the bridge, turn around. break; - + // At the start, turn around and prepare to walk erratically across the bridge. case SL_WALKING_PENGUIN_ACT_TURNING_FORWARDS: if (sl_walking_penguin_turn()) o->oAction = SL_WALKING_PENGUIN_ACT_MOVING_FORWARDS; // Finished turning break; } - + cur_obj_move_standard(-78); if (!cur_obj_hide_if_mario_far_away_y(1000.0f)) play_penguin_walking_sound(PENGUIN_WALK_BIG); - + // Adjust the position to get a point better lined up with the visual model, for stopping the wind. // The new point is 60 units behind the penguin and 100 units perpedicularly, away from the snowman. - + adjustedXPos = o->oPosX + sins(0xDBB0) * 60.0f; // 0xDBB0 = -51 degrees, the angle the penguin is facing adjustedZPos = o->oPosZ + coss(0xDBB0) * 60.0f; adjustedXPos += perpendicularOffset * sins(0x1BB0); // 0x1BB0 = 39 degrees, perpendicular to the penguin adjustedZPos += perpendicularOffset * coss(0x1BB0); o->oSLWalkingPenguinWindCollisionXPos = adjustedXPos; o->oSLWalkingPenguinWindCollisionZPos = adjustedZPos; - + print_debug_bottom_up("x %d", o->oPosX); print_debug_bottom_up("z %d", o->oPosZ); } diff --git a/src/game/behaviors/snowman.inc.c b/src/game/behaviors/snowman.inc.c index 3a10e81a..86d0e7ad 100644 --- a/src/game/behaviors/snowman.inc.c +++ b/src/game/behaviors/snowman.inc.c @@ -256,6 +256,10 @@ void bhv_snowmans_head_loop(void) { } void bhv_snowmans_body_checkpoint_loop(void) { + if (!o->parentObj) { + return; + } + if (is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 800)) { o->parentObj->oSnowmansBottomUnk1AC++; o->activeFlags = ACTIVE_FLAG_DEACTIVATED; diff --git a/src/game/behaviors/sparkle_spawn_star.inc.c b/src/game/behaviors/sparkle_spawn_star.inc.c index ef31f16b..172ef187 100644 --- a/src/game/behaviors/sparkle_spawn_star.inc.c +++ b/src/game/behaviors/sparkle_spawn_star.inc.c @@ -13,8 +13,9 @@ struct ObjectHitbox sSparkleSpawnStarHitbox = { }; void bhv_spawned_star_init(void) { - if (!(o->oInteractionSubtype & INT_SUBTYPE_NO_EXIT)) + if (!(o->oInteractionSubtype & INT_SUBTYPE_NO_EXIT) && o->parentObj) { o->oBehParams = o->parentObj->oBehParams; + } s32 sp24 = (o->oBehParams >> 24) & 0xFF; if (bit_shift_left(sp24) & save_file_get_star_flags(gCurrSaveFileNum - 1, gCurrCourseNum - 1)) cur_obj_set_model(smlua_model_util_load(E_MODEL_TRANSPARENT_STAR)); diff --git a/src/game/behaviors/thi_top.inc.c b/src/game/behaviors/thi_top.inc.c index 151cf4b5..7ada56f9 100644 --- a/src/game/behaviors/thi_top.inc.c +++ b/src/game/behaviors/thi_top.inc.c @@ -41,7 +41,7 @@ void bhv_thi_tiny_island_top_loop(void) { } } else { if (o->oTimer < 50) { - gEnvironmentRegions[18]--; + if (gEnvironmentRegions) { gEnvironmentRegions[18]--; } cur_obj_play_sound_1(SOUND_ENV_WATER_DRAIN); } else { gTHIWaterDrained |= 1; @@ -50,8 +50,9 @@ void bhv_thi_tiny_island_top_loop(void) { } } } else { - if (o->oTimer == 0) - gEnvironmentRegions[18] = 700; + if (o->oTimer == 0) { + if (gEnvironmentRegions) { gEnvironmentRegions[18] = 700; } + } cur_obj_hide(); } } diff --git a/src/game/behaviors/tower_platform.inc.c b/src/game/behaviors/tower_platform.inc.c index 2fd708d4..592a7461 100644 --- a/src/game/behaviors/tower_platform.inc.c +++ b/src/game/behaviors/tower_platform.inc.c @@ -1,6 +1,7 @@ // tower_platform.c.inc void bhv_wf_solid_tower_platform_loop(void) { + if (!o->parentObj) { return; } if (o->parentObj->oAction == 1) { cur_obj_become_tangible(); o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; @@ -45,12 +46,14 @@ void bhv_wf_elevator_tower_platform_loop(void) { break; } - if (o->parentObj->oAction == 1) { - cur_obj_become_tangible(); - o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; - } else if (o->parentObj->oAction > 1) { - cur_obj_become_intangible(); - o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; + if (o->parentObj) { + if (o->parentObj->oAction == 1) { + cur_obj_become_tangible(); + o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; + } else if (o->parentObj->oAction > 1) { + cur_obj_become_intangible(); + o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; + } } } @@ -73,12 +76,14 @@ void bhv_wf_sliding_tower_platform_loop(void) { o->oPosX += o->oVelX; o->oPosZ += o->oVelZ; - if (o->parentObj->oAction == 1) { - cur_obj_become_tangible(); - o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; - } else if (o->parentObj->oAction > 1) { - cur_obj_become_intangible(); - o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; + if (o->parentObj) { + if (o->parentObj->oAction == 1) { + cur_obj_become_tangible(); + o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; + } else if (o->parentObj->oAction > 1) { + cur_obj_become_intangible(); + o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; + } } } diff --git a/src/game/behaviors/tox_box.inc.c b/src/game/behaviors/tox_box.inc.c index 2a5bbd5d..48fe6436 100644 --- a/src/game/behaviors/tox_box.inc.c +++ b/src/game/behaviors/tox_box.inc.c @@ -66,6 +66,7 @@ void tox_box_act_3(void) { } void tox_box_act_0(void) { + if (!BHV_ARR_CHECK(D_8032F96C, o->oBehParams2ndByte, s8*)) { return; } s8 *sp1C = D_8032F96C[o->oBehParams2ndByte]; o->oAction = cur_obj_set_direction_table(sp1C); } diff --git a/src/game/behaviors/treasure_chest.inc.c b/src/game/behaviors/treasure_chest.inc.c index 7912d514..fb905a1c 100644 --- a/src/game/behaviors/treasure_chest.inc.c +++ b/src/game/behaviors/treasure_chest.inc.c @@ -17,6 +17,10 @@ static struct ObjectHitbox sTreasureChestBottomHitbox = { void bhv_treasure_chest_top_loop(void) { + if (!o->parentObj || !o->parentObj->parentObj) { + obj_mark_for_deletion(o); + return; + } struct Object *rootParent = o->parentObj->parentObj; switch (o->oAction) { @@ -67,6 +71,7 @@ void bhv_treasure_chest_bottom_init(void) { } void bhv_treasure_chest_bottom_loop(void) { + if (!o->parentObj) { return; } if (o->parentObj != NULL && o->parentObj->oTreasureChestSound != 0) { switch (o->parentObj->oTreasureChestSound) { case 1: play_sound(SOUND_GENERAL2_RIGHT_ANSWER, gGlobalSoundSource); break; diff --git a/src/game/behaviors/triplet_butterfly.inc.c b/src/game/behaviors/triplet_butterfly.inc.c index 5007cc8b..fb06d744 100644 --- a/src/game/behaviors/triplet_butterfly.inc.c +++ b/src/game/behaviors/triplet_butterfly.inc.c @@ -36,10 +36,12 @@ static void triplet_butterfly_act_init(void) { } //! TODO: Describe this glitch - if (o->parentObj->oTripletButterflySelectedButterfly == o->oBehParams2ndByte) { - o->oTripletButterflyType = TRIPLET_BUTTERFLY_TYPE_SPAWN_1UP; - } else if (o->parentObj->oBehParams2ndByte & TRIPLET_BUTTERFLY_BP_NO_BOMBS) { - o->oTripletButterflyType = TRIPLET_BUTTERFLY_TYPE_NORMAL; + if (o->parentObj) { + if (o->parentObj->oTripletButterflySelectedButterfly == o->oBehParams2ndByte) { + o->oTripletButterflyType = TRIPLET_BUTTERFLY_TYPE_SPAWN_1UP; + } else if (o->parentObj->oBehParams2ndByte & TRIPLET_BUTTERFLY_BP_NO_BOMBS) { + o->oTripletButterflyType = TRIPLET_BUTTERFLY_TYPE_NORMAL; + } } // Default butterfly type is TRIPLET_BUTTERFLY_TYPE_EXPLODES @@ -82,6 +84,7 @@ static void triplet_butterfly_act_wander(void) { } static void triplet_butterfly_act_activate(void) { + if (!BHV_ARR_CHECK(sTripletButterflyActivationData, o->oTripletButterflyType, struct TripletButterflyActivationData)) { return; } if (o->oTimer > 20) { if (o->oTripletButterflyModel == 0) { spawn_object_relative_with_scale(0, 0, -40, 0, 1.5f, o, MODEL_SMOKE, bhvWhitePuffSmoke2); @@ -90,8 +93,7 @@ static void triplet_butterfly_act_activate(void) { obj_set_billboard(o); o->oTripletButterflyScale = 0.0f; o->oHomeY = o->oPosY; - } else if (o->oTripletButterflyScale - >= sTripletButterflyActivationData[o->oTripletButterflyType].scale) { + } else if (o->oTripletButterflyScale >= sTripletButterflyActivationData[o->oTripletButterflyType].scale) { if (o->oTripletButterflyType != TRIPLET_BUTTERFLY_TYPE_EXPLODES) { spawn_object(o, o->oTripletButterflyModel, sTripletButterflyActivationData[o->oTripletButterflyType].behavior); @@ -102,8 +104,7 @@ static void triplet_butterfly_act_activate(void) { } } - o->oTripletButterflyScale += - sTripletButterflyActivationData[o->oTripletButterflyType].scale / 30.0f; + o->oTripletButterflyScale += sTripletButterflyActivationData[o->oTripletButterflyType].scale / 30.0f; if (o->oTripletButterflyType == TRIPLET_BUTTERFLY_TYPE_EXPLODES) { o->oGraphYOffset = 250.0f * o->oTripletButterflyScale; o->oPosY = o->oHomeY - o->oGraphYOffset; diff --git a/src/game/behaviors/ttc_2d_rotator.inc.c b/src/game/behaviors/ttc_2d_rotator.inc.c index ac0f72df..68c843d2 100644 --- a/src/game/behaviors/ttc_2d_rotator.inc.c +++ b/src/game/behaviors/ttc_2d_rotator.inc.c @@ -37,9 +37,10 @@ static s16 sTTC2DRotatorTimeBetweenTurns[][4] = { * Init function for bhvTTC2DRotator. */ void bhv_ttc_2d_rotator_init(void) { - o->oTTC2DRotatorMinTimeUntilNextTurn = - sTTC2DRotatorTimeBetweenTurns[o->oBehParams2ndByte][gTTCSpeedSetting]; - o->oTTC2DRotatorIncrement = o->oTTC2DRotatorSpeed = sTTC2DRotatorSpeeds[o->oBehParams2ndByte]; + if (o->oBehParams2ndByte < 2 && gTTCSpeedSetting < 4) { + o->oTTC2DRotatorMinTimeUntilNextTurn = sTTC2DRotatorTimeBetweenTurns[o->oBehParams2ndByte][gTTCSpeedSetting]; + o->oTTC2DRotatorIncrement = o->oTTC2DRotatorSpeed = sTTC2DRotatorSpeeds[o->oBehParams2ndByte]; + } struct SyncObject* so = sync_object_init(o, 4000.0f); if (so) { diff --git a/src/game/behaviors/ttc_pit_block.inc.c b/src/game/behaviors/ttc_pit_block.inc.c index 53b8996e..c9882e4f 100644 --- a/src/game/behaviors/ttc_pit_block.inc.c +++ b/src/game/behaviors/ttc_pit_block.inc.c @@ -37,7 +37,9 @@ static struct TTCPitBlockProperties sTTCPitBlockProperties[][2] = { * Init function for bhvTTCPitBlock. */ void bhv_ttc_pit_block_init(void) { - o->collisionData = segmented_to_virtual(sTTCPitBlockCollisionModels[o->oBehParams2ndByte]); + if (BHV_ARR_CHECK(sTTCPitBlockCollisionModels, o->oBehParams2ndByte, Collision const *)) { + o->collisionData = segmented_to_virtual(sTTCPitBlockCollisionModels[o->oBehParams2ndByte]); + } o->oTTCPitBlockPeakY = o->oPosY + 330.0f; @@ -65,13 +67,15 @@ void bhv_ttc_pit_block_update(void) { if (clamp_f32(&o->oPosY, o->oHomeY, o->oTTCPitBlockPeakY)) { o->oTTCPitBlockDir = o->oTTCPitBlockDir ^ 0x1; - if ((o->oTTCPitBlockWaitTime = - sTTCPitBlockProperties[gTTCSpeedSetting][o->oTTCPitBlockDir & 0x1].waitTime) - < 0) { - o->oTTCPitBlockWaitTime = random_mod_offset(10, 20, 6); - } + if (gTTCSpeedSetting < 4) { + if ((o->oTTCPitBlockWaitTime = sTTCPitBlockProperties[gTTCSpeedSetting][o->oTTCPitBlockDir & 0x1].waitTime) < 0) { + o->oTTCPitBlockWaitTime = random_mod_offset(10, 20, 6); + } - o->oVelY = sTTCPitBlockProperties[gTTCSpeedSetting][o->oTTCPitBlockDir].speed; + if (o->oTTCPitBlockDir < 2) { + o->oVelY = sTTCPitBlockProperties[gTTCSpeedSetting][o->oTTCPitBlockDir].speed; + } + } o->oTimer = 0; } } diff --git a/src/game/behaviors/ttc_rotating_solid.inc.c b/src/game/behaviors/ttc_rotating_solid.inc.c index ca76d906..33465e8d 100644 --- a/src/game/behaviors/ttc_rotating_solid.inc.c +++ b/src/game/behaviors/ttc_rotating_solid.inc.c @@ -26,7 +26,9 @@ static u8 sTTCRotatingSolidInitialDelays[] = { * Init function for bhvTTCRotatingSolid. */ void bhv_ttc_rotating_solid_init(void) { - o->collisionData = segmented_to_virtual(sTTCRotatingSolidCollisionModels[o->oBehParams2ndByte]); + if (BHV_ARR_CHECK(sTTCRotatingSolidCollisionModels, o->oBehParams2ndByte, void const*)) { + o->collisionData = segmented_to_virtual(sTTCRotatingSolidCollisionModels[o->oBehParams2ndByte]); + } o->oTTCRotatingSolidNumSides = o->oBehParams2ndByte == TTC_ROTATING_SOLID_BP_CUBE ? 4 : 3; @@ -68,8 +70,9 @@ void bhv_ttc_rotating_solid_update(void) { if (o->oAngleVelRoll == 0) { cur_obj_play_sound_2(SOUND_GENERAL2_ROTATING_BLOCK_CLICK); - o->oTTCRotatingSolidNumTurns = - (o->oTTCRotatingSolidNumTurns + 1) % o->oTTCRotatingSolidNumSides; + if (o->oTTCRotatingSolidNumSides) { + o->oTTCRotatingSolidNumTurns = (o->oTTCRotatingSolidNumTurns + 1) % o->oTTCRotatingSolidNumSides; + } o->oTimer = 0; if (gTTCSpeedSetting == TTC_SPEED_RANDOM) { diff --git a/src/game/behaviors/tumbling_bridge.inc.c b/src/game/behaviors/tumbling_bridge.inc.c index c8ce02b9..9c1dd40e 100644 --- a/src/game/behaviors/tumbling_bridge.inc.c +++ b/src/game/behaviors/tumbling_bridge.inc.c @@ -31,7 +31,7 @@ void bhv_tumbling_bridge_platform_loop(void) { } } - if (o->parentObj != NULL && gCurrCourseNum == COURSE_LLL) { + if (o->parentObj && gCurrCourseNum == COURSE_LLL) { if (o->parentObj->oIntangibleTimer == -1) { cur_obj_hide(); o->oIntangibleTimer = o->parentObj->oIntangibleTimer; @@ -74,12 +74,12 @@ void bhv_tumbling_bridge_platform_loop(void) { case 3: break; } - if (o->parentObj->oAction == 3) { + if (o->parentObj && o->parentObj->oAction == 3) { obj_mark_for_deletion(o); if (isLLL) { network_send_object(o); } } - if (o->parentObj != NULL && o->parentObj->oIntangibleTimer != -1) { + if (o->parentObj && o->parentObj->oIntangibleTimer != -1) { load_object_collision_model(); } else if (gCurrCourseNum != COURSE_LLL) { load_object_collision_model(); @@ -94,6 +94,7 @@ void tumbling_bridge_act_1(void) { s32 relativePlatformZ; s32 relativePlatformY = 0; s32 relativeInitialPlatformY = 0; + if (!BHV_ARR_CHECK(sTumblingBridgeParams, bridgeID, struct Struct8032F34C)) { return; } for (i = 0; i < sTumblingBridgeParams[bridgeID].numBridgeSections; i++) { relativePlatformX = 0; diff --git a/src/game/behaviors/tuxie.inc.c b/src/game/behaviors/tuxie.inc.c index 0b1fe7a4..d84b31e4 100644 --- a/src/game/behaviors/tuxie.inc.c +++ b/src/game/behaviors/tuxie.inc.c @@ -57,7 +57,7 @@ void tuxies_mother_act_1(void) { cur_obj_init_animation_with_sound(3); if (!cur_obj_is_mario_on_platform()) { sp2C = (o->oBehParams >> 0x10) & 0xFF; - sp28 = (o->prevObj->oBehParams >> 0x10) & 0xFF; + sp28 = o->prevObj ? ((o->prevObj->oBehParams >> 0x10) & 0xFF) : 0; if (sp2C == sp28) { dialogID = gBehaviorValues.dialogs.TuxieMotherBabyFoundDialog; } else { @@ -75,7 +75,7 @@ void tuxies_mother_act_1(void) { cur_obj_init_animation_with_sound(0); break; case 1: - if (o->prevObj->oHeldState == HELD_FREE) { + if (o->prevObj && o->prevObj->oHeldState == HELD_FREE) { //! This line is was almost certainly supposed to be something // like o->prevObj->oInteractionSubtype &= ~INT_SUBTYPE_DROP_IMMEDIATELY; // however, this code uses the value of o->oInteractionSubtype @@ -98,7 +98,7 @@ void tuxies_mother_act_1(void) { } break; case 2: - if (o->prevObj->oHeldState == HELD_FREE) { + if (o->prevObj && o->prevObj->oHeldState == HELD_FREE) { //! Same bug as above o->prevObj->OBJECT_FIELD_S32(o->oInteractionSubtype) &= ~INT_SUBTYPE_DROP_IMMEDIATELY; obj_set_behavior(o->prevObj, bhvPenguinBaby); diff --git a/src/game/behaviors/ukiki.inc.c b/src/game/behaviors/ukiki.inc.c index 1d437351..67c4df73 100644 --- a/src/game/behaviors/ukiki.inc.c +++ b/src/game/behaviors/ukiki.inc.c @@ -516,7 +516,7 @@ void ukiki_free_loop(void) { handle_cap_ukiki_reset(); if(!(o->oMoveFlags & OBJ_MOVE_MASK_IN_WATER)) { - exec_anim_sound_state(sUkikiSoundStates); + exec_anim_sound_state(sUkikiSoundStates, sizeof(sUkikiSoundStates) / sizeof(struct SoundState)); } } diff --git a/src/game/behaviors/ukiki_cage.inc.c b/src/game/behaviors/ukiki_cage.inc.c index 31b47d40..32c9072b 100644 --- a/src/game/behaviors/ukiki_cage.inc.c +++ b/src/game/behaviors/ukiki_cage.inc.c @@ -29,7 +29,7 @@ void bhv_ukiki_cage_star_loop(void) { obj_copy_behavior_params(o, o->parentObj); // When they cage hides itself, spawn particles and the star. - if (o->parentObj->oAction == UKIKI_CAGE_ACT_HIDE) { + if (o->parentObj && o->parentObj->oAction == UKIKI_CAGE_ACT_HIDE) { o->oAction++; } break; diff --git a/src/game/behaviors/unagi.inc.c b/src/game/behaviors/unagi.inc.c index 5971ce2e..83c41f1e 100644 --- a/src/game/behaviors/unagi.inc.c +++ b/src/game/behaviors/unagi.inc.c @@ -53,9 +53,11 @@ void unagi_act_0(void) { s32 distanceToPlayer = player ? dist_between_objects(o, player) : 10000; if (distanceToPlayer > 4500.0f && o->oSubAction != 0) { o->oAction = 1; - o->oPosX = o->oPathedStartWaypoint->pos[0]; - o->oPosY = o->oPathedStartWaypoint->pos[1]; - o->oPosZ = o->oPathedStartWaypoint->pos[2]; + if (o->oPathedStartWaypoint) { + o->oPosX = o->oPathedStartWaypoint->pos[0]; + o->oPosY = o->oPathedStartWaypoint->pos[1]; + o->oPosZ = o->oPathedStartWaypoint->pos[2]; + } } else if (o->oUnagiUnk1AC < 700.0f) { o->oSubAction = 1; } @@ -200,7 +202,7 @@ void bhv_unagi_subobject_loop(void) { struct Object* player = nearest_player_to_object(o); s32 distanceToPlayer = player ? dist_between_objects(o, player) : 10000; - if (o->parentObj->oUnagiUnk1B2 == 0) { + if (!o->parentObj || o->parentObj->oUnagiUnk1B2 == 0) { obj_mark_for_deletion(o); } else { val04 = 300.0f * o->oBehParams2ndByte; diff --git a/src/game/behaviors/water_bomb.inc.c b/src/game/behaviors/water_bomb.inc.c index 706a2c6e..cf9082cb 100644 --- a/src/game/behaviors/water_bomb.inc.c +++ b/src/game/behaviors/water_bomb.inc.c @@ -54,12 +54,12 @@ void bhv_water_bomb_spawner_update(void) { marioState = &gMarioStates[i]; } } + if (!player) { return; } spawnerRadius = 50 * (u16)(o->oBehParams >> 16) + 200.0f; // When mario is in range and a water bomb isn't already active - if (!o->oWaterBombSpawnerBombActive && latDistToMario < spawnerRadius - && player->oPosY - o->oPosY < 1000.0f) { + if (!o->oWaterBombSpawnerBombActive && latDistToMario < spawnerRadius && player->oPosY - o->oPosY < 1000.0f) { if (o->oWaterBombSpawnerTimeToSpawn != 0) { o->oWaterBombSpawnerTimeToSpawn -= 1; } else if (sync_object_is_owned_locally(o->oSyncID)) { @@ -206,7 +206,9 @@ static void water_bomb_act_drop(void) { */ static void water_bomb_act_explode(void) { water_bomb_spawn_explode_particles(25, 60, 10); - o->parentObj->oWaterBombSpawnerBombActive = FALSE; + if (o->parentObj) { + o->parentObj->oWaterBombSpawnerBombActive = FALSE; + } obj_mark_for_deletion(o); } @@ -278,7 +280,7 @@ void bhv_water_bomb_update(void) { * Despawn when the parent water bomb does. */ void bhv_water_bomb_shadow_update(void) { - if (o->parentObj->oAction == WATER_BOMB_ACT_EXPLODE) { + if (!o->parentObj || o->parentObj->oAction == WATER_BOMB_ACT_EXPLODE) { obj_mark_for_deletion(o); } else { // TODO: What is happening here diff --git a/src/game/behaviors/water_bomb_cannon.inc.c b/src/game/behaviors/water_bomb_cannon.inc.c index a53a9b9c..a14cf2e9 100644 --- a/src/game/behaviors/water_bomb_cannon.inc.c +++ b/src/game/behaviors/water_bomb_cannon.inc.c @@ -3,7 +3,7 @@ void bhv_bubble_cannon_barrel_loop(void) { struct Object *val04; - if (o->parentObj->oAction == 2) { + if (!o->parentObj || o->parentObj->oAction == 2) { obj_mark_for_deletion(o); } else { o->oMoveAngleYaw = o->parentObj->oFaceAngleYaw; diff --git a/src/game/behaviors/water_pillar.inc.c b/src/game/behaviors/water_pillar.inc.c index c8fc02f7..7e1f2810 100644 --- a/src/game/behaviors/water_pillar.inc.c +++ b/src/game/behaviors/water_pillar.inc.c @@ -81,6 +81,8 @@ void bhv_water_level_pillar_loop(void) { water_level_pillar_drained(); else water_level_pillar_undrained(); - gEnvironmentRegions[18] = gEnvironmentLevels[2]; - gEnvironmentRegions[6] = gEnvironmentLevels[0]; + if (gEnvironmentRegions) { + gEnvironmentRegions[18] = gEnvironmentLevels[2]; + gEnvironmentRegions[6] = gEnvironmentLevels[0]; + } } diff --git a/src/game/behaviors/water_ring.inc.c b/src/game/behaviors/water_ring.inc.c index 5647a1d6..9e9a3368 100644 --- a/src/game/behaviors/water_ring.inc.c +++ b/src/game/behaviors/water_ring.inc.c @@ -116,7 +116,9 @@ void water_ring_act_not_collected(void) { //! In this case ringSpawner and ringManager are the same object, // because the Jet Stream Ring Spawner is its own parent object. struct Object *ringSpawner = o->parentObj; + if (!ringSpawner) { return; } struct Object *ringManager = ringSpawner->parentObj; + if (!ringManager) { return; } if (o->oTimer >= 226) { o->oOpacity -= 2; @@ -160,7 +162,8 @@ void water_ring_spawner_act_inactive(void) { // from the Manta Ray, which spawns rings but also has a Ring Manager object as its // parent. The Jet Stream Ring Spawner functions as both a spawner and a Ring Manager. struct Object *currentObj = o->parentObj; - struct Object *waterRing; + struct Object *waterRing = NULL; + if (!currentObj) { return; } //! Because the index counter overflows at 10000, it's possible to wait // for about 4 hours and 38 minutes if you miss a ring, and the index will @@ -217,7 +220,9 @@ void bhv_manta_ray_water_ring_init(void) { void manta_water_ring_act_not_collected(void) { f32 avgScale = (f32) o->oTimer / 50.0f * 1.3 + 0.1; struct Object *ringSpawner = o->parentObj; + if (!ringSpawner) { return; } struct Object *ringManager = ringSpawner->parentObj; + if (!ringManager) { return; } if (avgScale > 1.3) avgScale = 1.3; diff --git a/src/game/behaviors/wdw_water_level.inc.c b/src/game/behaviors/wdw_water_level.inc.c index 66579f5a..5e96d69e 100644 --- a/src/game/behaviors/wdw_water_level.inc.c +++ b/src/game/behaviors/wdw_water_level.inc.c @@ -22,9 +22,10 @@ void bhv_init_changing_water_level_loop(void) { } } + if (!gEnvironmentRegions) { return; } + if (gCurrentObject->oAction == 0) { - if (gEnvironmentRegions != NULL) - gCurrentObject->oAction++; + gCurrentObject->oAction++; } else if (gCurrentObject->oTimer < 10) *gEnvironmentLevels = gEnvironmentRegions[6]; else { diff --git a/src/game/behaviors/wiggler.inc.c b/src/game/behaviors/wiggler.inc.c index 7b3d809d..a74dc608 100644 --- a/src/game/behaviors/wiggler.inc.c +++ b/src/game/behaviors/wiggler.inc.c @@ -72,6 +72,7 @@ void bhv_wiggler_body_part_update(void) { // This should never be higher then 3 // in normal circumstances. if (o->oBehParams2ndByte > 3 || o->oBehParams2ndByte < 0) { return; } + if (!parent->oWigglerSegments) { return; } struct ChainSegment *segment = &parent->oWigglerSegments[o->oBehParams2ndByte]; @@ -126,11 +127,13 @@ void bhv_wiggler_body_part_update(void) { */ void wiggler_init_segments(void) { struct ChainSegment *segments = mem_pool_alloc(gObjectMemoryPool, 4 * sizeof(struct ChainSegment)); + + // Each segment represents the global position and orientation of each + // object. Segment 0 represents the wiggler's head, and segment i>0 + // represents body part i. + o->oWigglerSegments = segments; + if (segments != NULL) { - // Each segment represents the global position and orientation of each - // object. Segment 0 represents the wiggler's head, and segment i>0 - // represents body part i. - o->oWigglerSegments = segments; for (s32 i = 0; i <= 3; i++) { chain_segment_init(segments + i); @@ -171,11 +174,12 @@ void wiggler_init_segments(void) { */ void wiggler_update_segments(void) { f32 segmentLength = 35.0f * o->header.gfx.scale[0]; + if (!o->oWigglerSegments) { return; } for (s32 i = 1; i <= 3; i++) { struct ChainSegment *prevBodyPart = &o->oWigglerSegments[i - 1]; struct ChainSegment *bodyPart = &o->oWigglerSegments[i]; - + if (!prevBodyPart || !bodyPart) { continue; } f32 dx = bodyPart->posX - prevBodyPart->posX; f32 dy = bodyPart->posY - prevBodyPart->posY; f32 dz = bodyPart->posZ - prevBodyPart->posZ; @@ -235,7 +239,7 @@ static void wiggler_act_walk(void) { // to 4 until after this runs the first time. It indexes out of bounds // and uses the value 113762.3 for one frame on US. This is fixed up // in wiggler_init_segments if AVOID_UB is defined. - obj_forward_vel_approach(sWigglerSpeeds[o->oHealth - 1], 1.0f); + obj_forward_vel_approach(BHV_ARR(sWigglerSpeeds, o->oHealth - 1, f32), 1.0f); if (o->oWigglerWalkAwayFromWallTimer != 0) { o->oWigglerWalkAwayFromWallTimer -= 1; @@ -522,11 +526,13 @@ void bhv_wiggler_update(void) { } // Update segment 0 with data from the wiggler object - o->oWigglerSegments[0].posX = o->oPosX; - o->oWigglerSegments[0].posY = o->oPosY; - o->oWigglerSegments[0].posZ = o->oPosZ; - o->oWigglerSegments[0].pitch = o->oFaceAnglePitch; - o->oWigglerSegments[0].yaw = o->oFaceAngleYaw; + if (o->oWigglerSegments) { + o->oWigglerSegments[0].posX = o->oPosX; + o->oWigglerSegments[0].posY = o->oPosY; + o->oWigglerSegments[0].posZ = o->oPosZ; + o->oWigglerSegments[0].pitch = o->oFaceAnglePitch; + o->oWigglerSegments[0].yaw = o->oFaceAngleYaw; + } // Update the rest of the segments to follow segment 0 wiggler_update_segments(); diff --git a/src/game/camera.c b/src/game/camera.c index eccbc791..2b3c37b5 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -3658,24 +3658,28 @@ void stub_camera_3(UNUSED struct Camera *c) { } void vec3f_sub(Vec3f dst, Vec3f src) { + if (!dst || !src) { return; } dst[0] -= src[0]; dst[1] -= src[1]; dst[2] -= src[2]; } void object_pos_to_vec3f(Vec3f dst, struct Object *o) { + if (!dst || !o) { return; } dst[0] = o->oPosX; dst[1] = o->oPosY; dst[2] = o->oPosZ; } void vec3f_to_object_pos(struct Object *o, Vec3f src) { + if (!o || !src) { return; } o->oPosX = src[0]; o->oPosY = src[1]; o->oPosZ = src[2]; } void unused_object_angle_to_vec3s(Vec3s dst, struct Object *o) { + if (!dst || !o) { return; } dst[0] = o->oMoveAnglePitch; dst[1] = o->oMoveAngleYaw; dst[2] = o->oMoveAngleRoll; diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index dda979aa..09b43e0c 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -1479,7 +1479,7 @@ void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 l while (pageState == DIALOG_PAGE_STATE_NONE) { change_and_flash_dialog_text_color_lines(colorMode, lineNum); - strChar = str[strIdx]; + strChar = str ? str[strIdx] : DIALOG_CHAR_TERMINATOR; switch (strChar) { case DIALOG_CHAR_TERMINATOR: @@ -1932,6 +1932,10 @@ void render_dialog_entries(void) { break; } #else + if (gDialogID >= DIALOG_COUNT || gDialogID < 0) { + gDialogID = -1; + return; + } dialogTable = segmented_to_virtual(seg2_dialog_table); #endif dialog = segmented_to_virtual(dialogTable[gDialogID]); diff --git a/src/game/interaction.c b/src/game/interaction.c index 171a95f2..7f18e852 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -2239,7 +2239,7 @@ void mario_process_interactions(struct MarioState *m) { m->collidedObjInteractTypes &= ~interactType; - if (!(object->oInteractStatus & INT_STATUS_INTERACTED)) { + if (object && !(object->oInteractStatus & INT_STATUS_INTERACTED)) { bool allow = true; smlua_call_event_hooks_interact_params_ret_bool(HOOK_ALLOW_INTERACT, m, object, interactType, &allow); if (allow) { diff --git a/src/game/level_update.c b/src/game/level_update.c index 8aa73fc5..5f11b95d 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -677,6 +677,7 @@ s16 music_changed_through_warp(s16 arg) { } struct ObjectWarpNode *warpNode = area_get_warp_node(arg); + if (!warpNode) { return FALSE; } s16 levelNum = warpNode->node.destLevel & 0x7F; #if BUGFIX_KOOPA_RACE_MUSIC diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index e9eaab79..58a15e50 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -2313,9 +2313,11 @@ static void end_peach_cutscene_summon_jumbo_star(struct MarioState *m) { advance_cutscene_step(m); } - sEndJumboStarObj->oFaceAngleYaw += 0x0400; - generate_yellow_sparkles(0, 2528, -1800, 250.0f); - play_sound(SOUND_AIR_PEACH_TWINKLE, sEndJumboStarObj->header.gfx.cameraToObject); + if (sEndJumboStarObj) { + sEndJumboStarObj->oFaceAngleYaw += 0x0400; + generate_yellow_sparkles(0, 2528, -1800, 250.0f); + play_sound(SOUND_AIR_PEACH_TWINKLE, sEndJumboStarObj->header.gfx.cameraToObject); + } } #if defined(VERSION_EU) @@ -2344,7 +2346,7 @@ static void end_peach_cutscene_spawn_peach(struct MarioState *m) { play_transition(WARP_TRANSITION_FADE_FROM_COLOR, 192, 255, 255, 255); } if (m->actionTimer == 40) { - obj_mark_for_deletion(sEndJumboStarObj); + if (sEndJumboStarObj) { obj_mark_for_deletion(sEndJumboStarObj); } sEndPeachObj = spawn_object_abs_with_rot(gCurrentObject, 0, MODEL_PEACH, bhvEndPeach, 0, 2428, -1300, 0, 0, 0); diff --git a/src/game/memory.c b/src/game/memory.c index b42a5a9f..40510826 100644 --- a/src/game/memory.c +++ b/src/game/memory.c @@ -287,6 +287,8 @@ void *alloc_only_pool_alloc(struct AllocOnlyPool *pool, s32 size) { } if (addr == NULL) { LOG_ERROR("Allocate only pool failed to allocate memory of size 0x%X on at pool %p.", size, pool); + } else { + memset(addr, 0, size); } return addr; } @@ -374,6 +376,7 @@ void *mem_pool_alloc(struct MemoryPool *pool, u32 size) { * Free a block that was allocated using mem_pool_alloc. */ void mem_pool_free(struct MemoryPool *pool, void *addr) { + if (!addr) { return; } struct MemoryBlock *block = (struct MemoryBlock *) ((u8 *) addr - sizeof(struct MemoryBlock)); struct MemoryBlock *freeList = pool->freeList.next; @@ -419,6 +422,7 @@ void *alloc_display_list(u32 size) { if (gGfxPoolEnd - size >= (u8 *) gDisplayListHead) { gGfxPoolEnd -= size; ptr = gGfxPoolEnd; + memset(ptr, 0, size); } else { LOG_ERROR("Failed to allocate display list of size 0x%X!", size); } diff --git a/src/game/moving_texture.c b/src/game/moving_texture.c index fdac4949..47f4cf4d 100644 --- a/src/game/moving_texture.c +++ b/src/game/moving_texture.c @@ -319,8 +319,10 @@ Gfx *geo_wdw_set_initial_water_level(s32 callContext, UNUSED struct GraphNode *n } else { wdwWaterHeight = 1024; } - for (i = 0; i < *gEnvironmentRegions; i++) { - gEnvironmentRegions[i * 6 + 6] = wdwWaterHeight; + if (gEnvironmentRegions) { + for (i = 0; i < *gEnvironmentRegions; i++) { + gEnvironmentRegions[i * 6 + 6] = wdwWaterHeight; + } } gWdwWaterLevelSet = TRUE; } diff --git a/src/game/obj_behaviors_2.c b/src/game/obj_behaviors_2.c index 3f4eae0f..36530cdd 100644 --- a/src/game/obj_behaviors_2.c +++ b/src/game/obj_behaviors_2.c @@ -178,6 +178,7 @@ void platform_on_track_update_pos_or_spawn_ball(s32 ballIndex, f32 x, f32 y, f32 do { prevWaypoint = nextWaypoint; + if (!prevWaypoint) { break; } nextWaypoint += 1; if (nextWaypoint->flags == WAYPOINT_FLAGS_END) { diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index 81e8f340..1a6fa674 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -219,7 +219,7 @@ Gfx *geo_switch_area(s32 callContext, struct GraphNode *node) { if (door == NULL) { continue; } if (door->oInteractType != INTERACT_DOOR) { continue; } if (door->oAction == 0) { continue; } - if (gDoorAdjacentRooms[door->oDoorUnkF8][0] != gMarioCurrentRoom && gDoorAdjacentRooms[door->oDoorUnkF8][1] != gMarioCurrentRoom) { continue; } + if (door->oDoorUnkF8 < 60 && gDoorAdjacentRooms[door->oDoorUnkF8][0] != gMarioCurrentRoom && gDoorAdjacentRooms[door->oDoorUnkF8][1] != gMarioCurrentRoom) { continue; } find_floor(door->oHomeX, door->oHomeY, door->oHomeZ, &sp20); if (!sp20) { continue; } @@ -755,6 +755,7 @@ void cur_obj_move_using_vel(void) { } void obj_copy_graph_y_offset(struct Object *dst, struct Object *src) { + if (!dst || !src) { return; } dst->oGraphYOffset = src->oGraphYOffset; } @@ -764,12 +765,14 @@ void obj_copy_pos_and_angle(struct Object *dst, struct Object *src) { } void obj_copy_pos(struct Object *dst, struct Object *src) { + if (!dst || !src) { return; } dst->oPosX = src->oPosX; dst->oPosY = src->oPosY; dst->oPosZ = src->oPosZ; } void obj_copy_angle(struct Object *dst, struct Object *src) { + if (!dst || !src) { return; } dst->oMoveAnglePitch = src->oMoveAnglePitch; dst->oMoveAngleYaw = src->oMoveAngleYaw; dst->oMoveAngleRoll = src->oMoveAngleRoll; @@ -780,6 +783,7 @@ void obj_copy_angle(struct Object *dst, struct Object *src) { } void obj_set_gfx_pos_from_pos(struct Object *obj) { + if (!obj) { return; } obj->header.gfx.pos[0] = obj->oPosX; obj->header.gfx.pos[1] = obj->oPosY; obj->header.gfx.pos[2] = obj->oPosZ; @@ -1211,15 +1215,15 @@ BAD_RETURN(s16) cur_obj_reverse_animation(void) { BAD_RETURN(s32) cur_obj_extend_animation_if_at_end(void) { s32 sp4 = o->header.gfx.animInfo.animFrame; - s32 sp0 = o->header.gfx.animInfo.curAnim->loopEnd - 2; + s32 sp0 = o->header.gfx.animInfo.curAnim ? o->header.gfx.animInfo.curAnim->loopEnd - 2 : 0; if (sp4 == sp0) o->header.gfx.animInfo.animFrame--; } s32 cur_obj_check_if_near_animation_end(void) { - u32 animFlags = (s32) o->header.gfx.animInfo.curAnim->flags; + u32 animFlags = o->header.gfx.animInfo.curAnim ? (s32) o->header.gfx.animInfo.curAnim->flags : 0; s32 animFrame = o->header.gfx.animInfo.animFrame; - s32 nearLoopEnd = o->header.gfx.animInfo.curAnim->loopEnd - 2; + s32 nearLoopEnd = o->header.gfx.animInfo.curAnim ? o->header.gfx.animInfo.curAnim->loopEnd - 2 : 0; s32 isNearEnd = FALSE; if (animFlags & ANIM_FLAG_NOLOOP && nearLoopEnd + 1 == animFrame) { @@ -1235,7 +1239,7 @@ s32 cur_obj_check_if_near_animation_end(void) { s32 cur_obj_check_if_at_animation_end(void) { s32 animFrame = o->header.gfx.animInfo.animFrame; - s32 lastFrame = o->header.gfx.animInfo.curAnim->loopEnd - 1; + s32 lastFrame = o->header.gfx.animInfo.curAnim ? o->header.gfx.animInfo.curAnim->loopEnd - 1 : 0; if (animFrame == lastFrame) { return TRUE; @@ -1732,6 +1736,7 @@ s32 cur_obj_has_behavior(const BehaviorScript *behavior) { } s32 obj_has_behavior(struct Object *obj, const BehaviorScript *behavior) { + if (!obj || !behavior) { return FALSE; } behavior = smlua_override_behavior(behavior); if (obj->behavior == segmented_to_virtual(behavior)) { return TRUE; @@ -2242,6 +2247,7 @@ void obj_set_throw_matrix_from_transform(struct Object *obj) { void obj_build_transform_relative_to_parent(struct Object *obj) { if (obj == NULL) { return; } struct Object *parent = obj->parentObj; + if (!parent) { return; } obj_build_transform_from_pos_and_angle(obj, O_PARENT_RELATIVE_POS_INDEX, O_FACE_ANGLE_INDEX); obj_apply_scale_to_transform(obj); @@ -2305,6 +2311,8 @@ s32 cur_obj_follow_path(UNUSED s32 unusedArg) { startWaypoint = o->oPathedStartWaypoint; lastWaypoint = o->oPathedPrevWaypoint; + if (!startWaypoint) { return PATH_NONE; } + // sanity check waypoints if (lastWaypoint == NULL) { lastWaypoint = startWaypoint; } struct Waypoint* tmpWaypoint = (lastWaypoint + 1); @@ -2593,6 +2601,7 @@ s32 cur_obj_progress_direction_table(void) { s8 spF; s8 *sp8 = o->oToxBoxMovementPattern; s32 sp4 = o->oToxBoxMovementStep + 1; + if (!sp8) { return 0; } if (sp8[sp4] != -1) { spF = sp8[sp4]; @@ -2701,7 +2710,7 @@ void spawn_base_star_with_no_lvl_exit(void) { } s32 bit_shift_left(s32 a0) { - return D_8032F0A4[a0]; + return BHV_ARR(D_8032F0A4, a0, s16); } s32 cur_obj_mario_far_away(void) { @@ -3297,4 +3306,15 @@ void cur_obj_set_home_once(void) { o->oHomeX = o->oPosX; o->oHomeY = o->oPosY; o->oHomeZ = o->oPosZ; +} + +s32 get_trajectory_length(Trajectory* trajectory) { + if (!trajectory) { return 0; } + s32 count = 0; + s16* c = trajectory; + while (*c != -1) { + count++; + c += 4; + } + return count; } \ No newline at end of file diff --git a/src/game/object_helpers.h b/src/game/object_helpers.h index 570477e6..7e9675f1 100644 --- a/src/game/object_helpers.h +++ b/src/game/object_helpers.h @@ -326,5 +326,6 @@ void cur_obj_spawn_star_at_y_offset(f32 targetX, f32 targetY, f32 targetZ, f32 o #endif void cur_obj_set_home_once(void); +s32 get_trajectory_length(Trajectory* trajectory); #endif // OBJECT_HELPERS_H diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index aff4bcf6..9004725a 100644 --- a/src/game/object_list_processor.c +++ b/src/game/object_list_processor.c @@ -275,6 +275,7 @@ void bhv_mario_update(void) { // set mario state to the current player s32 stateIndex = (gCurrentObject->oBehParams - 1); + if (stateIndex > MAX_PLAYERS) { return; } gMarioState = &gMarioStates[stateIndex]; // sanity check torsoPos, it isn't updated off-screen otherwise @@ -465,6 +466,7 @@ void set_object_respawn_info_bits(struct Object *obj, u8 bits) { u16 *info16; u8 oldRespawnInfoBits = 0; u8 newRespawnInfoBits = 0; + if (!obj) { return; } switch (obj->respawnInfoType) { case RESPAWN_INFO_TYPE_32: diff --git a/src/game/spawn_object.c b/src/game/spawn_object.c index 7a39a643..78c9aaaf 100644 --- a/src/game/spawn_object.c +++ b/src/game/spawn_object.c @@ -109,11 +109,14 @@ struct Object *try_allocate_object(struct ObjectNode *destList, struct ObjectNod geo_remove_child(&nextObj->gfx.node); geo_add_child(&gObjParentGraphNode, &nextObj->gfx.node); - ((struct Object *)nextObj)->ctx = 0 + struct Object* ret = (struct Object *) nextObj; + ret->ctx = 0 | ((u8)CTX_WITHIN(CTX_LEVEL_SCRIPT) << 0) | ((u8)CTX_WITHIN(CTX_HOOK) << 1); - return (struct Object *) nextObj; + ret->header.gfx.sharedChild = NULL; + + return ret; } /** diff --git a/src/game/spawn_sound.c b/src/game/spawn_sound.c index 6f7afdc7..9e4bced4 100644 --- a/src/game/spawn_sound.c +++ b/src/game/spawn_sound.c @@ -15,8 +15,9 @@ * of sound states. Used for the stepping sounds of various * objects. (King Bobomb, Bowser, King Whomp) */ -void exec_anim_sound_state(struct SoundState *soundStates) { +void exec_anim_sound_state(struct SoundState *soundStates, u16 maxSoundStates) { s32 stateIdx = gCurrentObject->oSoundStateID; + if (stateIdx >= maxSoundStates) { return; } switch (soundStates[stateIdx].playSound) { // since we have an array of sound states corresponding to diff --git a/src/game/spawn_sound.h b/src/game/spawn_sound.h index c00a13be..b125049a 100644 --- a/src/game/spawn_sound.h +++ b/src/game/spawn_sound.h @@ -19,6 +19,6 @@ struct SoundState void cur_obj_play_sound_1(s32 soundMagic); void cur_obj_play_sound_2(s32 soundMagic); void create_sound_spawner(s32 soundMagic); -void exec_anim_sound_state(struct SoundState *soundStates); +void exec_anim_sound_state(struct SoundState *soundStates, u16 maxSoundStates); #endif // SPAWN_SOUND_H diff --git a/src/menu/file_select.c b/src/menu/file_select.c index 9452c919..b4d68097 100644 --- a/src/menu/file_select.c +++ b/src/menu/file_select.c @@ -577,7 +577,7 @@ void render_score_menu_buttons(struct Object *scoreButton) { spawn_object_rel_with_rot(scoreButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, 711, 311, -100, 0, -0x8000, 0); } - sMainMenuButtons[MENU_BUTTON_SCORE_FILE_A]->oMenuButtonScale = 0.11111111f; + if (sMainMenuButtons[MENU_BUTTON_SCORE_FILE_A]) { sMainMenuButtons[MENU_BUTTON_SCORE_FILE_A]->oMenuButtonScale = 0.11111111f; } // File B if (save_file_exists(SAVE_FILE_B) == TRUE) { sMainMenuButtons[MENU_BUTTON_SCORE_FILE_B] = @@ -588,7 +588,7 @@ void render_score_menu_buttons(struct Object *scoreButton) { spawn_object_rel_with_rot(scoreButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, -166, 311, -100, 0, -0x8000, 0); } - sMainMenuButtons[MENU_BUTTON_SCORE_FILE_B]->oMenuButtonScale = 0.11111111f; + if (sMainMenuButtons[MENU_BUTTON_SCORE_FILE_B]) { sMainMenuButtons[MENU_BUTTON_SCORE_FILE_B]->oMenuButtonScale = 0.11111111f; } // File C if (save_file_exists(SAVE_FILE_C) == TRUE) { sMainMenuButtons[MENU_BUTTON_SCORE_FILE_C] = spawn_object_rel_with_rot( @@ -597,7 +597,7 @@ void render_score_menu_buttons(struct Object *scoreButton) { sMainMenuButtons[MENU_BUTTON_SCORE_FILE_C] = spawn_object_rel_with_rot( scoreButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, 711, 0, -100, 0, -0x8000, 0); } - sMainMenuButtons[MENU_BUTTON_SCORE_FILE_C]->oMenuButtonScale = 0.11111111f; + if (sMainMenuButtons[MENU_BUTTON_SCORE_FILE_C]) { sMainMenuButtons[MENU_BUTTON_SCORE_FILE_C]->oMenuButtonScale = 0.11111111f; } // File D if (save_file_exists(SAVE_FILE_D) == TRUE) { sMainMenuButtons[MENU_BUTTON_SCORE_FILE_D] = @@ -607,19 +607,19 @@ void render_score_menu_buttons(struct Object *scoreButton) { sMainMenuButtons[MENU_BUTTON_SCORE_FILE_D] = spawn_object_rel_with_rot( scoreButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, -166, 0, -100, 0, -0x8000, 0); } - sMainMenuButtons[MENU_BUTTON_SCORE_FILE_D]->oMenuButtonScale = 0.11111111f; + if (sMainMenuButtons[MENU_BUTTON_SCORE_FILE_D]) { sMainMenuButtons[MENU_BUTTON_SCORE_FILE_D]->oMenuButtonScale = 0.11111111f; } // Return to main menu button sMainMenuButtons[MENU_BUTTON_SCORE_RETURN] = spawn_object_rel_with_rot( scoreButton, MODEL_MAIN_MENU_YELLOW_FILE_BUTTON, bhvMenuButton, 711, -388, -100, 0, -0x8000, 0); - sMainMenuButtons[MENU_BUTTON_SCORE_RETURN]->oMenuButtonScale = 0.11111111f; + if (sMainMenuButtons[MENU_BUTTON_SCORE_RETURN]) { sMainMenuButtons[MENU_BUTTON_SCORE_RETURN]->oMenuButtonScale = 0.11111111f; } // Switch to copy menu button sMainMenuButtons[MENU_BUTTON_SCORE_COPY_FILE] = spawn_object_rel_with_rot( scoreButton, MODEL_MAIN_MENU_BLUE_COPY_BUTTON, bhvMenuButton, 0, -388, -100, 0, -0x8000, 0); - sMainMenuButtons[MENU_BUTTON_SCORE_COPY_FILE]->oMenuButtonScale = 0.11111111f; + if (sMainMenuButtons[MENU_BUTTON_SCORE_COPY_FILE]) { sMainMenuButtons[MENU_BUTTON_SCORE_COPY_FILE]->oMenuButtonScale = 0.11111111f; } // Switch to erase menu button sMainMenuButtons[MENU_BUTTON_SCORE_ERASE_FILE] = spawn_object_rel_with_rot( scoreButton, MODEL_MAIN_MENU_RED_ERASE_BUTTON, bhvMenuButton, -711, -388, -100, 0, -0x8000, 0); - sMainMenuButtons[MENU_BUTTON_SCORE_ERASE_FILE]->oMenuButtonScale = 0.11111111f; + if (sMainMenuButtons[MENU_BUTTON_SCORE_ERASE_FILE]) { sMainMenuButtons[MENU_BUTTON_SCORE_ERASE_FILE]->oMenuButtonScale = 0.11111111f; } } #ifdef VERSION_EU @@ -1325,7 +1325,7 @@ void bhv_menu_button_manager_init(void) { spawn_object_rel_with_rot(gCurrentObject, MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE, bhvMenuButton, -6400, 2800, 0, 0, 0, 0); } - sMainMenuButtons[MENU_BUTTON_PLAY_FILE_A]->oMenuButtonScale = 1.0f; + if (sMainMenuButtons[MENU_BUTTON_PLAY_FILE_A]) { sMainMenuButtons[MENU_BUTTON_PLAY_FILE_A]->oMenuButtonScale = 1.0f; } // File B if (save_file_exists(SAVE_FILE_B) == TRUE) { sMainMenuButtons[MENU_BUTTON_PLAY_FILE_B] = @@ -1336,7 +1336,7 @@ void bhv_menu_button_manager_init(void) { spawn_object_rel_with_rot(gCurrentObject, MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE, bhvMenuButton, 1500, 2800, 0, 0, 0, 0); } - sMainMenuButtons[MENU_BUTTON_PLAY_FILE_B]->oMenuButtonScale = 1.0f; + if (sMainMenuButtons[MENU_BUTTON_PLAY_FILE_B]) { sMainMenuButtons[MENU_BUTTON_PLAY_FILE_B]->oMenuButtonScale = 1.0f; } // File C if (save_file_exists(SAVE_FILE_C) == TRUE) { sMainMenuButtons[MENU_BUTTON_PLAY_FILE_C] = @@ -1346,7 +1346,7 @@ void bhv_menu_button_manager_init(void) { sMainMenuButtons[MENU_BUTTON_PLAY_FILE_C] = spawn_object_rel_with_rot( gCurrentObject, MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE, bhvMenuButton, -6400, 0, 0, 0, 0, 0); } - sMainMenuButtons[MENU_BUTTON_PLAY_FILE_C]->oMenuButtonScale = 1.0f; + if (sMainMenuButtons[MENU_BUTTON_PLAY_FILE_C]) { sMainMenuButtons[MENU_BUTTON_PLAY_FILE_C]->oMenuButtonScale = 1.0f; } // File D if (save_file_exists(SAVE_FILE_D) == TRUE) { sMainMenuButtons[MENU_BUTTON_PLAY_FILE_D] = spawn_object_rel_with_rot( @@ -1355,23 +1355,23 @@ void bhv_menu_button_manager_init(void) { sMainMenuButtons[MENU_BUTTON_PLAY_FILE_D] = spawn_object_rel_with_rot( gCurrentObject, MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE, bhvMenuButton, 1500, 0, 0, 0, 0, 0); } - sMainMenuButtons[MENU_BUTTON_PLAY_FILE_D]->oMenuButtonScale = 1.0f; + if (sMainMenuButtons[MENU_BUTTON_PLAY_FILE_D]) { sMainMenuButtons[MENU_BUTTON_PLAY_FILE_D]->oMenuButtonScale = 1.0f; } // Score menu button sMainMenuButtons[MENU_BUTTON_SCORE] = spawn_object_rel_with_rot( gCurrentObject, MODEL_MAIN_MENU_GREEN_SCORE_BUTTON, bhvMenuButton, -6400, -3500, 0, 0, 0, 0); - sMainMenuButtons[MENU_BUTTON_SCORE]->oMenuButtonScale = 1.0f; + if (sMainMenuButtons[MENU_BUTTON_SCORE]) { sMainMenuButtons[MENU_BUTTON_SCORE]->oMenuButtonScale = 1.0f; } // Copy menu button sMainMenuButtons[MENU_BUTTON_COPY] = spawn_object_rel_with_rot( gCurrentObject, MODEL_MAIN_MENU_BLUE_COPY_BUTTON, bhvMenuButton, -2134, -3500, 0, 0, 0, 0); - sMainMenuButtons[MENU_BUTTON_COPY]->oMenuButtonScale = 1.0f; + if (sMainMenuButtons[MENU_BUTTON_COPY]) { sMainMenuButtons[MENU_BUTTON_COPY]->oMenuButtonScale = 1.0f; } // Erase menu button sMainMenuButtons[MENU_BUTTON_ERASE] = spawn_object_rel_with_rot( gCurrentObject, MODEL_MAIN_MENU_RED_ERASE_BUTTON, bhvMenuButton, 2134, -3500, 0, 0, 0, 0); - sMainMenuButtons[MENU_BUTTON_ERASE]->oMenuButtonScale = 1.0f; + if (sMainMenuButtons[MENU_BUTTON_ERASE]) { sMainMenuButtons[MENU_BUTTON_ERASE]->oMenuButtonScale = 1.0f; } // Sound mode menu button (Option Mode in EU) sMainMenuButtons[MENU_BUTTON_SOUND_MODE] = spawn_object_rel_with_rot( gCurrentObject, MODEL_MAIN_MENU_PURPLE_SOUND_BUTTON, bhvMenuButton, 6400, -3500, 0, 0, 0, 0); - sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oMenuButtonScale = 1.0f; + if (sMainMenuButtons[MENU_BUTTON_SOUND_MODE]) { sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oMenuButtonScale = 1.0f; } sTextBaseAlpha = 0; } @@ -1392,7 +1392,7 @@ void check_main_menu_clicked_buttons(void) { #endif // Sound mode menu is handled separately because the button ID for it // is not grouped with the IDs of the other submenus. - if (check_clicked_button(sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oPosX, + if (sMainMenuButtons[MENU_BUTTON_SOUND_MODE] && check_clicked_button(sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oPosX, sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oPosY, 200.0f) == TRUE) { sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oMenuButtonState = MENU_BUTTON_STATE_GROWING; sSelectedButtonID = MENU_BUTTON_SOUND_MODE; @@ -1401,6 +1401,7 @@ void check_main_menu_clicked_buttons(void) { s8 buttonID; // Configure Main Menu button group for (buttonID = MENU_BUTTON_MAIN_MIN; buttonID < MENU_BUTTON_MAIN_MAX; buttonID++) { + if (!sMainMenuButtons[buttonID]) { continue; } s16 buttonX = sMainMenuButtons[buttonID]->oPosX; s16 buttonY = sMainMenuButtons[buttonID]->oPosY; @@ -1415,7 +1416,9 @@ void check_main_menu_clicked_buttons(void) { #ifdef VERSION_EU // Open Options Menu if sOpenLangSettings is TRUE (It's TRUE when there's no saves) if (sOpenLangSettings == TRUE) { - sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oMenuButtonState = MENU_BUTTON_STATE_GROWING; + if (sMainMenuButtons[MENU_BUTTON_SOUND_MODE]) { + sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oMenuButtonState = MENU_BUTTON_STATE_GROWING; + } sSelectedButtonID = MENU_BUTTON_SOUND_MODE; sOpenLangSettings = FALSE; } diff --git a/src/menu/star_select.c b/src/menu/star_select.c index 64aeb3bc..d1d993ca 100644 --- a/src/menu/star_select.c +++ b/src/menu/star_select.c @@ -34,20 +34,20 @@ */ // Star Selector count models printed in the act selector menu. -static struct Object *sStarSelectorModels[8]; +static struct Object *sStarSelectorModels[8] = { 0 }; // The act the course is loaded as, affects whether some objects spawn. -s8 sLoadedActNum; +s8 sLoadedActNum = 0; s8 sReceivedLoadedActNum = 0; // Number of obtained stars, excluding the coin star. -static u8 sObtainedStars; +static u8 sObtainedStars = 0; // Total number of stars that appear in the act selector menu. -static s8 sVisibleStars; +static s8 sVisibleStars = 0; // Act selected when the act menu is first opened. -static u8 sInitSelectedActNum; +static u8 sInitSelectedActNum = 0; // Index value of the act selected in the act menu. s8 sSelectedActIndex = 0; @@ -96,7 +96,7 @@ void bhv_act_selector_star_type_loop(void) { * Renders the 100 coin star with an special star selector type. */ void render_100_coin_star(u8 stars) { - if (stars & (1 << 6)) { + if ((stars & (1 << 6)) && sStarSelectorModels[6]) { // If the 100 coin star has been collected, create a new star selector next to the coin score. sStarSelectorModels[6] = spawn_object_abs_with_rot(gCurrentObject, 0, MODEL_STAR, bhvActSelectorStarType, 370, 24, -300, 0, 0, 0); @@ -205,6 +205,7 @@ void bhv_act_selector_loop(void) { // Star selector type handler for (i = 0; i < sVisibleStars; i++) { + if (!sStarSelectorModels[i]) { continue; } if (sSelectedActIndex == i) { sStarSelectorModels[i]->oStarSelectorType = STAR_SELECTOR_SELECTED; } else { diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index edd9302a..2875683e 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -4022,8 +4022,8 @@ char gSmluaConstants[] = "" "COOP_OBJ_FLAG_NON_SYNC = (1 << 2)\n" "COOP_OBJ_FLAG_INITIALIZED = (1 << 3)\n" "VERSION_TEXT = 'beta'\n" -"VERSION_NUMBER = 34\n" -"MINOR_VERSION_NUMBER = 1\n" +"VERSION_NUMBER = 35\n" +"MINOR_VERSION_NUMBER = 0\n" "PATCH_VERSION_NUMBER = 0\n" "VERSION_REGION = 'JP'\n" "VERSION_REGION = 'EU'\n" diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index 1b166a46..eb3862cc 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -23663,6 +23663,24 @@ int smlua_func_get_object_list_from_behavior(lua_State* L) { return 1; } +int smlua_func_get_trajectory_length(lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 1) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "get_trajectory_length", 1, top); + return 0; + } + + Trajectory* trajectory = (Trajectory*)smlua_to_cpointer(L, 1, LVT_TRAJECTORY_P); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "get_trajectory_length"); return 0; } + + extern s32 get_trajectory_length(Trajectory* trajectory); + lua_pushinteger(L, get_trajectory_length(trajectory)); + + return 1; +} + int smlua_func_increment_velocity_toward_range(lua_State* L) { if (L == NULL) { return 0; } @@ -29058,16 +29076,18 @@ int smlua_func_exec_anim_sound_state(lua_State* L) { if (L == NULL) { return 0; } int top = lua_gettop(L); - if (top != 1) { - LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "exec_anim_sound_state", 1, top); + if (top != 2) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "exec_anim_sound_state", 2, top); return 0; } struct SoundState* soundStates = (struct SoundState*)smlua_to_cobject(L, 1, LOT_SOUNDSTATE); if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "exec_anim_sound_state"); return 0; } + u16 maxSoundStates = smlua_to_integer(L, 2); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "exec_anim_sound_state"); return 0; } - extern void exec_anim_sound_state(struct SoundState *soundStates); - exec_anim_sound_state(soundStates); + extern void exec_anim_sound_state(struct SoundState *soundStates, u16 maxSoundStates); + exec_anim_sound_state(soundStates, maxSoundStates); return 1; } @@ -30685,6 +30705,7 @@ void smlua_bind_functions_autogen(void) { //smlua_bind_function(L, "geo_update_layer_transparency", smlua_func_geo_update_layer_transparency); <--- UNIMPLEMENTED //smlua_bind_function(L, "geo_update_projectile_pos_from_parent", smlua_func_geo_update_projectile_pos_from_parent); <--- UNIMPLEMENTED smlua_bind_function(L, "get_object_list_from_behavior", smlua_func_get_object_list_from_behavior); + smlua_bind_function(L, "get_trajectory_length", smlua_func_get_trajectory_length); smlua_bind_function(L, "increment_velocity_toward_range", smlua_func_increment_velocity_toward_range); smlua_bind_function(L, "is_item_in_array", smlua_func_is_item_in_array); smlua_bind_function(L, "is_mario_moving_fast_or_in_air", smlua_func_is_mario_moving_fast_or_in_air); diff --git a/src/pc/lua/utils/smlua_model_utils.c b/src/pc/lua/utils/smlua_model_utils.c index 879dbcbd..2a045a20 100644 --- a/src/pc/lua/utils/smlua_model_utils.c +++ b/src/pc/lua/utils/smlua_model_utils.c @@ -585,6 +585,11 @@ u16 smlua_model_util_load_with_pool_and_cache_id(enum ModelExtendedId extId, str } } + if (pickLoadedId >= MAX_LOADED_GRAPH_NODES) { + LOG_ERROR("Could not find slot for extId - %u", extId); + return UNLOADED_ID; + } + // load bool resizePool = false; if (pool == NULL) { diff --git a/src/pc/lua/utils/smlua_obj_utils.c b/src/pc/lua/utils/smlua_obj_utils.c index 175681fe..e090403f 100644 --- a/src/pc/lua/utils/smlua_obj_utils.c +++ b/src/pc/lua/utils/smlua_obj_utils.c @@ -404,3 +404,23 @@ void set_whirlpools(f32 x, f32 y, f32 z, s16 strength, s16 area, s32 index) { gAreas[area].whirlpools[index]->pos[2] = z; gAreas[area].whirlpools[index]->strength = strength; } + +#ifdef DEVELOPMENT +void obj_randomize(struct Object* o) { + for (int i = 0; i < 80; i++) { + if (rand() % 10 < 5) { + o->rawData.asU32[i] = rand() % 10; + } else { + o->rawData.asU32[i] = rand(); + } + } + struct Object* objs[] = { NULL, gMarioStates[0].marioObj, o }; + if (rand()%4 > 0) { o->parentObj = objs[rand()%3]; } + if (rand()%4 > 0) { o->prevObj = objs[rand()%3]; } + if (rand()%4 > 0) { o->usingObj = objs[rand()%3]; } + + if (rand() % 10 < 5) { + o->oAction = rand() % 10; + } +} +#endif \ No newline at end of file diff --git a/src/pc/network/packets/packet_area.c b/src/pc/network/packets/packet_area.c index b2d61fe5..93789a62 100644 --- a/src/pc/network/packets/packet_area.c +++ b/src/pc/network/packets/packet_area.c @@ -103,7 +103,7 @@ void network_send_area(struct NetworkPlayer* toNp) { // TODO: move find model to a utility file/function // find model u32 model = 0; - for (s32 j = 0; j < 256; j++) { + for (s32 j = 0; j < MAX_LOADED_GRAPH_NODES; j++) { if (so->o->header.gfx.sharedChild == gLoadedGraphNodes[j]) { model = j; break;