Ported the rest of DynOS, but left the options menu disabled

This commit is contained in:
MysterD 2022-03-10 01:18:53 -08:00
parent b3ed387711
commit f92857704d
17 changed files with 1457 additions and 40 deletions

View file

@ -10,9 +10,6 @@ void dynos_update_opt (void *pad);
s32 dynos_gfx_import_texture (void **output, void *ptr, s32 tile, void *grapi, void **hashmap, void *pool, s32 *poolpos, s32 poolsize);
void dynos_gfx_swap_animations(void *ptr);
#ifdef COOP
bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct);
#endif
#endif
#endif

View file

@ -616,7 +616,6 @@ void DynOS_ReturnToMainMenu();
// Opt
//
#ifndef COOP
s32 DynOS_Opt_GetValue(const String &aName);
void DynOS_Opt_SetValue(const String &aName, s32 aValue);
void DynOS_Opt_AddAction(const String &aFuncName, bool (*aFuncPtr)(const char *), bool aOverwrite);
@ -629,7 +628,6 @@ void DynOS_Opt_LoadConfig(DynosOption *aMenu);
void DynOS_Opt_SaveConfig(DynosOption *aMenu);
void DynOS_Opt_DrawMenu(DynosOption *aCurrentOption, DynosOption *aCurrentMenu, DynosOption *aOptionsMenu, DynosOption *aDynosMenu);
void DynOS_Opt_DrawPrompt(DynosOption *aCurrentMenu, DynosOption *aOptionsMenu, DynosOption *aDynosMenu);
#endif
//
// Gfx

View file

@ -21,10 +21,4 @@ void dynos_gfx_swap_animations(void *ptr) {
return DynOS_Gfx_SwapAnimations(ptr);
}
#ifdef COOP
bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct) {
return DynOS_Warp_ToLevel(aLevel, aArea, aAct);
}
#endif
}

10
data/dynos_coop.c.h Normal file
View file

@ -0,0 +1,10 @@
#ifdef COOP
#ifndef DYNOS_COOP_C_H
#define DYNOS_COOP_C_H
#ifndef __cplusplus
bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct);
#endif
#endif
#endif

10
data/dynos_coop_c.cpp Normal file
View file

@ -0,0 +1,10 @@
#ifdef COOP
#include "dynos.cpp.h"
extern "C" {
bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct) {
return DynOS_Warp_ToLevel(aLevel, aArea, aAct);
}
}
#endif

View file

