From 0fc9c95dbe6b6bda30fedfce2219fb21e240e77e Mon Sep 17 00:00:00 2001 From: Leaze Date: Sat, 11 Mar 2023 15:11:47 +0100 Subject: [PATCH] reset: implement quick-reset --- src/game/area.c | 11 +++++ src/game/area.h | 1 + src/game/level_update.c | 82 +++++++++++++++++++++++++++---- src/game/level_update.h | 1 + src/game/mario_actions_cutscene.c | 13 +++-- 5 files changed, 93 insertions(+), 15 deletions(-) diff --git a/src/game/area.c b/src/game/area.c index bca1ceaa..204e254d 100644 --- a/src/game/area.c +++ b/src/game/area.c @@ -251,6 +251,17 @@ void unload_area(void) { } } +void reload_objects(void) { + if (TRUE + || gCurrentArea != NULL && (gCurrentArea->flags & 0x01) + && gCurrentArea->index == gMarioSpawnInfo->areaIndex) { + unload_objects_from_area(0, gMarioSpawnInfo->activeAreaIndex); + + gCurrentArea->flags |= 0x01; + spawn_objects_from_info(0, gMarioSpawnInfo); + } +} + void load_mario_area(void) { stop_sounds_in_continuous_banks(); load_area(gMarioSpawnInfo->areaIndex); diff --git a/src/game/area.h b/src/game/area.h index 9141005b..3bb70c23 100644 --- a/src/game/area.h +++ b/src/game/area.h @@ -156,6 +156,7 @@ void clear_areas(void); void clear_area_graph_nodes(void); void load_area(s32 index); void unload_area(void); +void reload_objects(void); void load_mario_area(void); void unload_mario_area(void); void change_area(s32 index); diff --git a/src/game/level_update.c b/src/game/level_update.c index 71707666..c5bfee33 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -39,6 +39,7 @@ #define WARP_TYPE_CHANGE_LEVEL 1 #define WARP_TYPE_CHANGE_AREA 2 #define WARP_TYPE_SAME_AREA 3 +#define WARP_TYPE_RELOAD_LEVEL 4 #define WARP_NODE_F0 0xF0 #define WARP_NODE_DEATH 0xF1 @@ -164,6 +165,8 @@ s16 sCurrPlayMode; u16 D_80339ECA; s16 sTransitionTimer; void (*sTransitionUpdate)(s16 *); +s16 recentWarpSourceNodeId = -1; +struct WarpDest recentWarpDest; struct WarpDest sWarpDest; s16 D_80339EE0; s16 sDelayedWarpOp; @@ -220,6 +223,19 @@ u32 pressed_pause(void) { return FALSE; } +u32 pressed_reset(void) { + u32 dialogActive = get_dialog_id() >= 0; + // TODO prevent resetting during star animations in speedrun mode + u32 intangible = (gMarioState->action & ACT_FLAG_INTANGIBLE) != 0; + + if (!gWarpTransition.isActive && sDelayedWarpOp == WARP_OP_NONE + && (gPlayer1Controller->buttonPressed & L_TRIG)) { + return TRUE; + } + + return FALSE; +} + void set_play_mode(s16 playMode) { sCurrPlayMode = playMode; D_80339ECA = 0; @@ -387,10 +403,15 @@ void init_mario_after_warp(void) { init_door_warp(&gPlayerSpawnInfos[0], sWarpDest.arg); } - if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL || sWarpDest.type == WARP_TYPE_CHANGE_AREA) { + if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL || sWarpDest.type == WARP_TYPE_CHANGE_AREA + || sWarpDest.type == WARP_TYPE_RELOAD_LEVEL) { gPlayerSpawnInfos[0].areaIndex = sWarpDest.areaIdx; load_mario_area(); } + if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL || sWarpDest.type == WARP_TYPE_RELOAD_LEVEL) { + gMarioState->numCoins = 0; + gHudDisplay.coins = 0; + } init_mario(); set_mario_initial_action(gMarioState, marioSpawnType, sWarpDest.arg); @@ -618,7 +639,7 @@ s16 music_changed_through_warp(s16 arg) { /** * Set the current warp type and destination level/area/node. */ -void initiate_warp(s16 destLevel, s16 destArea, s16 destWarpNode, s32 arg3) { +void initiate_warp(s16 destLevel, s16 destArea, s16 destWarpNode, s32 arg3, bool reloadOnSameArea) { if (destWarpNode >= WARP_NODE_CREDITS_MIN) { sWarpDest.type = WARP_TYPE_CHANGE_LEVEL; } else if (destLevel != gCurrLevelNum) { @@ -626,13 +647,18 @@ void initiate_warp(s16 destLevel, s16 destArea, s16 destWarpNode, s32 arg3) { } else if (destArea != gCurrentArea->index) { sWarpDest.type = WARP_TYPE_CHANGE_AREA; } else { - sWarpDest.type = WARP_TYPE_SAME_AREA; + if (reloadOnSameArea) { + sWarpDest.type = WARP_TYPE_CHANGE_LEVEL; + } else { + sWarpDest.type = WARP_TYPE_SAME_AREA; + } } sWarpDest.levelNum = destLevel; sWarpDest.areaIdx = destArea; sWarpDest.nodeId = destWarpNode; sWarpDest.arg = arg3; + recentWarpDest = sWarpDest; } // From Surface 0xD3 to 0xFC @@ -676,7 +702,8 @@ void initiate_painting_warp(void) { sWarpCheckpointActive = check_warp_checkpoint(&warpNode); } - initiate_warp(warpNode.destLevel & 0x7F, warpNode.destArea, warpNode.destNode, 0); + initiate_warp(warpNode.destLevel & 0x7F, warpNode.destArea, warpNode.destNode, 0, + FALSE); check_if_should_set_warp_checkpoint(&warpNode); play_transition_after_delay(WARP_TRANSITION_FADE_INTO_COLOR, 30, 255, 255, 255, 45); @@ -727,6 +754,12 @@ s16 level_trigger_warp(struct MarioState *m, s32 warpOp) { play_transition(WARP_TRANSITION_FADE_INTO_COLOR, 0x3C, 0x00, 0x00, 0x00); break; + case WARP_OP_RELOAD: + sDelayedWarpTimer = 4; + sSourceWarpNodeId = WARP_NODE_F0; + play_transition(WARP_TRANSITION_FADE_INTO_COLOR, 0x3C, 0x00, 0x00, 0x00); + break; + case WARP_OP_STAR_EXIT: sDelayedWarpTimer = 32; sSourceWarpNodeId = WARP_NODE_F0; @@ -814,6 +847,7 @@ s16 level_trigger_warp(struct MarioState *m, s32 warpOp) { if (val04 && gCurrDemoInput == NULL) { fadeout_music((3 * sDelayedWarpTimer / 2) * 8 - 2); } + recentWarpSourceNodeId = sSourceWarpNodeId; } return sDelayedWarpTimer; @@ -857,7 +891,7 @@ void initiate_delayed_warp(void) { case WARP_OP_CREDITS_START: gCurrCreditsEntry = &sCreditsSequence[0]; initiate_warp(gCurrCreditsEntry->levelNum, gCurrCreditsEntry->areaIndex, - WARP_NODE_CREDITS_START, 0); + WARP_NODE_CREDITS_START, 0, FALSE); break; case WARP_OP_CREDITS_NEXT: @@ -872,14 +906,19 @@ void initiate_delayed_warp(void) { } initiate_warp(gCurrCreditsEntry->levelNum, gCurrCreditsEntry->areaIndex, - destWarpNode, 0); + destWarpNode, 0, FALSE); + break; + + case WARP_OP_RELOAD: + initiate_warp(recentWarpDest.levelNum & 0x7F, recentWarpDest.areaIdx, + recentWarpDest.nodeId, recentWarpDest.arg, TRUE); break; default: warpNode = area_get_warp_node(sSourceWarpNodeId); initiate_warp(warpNode->node.destLevel & 0x7F, warpNode->node.destArea, - warpNode->node.destNode, sDelayedWarpArg); + warpNode->node.destNode, sDelayedWarpArg, TRUE); check_if_should_set_warp_checkpoint(&warpNode->node); if (sWarpDest.type != WARP_TYPE_CHANGE_LEVEL) { @@ -994,13 +1033,15 @@ s32 play_mode_normal(void) { initiate_painting_warp(); initiate_delayed_warp(); - // If either initiate_painting_warp or initiate_delayed_warp initiated a - // warp, change play mode accordingly. if (sCurrPlayMode == PLAY_MODE_NORMAL) { if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL) { set_play_mode(PLAY_MODE_CHANGE_LEVEL); } else if (sTransitionTimer != 0) { set_play_mode(PLAY_MODE_CHANGE_AREA); + } else if (pressed_reset()) { + if (recentWarpSourceNodeId >= 0) { + level_trigger_warp(gMarioState, WARP_OP_RELOAD); + } } else if (pressed_pause()) { lower_background_noise(1); #if ENABLE_RUMBLE @@ -1025,7 +1066,7 @@ s32 play_mode_paused(void) { if (gDebugLevelSelect) { fade_into_special_warp(-9, 1); } else { - initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0); + initiate_warp(LEVEL_CASTLE, 1, 0x0A, 0, FALSE); // TODO set pause menu warp here fade_into_special_warp(0, 0); gSavedCourseNum = COURSE_NONE; } @@ -1258,10 +1299,31 @@ s32 lvl_init_from_save_file(UNUSED s16 arg0, s32 levelNum) { break; } #endif + recentWarpDest.type = WARP_TYPE_NOT_WARPING; sWarpDest.type = WARP_TYPE_NOT_WARPING; sDelayedWarpOp = WARP_OP_NONE; gNeverEnteredCastle = !save_file_exists(gCurrSaveFileNum - 1); + // TODO maybe do that independent of level? + if (gCurrLevelNum == LEVEL_CASTLE) + return 0; + if (gCurrLevelNum == LEVEL_BOB) + return 0; + if (gCurrLevelNum == LEVEL_HMC) + return 0; + if (gCurrLevelNum == LEVEL_LLL) + return 0; + if (gCurrLevelNum == LEVEL_SSL) + return 0; + if (gCurrLevelNum == LEVEL_BBH) + return 0; + if (gCurrLevelNum == LEVEL_CCM) + return 0; + if (gCurrLevelNum == LEVEL_JRB) + return 0; + if (gCurrLevelNum == LEVEL_WF) + return 0; + gCurrLevelNum = levelNum; gCurrCourseNum = COURSE_NONE; gSavedCourseNum = COURSE_NONE; diff --git a/src/game/level_update.h b/src/game/level_update.h index b55d2737..c020d5d1 100644 --- a/src/game/level_update.h +++ b/src/game/level_update.h @@ -17,6 +17,7 @@ #define WARP_OP_WARP_DOOR 0x03 #define WARP_OP_WARP_OBJECT 0x04 #define WARP_OP_TELEPORT 0x05 +#define WARP_OP_RELOAD 0x06 #define WARP_OP_STAR_EXIT 0x11 #define WARP_OP_DEATH 0x12 #define WARP_OP_WARP_FLOOR 0x13 diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index ab797405..c31dc95d 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -638,6 +638,7 @@ void general_star_dance_handler(struct MarioState *m, s32 isInWater) { } s32 act_star_dance(struct MarioState *m) { + // TODO end timer m->faceAngle[1] = m->area->camera->yaw; set_mario_animation(m, m->actionState == 2 ? MARIO_ANIM_RETURN_FROM_STAR_DANCE : MARIO_ANIM_STAR_DANCE); @@ -650,6 +651,7 @@ s32 act_star_dance(struct MarioState *m) { } s32 act_star_dance_water(struct MarioState *m) { + // TODO end timer m->faceAngle[1] = m->area->camera->yaw; set_mario_animation(m, m->actionState == 2 ? MARIO_ANIM_RETURN_FROM_WATER_STAR_DANCE : MARIO_ANIM_WATER_STAR_DANCE); @@ -1173,19 +1175,20 @@ s32 act_death_exit(struct MarioState *m) { return FALSE; } +/** (Ab-)used as a life-restoring level entry with no control downtime **/ s32 act_unused_death_exit(struct MarioState *m) { + // TODO begin timer + if (launch_mario_until_land(m, ACT_FREEFALL_LAND_STOP, MARIO_ANIM_GENERAL_FALL, 0.0f)) { #ifdef VERSION_JP play_sound(SOUND_MARIO_OOOF, m->marioObj->header.gfx.cameraToObject); #else play_sound(SOUND_MARIO_OOOF2, m->marioObj->header.gfx.cameraToObject); #endif - m->numLives--; - // restore 7.75 units of health - m->healCounter = 31; } - // one unit of health - m->health = 0x0100; + // restore 7.75 units of health + m->healCounter = 31; + m->health = 0x880; return FALSE; }