mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2025-10-30 08:01:01 +00:00
Ported the rest of DynOS, but left the options menu disabled
This commit is contained in:
parent
b3ed387711
commit
f92857704d
17 changed files with 1457 additions and 40 deletions
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
10
data/dynos_coop.c.h
Normal 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
10
data/dynos_coop_c.cpp
Normal 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
|
||||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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
748
data/dynos_opt.cpp
Normal 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
62
data/dynos_opt_config.cpp
Normal 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
70
data/dynos_opt_cont.cpp
Normal 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
309
data/dynos_opt_render.cpp
Normal 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
159
data/dynos_opt_vanilla.cpp
Normal 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;
|
||||
}
|
||||
72
data/dynos_opt_vanilla_c.c
Normal file
72
data/dynos_opt_vanilla_c.c
Normal 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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
8
src/game/options_menu.h
Normal 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
|
||||
Loading…
Add table
Reference in a new issue