@ -107,6 +107,7 @@ void DynOS_Gfx_Update() {
const Array<PackData *> &pDynosPacks = DynOS_Gfx_GetPacks();
for (s32 i = 0; i != pDynosPacks.Count(); ++i) {
#ifdef COOP
// TODO: needs to be adjusted from djui
_Enabled.Add(true);
#else
_Enabled.Add(DynOS_Opt_GetValue(String("dynos_pack_%d", i)));

View file

@ -3,9 +3,7 @@ extern "C" {
#include "sm64.h"
#include "level_commands.h"
#include "game/level_update.h"
#ifndef COOP
#include "game/options_menu.h"
#endif
#include "game/object_list_processor.h"
extern s16 gMenuMode;
extern s8 gDialogBoxState;
@ -19,9 +17,7 @@ extern void omm_opt_init();
//
void DynOS_ReturnToMainMenu() {
#ifndef COOP
optmenu_toggle();
#endif
level_set_transition(0, NULL);
gDialogBoxState = 0;
gMenuMode = -1;
@ -33,18 +29,10 @@ void DynOS_ReturnToMainMenu() {
//
DYNOS_AT_STARTUP void DynOS_Init() {
#ifdef COOP
Array<String> _Packs = DynOS_Gfx_Init();
if (_Packs.Count() == 0) {
return;
}
#else
#ifdef OMM_DEFINES_H
omm_opt_init();
#endif
DynOS_Opt_Init();
#endif
}
//
@ -57,9 +45,7 @@ void DynOS_UpdateOpt(void *aPad) {
DynOS_Warp_SetParam(gCurrLevelNum, -1);
sDynosIsLevelEntry = false;
}
#ifndef COOP
DynOS_Opt_Update((OSContPad *) aPad);
#endif
gPrevFrameObjectCount = 0;
}

748
data/dynos_opt.cpp Normal file
View file

@ -0,0 +1,748 @@
#include "dynos.cpp.h"
extern "C" {
#include "pc/configfile.h"
#include "audio/external.h"
#include "game/game_init.h"
#include "pc/controller/controller_keyboard.h"
#ifdef BETTERCAMERA
#include "game/bettercamera.h"
#endif
}
//
// Data
//
static DynosOption *sPrevOpt = NULL;
static DynosOption *sDynosMenu = NULL;
static DynosOption *sOptionsMenu = NULL;
static DynosOption *sCurrentMenu = NULL;
static DynosOption *sCurrentOpt = NULL;
extern s32 sBindingState;
//
// Action list
//
typedef bool (*DynosActionFunction)(const char *);
struct DynosAction : NoCopy {
String mFuncName;
DynosActionFunction mAction;
};
STATIC_STORAGE(Array<DynosAction *>, DynosActions);
#define sDynosActions __DynosActions()
static DynosActionFunction DynOS_Opt_GetAction(const String& aFuncName) {
for (auto &_DynosAction : sDynosActions) {
if (_DynosAction->mFuncName == aFuncName) {
return _DynosAction->mAction;
}
}
return NULL;
}
void DynOS_Opt_AddAction(const String& aFuncName, bool (*aFuncPtr)(const char *), bool aOverwrite) {
for (auto &_DynosAction : sDynosActions) {
if (_DynosAction->mFuncName == aFuncName) {
if (aOverwrite) {
_DynosAction->mAction = aFuncPtr;
}
return;
}
}
DynosAction *_DynosAction = New<DynosAction>();
_DynosAction->mFuncName = aFuncName;
_DynosAction->mAction = aFuncPtr;
sDynosActions.Add(_DynosAction);
}
//
// Constructors
//
static DynosOption *DynOS_Opt_GetExistingOption(DynosOption *aOpt, const String &aName) {
while (aOpt) {
if (aOpt->mName == aName) {
return aOpt;
}
if (aOpt->mType == DOPT_SUBMENU) {
DynosOption *_Opt = DynOS_Opt_GetExistingOption(aOpt->mSubMenu.mChild, aName);
if (_Opt) {
return _Opt;
}
}
aOpt = aOpt->mNext;
}
return NULL;
}
static DynosOption *DynOS_Opt_NewOption(const String &aName, const String &aConfigName, const String &aLabel, const String &aTitle) {
// Check if the option already exists
static DynosOption sDummyOpt;
if (DynOS_Opt_GetExistingOption(sDynosMenu, aName)) {
return &sDummyOpt;
}
// Create a new option
DynosOption *_Opt = New<DynosOption>();
_Opt->mName = aName;
_Opt->mConfigName = aConfigName;
_Opt->mLabel = { aLabel, NULL };
_Opt->mTitle = { aTitle, NULL };
_Opt->mDynos = true;
if (sPrevOpt == NULL) { // The very first option
_Opt->mPrev = NULL;
_Opt->mNext = NULL;
_Opt->mParent = NULL;
sDynosMenu = _Opt;
} else {
if (sPrevOpt->mType == DOPT_SUBMENU && sPrevOpt->mSubMenu.mEmpty) { // First option of a sub-menu
_Opt->mPrev = NULL;
_Opt->mNext = NULL;
_Opt->mParent = sPrevOpt;
sPrevOpt->mSubMenu.mChild = _Opt;
sPrevOpt->mSubMenu.mEmpty = false;
} else {
_Opt->mPrev = sPrevOpt;
_Opt->mNext = NULL;
_Opt->mParent = sPrevOpt->mParent;
sPrevOpt->mNext = _Opt;
}
}
sPrevOpt = _Opt;
return _Opt;
}
static void DynOS_Opt_EndSubMenu() {
if (sPrevOpt && sPrevOpt->mParent) {
if (sPrevOpt->mType == DOPT_SUBMENU && sPrevOpt->mSubMenu.mEmpty) { // ENDMENU command following a SUBMENU command
sPrevOpt->mSubMenu.mEmpty = false;
} else {
sPrevOpt = sPrevOpt->mParent;
}
}
}
static void DynOS_Opt_CreateSubMenu(const String &aName, const String &aLabel, const String &aTitle) {
DynosOption *_Opt = DynOS_Opt_NewOption(aName, "", aLabel, aTitle);
_Opt->mType = DOPT_SUBMENU;
_Opt->mSubMenu.mChild = NULL;
_Opt->mSubMenu.mEmpty = true;
}
static void DynOS_Opt_CreateToggle(const String &aName, const String &aConfigName, const String &aLabel, s32 aValue) {
DynosOption *_Opt = DynOS_Opt_NewOption(aName, aConfigName, aLabel, aLabel);
_Opt->mType = DOPT_TOGGLE;
_Opt->mToggle.mTog = New<bool>();
*_Opt->mToggle.mTog = (bool) aValue;
}
static void DynOS_Opt_CreateScroll(const String &aName, const String &aConfigName, const String &aLabel, s32 aMin, s32 aMax, s32 aStep, s32 aValue) {
DynosOption *_Opt = DynOS_Opt_NewOption(aName, aConfigName, aLabel, aLabel);
_Opt->mType = DOPT_SCROLL;
_Opt->mScroll.mMin = aMin;
_Opt->mScroll.mMax = aMax;
_Opt->mScroll.mStep = aStep;
_Opt->mScroll.mValue = New<s32>();
*_Opt->mScroll.mValue = aValue;
}
static void DynOS_Opt_CreateChoice(const String &aName, const String &aConfigName, const String &aLabel, const Array<String>& aChoices, s32 aValue) {
DynosOption *_Opt = DynOS_Opt_NewOption(aName, aConfigName, aLabel, aLabel);
_Opt->mType = DOPT_CHOICE;
_Opt->mChoice.mIndex = New<s32>();
*_Opt->mChoice.mIndex = aValue;
for (const auto &_Choice : aChoices) {
_Opt->mChoice.mChoices.Add({ _Choice, NULL });
}
}
static void DynOS_Opt_CreateButton(const String &aName, const String &aLabel, const String& aFuncName) {
DynosOption *_Opt = DynOS_Opt_NewOption(aName, "", aLabel, aLabel);
_Opt->mType = DOPT_BUTTON;
_Opt->mButton.mFuncName = aFuncName;
}
static void DynOS_Opt_CreateBind(const String &aName, const String &aConfigName, const String &aLabel, u32 aMask, u32 aBind0, u32 aBind1, u32 aBind2) {
DynosOption *_Opt = DynOS_Opt_NewOption(aName, aConfigName, aLabel, aLabel);
_Opt->mType = DOPT_BIND;
_Opt->mBind.mMask = aMask;
_Opt->mBind.mBinds = New<u32>(3);
_Opt->mBind.mBinds[0] = aBind0;
_Opt->mBind.mBinds[1] = aBind1;
_Opt->mBind.mBinds[2] = aBind2;
_Opt->mBind.mIndex = 0;
}
//
// Loop through DynosOptions
//
DynosOption *DynOS_Opt_Loop(DynosOption *aOpt, DynosLoopFunc aFunc, void *aData) {
while (aOpt) {
if (aFunc(aOpt, aData)) {
return aOpt;
} else if (aOpt->mType == DOPT_SUBMENU) {
DynosOption *_Opt = DynOS_Opt_Loop(aOpt->mSubMenu.mChild, aFunc, aData);
if (_Opt) {
return _Opt;
}
}
aOpt = aOpt->mNext;
}
return NULL;
}
//
// Get/Set values
//
static bool DynOS_Opt_Get(DynosOption *aOpt, void *aData) {
return aOpt->mName == (const char *) aData;
}
s32 DynOS_Opt_GetValue(const String &aName) {
DynosOption *_Opt = DynOS_Opt_Loop(sDynosMenu, DynOS_Opt_Get, (void *) aName.begin());
if (_Opt) {
switch (_Opt->mType) {
case DOPT_TOGGLE: return *_Opt->mToggle.mTog;
case DOPT_CHOICE: return *_Opt->mChoice.mIndex;
case DOPT_CHOICELEVEL: return *_Opt->mChoice.mIndex;
case DOPT_CHOICEAREA: return *_Opt->mChoice.mIndex;
case DOPT_CHOICESTAR: return *_Opt->mChoice.mIndex;
case DOPT_CHOICEPARAM: return *_Opt->mChoice.mIndex;
case DOPT_SCROLL: return *_Opt->mScroll.mValue;
default: break;
}
}
return 0;
}
void DynOS_Opt_SetValue(const String &aName, s32 aValue) {
DynosOption *_Opt = DynOS_Opt_Loop(sDynosMenu, DynOS_Opt_Get, (void *) aName.begin());
if (_Opt) {
switch (_Opt->mType) {
case DOPT_TOGGLE: *_Opt->mToggle.mTog = aValue; break;
case DOPT_CHOICE: *_Opt->mChoice.mIndex = aValue; break;
case DOPT_CHOICELEVEL: *_Opt->mChoice.mIndex = aValue; break;
case DOPT_CHOICEAREA: *_Opt->mChoice.mIndex = aValue; break;
case DOPT_CHOICESTAR: *_Opt->mChoice.mIndex = aValue; break;
case DOPT_CHOICEPARAM: *_Opt->mChoice.mIndex = aValue; break;
case DOPT_SCROLL: *_Opt->mScroll.mValue = aValue; break;
default: break;
}
}
}
//
// Processing
//
#define SOUND_DYNOS_SAVED (SOUND_MENU_MARIO_CASTLE_WARP2 | (0xFF << 8))
#define SOUND_DYNOS_SELECT (SOUND_MENU_CHANGE_SELECT | (0xF8 << 8))
#define SOUND_DYNOS_OK (SOUND_MENU_CHANGE_SELECT | (0xF8 << 8))
#define SOUND_DYNOS_CANCEL (SOUND_MENU_CAMERA_BUZZ | (0xFC << 8))
enum {
INPUT_LEFT,
INPUT_RIGHT,
INPUT_A,
INPUT_Z
};
enum {
RESULT_NONE,
RESULT_OK,
RESULT_CANCEL
};
static s32 DynOS_Opt_ProcessInput(DynosOption *aOpt, s32 input) {
switch (aOpt->mType) {
case DOPT_TOGGLE:
if (input == INPUT_LEFT) {
*aOpt->mToggle.mTog = false;
return RESULT_OK;
}
if (input == INPUT_RIGHT) {
*aOpt->mToggle.mTog = true;
return RESULT_OK;
}
if (input == INPUT_A) {
*aOpt->mToggle.mTog = !(*aOpt->mToggle.mTog);
return RESULT_OK;
}
break;
case DOPT_CHOICE:
if (input == INPUT_LEFT) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + aOpt->mChoice.mChoices.Count() - 1) % (aOpt->mChoice.mChoices.Count());
return RESULT_OK;
}
if (input == INPUT_RIGHT || input == INPUT_A) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (aOpt->mChoice.mChoices.Count());
return RESULT_OK;
}
break;
case DOPT_CHOICELEVEL:
if (input == INPUT_LEFT) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + DynOS_Level_GetCount() - 1) % (DynOS_Level_GetCount());
return RESULT_OK;
}
if (input == INPUT_RIGHT || input == INPUT_A) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (DynOS_Level_GetCount());
return RESULT_OK;
}
break;
case DOPT_CHOICEAREA:
if (input == INPUT_LEFT) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 3) % (4);
return RESULT_OK;
}
if (input == INPUT_RIGHT || input == INPUT_A) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (4);
return RESULT_OK;
}
break;
case DOPT_CHOICESTAR:
if (input == INPUT_LEFT) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 5) % (6);
return RESULT_OK;
}
if (input == INPUT_RIGHT || input == INPUT_A) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (6);
return RESULT_OK;
}
break;
case DOPT_CHOICEPARAM:
if (input == INPUT_LEFT) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 4) % (5);
return RESULT_OK;
}
if (input == INPUT_RIGHT || input == INPUT_A) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (5);
return RESULT_OK;
}
break;
case DOPT_SCROLL:
if (input == INPUT_LEFT) {
*aOpt->mScroll.mValue = MAX(aOpt->mScroll.mMin, *aOpt->mScroll.mValue - aOpt->mScroll.mStep * (gPlayer1Controller->buttonDown & A_BUTTON ? 5 : 1));
return RESULT_OK;
}
if (input == INPUT_RIGHT) {
*aOpt->mScroll.mValue = MIN(aOpt->mScroll.mMax, *aOpt->mScroll.mValue + aOpt->mScroll.mStep * (gPlayer1Controller->buttonDown & A_BUTTON ? 5 : 1));
return RESULT_OK;
}
break;
case DOPT_BIND:
if (input == INPUT_LEFT) {
aOpt->mBind.mIndex = MAX(0, aOpt->mBind.mIndex - 1);
return RESULT_OK;
}
if (input == INPUT_RIGHT) {
aOpt->mBind.mIndex = MIN(2, aOpt->mBind.mIndex + 1);
return RESULT_OK;
}
if (input == INPUT_Z) {
aOpt->mBind.mBinds[aOpt->mBind.mIndex] = VK_INVALID;
return RESULT_OK;
}
if (input == INPUT_A) {
aOpt->mBind.mBinds[aOpt->mBind.mIndex] = VK_INVALID;
sBindingState = 1;
controller_get_raw_key();
return RESULT_OK;
}
break;
case DOPT_BUTTON:
if (input == INPUT_A) {
DynosActionFunction _Action = DynOS_Opt_GetAction(aOpt->mButton.mFuncName);
if (_Action != NULL && _Action(aOpt->mName.begin())) {
return RESULT_OK;
}
return RESULT_CANCEL;
}
break;
case DOPT_SUBMENU:
if (input == INPUT_A) {
if (aOpt->mSubMenu.mChild != NULL) {
sCurrentOpt = aOpt->mSubMenu.mChild;
return RESULT_OK;
}
return RESULT_CANCEL;
}
break;
}
return RESULT_NONE;
}
static void DynOS_Opt_Open(DynosOption *aMenu) {
play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
sCurrentMenu = aMenu;
sCurrentOpt = aMenu;
}
static void DynOS_Opt_Close(bool aPlaySavedSfx) {
if (sCurrentMenu != NULL) {
if (aPlaySavedSfx) {
play_sound(SOUND_DYNOS_SAVED, gDefaultSoundArgs);
}
#ifdef BETTERCAMERA
newcam_init_settings();
#endif
controller_reconfigure();
configfile_save(configfile_name());
DynOS_Opt_SaveConfig(sDynosMenu);
sCurrentMenu = NULL;
}
}
static void DynOS_Opt_ProcessInputs() {
static s32 sStickTimer = 0;
static bool sPrevStick = 0;
// Stick values
f32 _StickX = gPlayer1Controller->stickX;
f32 _StickY = gPlayer1Controller->stickY;
if (absx(_StickX) > 60 || absx(_StickY) > 60) {
if (sStickTimer == 0) {
sStickTimer = (sPrevStick ? 2 : 9);
} else {
_StickX = 0;
_StickY = 0;
sStickTimer--;
}
sPrevStick = true;
} else {
sStickTimer = 0;
sPrevStick = false;
}
// Key binding
if (sBindingState != 0) {
u32 _Key = (sCurrentOpt->mDynos ? (u32) DynOS_Opt_ControllerGetKeyPressed() : controller_get_raw_key());
if (_Key != VK_INVALID) {
play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
sCurrentOpt->mBind.mBinds[sCurrentOpt->mBind.mIndex] = _Key;
sBindingState = false;
}
return;
}
if (sCurrentMenu != NULL) {
// Up
if (_StickY > +60) {
if (sCurrentOpt->mPrev != NULL) {
sCurrentOpt = sCurrentOpt->mPrev;
} else {
while (sCurrentOpt->mNext) sCurrentOpt = sCurrentOpt->mNext;
}
play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
return;
}
// Down
if (_StickY < -60) {
if (sCurrentOpt->mNext != NULL) {
sCurrentOpt = sCurrentOpt->mNext;
} else {
while (sCurrentOpt->mPrev) sCurrentOpt = sCurrentOpt->mPrev;
}
play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
return;
}
// Left
if (_StickX < -60) {
switch (DynOS_Opt_ProcessInput(sCurrentOpt, INPUT_LEFT)) {
case RESULT_OK: play_sound(SOUND_DYNOS_OK, gDefaultSoundArgs); break;
case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gDefaultSoundArgs); break;
case RESULT_NONE: break;
}
return;
}
// Right
if (_StickX > +60) {
switch (DynOS_Opt_ProcessInput(sCurrentOpt, INPUT_RIGHT)) {
case RESULT_OK: play_sound(SOUND_DYNOS_OK, gDefaultSoundArgs); break;
case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gDefaultSoundArgs); break;
case RESULT_NONE: break;
}
return;
}
// A
if (gPlayer1Controller->buttonPressed & A_BUTTON) {
switch (DynOS_Opt_ProcessInput(sCurrentOpt, INPUT_A)) {
case RESULT_OK: play_sound(SOUND_DYNOS_OK, gDefaultSoundArgs); break;
case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gDefaultSoundArgs); break;
case RESULT_NONE: break;
}
return;
}
// B
if (gPlayer1Controller->buttonPressed & B_BUTTON) {
if (sCurrentOpt->mParent != NULL) {
sCurrentOpt = sCurrentOpt->mParent;
play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
} else {
DynOS_Opt_Close(true);
}
return;
}
// Z
if (gPlayer1Controller->buttonPressed & Z_TRIG) {
switch (DynOS_Opt_ProcessInput(sCurrentOpt, INPUT_Z)) {
case RESULT_OK: play_sound(SOUND_DYNOS_OK, gDefaultSoundArgs); break;
case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gDefaultSoundArgs); break;
case RESULT_NONE:
if (sCurrentMenu == sDynosMenu) {
DynOS_Opt_Close(true);
} else {
DynOS_Opt_Open(sDynosMenu);
} break;
}
return;
}
// R
if (gPlayer1Controller->buttonPressed & R_TRIG) {
if (sCurrentMenu == sOptionsMenu) {
DynOS_Opt_Close(true);
} else {
DynOS_Opt_Open(sOptionsMenu);
}
return;
}
// Start
if (gPlayer1Controller->buttonPressed & START_BUTTON) {
DynOS_Opt_Close(true);
return;
}
} else if (gPlayer1Controller->buttonPressed & R_TRIG) {
DynOS_Opt_Open(sOptionsMenu);
} else if (gPlayer1Controller->buttonPressed & Z_TRIG) {
DynOS_Opt_Open(sDynosMenu);
}
}
//
// Init
//
static void DynOS_Opt_CreateWarpToLevelSubMenu() {
DynOS_Opt_CreateSubMenu("dynos_warp_to_level_submenu", "Warp to Level", "WARP TO LEUEL");
// Level select
{
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_level", "", "Level Select", "");
aOpt->mType = DOPT_CHOICELEVEL;
aOpt->mChoice.mIndex = New<s32>();
*aOpt->mChoice.mIndex = 0;
}
// Area select
{
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_area", "", "Area Select", "");
aOpt->mType = DOPT_CHOICEAREA;
aOpt->mChoice.mIndex = New<s32>();
*aOpt->mChoice.mIndex = 0;
}
// Star select
{
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_act", "", "Star Select", "");
aOpt->mType = DOPT_CHOICESTAR;
aOpt->mChoice.mIndex = New<s32>();
*aOpt->mChoice.mIndex = 0;
}
// Param select
{
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_param", "", "Param Select", "");
aOpt->mType = DOPT_CHOICEPARAM;
aOpt->mChoice.mIndex = New<s32>();
*aOpt->mChoice.mIndex = 0;
}
DynOS_Opt_CreateButton("dynos_warp_to_level", "Warp", "DynOS_Opt_WarpToLevel");
DynOS_Opt_EndSubMenu();
}
static void DynOS_Opt_CreateWarpToCastleSubMenu() {
DynOS_Opt_CreateSubMenu("dynos_warp_to_castle_submenu", "Warp to Castle", "WARP TO CASTLE");
// Level select
{
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_castle", "", "Level Exit", "");
aOpt->mType = DOPT_CHOICELEVEL;
aOpt->mChoice.mIndex = New<s32>();
*aOpt->mChoice.mIndex = 0;
}
DynOS_Opt_CreateButton("dynos_warp_to_castle", "Warp", "DynOS_Opt_WarpToCastle");
DynOS_Opt_EndSubMenu();
}
static u32 DynOS_Opt_GetHash(const String& aStr) {
u32 _Hash = 5381u;
for (char c : aStr) { _Hash += c + (_Hash << 5); }
return _Hash;
}
static void DynOS_Opt_CreateModelPacksSubMenu() {
Array<String> _Packs = DynOS_Gfx_Init();
if (_Packs.Count() == 0) {
return;
}
DynOS_Opt_CreateSubMenu("dynos_model_loader_submenu", "Model Packs", "MODEL PACKS");
for (s32 i = 0; i != _Packs.Count(); ++i) {
DynOS_Opt_CreateToggle(String("dynos_pack_%d", i), String("dynos_pack_%08X", DynOS_Opt_GetHash(_Packs[i])), _Packs[i], false);
}
DynOS_Opt_CreateButton("dynos_packs_disable_all", "Disable all packs", "DynOS_Opt_DisableAllPacks");
DynOS_Opt_EndSubMenu();
}
void DynOS_Opt_Init() {
#ifdef COOP
DynOS_Gfx_Init();
#else
// Convert options menu
DynOS_Opt_InitVanilla(sOptionsMenu);
// Warp to level
DynOS_Opt_CreateWarpToLevelSubMenu();
// Warp to castle
DynOS_Opt_CreateWarpToCastleSubMenu();
// Restart level
DynOS_Opt_CreateButton("dynos_restart_level", "Restart Level", "DynOS_Opt_RestartLevel");
// Exit level
DynOS_Opt_CreateButton("dynos_exit_level", "Exit Level", "DynOS_Opt_ExitLevel");
// Return to main menu
DynOS_Opt_CreateButton("dynos_return_to_main_menu", "Return to Main Menu", "DynOS_Opt_ReturnToMainMenu");
// Model loader
DynOS_Opt_CreateModelPacksSubMenu();
#endif
// Init config
DynOS_Opt_LoadConfig(sDynosMenu);
}
//
// Update
//
void DynOS_Opt_Update(OSContPad *aPad) {
DynOS_Opt_Loop(sDynosMenu, DynOS_Opt_ControllerUpdate, (void *) aPad);
if (DynOS_IsTransitionActive()) {
aPad->button = 0;
aPad->stick_x = 0;
aPad->stick_y = 0;
aPad->ext_stick_x = 0;
aPad->ext_stick_y = 0;
}
}
//
// Hijack
// This is C code
//
extern "C" {
u8 optmenu_open = 0;
void optmenu_toggle(void) {
DynOS_Opt_Close(false);
optmenu_open = 0;
}
void optmenu_draw(void) {
DynOS_Opt_DrawMenu(sCurrentOpt, sCurrentMenu, sOptionsMenu, sDynosMenu);
}
void optmenu_draw_prompt(void) {
DynOS_Opt_DrawPrompt(sCurrentMenu, sOptionsMenu, sDynosMenu);
DynOS_Opt_ProcessInputs();
optmenu_open = (sCurrentMenu != NULL);
}
void optmenu_check_buttons(void) {
}
}
//
// Built-in options
//
#define DYNOS_DEFINE_ACTION(func) \
DYNOS_AT_STARTUP static void DynOS_Opt_AddAction_##func() { \
DynOS_Opt_AddAction(#func, func, false); \
}
#ifndef COOP
static bool DynOS_Opt_ReturnToMainMenu(UNUSED const char *optName) {
DynOS_ReturnToMainMenu();
return true;
}
DYNOS_DEFINE_ACTION(DynOS_Opt_ReturnToMainMenu);
static bool DynOS_Opt_WarpToLevel(UNUSED const char *optName) {
s32 _Level = DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")];
s32 _Area = DynOS_Opt_GetValue("dynos_warp_area") + 1;
s32 _Act = DynOS_Opt_GetValue("dynos_warp_act") + 1;
return DynOS_Warp_ToLevel(_Level, _Area, _Act);
}
DYNOS_DEFINE_ACTION(DynOS_Opt_WarpToLevel);
static bool DynOS_Opt_WarpToCastle(UNUSED const char *optName) {
s32 _Level = DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_castle")];
return DynOS_Warp_ToCastle(_Level);
}
DYNOS_DEFINE_ACTION(DynOS_Opt_WarpToCastle);
static bool DynOS_Opt_RestartLevel(UNUSED const char *optName) {
return DynOS_Warp_RestartLevel();
}
DYNOS_DEFINE_ACTION(DynOS_Opt_RestartLevel);
static bool DynOS_Opt_ExitLevel(UNUSED const char *optName) {
return DynOS_Warp_ExitLevel(30);
}
DYNOS_DEFINE_ACTION(DynOS_Opt_ExitLevel);
static bool DynOS_Opt_DisableAllPacks(UNUSED const char *optName) {
const Array<PackData *> &pDynosPacks = DynOS_Gfx_GetPacks();
for (s32 i = 0; i != pDynosPacks.Count(); ++i) {
DynOS_Opt_SetValue(String("dynos_pack_%d", i), false);
}
return true;
}
DYNOS_DEFINE_ACTION(DynOS_Opt_DisableAllPacks);
#endif
#undef DYNOS_DEFINE_ACTION

