mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-04-27 12:51:42 +00:00
options_menu: implemented greyed out options and localisation
This commit is contained in:
parent
49b6b0e262
commit
1f7f093e22
12 changed files with 300 additions and 181 deletions
|
|
@ -36,6 +36,7 @@
|
||||||
#include "SWA/CSD/CsdProject.h"
|
#include "SWA/CSD/CsdProject.h"
|
||||||
#include "SWA/CSD/CsdTexListMirage.h"
|
#include "SWA/CSD/CsdTexListMirage.h"
|
||||||
#include "SWA/CSD/GameObjectCSD.h"
|
#include "SWA/CSD/GameObjectCSD.h"
|
||||||
|
#include "SWA/HUD/Pause/HudPause.h"
|
||||||
#include "SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h"
|
#include "SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h"
|
||||||
#include "SWA/Player/Character/EvilSonic/EvilSonic.h"
|
#include "SWA/Player/Character/EvilSonic/EvilSonic.h"
|
||||||
#include "SWA/Player/Character/EvilSonic/EvilSonicContext.h"
|
#include "SWA/Player/Character/EvilSonic/EvilSonicContext.h"
|
||||||
|
|
|
||||||
55
UnleashedRecomp/api/SWA/HUD/Pause/HudPause.h
Normal file
55
UnleashedRecomp/api/SWA/HUD/Pause/HudPause.h
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SWA.inl>
|
||||||
|
|
||||||
|
namespace SWA
|
||||||
|
{
|
||||||
|
enum EActionType : uint32_t
|
||||||
|
{
|
||||||
|
eActionType_Undefined,
|
||||||
|
eActionType_Status,
|
||||||
|
eActionType_Return,
|
||||||
|
eActionType_Inventory,
|
||||||
|
eActionType_Skills,
|
||||||
|
eActionType_Lab,
|
||||||
|
eActionType_Wait,
|
||||||
|
eActionType_Restart = 8,
|
||||||
|
eActionType_Continue
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EMenuType : uint32_t
|
||||||
|
{
|
||||||
|
eMenuType_WorldMap,
|
||||||
|
eMenuType_Village,
|
||||||
|
eMenuType_Stage,
|
||||||
|
eMenuType_Hub,
|
||||||
|
eMenuType_Misc
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EStatusType : uint32_t
|
||||||
|
{
|
||||||
|
eStatusType_Idle,
|
||||||
|
eStatusType_Accept,
|
||||||
|
eStatusType_Decline
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ETransitionType : uint32_t
|
||||||
|
{
|
||||||
|
eTransitionType_Undefined,
|
||||||
|
eTransitionType_Quit = 2,
|
||||||
|
eTransitionType_Dialog = 5,
|
||||||
|
eTransitionType_Hide,
|
||||||
|
eTransitionType_Abort,
|
||||||
|
eTransitionType_SubMenu
|
||||||
|
};
|
||||||
|
|
||||||
|
class CHudPause : public CGameObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SWA_INSERT_PADDING(0xC8);
|
||||||
|
be<EActionType> m_Action;
|
||||||
|
be<EMenuType> m_Menu;
|
||||||
|
be<EStatusType> m_Status;
|
||||||
|
be<ETransitionType> m_Transition;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -15,7 +15,7 @@ PPC_FUNC(sub_822C1130)
|
||||||
SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
|
SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
|
||||||
|
|
||||||
Window::Update();
|
Window::Update();
|
||||||
audio_patches::Update(g_deltaTime);
|
AudioPatches::Update(g_deltaTime);
|
||||||
|
|
||||||
__imp__sub_822C1130(ctx, base);
|
__imp__sub_822C1130(ctx, base);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "config_detail.h"
|
#include <cfg/config_detail.h>
|
||||||
#include "config_locale.h"
|
#include <locale/config_locale.h>
|
||||||
#include "exports.h"
|
#include <exports.h>
|
||||||
|
|
||||||
class Config
|
class Config
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "config_detail.h"
|
#include <cfg/config_detail.h>
|
||||||
|
|
||||||
#define CONFIG_DEFINE_LOCALE(name) \
|
#define CONFIG_DEFINE_LOCALE(name) \
|
||||||
inline static std::unordered_map<ELanguage, std::tuple<std::string, std::string>> g_##name##_locale =
|
inline static std::unordered_map<ELanguage, std::tuple<std::string, std::string>> g_##name##_locale =
|
||||||
65
UnleashedRecomp/locale/locale.h
Normal file
65
UnleashedRecomp/locale/locale.h
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cfg/config.h>
|
||||||
|
|
||||||
|
inline static std::string g_localeMissing = "<missing string>";
|
||||||
|
|
||||||
|
inline static std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_locale
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"Options_Category_System",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "SYSTEM" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Options_Category_Input",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "INPUT" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Options_Category_Audio",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "AUDIO" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Options_Category_Video",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "VIDEO" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Options_Value_Max",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "MAX" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Options_Desc_NotAvailable",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "This option is not available at this location." }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string& Localise(const char* key)
|
||||||
|
{
|
||||||
|
if (!g_locale.count(key))
|
||||||
|
return g_localeMissing;
|
||||||
|
|
||||||
|
if (!g_locale[key].count(Config::Language))
|
||||||
|
{
|
||||||
|
if (g_locale[key].count(ELanguage::English))
|
||||||
|
{
|
||||||
|
return g_locale[key][ELanguage::English];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return g_localeMissing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_locale[key][Config::Language];
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,7 @@ be<float>* GetVolume(bool isMusic = true)
|
||||||
return (be<float>*)g_memory.Translate(4 * ((int)isMusic + 0x1C) + ((be<uint32_t>*)g_memory.Translate(ppUnkClass->get() + 4))->get());
|
return (be<float>*)g_memory.Translate(4 * ((int)isMusic + 0x1C) + ((be<uint32_t>*)g_memory.Translate(ppUnkClass->get() + 4))->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_patches::Update(float deltaTime)
|
void AudioPatches::Update(float deltaTime)
|
||||||
{
|
{
|
||||||
auto pMusicVolume = GetVolume();
|
auto pMusicVolume = GetVolume();
|
||||||
auto pSEVolume = GetVolume(false);
|
auto pSEVolume = GetVolume(false);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class audio_patches
|
class AudioPatches
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void Update(float deltaTime);
|
static void Update(float deltaTime);
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@
|
||||||
#include <api/SWA.h>
|
#include <api/SWA.h>
|
||||||
#include <ui/options_menu.h>
|
#include <ui/options_menu.h>
|
||||||
|
|
||||||
bool m_isOptionsFromPause = false;
|
|
||||||
|
|
||||||
void CHudPauseAddOptionsItemMidAsmHook(PPCRegister& pThis)
|
void CHudPauseAddOptionsItemMidAsmHook(PPCRegister& pThis)
|
||||||
{
|
{
|
||||||
auto pStrMemory = __HH_ALLOC(8);
|
auto pStrMemory = __HH_ALLOC(8);
|
||||||
|
|
@ -23,74 +21,43 @@ void CHudPauseAddOptionsItemMidAsmHook(PPCRegister& pThis)
|
||||||
|
|
||||||
bool InjectOptionsBehaviour(uint32_t pThis, uint32_t count)
|
bool InjectOptionsBehaviour(uint32_t pThis, uint32_t count)
|
||||||
{
|
{
|
||||||
auto status = *(be<uint32_t>*)g_memory.Translate(pThis + 0x190);
|
auto pHudPause = (SWA::CHudPause*)g_memory.Translate(pThis);
|
||||||
auto pauseType = *(be<uint32_t>*)g_memory.Translate(pThis + 0x18C);
|
|
||||||
auto cursorIndex = *(be<uint32_t>*)g_memory.Translate(4 * (*(be<uint32_t>*)g_memory.Translate(pThis + 0x19C) + 0x68) + pThis);
|
auto cursorIndex = *(be<uint32_t>*)g_memory.Translate(4 * (*(be<uint32_t>*)g_memory.Translate(pThis + 0x19C) + 0x68) + pThis);
|
||||||
|
|
||||||
/*
|
auto exitType = SWA::eActionType_Undefined;
|
||||||
0 ---- Undefined
|
auto transitionType = SWA::eTransitionType_Undefined;
|
||||||
1 ---- Status
|
|
||||||
2 ---- Return to Previous Area
|
|
||||||
3 ---- Inventory
|
|
||||||
4 ---- Skills
|
|
||||||
5 ---- Go to the Lab
|
|
||||||
6 ---- Wait until Day/Night
|
|
||||||
7 ---- Undefined
|
|
||||||
8 ---- Restart Stage
|
|
||||||
9 ---- Continue Stage
|
|
||||||
<=10 - Undefined
|
|
||||||
*/
|
|
||||||
auto pExitType = (be<uint32_t>*)g_memory.Translate(pThis + 0x188);
|
|
||||||
|
|
||||||
/*
|
switch (pHudPause->m_Menu)
|
||||||
0 --- Undefined
|
|
||||||
1 --- Unknown menu
|
|
||||||
2 --- Quit menu
|
|
||||||
3 --- Pause menu?
|
|
||||||
4 --- Undefined
|
|
||||||
5 --- Make cursor small?
|
|
||||||
6 --- Hide UI and ignore face buttons
|
|
||||||
7 --- Stop updating pause menu
|
|
||||||
8 --- Hide UI (apart from pause header) and ignore face buttons
|
|
||||||
<=9 - Stop updating pause menu
|
|
||||||
*/
|
|
||||||
auto pTransitionType = (be<uint32_t>*)g_memory.Translate(pThis + 0x194);
|
|
||||||
|
|
||||||
auto exitType = 0;
|
|
||||||
auto transitionType = 0;
|
|
||||||
|
|
||||||
switch (pauseType)
|
|
||||||
{
|
{
|
||||||
case 0: // World Map
|
case SWA::eMenuType_WorldMap:
|
||||||
case 2: // Stage
|
case SWA::eMenuType_Stage:
|
||||||
case 4: // Misc
|
case SWA::eMenuType_Misc:
|
||||||
exitType = 2;
|
exitType = SWA::eActionType_Return;
|
||||||
transitionType = 2;
|
transitionType = SWA::eTransitionType_Quit;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: // Village
|
case SWA::eMenuType_Village:
|
||||||
case 3: // Hub
|
case SWA::eMenuType_Hub:
|
||||||
exitType = 2;
|
exitType = SWA::eActionType_Return;
|
||||||
transitionType = 6;
|
transitionType = SWA::eTransitionType_Hide;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == 1)
|
if (pHudPause->m_Status == SWA::eStatusType_Accept)
|
||||||
{
|
{
|
||||||
if (cursorIndex == count - 2)
|
if (cursorIndex == count - 2)
|
||||||
{
|
{
|
||||||
OptionsMenu::Open(pauseType);
|
OptionsMenu::Open(true, pHudPause->m_Menu);
|
||||||
m_isOptionsFromPause = true;
|
|
||||||
|
|
||||||
*pExitType = 0;
|
pHudPause->m_Action = SWA::eActionType_Undefined;
|
||||||
*pTransitionType = 6;
|
pHudPause->m_Transition = SWA::eTransitionType_Hide;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cursorIndex == count - 1)
|
else if (cursorIndex == count - 1)
|
||||||
{
|
{
|
||||||
*pExitType = exitType;
|
pHudPause->m_Action = exitType;
|
||||||
*pTransitionType = transitionType;
|
pHudPause->m_Transition = transitionType;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -130,21 +97,18 @@ bool CHudPauseMiscInjectOptionsMidAsmHook(PPCRegister& pThis)
|
||||||
PPC_FUNC_IMPL(__imp__sub_824B0930);
|
PPC_FUNC_IMPL(__imp__sub_824B0930);
|
||||||
PPC_FUNC(sub_824B0930)
|
PPC_FUNC(sub_824B0930)
|
||||||
{
|
{
|
||||||
if (!OptionsMenu::s_isVisible || !m_isOptionsFromPause)
|
if (!OptionsMenu::s_isVisible || !OptionsMenu::s_isPause)
|
||||||
{
|
{
|
||||||
__imp__sub_824B0930(ctx, base);
|
__imp__sub_824B0930(ctx, base);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pauseType = *(be<uint32_t>*)g_memory.Translate(ctx.r3.u32 + 0x18C);
|
|
||||||
|
|
||||||
if (auto pInputState = SWA::CInputState::GetInstance())
|
if (auto pInputState = SWA::CInputState::GetInstance())
|
||||||
{
|
{
|
||||||
// TODO: disable Start button closing menu.
|
// TODO: disable Start button closing menu.
|
||||||
if (OptionsMenu::CanClose() && pInputState->GetPadState().IsTapped(SWA::eKeyState_B))
|
if (OptionsMenu::CanClose() && pInputState->GetPadState().IsTapped(SWA::eKeyState_B))
|
||||||
{
|
{
|
||||||
OptionsMenu::Close(pauseType);
|
OptionsMenu::Close();
|
||||||
m_isOptionsFromPause = false;
|
|
||||||
|
|
||||||
// Re-open pause menu.
|
// Re-open pause menu.
|
||||||
GuestToHostFunction<int>(0x824AFD28, ctx.r3.u32, 0, 0, 0, 1);
|
GuestToHostFunction<int>(0x824AFD28, ctx.r3.u32, 0, 0, 0, 1);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ PPC_FUNC(sub_825882B8)
|
||||||
{
|
{
|
||||||
Game_PlaySound("sys_worldmap_window");
|
Game_PlaySound("sys_worldmap_window");
|
||||||
Game_PlaySound("sys_worldmap_decide");
|
Game_PlaySound("sys_worldmap_decide");
|
||||||
|
|
||||||
OptionsMenu::Open();
|
OptionsMenu::Open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -29,6 +30,7 @@ PPC_FUNC(sub_825882B8)
|
||||||
if (OptionsMenu::CanClose() && pInputState->GetPadState().IsTapped(SWA::eKeyState_B))
|
if (OptionsMenu::CanClose() && pInputState->GetPadState().IsTapped(SWA::eKeyState_B))
|
||||||
{
|
{
|
||||||
Game_PlaySound("sys_worldmap_cansel");
|
Game_PlaySound("sys_worldmap_cansel");
|
||||||
|
|
||||||
OptionsMenu::Close();
|
OptionsMenu::Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include <gpu/imgui_common.h>
|
#include <gpu/imgui_common.h>
|
||||||
#include <kernel/heap.h>
|
#include <kernel/heap.h>
|
||||||
#include <kernel/memory.h>
|
#include <kernel/memory.h>
|
||||||
|
#include <locale/locale.h>
|
||||||
|
|
||||||
constexpr float COMMON_PADDING_POS_Y = 118.0f;
|
constexpr float COMMON_PADDING_POS_Y = 118.0f;
|
||||||
constexpr float COMMON_PADDING_POS_X = 30.0f;
|
constexpr float COMMON_PADDING_POS_X = 30.0f;
|
||||||
|
|
@ -16,6 +17,7 @@ static ImFont* g_dfsogeistdFont;
|
||||||
static ImFont* g_newRodinFont;
|
static ImFont* g_newRodinFont;
|
||||||
|
|
||||||
static const IConfigDef* g_selectedItem;
|
static const IConfigDef* g_selectedItem;
|
||||||
|
static bool g_isSelectedItemAccessible;
|
||||||
|
|
||||||
static bool g_isEnterKeyBuffered = false;
|
static bool g_isEnterKeyBuffered = false;
|
||||||
|
|
||||||
|
|
@ -151,7 +153,7 @@ static void DrawScanlineBars()
|
||||||
auto& res = ImGui::GetIO().DisplaySize;
|
auto& res = ImGui::GetIO().DisplaySize;
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
|
||||||
if (OptionsMenu::s_isStage)
|
if (OptionsMenu::s_pauseMenuType != SWA::eMenuType_WorldMap)
|
||||||
{
|
{
|
||||||
// Top bar fade
|
// Top bar fade
|
||||||
drawList->AddRectFilledMultiColor(
|
drawList->AddRectFilledMultiColor(
|
||||||
|
|
@ -291,19 +293,23 @@ static void DrawContainer(ImVec2 min, ImVec2 max)
|
||||||
drawList->PushClipRect({ min.x + gridSize * 2.0f, min.y + gridSize * 2.0f }, { max.x - gridSize * 2.0f + 1.0f, max.y - gridSize * 2.0f + 1.0f });
|
drawList->PushClipRect({ min.x + gridSize * 2.0f, min.y + gridSize * 2.0f }, { max.x - gridSize * 2.0f + 1.0f, max.y - gridSize * 2.0f + 1.0f });
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: localise this.
|
static int32_t g_categoryCount = 4;
|
||||||
static constexpr const char* CATEGORIES[] =
|
|
||||||
{
|
|
||||||
"SYSTEM",
|
|
||||||
"INPUT",
|
|
||||||
"AUDIO",
|
|
||||||
"VIDEO"
|
|
||||||
};
|
|
||||||
|
|
||||||
static int32_t g_categoryIndex;
|
static int32_t g_categoryIndex;
|
||||||
static ImVec2 g_categoryAnimMin;
|
static ImVec2 g_categoryAnimMin;
|
||||||
static ImVec2 g_categoryAnimMax;
|
static ImVec2 g_categoryAnimMax;
|
||||||
|
|
||||||
|
static std::string& GetCategory(int index)
|
||||||
|
{
|
||||||
|
// TODO: Don't use raw numbers here!
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0: return Localise("Options_Category_System");
|
||||||
|
case 1: return Localise("Options_Category_Input");
|
||||||
|
case 2: return Localise("Options_Category_Audio");
|
||||||
|
case 3: return Localise("Options_Category_Video");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t g_firstVisibleRowIndex;
|
static int32_t g_firstVisibleRowIndex;
|
||||||
static int32_t g_prevSelectedRowIndex;
|
static int32_t g_prevSelectedRowIndex;
|
||||||
static int32_t g_selectedRowIndex;
|
static int32_t g_selectedRowIndex;
|
||||||
|
|
@ -352,12 +358,12 @@ static bool DrawCategories()
|
||||||
{
|
{
|
||||||
--g_categoryIndex;
|
--g_categoryIndex;
|
||||||
if (g_categoryIndex < 0)
|
if (g_categoryIndex < 0)
|
||||||
g_categoryIndex = std::size(CATEGORIES) - 1;
|
g_categoryIndex = g_categoryCount - 1;
|
||||||
}
|
}
|
||||||
else if (moveRight)
|
else if (moveRight)
|
||||||
{
|
{
|
||||||
++g_categoryIndex;
|
++g_categoryIndex;
|
||||||
if (g_categoryIndex >= std::size(CATEGORIES))
|
if (g_categoryIndex >= g_categoryCount)
|
||||||
g_categoryIndex = 0;
|
g_categoryIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -376,22 +382,22 @@ static bool DrawCategories()
|
||||||
float tabPadding = gridSize;
|
float tabPadding = gridSize;
|
||||||
|
|
||||||
float size = Scale(32.0f);
|
float size = Scale(32.0f);
|
||||||
ImVec2 textSizes[std::size(CATEGORIES)];
|
ImVec2 textSizes[g_categoryCount];
|
||||||
float tabWidthSum = 0.0f;
|
float tabWidthSum = 0.0f;
|
||||||
for (size_t i = 0; i < std::size(CATEGORIES); i++)
|
for (size_t i = 0; i < g_categoryCount; i++)
|
||||||
{
|
{
|
||||||
textSizes[i] = g_dfsogeistdFont->CalcTextSizeA(size, FLT_MAX, 0.0f, CATEGORIES[i]);
|
textSizes[i] = g_dfsogeistdFont->CalcTextSizeA(size, FLT_MAX, 0.0f, GetCategory(i).c_str());
|
||||||
tabWidthSum += textSizes[i].x + textPadding * 2.0f;
|
tabWidthSum += textSizes[i].x + textPadding * 2.0f;
|
||||||
}
|
}
|
||||||
tabWidthSum += (std::size(CATEGORIES) - 1) * tabPadding;
|
tabWidthSum += (g_categoryCount - 1) * tabPadding;
|
||||||
|
|
||||||
float tabHeight = gridSize * 4.0f;
|
float tabHeight = gridSize * 4.0f;
|
||||||
float xOffset = ((clipRectMax.x - clipRectMin.x) - tabWidthSum) / 2.0f;
|
float xOffset = ((clipRectMax.x - clipRectMin.x) - tabWidthSum) / 2.0f;
|
||||||
xOffset -= (1.0 - motion) * gridSize * 4.0;
|
xOffset -= (1.0 - motion) * gridSize * 4.0;
|
||||||
|
|
||||||
ImVec2 minVec[std::size(CATEGORIES)];
|
ImVec2 minVec[g_categoryCount];
|
||||||
|
|
||||||
for (size_t i = 0; i < std::size(CATEGORIES); i++)
|
for (size_t i = 0; i < g_categoryCount; i++)
|
||||||
{
|
{
|
||||||
ImVec2 min = { clipRectMin.x + xOffset, clipRectMin.y };
|
ImVec2 min = { clipRectMin.x + xOffset, clipRectMin.y };
|
||||||
|
|
||||||
|
|
@ -454,7 +460,7 @@ static bool DrawCategories()
|
||||||
minVec[i] = min;
|
minVec[i] = min;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < std::size(CATEGORIES); i++)
|
for (size_t i = 0; i < g_categoryCount; i++)
|
||||||
{
|
{
|
||||||
auto& min = minVec[i];
|
auto& min = minVec[i];
|
||||||
uint8_t alpha = (i == g_categoryIndex ? 235 : 128) * motion;
|
uint8_t alpha = (i == g_categoryIndex ? 235 : 128) * motion;
|
||||||
|
|
@ -470,7 +476,7 @@ static bool DrawCategories()
|
||||||
size,
|
size,
|
||||||
min,
|
min,
|
||||||
IM_COL32_WHITE,
|
IM_COL32_WHITE,
|
||||||
CATEGORIES[i],
|
GetCategory(i).c_str(),
|
||||||
Scale(3),
|
Scale(3),
|
||||||
IM_COL32_BLACK);
|
IM_COL32_BLACK);
|
||||||
|
|
||||||
|
|
@ -490,16 +496,13 @@ static bool DrawCategories()
|
||||||
extern void VideoConfigValueChangedCallback(IConfigDef* config);
|
extern void VideoConfigValueChangedCallback(IConfigDef* config);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* config, T valueMin = T(0), T valueCenter = T(0.5), T valueMax = T(1))
|
static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* config, bool isAccessible, T valueMin = T(0), T valueCenter = T(0.5), T valueMax = T(1))
|
||||||
{
|
{
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
auto clipRectMin = drawList->GetClipRectMin();
|
auto clipRectMin = drawList->GetClipRectMin();
|
||||||
auto clipRectMax = drawList->GetClipRectMax();
|
auto clipRectMax = drawList->GetClipRectMax();
|
||||||
auto& padState = SWA::CInputState::GetInstance()->GetPadState();
|
auto& padState = SWA::CInputState::GetInstance()->GetPadState();
|
||||||
|
|
||||||
constexpr ImU32 COLOR0 = IM_COL32(0xE2, 0x71, 0x22, 0x80);
|
|
||||||
constexpr ImU32 COLOR1 = IM_COL32(0x92, 0xFF, 0x31, 0x80);
|
|
||||||
|
|
||||||
auto gridSize = Scale(GRID_SIZE);
|
auto gridSize = Scale(GRID_SIZE);
|
||||||
auto optionWidth = gridSize * 54.0f;
|
auto optionWidth = gridSize * 54.0f;
|
||||||
auto optionHeight = gridSize * 5.5f;
|
auto optionHeight = gridSize * 5.5f;
|
||||||
|
|
@ -524,64 +527,75 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
if (g_selectedRowIndex == rowIndex)
|
if (g_selectedRowIndex == rowIndex)
|
||||||
{
|
{
|
||||||
g_selectedItem = config;
|
g_selectedItem = config;
|
||||||
|
g_isSelectedItemAccessible = isAccessible;
|
||||||
|
|
||||||
if (!g_isEnterKeyBuffered)
|
if (!g_isEnterKeyBuffered)
|
||||||
{
|
{
|
||||||
if constexpr (std::is_same_v<T, bool>)
|
if (isAccessible)
|
||||||
{
|
{
|
||||||
if (padState.IsTapped(SWA::eKeyState_A))
|
if constexpr (std::is_same_v<T, bool>)
|
||||||
{
|
{
|
||||||
config->Value = !config->Value;
|
if (padState.IsTapped(SWA::eKeyState_A))
|
||||||
|
|
||||||
if (config->Callback)
|
|
||||||
config->Callback(config);
|
|
||||||
|
|
||||||
VideoConfigValueChangedCallback(config);
|
|
||||||
|
|
||||||
Game_PlaySound("sys_worldmap_finaldecide");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static T s_oldValue;
|
|
||||||
|
|
||||||
if (padState.IsTapped(SWA::eKeyState_A))
|
|
||||||
{
|
|
||||||
g_lockedOnOption ^= true;
|
|
||||||
if (g_lockedOnOption)
|
|
||||||
{
|
{
|
||||||
g_leftWasHeld = false;
|
config->Value = !config->Value;
|
||||||
g_rightWasHeld = false;
|
|
||||||
// remember value
|
|
||||||
s_oldValue = config->Value;
|
|
||||||
|
|
||||||
Game_PlaySound("sys_worldmap_decide");
|
if (config->Callback)
|
||||||
}
|
config->Callback(config);
|
||||||
else
|
|
||||||
{
|
VideoConfigValueChangedCallback(config);
|
||||||
// released lock, call video callbacks if value is different
|
|
||||||
if (config->Value != s_oldValue)
|
|
||||||
VideoConfigValueChangedCallback(config);
|
|
||||||
|
|
||||||
Game_PlaySound("sys_worldmap_finaldecide");
|
Game_PlaySound("sys_worldmap_finaldecide");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (padState.IsTapped(SWA::eKeyState_B))
|
else
|
||||||
{
|
{
|
||||||
// released lock, restore old value
|
static T s_oldValue;
|
||||||
config->Value = s_oldValue;
|
|
||||||
g_lockedOnOption = false;
|
|
||||||
|
|
||||||
Game_PlaySound("sys_worldmap_cansel");
|
if (padState.IsTapped(SWA::eKeyState_A))
|
||||||
|
{
|
||||||
|
g_lockedOnOption ^= true;
|
||||||
|
|
||||||
|
if (g_lockedOnOption)
|
||||||
|
{
|
||||||
|
g_leftWasHeld = false;
|
||||||
|
g_rightWasHeld = false;
|
||||||
|
// remember value
|
||||||
|
s_oldValue = config->Value;
|
||||||
|
|
||||||
|
Game_PlaySound("sys_worldmap_decide");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// released lock, call video callbacks if value is different
|
||||||
|
if (config->Value != s_oldValue)
|
||||||
|
VideoConfigValueChangedCallback(config);
|
||||||
|
|
||||||
|
Game_PlaySound("sys_worldmap_finaldecide");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (padState.IsTapped(SWA::eKeyState_B))
|
||||||
|
{
|
||||||
|
// released lock, restore old value
|
||||||
|
config->Value = s_oldValue;
|
||||||
|
g_lockedOnOption = false;
|
||||||
|
|
||||||
|
Game_PlaySound("sys_worldmap_cansel");
|
||||||
|
}
|
||||||
|
|
||||||
|
lockedOnOption = g_lockedOnOption;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
lockedOnOption = g_lockedOnOption;
|
else
|
||||||
|
{
|
||||||
|
if (padState.IsTapped(SWA::eKeyState_A))
|
||||||
|
Game_PlaySound("sys_actstg_stateserror");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fadedOut = g_lockedOnOption && g_selectedItem != config;
|
auto fadedOut = (g_lockedOnOption && g_selectedItem != config) || !isAccessible;
|
||||||
float alpha = fadedOut ? 0.5f : 1.0f;
|
auto alpha = fadedOut ? 0.5f : 1.0f;
|
||||||
|
auto textColour = IM_COL32(255, 255, 255, 255 * alpha);
|
||||||
|
|
||||||
if (g_selectedItem == config)
|
if (g_selectedItem == config)
|
||||||
{
|
{
|
||||||
|
|
@ -589,13 +603,16 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
double animRatio = std::clamp((ImGui::GetTime() - g_rowSelectionTime) * 60.0 / 8.0, 0.0, 1.0);
|
double animRatio = std::clamp((ImGui::GetTime() - g_rowSelectionTime) * 60.0 / 8.0, 0.0, 1.0);
|
||||||
prevItemOffset *= pow(1.0 - animRatio, 3.0);
|
prevItemOffset *= pow(1.0 - animRatio, 3.0);
|
||||||
|
|
||||||
drawList->AddRectFilledMultiColor({ min.x, min.y + prevItemOffset }, { max.x, max.y + prevItemOffset }, COLOR0, COLOR0, COLOR1, COLOR1);
|
auto c0 = IM_COL32(0xE2, 0x71, 0x22, isAccessible ? 0x80 : 0x30);
|
||||||
|
auto c1 = IM_COL32(0x92, 0xFF, 0x31, isAccessible ? 0x80 : 0x30);
|
||||||
|
|
||||||
DrawTextWithMarquee(g_seuratFont, size, textPos, min, max, IM_COL32_WHITE, configName.c_str(), g_rowSelectionTime, 0.9, 250.0);
|
drawList->AddRectFilledMultiColor({ min.x, min.y + prevItemOffset }, { max.x, max.y + prevItemOffset }, c0, c0, c1, c1);
|
||||||
|
|
||||||
|
DrawTextWithMarquee(g_seuratFont, size, textPos, min, max, textColour, configName.c_str(), g_rowSelectionTime, 0.9, 250.0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
drawList->AddText(g_seuratFont, size, textPos, IM_COL32(255, 255, 255, 255 * alpha), configName.c_str(), 0, 0.0f, &textClipRect);
|
drawList->AddText(g_seuratFont, size, textPos, textColour, configName.c_str(), 0, 0.0f, &textClipRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right side
|
// Right side
|
||||||
|
|
@ -773,7 +790,7 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
if constexpr (std::is_same_v<T, float>)
|
if constexpr (std::is_same_v<T, float>)
|
||||||
valueText = std::format("{}%", int32_t(round(config->Value * 100.0f)));
|
valueText = std::format("{}%", int32_t(round(config->Value * 100.0f)));
|
||||||
else if constexpr (std::is_same_v<T, int32_t>)
|
else if constexpr (std::is_same_v<T, int32_t>)
|
||||||
valueText = config->Value >= valueMax ? "MAX" : std::format("{}", config->Value);
|
valueText = config->Value >= valueMax ? Localise("Options_Value_Max") : std::format("{}", config->Value);
|
||||||
else
|
else
|
||||||
valueText = config->GetValueLocalised();
|
valueText = config->GetValueLocalised();
|
||||||
|
|
||||||
|
|
@ -816,48 +833,50 @@ static void DrawConfigOptions()
|
||||||
|
|
||||||
int32_t rowCount = 0;
|
int32_t rowCount = 0;
|
||||||
|
|
||||||
|
bool isStage = OptionsMenu::s_pauseMenuType == SWA::eMenuType_Stage || OptionsMenu::s_pauseMenuType == SWA::eMenuType_Hub;
|
||||||
|
|
||||||
// TODO: Don't use raw numbers here!
|
// TODO: Don't use raw numbers here!
|
||||||
switch (g_categoryIndex)
|
switch (g_categoryIndex)
|
||||||
{
|
{
|
||||||
case 0: // SYSTEM
|
case 0: // SYSTEM
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::Language);
|
DrawConfigOption(rowCount++, yOffset, &Config::Language, !OptionsMenu::s_isPause);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::Hints);
|
DrawConfigOption(rowCount++, yOffset, &Config::Hints, !isStage);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::ControlTutorial);
|
DrawConfigOption(rowCount++, yOffset, &Config::ControlTutorial, !isStage);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::SaveScoreAtCheckpoints);
|
DrawConfigOption(rowCount++, yOffset, &Config::SaveScoreAtCheckpoints, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::UnleashGaugeBehaviour);
|
DrawConfigOption(rowCount++, yOffset, &Config::UnleashGaugeBehaviour, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::WerehogHubTransformVideo);
|
DrawConfigOption(rowCount++, yOffset, &Config::WerehogHubTransformVideo, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::LogoSkip);
|
DrawConfigOption(rowCount++, yOffset, &Config::LogoSkip, true);
|
||||||
break;
|
break;
|
||||||
case 1: // INPUT
|
case 1: // INPUT
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::CameraXInvert);
|
DrawConfigOption(rowCount++, yOffset, &Config::CameraXInvert, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::CameraYInvert);
|
DrawConfigOption(rowCount++, yOffset, &Config::CameraYInvert, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::XButtonHoming);
|
DrawConfigOption(rowCount++, yOffset, &Config::XButtonHoming, !OptionsMenu::s_isPause); // TODO: make this editable in stages.
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::UnleashCancel);
|
DrawConfigOption(rowCount++, yOffset, &Config::UnleashCancel, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::BackgroundInput);
|
DrawConfigOption(rowCount++, yOffset, &Config::BackgroundInput, true);
|
||||||
break;
|
break;
|
||||||
case 2: // AUDIO
|
case 2: // AUDIO
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::MusicVolume);
|
DrawConfigOption(rowCount++, yOffset, &Config::MusicVolume, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::SEVolume);
|
DrawConfigOption(rowCount++, yOffset, &Config::SEVolume, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::VoiceLanguage);
|
DrawConfigOption(rowCount++, yOffset, &Config::VoiceLanguage, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::Subtitles);
|
DrawConfigOption(rowCount++, yOffset, &Config::Subtitles, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::WerehogBattleMusic);
|
DrawConfigOption(rowCount++, yOffset, &Config::WerehogBattleMusic, true);
|
||||||
break;
|
break;
|
||||||
case 3: // VIDEO
|
case 3: // VIDEO
|
||||||
// TODO: expose WindowWidth/WindowHeight as WindowSize.
|
// TODO: expose WindowWidth/WindowHeight as WindowSize.
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::ResolutionScale, 0.25f, 1.0f, 2.0f);
|
DrawConfigOption(rowCount++, yOffset, &Config::ResolutionScale, true, 0.25f, 1.0f, 2.0f);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::Fullscreen);
|
DrawConfigOption(rowCount++, yOffset, &Config::Fullscreen, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::VSync);
|
DrawConfigOption(rowCount++, yOffset, &Config::VSync, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::TripleBuffering);
|
DrawConfigOption(rowCount++, yOffset, &Config::TripleBuffering, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::FPS, 15, 120, 240);
|
DrawConfigOption(rowCount++, yOffset, &Config::FPS, true, 15, 120, 240);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::Brightness);
|
DrawConfigOption(rowCount++, yOffset, &Config::Brightness, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::AntiAliasing);
|
DrawConfigOption(rowCount++, yOffset, &Config::AntiAliasing, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::AlphaToCoverage);
|
DrawConfigOption(rowCount++, yOffset, &Config::AlphaToCoverage, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::ShadowResolution);
|
DrawConfigOption(rowCount++, yOffset, &Config::ShadowResolution, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::GITextureFiltering);
|
DrawConfigOption(rowCount++, yOffset, &Config::GITextureFiltering, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::MotionBlur);
|
DrawConfigOption(rowCount++, yOffset, &Config::MotionBlur, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::Xbox360ColourCorrection);
|
DrawConfigOption(rowCount++, yOffset, &Config::Xbox360ColourCorrection, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::MovieScaleMode);
|
DrawConfigOption(rowCount++, yOffset, &Config::MovieScaleMode, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::UIScaleMode);
|
DrawConfigOption(rowCount++, yOffset, &Config::UIScaleMode, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -974,20 +993,27 @@ static void DrawInfoPanel()
|
||||||
{
|
{
|
||||||
auto desc = g_selectedItem->GetDescription();
|
auto desc = g_selectedItem->GetDescription();
|
||||||
|
|
||||||
// Specialised description for resolution scale
|
if (g_isSelectedItemAccessible)
|
||||||
if (g_selectedItem->GetName() == "ResolutionScale")
|
|
||||||
{
|
{
|
||||||
char buf[100];
|
// Specialised description for resolution scale
|
||||||
auto resScale = round(*(float*)g_selectedItem->GetValue() * 1000) / 1000;
|
if (g_selectedItem->GetName() == "ResolutionScale")
|
||||||
|
{
|
||||||
|
char buf[100];
|
||||||
|
auto resScale = round(*(float*)g_selectedItem->GetValue() * 1000) / 1000;
|
||||||
|
|
||||||
std::snprintf(buf, sizeof(buf), desc.c_str(),
|
std::snprintf(buf, sizeof(buf), desc.c_str(),
|
||||||
(int)((float)Window::s_width * resScale),
|
(int)((float)Window::s_width * resScale),
|
||||||
(int)((float)Window::s_height * resScale));
|
(int)((float)Window::s_height * resScale));
|
||||||
|
|
||||||
desc = buf;
|
desc = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc += "\n\n" + g_selectedItem->GetValueDescription();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
desc = Localise("Options_Desc_NotAvailable");
|
||||||
}
|
}
|
||||||
|
|
||||||
desc += "\n\n" + g_selectedItem->GetValueDescription();
|
|
||||||
|
|
||||||
auto size = Scale(26.0f);
|
auto size = Scale(26.0f);
|
||||||
|
|
||||||
|
|
@ -1022,7 +1048,7 @@ void OptionsMenu::Draw()
|
||||||
auto& res = ImGui::GetIO().DisplaySize;
|
auto& res = ImGui::GetIO().DisplaySize;
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
|
||||||
if (s_isStage)
|
if (s_isPause && s_pauseMenuType != SWA::eMenuType_WorldMap)
|
||||||
drawList->AddRectFilled({ 0.0f, 0.0f }, res, IM_COL32(0, 0, 0, 223));
|
drawList->AddRectFilled({ 0.0f, 0.0f }, res, IM_COL32(0, 0, 0, 223));
|
||||||
|
|
||||||
DrawScanlineBars();
|
DrawScanlineBars();
|
||||||
|
|
@ -1030,10 +1056,13 @@ void OptionsMenu::Draw()
|
||||||
DrawInfoPanel();
|
DrawInfoPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OptionsMenu::Open(bool stage)
|
void OptionsMenu::Open(bool isPause, SWA::EMenuType pauseMenuType)
|
||||||
{
|
{
|
||||||
s_isVisible = true;
|
s_isVisible = true;
|
||||||
s_isStage = stage;
|
s_isPause = isPause;
|
||||||
|
|
||||||
|
s_pauseMenuType = pauseMenuType;
|
||||||
|
|
||||||
g_appearTime = ImGui::GetTime();
|
g_appearTime = ImGui::GetTime();
|
||||||
g_categoryIndex = 0;
|
g_categoryIndex = 0;
|
||||||
g_categoryAnimMin = { 0.0f, 0.0f };
|
g_categoryAnimMin = { 0.0f, 0.0f };
|
||||||
|
|
@ -1051,10 +1080,9 @@ void OptionsMenu::Open(bool stage)
|
||||||
// TODO: animate Miles Electric in if we're in a stage.
|
// TODO: animate Miles Electric in if we're in a stage.
|
||||||
}
|
}
|
||||||
|
|
||||||
void OptionsMenu::Close(bool stage)
|
void OptionsMenu::Close()
|
||||||
{
|
{
|
||||||
s_isVisible = false;
|
s_isVisible = false;
|
||||||
s_isStage = stage;
|
|
||||||
|
|
||||||
*(bool*)g_memory.Translate(0x8328BB26) = true;
|
*(bool*)g_memory.Translate(0x8328BB26) = true;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,19 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <api/SWA.h>
|
||||||
|
|
||||||
struct OptionsMenu
|
struct OptionsMenu
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline static bool s_isVisible = false;
|
inline static bool s_isVisible = false;
|
||||||
inline static bool s_isStage = false;
|
inline static bool s_isPause = false;
|
||||||
|
|
||||||
|
inline static SWA::EMenuType s_pauseMenuType;
|
||||||
|
|
||||||
static void Init();
|
static void Init();
|
||||||
static void Draw();
|
static void Draw();
|
||||||
static void Open(bool stage = false);
|
static void Open(bool isPause = false, SWA::EMenuType pauseMenuType = SWA::eMenuType_WorldMap);
|
||||||
static void Close(bool stage = false);
|
static void Close();
|
||||||
|
|
||||||
static bool CanClose();
|
static bool CanClose();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue