QOL Redone: Zelda style level select

This commit is contained in:
AloXado320 2022-05-30 00:24:09 -05:00
parent 529ab3e494
commit 81891375ca
9 changed files with 315 additions and 2 deletions

View file

@ -19,6 +19,11 @@
#define HAS_FRAMEBUFFER 0
#endif
// --| Quality of life redone files
/// Adds Zelda level select used on OOT, MM and Animal Forest
/// Credits: (AloXado320)
#define ZELDA_STYLE_LEVEL_SELECT (0 || QOL_REDONE)
// --| Quality of life features
/// Adds an extra Z button trig for some menu files (Originally defined in EU)
/// Credits: (Original Devs)

View file

@ -10,6 +10,9 @@
#include "game/paintings.h"
#include "menu/debug_level_select.h"
#include "menu/intro_geo.h"
#if ZELDA_STYLE_LEVEL_SELECT
#include "menu/title_screen.h"
#endif
#include "make_const_nonconst.h"
@ -146,6 +149,7 @@ const GeoLayout intro_geo_000414[] = {
GEO_CAMERA_FRUSTUM(45, 128, 16384),
GEO_OPEN_NODE(),
GEO_CAMERA(0, 0, 0, 1200, 0, 0, 0, 0x00000000),
#if !ZELDA_STYLE_LEVEL_SELECT
GEO_OPEN_NODE(),
GEO_TRANSLATE_NODE_WITH_DL(LAYER_OPAQUE, -230, 300, 0, debug_level_select_dl_07000858),
GEO_TRANSLATE_NODE_WITH_DL(LAYER_OPAQUE, -120, 300, 0, debug_level_select_dl_07001100),
@ -158,8 +162,15 @@ const GeoLayout intro_geo_000414[] = {
GEO_TRANSLATE_NODE_WITH_DL(LAYER_OPAQUE, 180, 100, 0, debug_level_select_dl_070059F8),
GEO_TRANSLATE_NODE_WITH_DL(LAYER_OPAQUE, 300, 100, 0, debug_level_select_dl_070063B0),
GEO_CLOSE_NODE(),
#endif
GEO_CLOSE_NODE(),
GEO_CLOSE_NODE(),
#if ZELDA_STYLE_LEVEL_SELECT
GEO_ZBUFFER(0),
GEO_OPEN_NODE(),
GEO_ASM(0, geo_debug_level_select_strings),
GEO_CLOSE_NODE(),
#endif
GEO_CLOSE_NODE(),
GEO_END(),
};

View file

@ -154,6 +154,9 @@ const LevelScript level_intro_entry_4[] = {
FIXED_LOAD(/*loadAddr*/ _goddardSegmentStart, /*romStart*/ _goddardSegmentRomStart, /*romEnd*/ _goddardSegmentRomEnd),
#endif
ALLOC_LEVEL_POOL(),
#if ZELDA_STYLE_LEVEL_SELECT
CALL(/*arg*/ 0, /*func*/ lvl_init_intro_level_select),
#endif
AREA(/*index*/ 1, intro_geo_000414),
END_AREA(),

View file

@ -195,7 +195,7 @@ s16 get_str_x_pos_from_center_custom_ascii(s16 lutType, s16 centerPos, char *str
// return the x position of where the string starts as half the string's
// length from the position of the provided center.
return (centerPos - (spacesWidth / scale));
return (centerPos - (spacesWidth / 2.0));
}
/**

View file

@ -24,6 +24,9 @@ s16 get_hud_str_width(u8 *str);
s16 get_hud_str_width_ascii(char *str);
s16 get_string_width_ascii(char *str);
s16 get_str_x_pos_from_center_custom_hex(s16 lutType, s16 centerPos, u8 *strHex, u8 useScale, f32 scale);
s16 get_str_x_pos_from_center_custom_ascii(s16 lutType, s16 centerPos, char *strAscii, u8 useScale, f32 scale);
void print_generic_string_ascii(s16 x, s16 y, const char *str);
void print_generic_string_detail(s16 x, s16 y, u8 *text, u8 r, u8 g, u8 b, u8 a, s8 hasShadow, s8 shadowPad);
void print_generic_string_ascii_detail(s16 x, s16 y, const char *str, u8 r, u8 g, u8 b, u8 a, s8 hasShadow, s8 shadowPad);

View file

@ -0,0 +1,276 @@
/*
* Redone description:
* A backported version of the level select used in Zelda-engine games released on N64.
* Adapted to Super Mario 64 by AloXado320, replaces old debug level select.
* Props to ZeldaRET for decompiling the code (z_select.c).
*/
#include "game/segment2.h"
#include "game/ingame_menu.h"
#include "extras/draw_util.h"
#define MAX_PAGE_STRINGS 16
#define PAGE_DOWN_STOPS_MAX (LEVEL_MAX / MAX_PAGE_STRINGS)
struct ZDebugLevelSelect {
s32 count;
s32 currentScene;
s32 pageDownIndex; // Index of pageDownStops
s32 pageDownStops[PAGE_DOWN_STOPS_MAX];
s32 topDisplayedScene; // The scene which is currently at the top of the screen
s32 verticalInputAccumulator;
s32 verticalInput;
s32 timerUp;
s32 timerDown;
s32 lockUp;
s32 lockDown;
s32 refreshRate;
};
// Duplicate copy to initiate struct
struct ZDebugLevelSelect gZDbgLevelSelectInit;
struct ZDebugLevelSelect *gZDbgLevelSelect = &gZDbgLevelSelectInit;
void print_debug_level_select_menu(struct ZDebugLevelSelect *this) {
s32 scene;
s32 i;
char *name;
s32 xPos;
char *chrTemp;
u8 strScene[4];
gDPSetEnvColor(gDisplayListHead++, 255, 155, 150, 255);
chrTemp = "SUPER MARIO LEVEL SELECT";
xPos = get_str_x_pos_from_center_custom_ascii(LUT_TYPE_STR_ASCII, SCREEN_WIDTH / 2, chrTemp, FALSE, 0);
print_generic_string_ascii(xPos, 210, chrTemp);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
for (i = 0; i < MAX_PAGE_STRINGS; i++) {
scene = (this->topDisplayedScene + i + this->count) % this->count;
int_to_str(scene + 1, strScene);
if (scene == this->currentScene) {
gDPSetEnvColor(gDisplayListHead++, 255, 126, 0, 255);
} else {
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
}
name = gLevelSelectStageNames[scene];
if (name == NULL) {
name = "**Null**";
}
print_generic_string(100, 190 - i * 12, strScene);
print_generic_string_ascii(120, 190 - i * 12, name);
}
}
void print_debug_level_select_settings(void) {
u8 strSaveNum[4];
u8 strActNum[4];
char *chrTemp;
s16 saveNum = gCurrSaveFileNum;
s16 actNum = gCurrActNum;
int_to_str(saveNum, strSaveNum);
int_to_str(actNum, strActNum);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
chrTemp = "Save File: ";
print_generic_string_ascii(20, 40, chrTemp);
print_generic_string(20 + get_string_width_ascii(chrTemp), 40, strSaveNum);
chrTemp = "Level Act: ";
print_generic_string_ascii(20, 20, chrTemp);
print_generic_string(20 + get_string_width_ascii(chrTemp), 20, strActNum);
}
void print_debug_level_select_strings(struct ZDebugLevelSelect *this) {
create_dl_ortho_matrix();
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
print_debug_level_select_menu(this);
print_debug_level_select_settings();
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
}
Gfx *geo_debug_level_select_strings(s16 callContext, UNUSED struct GraphNode *node, UNUSED Mat4 mtx) {
if (callContext == GEO_CONTEXT_RENDER) {
print_debug_level_select_strings(gZDbgLevelSelect);
}
return NULL;
}
void debug_level_select_update(struct ZDebugLevelSelect *this) {
if (this->verticalInputAccumulator == 0) {
gCurrLevelNum = this->currentScene + 1;
if (gPlayer1Controller->buttonPressed & B_BUTTON) {
gCurrActNum++;
if (gCurrActNum > 6) {
gCurrActNum = 1;
}
}
if (gPlayer1Controller->buttonPressed & Z_TRIG) {
gCurrSaveFileNum++;
if (gCurrSaveFileNum > 4) {
gCurrSaveFileNum = 1;
}
}
if (gPlayer1Controller->buttonPressed & U_JPAD) {
if (this->lockUp == TRUE) {
this->timerUp = 0;
}
if (this->timerUp == 0) {
this->timerUp = 20;
this->lockUp = TRUE;
play_sound(SOUND_GENERAL_LEVEL_SELECT_CHANGE, gGlobalSoundSource);
this->verticalInput = this->refreshRate;
}
}
if (gPlayer1Controller->buttonDown & U_JPAD && this->timerUp == 0) {
play_sound(SOUND_GENERAL_LEVEL_SELECT_CHANGE, gGlobalSoundSource);
this->verticalInput = this->refreshRate * 3;
}
if (gPlayer1Controller->buttonPressed & D_JPAD) {
if (this->lockDown == TRUE) {
this->timerDown = 0;
}
if (this->timerDown == 0) {
this->timerDown = 20;
this->lockDown = TRUE;
play_sound(SOUND_GENERAL_LEVEL_SELECT_CHANGE, gGlobalSoundSource);
this->verticalInput = -this->refreshRate;
}
}
if (gPlayer1Controller->buttonDown & D_JPAD && this->timerDown == 0) {
play_sound(SOUND_GENERAL_LEVEL_SELECT_CHANGE, gGlobalSoundSource);
this->verticalInput = -this->refreshRate * 3;
}
if ((gPlayer1Controller->buttonPressed & L_JPAD) || (gPlayer1Controller->buttonDown & L_JPAD)) {
play_sound(SOUND_GENERAL_LEVEL_SELECT_CHANGE, gGlobalSoundSource);
this->verticalInput = this->refreshRate;
}
if ((gPlayer1Controller->buttonPressed & R_JPAD) || (gPlayer1Controller->buttonDown & R_JPAD)) {
play_sound(SOUND_GENERAL_LEVEL_SELECT_CHANGE, gGlobalSoundSource);
this->verticalInput = -this->refreshRate;
}
}
if (gPlayer1Controller->buttonPressed & R_TRIG) {
this->pageDownIndex++;
this->pageDownIndex =
(this->pageDownIndex + ARRAY_COUNT(this->pageDownStops)) % ARRAY_COUNT(this->pageDownStops);
this->currentScene = this->topDisplayedScene = this->pageDownStops[this->pageDownIndex];
}
this->verticalInputAccumulator += this->verticalInput;
if (this->verticalInputAccumulator < -7) {
this->verticalInput = 0;
this->verticalInputAccumulator = 0;
this->currentScene++;
this->currentScene = (this->currentScene + this->count) % this->count;
if (this->currentScene == ((this->topDisplayedScene + this->count + MAX_PAGE_STRINGS) % this->count)) {
this->topDisplayedScene++;
this->topDisplayedScene = (this->topDisplayedScene + this->count) % this->count;
}
}
if (this->verticalInputAccumulator > 7) {
this->verticalInput = 0;
this->verticalInputAccumulator = 0;
if (this->currentScene == this->topDisplayedScene) {
this->topDisplayedScene -= 2;
this->topDisplayedScene = (this->topDisplayedScene + this->count) % this->count;
}
this->currentScene--;
this->currentScene = (this->currentScene + this->count) % this->count;
if (this->currentScene == ((this->topDisplayedScene + this->count) % this->count)) {
this->topDisplayedScene--;
this->topDisplayedScene = (this->topDisplayedScene + this->count) % this->count;
}
}
this->currentScene = (this->currentScene + this->count) % this->count;
this->topDisplayedScene = (this->topDisplayedScene + this->count) % this->count;
if (this->timerUp != 0) {
this->timerUp--;
}
if (this->timerUp == 0) {
this->lockUp = FALSE;
}
if (this->timerDown != 0) {
this->timerDown--;
}
if (this->timerDown == 0) {
this->lockDown = FALSE;
}
}
s32 lvl_init_intro_level_select(UNUSED s32 arg, UNUSED s32 unused) {
s16 i;
gCurrSaveFileNum = 1;
gCurrActNum = 1;
for (i = 0; i < ARRAY_COUNT(gZDbgLevelSelect->pageDownStops); i++) {
gZDbgLevelSelect->pageDownStops[i] = MAX_PAGE_STRINGS * i;
}
gZDbgLevelSelect->count = ARRAY_COUNT(gLevelSelectStageNames);
gZDbgLevelSelect->verticalInputAccumulator = 0;
gZDbgLevelSelect->verticalInput = 0;
gZDbgLevelSelect->timerUp = 0;
gZDbgLevelSelect->timerDown = 0;
gZDbgLevelSelect->lockUp = 0;
gZDbgLevelSelect->lockDown = 0;
gZDbgLevelSelect->currentScene = gCurrLevelNum - 1;
gZDbgLevelSelect->topDisplayedScene = gCurrLevelNum - 1;
gZDbgLevelSelect->pageDownIndex = 0;
gZDbgLevelSelect->refreshRate = 1;
return 0;
}
s16 intro_level_select(void) {
debug_level_select_update(gZDbgLevelSelect);
// Resets the game and disables level select
if (gPlayer1Controller->buttonDown == (A_BUTTON | L_TRIG | R_TRIG)) {
play_sound(SOUND_MENU_ENTER_HOLE, gGlobalSoundSource);
gDebugLevelSelect = FALSE;
return -1;
}
// Starts level selected
if (gPlayer1Controller->buttonPressed & (A_BUTTON | START_BUTTON)) {
play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource);
return gCurrLevelNum;
}
return 0;
}

View file

@ -0,0 +1,5 @@
#pragma once
Gfx *geo_debug_level_select_strings(s16 callContext, UNUSED struct GraphNode *node, UNUSED Mat4 mtx);
s32 lvl_init_intro_level_select(UNUSED s32 arg, UNUSED s32 unused);

View file

@ -78,6 +78,9 @@ s32 run_level_id_or_demo(s32 level) {
return level;
}
#if ZELDA_STYLE_LEVEL_SELECT
#include "extras/redone/title_screen.inc.c"
#else
/**
* Level select intro function, updates the selected stage
* count if an input was received. signals the stage to be started
@ -143,6 +146,7 @@ s16 intro_level_select(void) {
}
return 0;
}
#endif
#ifdef GODDARD_MFACE
/**

View file

@ -4,8 +4,10 @@
#include <PR/ultratypes.h>
#include "macros.h"
#include "config.h"
extern char gLevelSelectStageNames[][16];
extern char gLevelSelectStageNames[64][16];
enum LevelScriptIntroArgs {
LVL_INTRO_PLAY_ITS_A_ME_MARIO,
LVL_INTRO_REGULAR,
@ -13,6 +15,10 @@ enum LevelScriptIntroArgs {
LVL_INTRO_LEVEL_SELECT
};
#if ZELDA_STYLE_LEVEL_SELECT
#include "extras/redone/title_screen.inc.h"
#endif
s32 lvl_intro_update(s16 arg, UNUSED s32 unusedArg);
#endif // TITLE_SCREEN_H