62
data/dynos_opt_config.cpp Normal file
View file

@ -0,0 +1,62 @@
#include "dynos.cpp.h"
extern DynosOption *DynOS_Opt_Loop(DynosOption *aOpt, DynosLoopFunc aFunc, void *aData);
static bool DynOS_Opt_ReadConfig(DynosOption *aOpt, void *aData) {
return (aOpt->mConfigName == (const char *) aData);
}
void DynOS_Opt_LoadConfig(DynosOption *aMenu) {
SysPath _Filename = fstring("%s/%s", DYNOS_USER_FOLDER, DYNOS_CONFIG_FILENAME);
FILE *_File = fopen(_Filename.c_str(), "r");
if (_File) {
char _Buffer[1024];
while (fgets(_Buffer, 1024, _File)) {
// Option strings
char *_NameBegin = _Buffer;
char *_DataBegin = strchr(_NameBegin, '=');
if (_NameBegin && _DataBegin) {
*(_DataBegin++) = 0;
// Option name
String _OptName = String(_NameBegin);
DynosOption *_Opt = DynOS_Opt_Loop(aMenu, DynOS_Opt_ReadConfig, (void *) _OptName.begin());
if (_Opt) {
// Option values
switch (_Opt->mType) {
case DOPT_TOGGLE: sscanf(_DataBegin, "%hhu\n", &_Opt->mToggle.mTog[0]); break;
case DOPT_CHOICE: sscanf(_DataBegin, "%d\n", &_Opt->mChoice.mIndex[0]); break;
case DOPT_SCROLL: sscanf(_DataBegin, "%d\n", &_Opt->mScroll.mValue[0]); break;
case DOPT_BIND: sscanf(_DataBegin, "%04X;%04X;%04X\n", &_Opt->mBind.mBinds[0], &_Opt->mBind.mBinds[1], &_Opt->mBind.mBinds[2]); break;
}
}
}
}
fclose(_File);
}
}
static bool DynOS_Opt_WriteConfig(DynosOption *aOpt, void *aData) {
if (aOpt->mConfigName.Length() != 0 &&
aOpt->mConfigName != "null" &&
aOpt->mConfigName != "NULL") {
switch (aOpt->mType) {
case DOPT_TOGGLE: fprintf((FILE *) aData, "%s=%hhu\n", aOpt->mConfigName.begin(), aOpt->mToggle.mTog[0]); break;
case DOPT_CHOICE: fprintf((FILE *) aData, "%s=%d\n", aOpt->mConfigName.begin(), aOpt->mChoice.mIndex[0]); break;
case DOPT_SCROLL: fprintf((FILE *) aData, "%s=%d\n", aOpt->mConfigName.begin(), aOpt->mScroll.mValue[0]); break;
case DOPT_BIND: fprintf((FILE *) aData, "%s=%04X;%04X;%04X\n", aOpt->mConfigName.begin(), aOpt->mBind.mBinds[0], aOpt->mBind.mBinds[1], aOpt->mBind.mBinds[2]); break;
}
}
return false;
}
void DynOS_Opt_SaveConfig(DynosOption *aMenu) {
SysPath _Filename = fstring("%s/%s", DYNOS_USER_FOLDER, DYNOS_CONFIG_FILENAME);
FILE *_File = fopen(_Filename.c_str(), "w");
if (_File) {
DynOS_Opt_Loop(aMenu, DynOS_Opt_WriteConfig, (void *) _File);
fclose(_File);
}
}

