From aedae64e8b5e1949daf6cec5b1c01ca91aa206ac Mon Sep 17 00:00:00 2001 From: Gregory Heskett Date: Tue, 30 Apr 2024 23:10:58 -0400 Subject: [PATCH] Remove destination warp node requirement (#788) Also add assertions for common warp crashes and remove the hardcoded get_mario_spawn_type table size --- src/engine/level_script.c | 2 -- src/game/area.c | 20 +++++++------------ src/game/area.h | 4 ++-- src/game/level_update.c | 42 +++++++++++++++++++++++++++++++-------- 4 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/engine/level_script.c b/src/engine/level_script.c index c7a47e6d6..c2a207d6f 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -523,8 +523,6 @@ static void level_cmd_create_warp_node(void) { warpNode->node.destArea = CMD_GET(u8, 4); warpNode->node.destNode = CMD_GET(u8, 5); - warpNode->object = NULL; - warpNode->next = gAreas[sCurrAreaIndex].warpNodes; gAreas[sCurrAreaIndex].warpNodes = warpNode; } diff --git a/src/game/area.c b/src/game/area.c index 1e99763f2..e383a1cf4 100644 --- a/src/game/area.c +++ b/src/game/area.c @@ -139,7 +139,7 @@ u32 get_mario_spawn_type(struct Object *obj) { s32 i; const BehaviorScript *behavior = virtual_to_segmented(SEGMENT_BEHAVIOR_DATA, obj->behavior); - for (i = 0; i < 20; i++) { + for (i = 0; i < ARRAY_COUNT(sWarpBhvSpawnTable); i++) { if (sWarpBhvSpawnTable[i] == behavior) { return sSpawnTypeFromWarpBhv[i]; } @@ -158,25 +158,20 @@ struct ObjectWarpNode *area_get_warp_node(u8 id) { return node; } -struct ObjectWarpNode *area_get_warp_node_from_params(struct Object *obj) { - return area_get_warp_node(GET_BPARAM2(obj->oBehParams)); -} - -void load_obj_warp_nodes(void) { - struct ObjectWarpNode *warpNode; +struct Object *get_destination_warp_object(u8 warpDestId) { struct Object *children = (struct Object *) gObjParentGraphNode.children; do { struct Object *obj = children; - if (obj->activeFlags != ACTIVE_FLAG_DEACTIVATED && get_mario_spawn_type(obj) != 0) { - warpNode = area_get_warp_node_from_params(obj); - if (warpNode != NULL) { - warpNode->object = obj; - } + u8 bparam2 = GET_BPARAM2(obj->oBehParams); + if (warpDestId == bparam2 && obj->activeFlags != ACTIVE_FLAG_DEACTIVATED && get_mario_spawn_type(obj) != MARIO_SPAWN_NONE) { + return obj; } } while ((children = (struct Object *) children->header.gfx.node.next) != (struct Object *) gObjParentGraphNode.children); + + return NULL; } void clear_areas(void) { @@ -251,7 +246,6 @@ void load_area(s32 index) { spawn_objects_from_info(0, gCurrentArea->objectSpawnInfos); } - load_obj_warp_nodes(); geo_call_global_function_nodes(&gCurrentArea->graphNode->node, GEO_CONTEXT_AREA_LOAD); } } diff --git a/src/game/area.h b/src/game/area.h index f6dd36100..c810fbb9e 100644 --- a/src/game/area.h +++ b/src/game/area.h @@ -16,8 +16,7 @@ struct WarpNode { struct ObjectWarpNode { /*0x00*/ struct WarpNode node; - /*0x04*/ struct Object *object; - /*0x08*/ struct ObjectWarpNode *next; + /*0x04*/ struct ObjectWarpNode *next; }; struct InstantWarp { @@ -185,6 +184,7 @@ void override_viewport_and_clip(Vp *a, Vp *b, u8 c, u8 d, u8 e); void print_intro_text(void); u32 get_mario_spawn_type(struct Object *obj); struct ObjectWarpNode *area_get_warp_node(u8 id); +struct Object *get_destination_warp_object(u8 warpDestId); void clear_areas(void); void clear_area_graph_nodes(void); void load_area(s32 index); diff --git a/src/game/level_update.c b/src/game/level_update.c index fc4938fd8..f222e7fbe 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -31,6 +31,7 @@ #include "puppycam2.h" #include "puppyprint.h" #include "level_commands.h" +#include "debug.h" #include "config.h" @@ -348,16 +349,24 @@ void set_mario_initial_action(struct MarioState *m, u32 spawnType, u32 actionArg } void init_mario_after_warp(void) { - struct ObjectWarpNode *spawnNode = area_get_warp_node(sWarpDest.nodeId); - u32 marioSpawnType = get_mario_spawn_type(spawnNode->object); + struct Object *object = get_destination_warp_object(sWarpDest.nodeId); + +#ifdef DEBUG_ASSERTIONS + if (!object) { + char errorMsg[40]; + sprintf(errorMsg, "No dest warp object found for: 0x%02X", sWarpDest.nodeId); + error(errorMsg); + } +#endif + u32 marioSpawnType = get_mario_spawn_type(object); if (gMarioState->action != ACT_UNINITIALIZED) { - gPlayerSpawnInfos[0].startPos[0] = (s16) spawnNode->object->oPosX; - gPlayerSpawnInfos[0].startPos[1] = (s16) spawnNode->object->oPosY; - gPlayerSpawnInfos[0].startPos[2] = (s16) spawnNode->object->oPosZ; + gPlayerSpawnInfos[0].startPos[0] = (s16) object->oPosX; + gPlayerSpawnInfos[0].startPos[1] = (s16) object->oPosY; + gPlayerSpawnInfos[0].startPos[2] = (s16) object->oPosZ; gPlayerSpawnInfos[0].startAngle[0] = 0; - gPlayerSpawnInfos[0].startAngle[1] = spawnNode->object->oMoveAngleYaw; + gPlayerSpawnInfos[0].startAngle[1] = object->oMoveAngleYaw; gPlayerSpawnInfos[0].startAngle[2] = 0; if (marioSpawnType == MARIO_SPAWN_DOOR_WARP) { @@ -372,8 +381,8 @@ void init_mario_after_warp(void) { init_mario(); set_mario_initial_action(gMarioState, marioSpawnType, sWarpDest.arg); - gMarioState->interactObj = spawnNode->object; - gMarioState->usedObj = spawnNode->object; + gMarioState->interactObj = object; + gMarioState->usedObj = object; } reset_camera(gCurrentArea->camera); @@ -569,6 +578,15 @@ void check_instant_warp(void) { s16 music_unchanged_through_warp(s16 arg) { struct ObjectWarpNode *warpNode = area_get_warp_node(arg); + +#ifdef DEBUG_ASSERTIONS + if (!warpNode) { + char errorMsg[40]; + sprintf(errorMsg, "No source warp node found for: 0x%02X", (u8) arg); + error(errorMsg); + } +#endif + s16 levelNum = warpNode->node.destLevel & 0x7F; s16 destArea = warpNode->node.destArea; @@ -896,6 +914,14 @@ void initiate_delayed_warp(void) { default: warpNode = area_get_warp_node(sSourceWarpNodeId); +#ifdef DEBUG_ASSERTIONS + if (!warpNode) { + char errorMsg[40]; + sprintf(errorMsg, "No source warp node found for: 0x%02X", (u8) sSourceWarpNodeId); + error(errorMsg); + } +#endif + initiate_warp(warpNode->node.destLevel & 0x7F, warpNode->node.destArea, warpNode->node.destNode, sDelayedWarpArg);