70
data/dynos_opt_cont.cpp Normal file
View file

@ -0,0 +1,70 @@
#include "dynos.cpp.h"
extern "C" {
#include "pc/controller/controller_api.h"
}
static bool DynOS_Opt_ControllerIsKeyDown(s32 aCont, s32 aKey) {
// Keyboard
if (aCont == 0 && aKey >= 0 && aKey < SDL_NUM_SCANCODES) {
return SDL_GetKeyboardState(NULL)[aKey];
}
// Game Controller
else if (aKey >= 0x1000) {
// Button
s32 _Button = (aKey - 0x1000);
if (_Button < SDL_CONTROLLER_BUTTON_MAX) {
return SDL_GameControllerGetButton(SDL_GameControllerOpen(aCont - 1), SDL_GameControllerButton(_Button));
}
// Axis
s32 _Axis = (aKey - 0x1000 - SDL_CONTROLLER_BUTTON_MAX);
if (_Axis < SDL_CONTROLLER_AXIS_MAX * 2) {
s32 _AxisValue = SDL_GameControllerGetAxis(SDL_GameControllerOpen(aCont - 1), SDL_GameControllerAxis(_Axis / 2));
if (_Axis & 1) return (_AxisValue < (SHRT_MIN / 2));
else return (_AxisValue > (SHRT_MAX / 2));
}
}
// Invalid
return false;
}
#define MAX_CONTS 8
bool DynOS_Opt_ControllerUpdate(DynosOption *aOpt, void *aData) {
if (aOpt->mType == DOPT_BIND) {
OSContPad *pad = (OSContPad *) aData;
for (s32 _Cont = 0; _Cont < MAX_CONTS; ++_Cont)
for (s32 _Bind = 0; _Bind < 3; ++_Bind) {
pad->button |= aOpt->mBind.mMask * DynOS_Opt_ControllerIsKeyDown(_Cont, aOpt->mBind.mBinds[_Bind]);
}
}
return false;
}
#define MAX_GKEYS (SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_AXIS_MAX * 2)
s32 sBindingState = 0; // 0 = No bind, 1 = Wait for all keys released, 2 = Return first pressed key
s32 DynOS_Opt_ControllerGetKeyPressed() {
// Keyboard
for (s32 _Key = 0; _Key < SDL_NUM_SCANCODES; ++_Key) {
if (DynOS_Opt_ControllerIsKeyDown(0, _Key)) {
if (sBindingState == 1) return VK_INVALID;
return _Key;
}
}
// Game Controller
for (s32 _Cont = 1; _Cont < MAX_CONTS; ++_Cont)
for (s32 _Key = 0; _Key < MAX_GKEYS; ++_Key) {
if (DynOS_Opt_ControllerIsKeyDown(_Cont, _Key + 0x1000)) {
if (sBindingState == 1) return VK_INVALID;
return _Key + 0x1000;
}
}
// No key
sBindingState = 2;
return VK_INVALID;
}

309
data/dynos_opt_render.cpp Normal file
View file

@ -0,0 +1,309 @@
#include "dynos.cpp.h"
extern "C" {
#include "course_table.h"
#include "game/game_init.h"
#include "game/ingame_menu.h"
#include "game/segment2.h"
#include "pc/controller/controller_api.h"
#include "gfx_dimensions.h"
}
extern s32 sBindingState;
#define DYNOS_TEXT_DYNOS_MENU { "DYNOS MENU", NULL }
#define DYNOS_TEXT_A { "([A]) >", NULL }
#define DYNOS_TEXT_OPEN_LEFT { "[Z] DynOS", NULL }
#define DYNOS_TEXT_CLOSE_LEFT { "[Z] Return", NULL }
#define DYNOS_TEXT_OPTIONS_MENU { "OPTIONS", NULL }
#define DYNOS_TEXT_DISABLED { "Disabled", NULL }
#define DYNOS_TEXT_ENABLED { "Enabled", NULL }
#define DYNOS_TEXT_NONE { "NONE", NULL }
#define DYNOS_TEXT_DOT_DOT_DOT { "...", NULL }
#define DYNOS_TEXT_OPEN_RIGHT { "[R] Options", NULL }
#define DYNOS_TEXT_CLOSE_RIGHT { "[R] Return", NULL }
static void RenderString(const u8 *aStr64, s32 aX, s32 aY) {
create_dl_translation_matrix(MENU_MTX_PUSH, aX, aY, 0);
for (; *aStr64 != DIALOG_CHAR_TERMINATOR; ++aStr64) {
if (*aStr64 != DIALOG_CHAR_SPACE) {
void **fontLUT = (void **) segmented_to_virtual(main_font_lut);
void *packedTexture = segmented_to_virtual(fontLUT[*aStr64]);
gDPPipeSync(gDisplayListHead++);
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(packedTexture));
gSPDisplayList(gDisplayListHead++, dl_ia_text_tex_settings);
}
create_dl_translation_matrix(MENU_MTX_NOPUSH, DynOS_String_WidthChar64(*aStr64), 0, 0);
}
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
static void PrintString(const Label& aLabel, s32 aX, s32 aY, u32 aFrontColorRGBA, u32 aBackColorRGBA, bool aAlignLeft) {
const u8 *_Str64 = (aLabel.second ? aLabel.second : DynOS_String_Convert(aLabel.first.begin(), false));
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
if ((aBackColorRGBA & 0xFF) != 0) {
gDPSetEnvColor(gDisplayListHead++, ((aBackColorRGBA >> 24) & 0xFF), ((aBackColorRGBA >> 16) & 0xFF), ((aBackColorRGBA >> 8) & 0xFF), ((aBackColorRGBA >> 0) & 0xFF));
if (aAlignLeft) {
RenderString(_Str64, GFX_DIMENSIONS_FROM_LEFT_EDGE(aX) + 1, aY - 1);
} else {
RenderString(_Str64, GFX_DIMENSIONS_FROM_RIGHT_EDGE(aX + DynOS_String_Width(_Str64) - 1), aY - 1);
}
}
if ((aFrontColorRGBA & 0xFF) != 0) {
gDPSetEnvColor(gDisplayListHead++, ((aFrontColorRGBA >> 24) & 0xFF), ((aFrontColorRGBA >> 16) & 0xFF), ((aFrontColorRGBA >> 8) & 0xFF), ((aFrontColorRGBA >> 0) & 0xFF));
if (aAlignLeft) {
RenderString(_Str64, GFX_DIMENSIONS_FROM_LEFT_EDGE(aX), aY);
} else {
RenderString(_Str64, GFX_DIMENSIONS_FROM_RIGHT_EDGE(aX + DynOS_String_Width(_Str64)), aY);
}
}
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
}
static void PrintBox(s32 aX, s32 aY, s32 aWidth, s32 aHeight, u32 aColorRGBA, bool aAlignLeft) {
if ((aColorRGBA && 0xFF) != 0) {
Mtx *_Matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
if (!_Matrix) return;
if (aAlignLeft) {
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_LEFT_EDGE(aX), aY + aHeight, 0);
} else {
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_RIGHT_EDGE(aX + aWidth), aY + aHeight, 0);
}
guScale(_Matrix, (f32) aWidth / 130.f, (f32) aHeight / 80.f, 1.f);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(_Matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
gDPSetEnvColor(gDisplayListHead++, ((aColorRGBA >> 24) & 0xFF), ((aColorRGBA >> 16) & 0xFF), ((aColorRGBA >> 8) & 0xFF), ((aColorRGBA >> 0) & 0xFF));
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
}
}
static const char *IntToString(const char *fmt, s32 x) {
static char sBuffer[16];
snprintf(sBuffer, 16, fmt, x);
return sBuffer;
}
#define get_label(opt) (opt->mLabel)
#define get_title(opt) (opt->mTitle)
#define get_choice(opt) (opt->mChoice.mChoices[*opt->mChoice.mIndex])
#define get_dec_number(n) { "", DynOS_String_Convert(IntToString("%d", n), false) }
#define get_hex_number(n) { "", DynOS_String_Convert(IntToString("%04X", n), false) }
#define get_level(opt) { "", DynOS_Level_GetName(DynOS_Level_GetList()[*opt->mChoice.mIndex], true, true) }
#define get_star(opt) { "", DynOS_Level_GetActName(DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")], *opt->mChoice.mIndex + 1, true, true) }
#define get_param(opt) { DynOS_Warp_GetParamName(DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")], *opt->mChoice.mIndex), NULL }
static s32 GetCurrentOptionCount(DynosOption *aCurrentOpt) {
s32 _Count = 0;
while (aCurrentOpt->mPrev) { aCurrentOpt = aCurrentOpt->mPrev; }
while (aCurrentOpt) { aCurrentOpt = aCurrentOpt->mNext; _Count++; }
return _Count;
}
static s32 GetCurrentOptionIndex(DynosOption *aCurrentOpt) {
s32 _Index = 0;
while (aCurrentOpt->mPrev) { aCurrentOpt = aCurrentOpt->mPrev; _Index++; }
return _Index;
}
#define PREV(opt) (opt == NULL ? NULL : opt->mPrev)
#define NEXT(opt) (opt == NULL ? NULL : opt->mNext)
static DynosOption **GetCurrentOptions(DynosOption *aCurrentOpt) {
static DynosOption *sOptionList[13];
sOptionList[6] = aCurrentOpt;
sOptionList[5] = PREV(sOptionList[6]);
sOptionList[4] = PREV(sOptionList[5]);
sOptionList[3] = PREV(sOptionList[4]);
sOptionList[2] = PREV(sOptionList[3]);
sOptionList[1] = PREV(sOptionList[2]);
sOptionList[0] = PREV(sOptionList[1]);
sOptionList[7] = NEXT(sOptionList[6]);
sOptionList[8] = NEXT(sOptionList[7]);
sOptionList[9] = NEXT(sOptionList[8]);
sOptionList[10] = NEXT(sOptionList[9]);
sOptionList[11] = NEXT(sOptionList[10]);
sOptionList[12] = NEXT(sOptionList[11]);
s32 _StartIndex = 12, _EndIndex = 0;
for (s32 i = 0; i != 13; ++i) {
if (sOptionList[i] != NULL) {
_StartIndex = MIN(_StartIndex, i);
_EndIndex = MAX(_EndIndex, i);
}
}
if (_EndIndex - _StartIndex < 7) {
return &sOptionList[_StartIndex];
}
if (_EndIndex <= 9) {
return &sOptionList[_EndIndex - 6];
}
if (_StartIndex >= 3) {
return &sOptionList[_StartIndex];
}
return &sOptionList[3];
}
#undef PREV
#undef NEXT
#define COLOR_WHITE 0xFFFFFFFF
#define COLOR_BLACK 0x000000FF
#define COLOR_GRAY 0xA0A0A0FF
#define COLOR_DARK_GRAY 0x808080FF
#define COLOR_SELECT 0x80E0FFFF
#define COLOR_SELECT_BOX 0x00FFFF20
#define COLOR_ENABLED 0x20E020FF
#define COLOR_DISABLED 0xFF2020FF
#define OFFSET_FROM_LEFT_EDGE (20.f * sqr(GFX_DIMENSIONS_ASPECT_RATIO))
#define OFFSET_FROM_RIGHT_EDGE (20.f * sqr(GFX_DIMENSIONS_ASPECT_RATIO))
#define SCROLL_BAR_SIZE ((s32) (45.f * GFX_DIMENSIONS_ASPECT_RATIO))
static void DynOS_Opt_DrawOption(DynosOption *aOpt, DynosOption *aCurrentOpt, s32 aY) {
if (aOpt == NULL) {
return;
}
// Selected box
if (aOpt == aCurrentOpt) {
u8 _Alpha = (u8) ((coss(gGlobalTimer * 0x800) + 1.f) * 0x20);
PrintBox(OFFSET_FROM_LEFT_EDGE - 4, aY - 2, GFX_DIMENSIONS_FROM_RIGHT_EDGE(OFFSET_FROM_RIGHT_EDGE) - GFX_DIMENSIONS_FROM_LEFT_EDGE(OFFSET_FROM_LEFT_EDGE) + 8, 20, COLOR_SELECT_BOX + _Alpha, 1);
}
// Label
if (aOpt == aCurrentOpt) {
PrintString(get_label(aOpt), OFFSET_FROM_LEFT_EDGE, aY, COLOR_SELECT, COLOR_BLACK, 1);
} else {
PrintString(get_label(aOpt), OFFSET_FROM_LEFT_EDGE, aY, COLOR_WHITE, COLOR_BLACK, 1);
}
// Values
switch (aOpt->mType) {
case DOPT_TOGGLE: {
if (*aOpt->mToggle.mTog) {
PrintString(DYNOS_TEXT_ENABLED, OFFSET_FROM_RIGHT_EDGE, aY, COLOR_ENABLED, COLOR_BLACK, 0);
} else {
PrintString(DYNOS_TEXT_DISABLED, OFFSET_FROM_RIGHT_EDGE, aY, COLOR_DISABLED, COLOR_BLACK, 0);
}
} break;
case DOPT_CHOICE: {
PrintString(get_choice(aOpt), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
} break;
case DOPT_CHOICELEVEL: {
PrintString(get_level(aOpt), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
} break;
case DOPT_CHOICEAREA: {
s32 _Level = DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")];
s32 _Area = *aOpt->mChoice.mIndex + 1;
const u8 *_Name = DynOS_Level_GetAreaName(_Level, _Area, true);
if (DynOS_Level_GetWarpEntry(_Level, _Area)) {
PrintString({ "", _Name }, OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
} else {
PrintString({ "", _Name }, OFFSET_FROM_RIGHT_EDGE, aY, COLOR_GRAY, COLOR_BLACK, 0);
}
} break;
case DOPT_CHOICESTAR: {
s32 _Course = DynOS_Level_GetCourse(DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")]);
if (_Course >= COURSE_MIN && _Course <= COURSE_STAGES_MAX) {
PrintString(get_star(aOpt), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
}
} break;
case DOPT_CHOICEPARAM: {
PrintString(get_param(aOpt), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
} break;
case DOPT_SCROLL: {
s32 _Width = (s32) (SCROLL_BAR_SIZE * (f32) (*aOpt->mScroll.mValue - aOpt->mScroll.mMin) / (f32) (aOpt->mScroll.mMax - aOpt->mScroll.mMin));
PrintString(get_dec_number(*aOpt->mScroll.mValue), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
PrintBox(OFFSET_FROM_RIGHT_EDGE + 28, aY + 4, SCROLL_BAR_SIZE + 2, 8, COLOR_DARK_GRAY, 0);
PrintBox(OFFSET_FROM_RIGHT_EDGE + 29 + SCROLL_BAR_SIZE - _Width, aY + 5, _Width, 6, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, 0);
} break;
case DOPT_BIND: {
for (s32 i = 0; i != 3; ++i) {
u32 _Bind = aOpt->mBind.mBinds[i];
if (aOpt == aCurrentOpt && i == aOpt->mBind.mIndex) {
if (sBindingState != 0) {
PrintString(DYNOS_TEXT_DOT_DOT_DOT, OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_SELECT, COLOR_BLACK, 0);
} else if (_Bind == VK_INVALID) {
PrintString(DYNOS_TEXT_NONE, OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_SELECT, COLOR_BLACK, 0);
} else {
PrintString(get_hex_number(_Bind), OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_SELECT, COLOR_BLACK, 0);
}
} else {
if (_Bind == VK_INVALID) {
PrintString(DYNOS_TEXT_NONE, OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_GRAY, COLOR_BLACK, 0);
} else {
PrintString(get_hex_number(_Bind), OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_WHITE, COLOR_BLACK, 0);
}
}
}
} break;
case DOPT_BUTTON: {
} break;
case DOPT_SUBMENU: {
if (aOpt == aCurrentOpt) {
PrintString(DYNOS_TEXT_A, OFFSET_FROM_RIGHT_EDGE, aY, COLOR_SELECT, COLOR_BLACK, 0);
}
} break;
}
}
void DynOS_Opt_DrawMenu(DynosOption *aCurrentOption, DynosOption *aCurrentMenu, DynosOption *aOptionsMenu, DynosOption *aDynosMenu) {
if (aCurrentMenu == NULL) {
return;
}
// Colorful label
Label _Title;
if (aCurrentOption->mParent) {
_Title = get_title(aCurrentOption->mParent);
} else if (aCurrentMenu == aDynosMenu) {
_Title = DYNOS_TEXT_DYNOS_MENU;
} else if (aCurrentMenu == aOptionsMenu) {
_Title = DYNOS_TEXT_OPTIONS_MENU;
}
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
if (!_Title.second) _Title.second = DynOS_String_Convert(_Title.first.begin(), false);
print_hud_lut_string(HUD_LUT_GLOBAL, (SCREEN_WIDTH / 2 - DynOS_String_Length(_Title.second) * 6), 40, _Title.second);
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
// Display options
DynosOption **_Options = GetCurrentOptions(aCurrentOption);
for (s32 i = 0; i != 7; ++i) {
DynOS_Opt_DrawOption(_Options[i], aCurrentOption, 156 - 20 * i);
}
// Scroll bar
s32 _OptCount = GetCurrentOptionCount(aCurrentOption);
s32 _OptIndex = GetCurrentOptionIndex(aCurrentOption);
if (_OptCount > 7) {
s32 _Height = (s32) (134.f * sqrtf(1.f / (_OptCount - 6)));
s32 _Y = 37 + (134 - _Height) * (1.f - MAX(0.f, MIN(1.f, (f32)(_OptIndex - 3) / (f32)(_OptCount - 6))));
PrintBox(OFFSET_FROM_RIGHT_EDGE - 16, 36, 8, 136, COLOR_DARK_GRAY, 0);
PrintBox(OFFSET_FROM_RIGHT_EDGE - 15, _Y, 6, _Height, COLOR_WHITE, 0);
}
}
#define PROMPT_OFFSET (56.25f * GFX_DIMENSIONS_ASPECT_RATIO)
void DynOS_Opt_DrawPrompt(DynosOption *aCurrentMenu, DynosOption *aOptionsMenu, DynosOption *aDynosMenu) {
if (aCurrentMenu == aOptionsMenu) {
PrintString(DYNOS_TEXT_OPEN_LEFT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 1);
PrintString(DYNOS_TEXT_CLOSE_RIGHT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 0);
} else if (aCurrentMenu == aDynosMenu) {
PrintString(DYNOS_TEXT_CLOSE_LEFT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 1);
PrintString(DYNOS_TEXT_OPEN_RIGHT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 0);
} else {
PrintString(DYNOS_TEXT_OPEN_LEFT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 1);
PrintString(DYNOS_TEXT_OPEN_RIGHT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 0);
}
}

159
data/dynos_opt_vanilla.cpp Normal file
View file

@ -0,0 +1,159 @@
#include "dynos.cpp.h"
static DynosOption *sPrevOpt = NULL;
static DynosOption *sOptionsMenu = NULL;
//
// Vanilla actions
//
typedef void (*VanillaActionFunction)(struct Option *, s32);
typedef struct VanillaAction {
String mFuncName;
VanillaActionFunction mAction;
} VanillaAction;
STATIC_STORAGE(Array<VanillaAction *>, VanillaActions);
#define sVanillaActions __VanillaActions()
static VanillaActionFunction DynOS_Opt_GetVanillaAction(const String& aFuncName) {
for (auto &_DynosAction : sVanillaActions) {
if (_DynosAction->mFuncName == aFuncName) {
return _DynosAction->mAction;
}
}
return NULL;
}
static void DynOS_Opt_AddVanillaAction(const String& aFuncName, void (*aFuncPtr)(struct Option *, s32)) {
for (auto &_DynosAction : sVanillaActions) {
if (_DynosAction->mFuncName == aFuncName) {
return;
}
}
VanillaAction *_DynosAction = New<VanillaAction>();
_DynosAction->mFuncName = aFuncName;
_DynosAction->mAction = aFuncPtr;
sVanillaActions.Add(_DynosAction);
}
static bool DynOS_Opt_CallVanillaAction(const char *aOptName) {
VanillaActionFunction _Func = DynOS_Opt_GetVanillaAction(aOptName);
if (_Func) {
_Func(NULL, 0);
return true;
}
return false;
}
//
// Convert classic options menu into DynOS menu
//
static DynosOption *DynOS_Opt_ConvertOption(const u8 *aLabel, const u8 *aTitle) {
static u32 sOptIdx = 0;
DynosOption *_Opt = New<DynosOption>();
_Opt->mName = String("vanilla_opt_%08X", sOptIdx++);
_Opt->mConfigName = "";
_Opt->mLabel = { "", aLabel };
_Opt->mTitle = { "", aTitle };
_Opt->mDynos = false;
if (sPrevOpt == NULL) { // The very first option
_Opt->mPrev = NULL;
_Opt->mNext = NULL;
_Opt->mParent = NULL;
sOptionsMenu = _Opt;
} else {
if (sPrevOpt->mType == DOPT_SUBMENU && sPrevOpt->mSubMenu.mEmpty) { // First option of a sub-menu
_Opt->mPrev = NULL;
_Opt->mNext = NULL;
_Opt->mParent = sPrevOpt;
sPrevOpt->mSubMenu.mChild = _Opt;
sPrevOpt->mSubMenu.mEmpty = false;
} else {
_Opt->mPrev = sPrevOpt;
_Opt->mNext = NULL;
_Opt->mParent = sPrevOpt->mParent;
sPrevOpt->mNext = _Opt;
}
}
sPrevOpt = _Opt;
return _Opt;
}
static void DynOS_Opt_EndSubMenu() {
if (sPrevOpt) {
if (sPrevOpt->mType == DOPT_SUBMENU && sPrevOpt->mSubMenu.mEmpty) { // ENDMENU command following a SUBMENU command
sPrevOpt->mSubMenu.mEmpty = false;
} else {
sPrevOpt = sPrevOpt->mParent;
}
}
}
static void DynOS_Opt_ConvertSubMenu(const u8 *aLabel, const u8 *aTitle) {
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aTitle);
_Opt->mType = DOPT_SUBMENU;
_Opt->mSubMenu.mChild = NULL;
_Opt->mSubMenu.mEmpty = true;
}
static void DynOS_Opt_ConvertToggle(const u8 *aLabel, bool *pValue) {
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
_Opt->mType = DOPT_TOGGLE;
_Opt->mToggle.mTog = (bool *) pValue;
}
static void DynOS_Opt_ConvertScroll(const u8 *aLabel, s32 aMin, s32 aMax, s32 aStep, u32 *pValue) {
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
_Opt->mType = DOPT_SCROLL;
_Opt->mScroll.mMin = aMin;
_Opt->mScroll.mMax = aMax;
_Opt->mScroll.mStep = aStep;
_Opt->mScroll.mValue = (s32 *) pValue;
}
static void DynOS_Opt_ConvertChoice(const u8 *aLabel, const u8 **aChoices, s32 aCount, u32 *pValue) {
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
_Opt->mType = DOPT_CHOICE;
_Opt->mChoice.mIndex = (s32 *) pValue;
for (s32 i = 0; i != aCount; ++i) {
_Opt->mChoice.mChoices.Add({ "", aChoices[i] });
}
}
static void DynOS_Opt_ConvertButton(const u8 *aLabel, VanillaActionFunction aAction) {
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
_Opt->mType = DOPT_BUTTON;
_Opt->mButton.mFuncName = "DynOS_Opt_CallVanillaAction";
DynOS_Opt_AddVanillaAction(_Opt->mName, aAction);
}
static void DynOS_Opt_ConvertBind(const u8 *aLabel, u32 *pBinds) {
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
_Opt->mType = DOPT_BIND;
_Opt->mBind.mMask = 0;
_Opt->mBind.mBinds = pBinds;
_Opt->mBind.mIndex = 0;
}
#ifndef COOP
extern "C" {
extern void dynos_opt_convert_vanilla_main_menu();
void dynos_opt_end_submenu() { return DynOS_Opt_EndSubMenu(); }
void dynos_opt_convert_submenu(const u8 *label, const u8 *title) { return DynOS_Opt_ConvertSubMenu(label, title); }
void dynos_opt_convert_toggle(const u8 *label, bool *bval) { return DynOS_Opt_ConvertToggle(label, bval); }
void dynos_opt_convert_scroll(const u8 *label, s32 min, s32 max, s32 step, u32 *uval) { return DynOS_Opt_ConvertScroll(label, min, max, step, uval); }
void dynos_opt_convert_choice(const u8 *label, const u8 **choices, s32 numChoices, u32 *uval) { return DynOS_Opt_ConvertChoice(label, choices, numChoices, uval); }
void dynos_opt_convert_button(const u8 *label, void *action) { return DynOS_Opt_ConvertButton(label, (VanillaActionFunction) action); }
void dynos_opt_convert_bind(const u8 *label, u32 *uval) { return DynOS_Opt_ConvertBind(label, uval); }
}
#endif
void DynOS_Opt_InitVanilla(DynosOption *&aOptionsMenu) {
sPrevOpt = NULL;
#ifndef COOP
dynos_opt_convert_vanilla_main_menu();
#endif
DynOS_Opt_AddAction("DynOS_Opt_CallVanillaAction", DynOS_Opt_CallVanillaAction, true);
aOptionsMenu = sOptionsMenu;
}

View file

@ -0,0 +1,72 @@
#ifndef COOP
// Not my problem
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsizeof-pointer-div"
#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
#pragma GCC diagnostic ignored "-Wpointer-sign"
#pragma GCC diagnostic ignored "-Wsign-compare"
#define optmenu_toggle optmenu_toggle_unused
#define optmenu_draw optmenu_draw_unused
#define optmenu_draw_prompt optmenu_draw_prompt_unused
#define optmenu_check_buttons optmenu_check_buttons_unused
#define optmenu_open optmenu_open_unused
#define DYNOS_INL
#include "game/options_menu.c"
#undef DYNOS_INL
#undef optmenu_toggle
#undef optmenu_draw
#undef optmenu_draw_prompt
#undef optmenu_check_buttons
#undef optmenu_open
#pragma GCC diagnostic pop
// Now, that's my problem
extern void dynos_opt_end_submenu();
extern void dynos_opt_convert_submenu(const u8 *label, const u8 *title);
extern void dynos_opt_convert_toggle(const u8 *label, bool *bval);
extern void dynos_opt_convert_scroll(const u8 *label, s32 min, s32 max, s32 step, u32 *uval);
extern void dynos_opt_convert_choice(const u8 *label, const u8 **choices, s32 numChoices, u32 *uval);
extern void dynos_opt_convert_button(const u8 *label, void *action);
extern void dynos_opt_convert_bind(const u8 *label, u32 *uval);
static void dynos_opt_convert_menu(struct SubMenu *submenu) {
for (s32 i = 0; i != submenu->numOpts; ++i) {
struct Option *opt = &submenu->opts[i];
switch (opt->type) {
case OPT_TOGGLE:
dynos_opt_convert_toggle(opt->label, opt->bval);
break;
case OPT_CHOICE:
dynos_opt_convert_choice(opt->label, opt->choices, opt->numChoices, opt->uval);
break;
case OPT_SCROLL:
dynos_opt_convert_scroll(opt->label, opt->scrMin, opt->scrMax, opt->scrStep, opt->uval);
break;
case OPT_SUBMENU:
dynos_opt_convert_submenu(opt->label, opt->nextMenu->label);
dynos_opt_convert_menu(opt->nextMenu);
dynos_opt_end_submenu();
break;
case OPT_BIND:
dynos_opt_convert_bind(opt->label, opt->uval);
break;
case OPT_BUTTON:
dynos_opt_convert_button(opt->label, opt->actionFn);
break;
default:
break;
}
}
}
void dynos_opt_convert_vanilla_main_menu() {
dynos_opt_convert_menu(&menuMain);
}
#endif

View file

@ -10,9 +10,7 @@ extern "C" {
#include "game/level_update.h"
#include "game/sound_init.h"
#include "game/object_list_processor.h"
#ifndef COOP
#include "game/options_menu.h"
#endif
extern s8 gDialogBoxState;
extern s16 gMenuMode;
extern s32 gWdwWaterLevelSet;
@ -25,10 +23,8 @@ extern void set_play_mode(s16);
// Data
//
#ifndef COOP
s32 gDDDBowsersSub = -1;
s32 gDDDPoles = -1;
#endif
static s32 sDynosWarpLevelNum = -1;
static s32 sDynosWarpAreaNum = -1;
static s32 sDynosWarpActNum = -1;
@ -64,9 +60,7 @@ bool DynOS_Warp_ExitLevel(s32 aDelay) {
}
// Close the pause menu if it was open
#ifndef COOP
optmenu_toggle();
#endif
level_set_transition(0, NULL);
gDialogBoxState = 0;
gMenuMode = -1;
@ -98,9 +92,7 @@ bool DynOS_Warp_ToCastle(s32 aLevel) {
}
// Close the pause menu if it was open
#ifndef COOP
optmenu_toggle();
#endif
level_set_transition(0, NULL);
gDialogBoxState = 0;
gMenuMode = -1;
@ -155,7 +147,6 @@ void DynOS_Warp_SetParam(s32 aLevel, s32 aIndex) {
sDynosWarpPrevParamIndex = aIndex;
}
#ifndef COOP
switch (aLevel) {
case LEVEL_DDD:
switch (aIndex) {
@ -195,7 +186,6 @@ void DynOS_Warp_SetParam(s32 aLevel, s32 aIndex) {
}
break;
}
#endif
}
//
@ -209,9 +199,7 @@ static void *DynOS_Warp_UpdateWarp(void *aCmd, bool aIsLevelInitDone) {
if (sDynosWarpTargetArea == -1) {
// Close the pause menu if it was open
#ifndef COOP
optmenu_toggle();
#endif
level_set_transition(0, NULL);
gDialogBoxState = 0;
gMenuMode = -1;
@ -323,13 +311,11 @@ static void *DynOS_Warp_UpdateWarp(void *aCmd, bool aIsLevelInitDone) {
}
}
#ifndef COOP
// Reset DDD settings to default
if (gCurrCourseNum == COURSE_NONE) {
gDDDBowsersSub = -1;
gDDDPoles = -1;
}
#endif
return NULL;
}

View file

@ -7,6 +7,7 @@
#include <ultra64.h>
#include "macros.h"
#include "data/dynos.c.h"
#include "data/dynos_coop.c.h"
#include "pc/network/version.h"
// Certain functions are marked as having return values, but do not

View file

@ -2821,6 +2821,12 @@ s16 render_pause_courses_and_castle(void) {
if (gPlayer1Controller->buttonPressed & R_TRIG)
djui_panel_pause_create(NULL);
#ifndef COOP
// call into DynOS's menu system
optmenu_draw();
optmenu_draw_prompt();
#endif
return 0;
}

8
src/game/options_menu.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef OPTIONS_MENU_H
#define OPTIONS_MENU_H
void optmenu_draw(void);
void optmenu_draw_prompt(void);
void optmenu_toggle(void);
#endif