From 4ae78459719add87b49d8a46bf8dcf44b27258f3 Mon Sep 17 00:00:00 2001 From: somewhatlurker <52014015+somewhatlurker@users.noreply.github.com> Date: Mon, 21 Oct 2019 01:20:44 +1100 Subject: [PATCH] pause: add SE volume submenu, improve some state management --- .../TLAC/Components/Input/InputEmulator.cpp | 4 +- .../source/plugins/TLAC/Components/Pause.cpp | 181 +++++++++++------- .../source/plugins/TLAC/Components/Pause.h | 41 +++- 3 files changed, 150 insertions(+), 76 deletions(-) diff --git a/source-code/source/plugins/TLAC/Components/Input/InputEmulator.cpp b/source-code/source/plugins/TLAC/Components/Input/InputEmulator.cpp index ce6776a..f7d6df1 100644 --- a/source-code/source/plugins/TLAC/Components/Input/InputEmulator.cpp +++ b/source-code/source/plugins/TLAC/Components/Input/InputEmulator.cpp @@ -237,13 +237,13 @@ namespace TLAC::Components { JvsButtons buttons = JVS_NONE; - if ((Pause::isPaused || !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN)) && + if ((Pause::pause || !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN)) && buttonTestFunc(MenuLBinding)) { buttons |= JVS_L; return buttons; } - if ((Pause::isPaused || !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN)) && + if ((Pause::pause || !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN)) && buttonTestFunc(MenuRBinding)) { buttons |= JVS_R; diff --git a/source-code/source/plugins/TLAC/Components/Pause.cpp b/source-code/source/plugins/TLAC/Components/Pause.cpp index 7652c76..2fd9772 100644 --- a/source-code/source/plugins/TLAC/Components/Pause.cpp +++ b/source-code/source/plugins/TLAC/Components/Pause.cpp @@ -11,10 +11,13 @@ namespace TLAC::Components { + bool Pause::pause = false; bool Pause::isPaused = false; bool Pause::giveUp = false; bool Pause::showUI = true; unsigned int Pause::menuPos = 0; + unsigned int Pause::mainMenuPos = 0; + unsigned int Pause::menuSet = menuset_main; std::chrono::time_point Pause::menuItemSelectTime; std::vector Pause::origAetMovOp; std::vector Pause::origFramespeedOp; @@ -55,12 +58,41 @@ namespace TLAC::Components void Pause::UpdatePostInput() { - if (isPaused) + if (pause) { + // enter pause mode on state transition + if (!isPaused) + { + ((void(*)())DSC_PAUSE_FUNC_ADDRESS)(); + + InjectCode(aetMovPatchAddress, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode(framespeedPatchAddress, { 0x0f, 0x57, 0xc0, 0xc3 }); // XORPS XMM0,XMM0; RET + + uint64_t audioMixerAddr = *(uint64_t*)(AUDIO_MAIN_CLASS_ADDRESS + 0x70); + uint64_t audioStreamsAddress = *(uint64_t*)(audioMixerAddr + 0x18);; + int nAudioStreams = *(uint64_t*)(audioMixerAddr + 0x20); + for (int i = 0; i < nAudioStreams; i++) + { + uint32_t* playstate = (uint32_t*)(audioStreamsAddress + i * 0x50 + 0x18); + if (i < streamPlayStates.size()) + streamPlayStates[i] = *playstate; + else + streamPlayStates.push_back(*playstate); + + *playstate = 0; + } + + menuPos = 0; + menuSet = menuset_main; + showUI = true; + menuItemSelectTime = std::chrono::high_resolution_clock::now(); + isPaused = true; + } + // always exit pause if key is tapped or no longer in game somehow if (isPauseKeyTapped() || *(GameState*)CURRENT_GAME_STATE_ADDRESS != GS_GAME || *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS != SUB_GAME_MAIN) { - setPaused(false); + pause = false; } else { @@ -84,15 +116,39 @@ namespace TLAC::Components menuItemSelectTime = std::chrono::high_resolution_clock::now(); } - menuPos %= menuItems.size(); + if (inputState->Tapped.Buttons & JVS_TRIANGLE) + { + if (menuSet != menuset_main) + { + menuSet = menuset_main; + menuPos = mainMenuPos; + menuItemSelectTime = std::chrono::high_resolution_clock::now(); + } + } + + menuPos %= menuItems[menuSet].size(); + + if (menuSet == menuset_main) + mainMenuPos = menuPos; // use released when unpausing from X so it doesn't trigger input if (inputState->Released.Buttons & JVS_CROSS) - setPaused(false); + pause = false; // use released because this can trigger an unpause too if (inputState->Released.Buttons & JVS_CIRCLE) - menuItems[menuPos].second(); + menuItems[menuSet][menuPos].second(); + + if (menuSet == menuset_sevol) + { + PlayerData* playerdata = (PlayerData*)PLAYER_DATA_ADDRESS; + const char volformat[] = "%d"; + size_t size = snprintf(nullptr, 0, volformat, playerdata->act_vol) + 1; + char* buf = new char[size]; + snprintf(buf, size, volformat, playerdata->act_vol); + menuItems[menuset_sevol][1].first = buf; + delete[] buf; + } } @@ -107,12 +163,33 @@ namespace TLAC::Components } else { + // exit pause mode on state transition + if (isPaused) + { + ((void(*)())DSC_UNPAUSE_FUNC_ADDRESS)(); + + InjectCode(aetMovPatchAddress, origAetMovOp); + InjectCode(framespeedPatchAddress, origFramespeedOp); + + uint64_t audioMixerAddr = *(uint64_t*)(AUDIO_MAIN_CLASS_ADDRESS + 0x70); + uint64_t audioStreamsAddress = *(uint64_t*)(audioMixerAddr + 0x18);; + int nAudioStreams = *(uint64_t*)(audioMixerAddr + 0x20); + for (int i = 0; i < nAudioStreams; i++) + { + uint32_t* playstate = (uint32_t*)(audioStreamsAddress + i * 0x50 + 0x18); + if (i < streamPlayStates.size()) + *playstate = streamPlayStates[i]; + } + + isPaused = false; + } + // only enter pause if in game if (*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN) { if (isPauseKeyTapped()) { - setPaused(true); + pause = true; } } } @@ -159,7 +236,7 @@ namespace TLAC::Components // selection cursor - int selectBoxOrigin = menuY - menuItemHeight * (menuItems.size() / 2.0) - (menuItemHeight - menuTextSize) / 2; + int selectBoxOrigin = menuY - menuItemHeight * (menuItems[menuSet].size() / 2.0) - (menuItemHeight - menuTextSize) / 2; int selectBoxPos = selectBoxOrigin + menuItemHeight * menuPos; const float selectBoxWidth = 200; const float selectBoxHeight = menuItemHeight; @@ -189,11 +266,11 @@ namespace TLAC::Components fontInfo.setSize(menuTextSize, menuTextSize); dtParams.xBegin = menuX; - dtParams.yBegin = menuY - menuItemHeight * (menuItems.size() / 2.0); + dtParams.yBegin = menuY - menuItemHeight * (menuItems[menuSet].size() / 2.0); - for (int i = 0; i < menuItems.size(); i++) + for (int i = 0; i < menuItems[menuSet].size(); i++) { - std::pair &item = menuItems[i]; + std::pair &item = menuItems[menuSet][i]; if (i == menuPos) { @@ -223,18 +300,25 @@ namespace TLAC::Components dtParams.yCurrent = dtParams.yBegin; dtParams.colour = 0xffffffff; drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L"L/R:Move "); - dtParams.colour = 0xff4040ff; - drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L"○"); - dtParams.colour = 0xffffffff; - drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L":Select "); - dtParams.colour = 0xffff8000; - drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L"×"); - dtParams.colour = 0xffffffff; - drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L":Close "); + if (menuSet != menuset_main) + { + dtParams.colour = 0xff40ff40; + drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L"△"); + dtParams.colour = 0xffffffff; + drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L":Back "); + } dtParams.colour = 0xffc0c0ff; drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L"□"); dtParams.colour = 0xffffffff; - drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L":Hide Menu"); + drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L":Hide Menu "); + dtParams.colour = 0xffff8020; + drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L"×"); + dtParams.colour = 0xffffffff; + drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L":Close "); + dtParams.colour = 0xff4040ff; + drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L"○"); + dtParams.colour = 0xffffffff; + drawTextW(&dtParams, (drawTextFlags)(DRAWTEXT_ENABLE_LAYOUT), L":Select"); } } @@ -243,71 +327,34 @@ namespace TLAC::Components return ((InputState*)(*(uint64_t*)INPUT_STATE_PTR_ADDRESS))->Tapped.Buttons & JVS_START; } - void Pause::setPaused(bool pause) - { - uint64_t audioMixerAddr = *(uint64_t*)(AUDIO_MAIN_CLASS_ADDRESS + 0x70); - uint64_t audioStreamsAddress = *(uint64_t*)(audioMixerAddr + 0x18);; - int nAudioStreams = *(uint64_t*)(audioMixerAddr + 0x20); - - if (pause) - { - ((void(*)())DSC_PAUSE_FUNC_ADDRESS)(); - - InjectCode(aetMovPatchAddress, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode(framespeedPatchAddress, { 0x0f, 0x57, 0xc0, 0xc3 }); // XORPS XMM0,XMM0; RET - - for (int i = 0; i < nAudioStreams; i++) - { - uint32_t* playstate = (uint32_t*)(audioStreamsAddress + i * 0x50 + 0x18); - if (i < streamPlayStates.size()) - streamPlayStates[i] = *playstate; - else - streamPlayStates.push_back(*playstate); - - *playstate = 0; - } - - menuPos = 0; - showUI = true; - menuItemSelectTime = std::chrono::high_resolution_clock::now(); - } - else - { - ((void(*)())DSC_UNPAUSE_FUNC_ADDRESS)(); - - InjectCode(aetMovPatchAddress, origAetMovOp); - InjectCode(framespeedPatchAddress, origFramespeedOp); - - for (int i = 0; i < nAudioStreams; i++) - { - uint32_t* playstate = (uint32_t*)(audioStreamsAddress + i * 0x50 + 0x18); - if (i < streamPlayStates.size()) - *playstate = streamPlayStates[i]; - } - } - - isPaused = pause; - } - bool Pause::hookedGiveUpFunc(void* cls) { if (giveUp) { giveUp = false; - setPaused(false); + pause = false; return true; } else { if (divaGiveUpFunc(cls)) { - setPaused(false); + pause = false; return true; } } return false; } + void Pause::setSEVolume(int amount) + { + PlayerData* playerdata = (PlayerData*)PLAYER_DATA_ADDRESS; + playerdata->act_vol += amount; + if (playerdata->act_vol < 0) playerdata->act_vol = 0; + if (playerdata->act_vol > 100) playerdata->act_vol = 100; + playerdata->act_slide_vol = playerdata->act_vol; + } + void Pause::InjectCode(void* address, const std::vector data) { const size_t byteCount = data.size() * sizeof(uint8_t); diff --git a/source-code/source/plugins/TLAC/Components/Pause.h b/source-code/source/plugins/TLAC/Components/Pause.h index e36aeff..1975e4f 100644 --- a/source-code/source/plugins/TLAC/Components/Pause.h +++ b/source-code/source/plugins/TLAC/Components/Pause.h @@ -1,6 +1,7 @@ #pragma once #include "../Constants.h" #include "EmulatorComponent.h" +#include "PlayerData.h" #include #include @@ -19,15 +20,16 @@ namespace TLAC::Components virtual void UpdatePostInput() override; virtual void UpdateDrawSprites() override; - static bool isPaused; - static bool giveUp; - static void setPaused(bool pause); + static bool pause; // set pause to change pause state + static bool giveUp; // set give up to end current song private: // this is a mess of static so that menuItems can work static bool isPauseKeyTapped(); static std::vector streamPlayStates; static void InjectCode(void* address, const std::vector data); + static bool isPaused; // tracks internal state + static std::vector origAetMovOp; static constexpr uint8_t* aetMovPatchAddress = (uint8_t*)0x1401703b3; @@ -36,6 +38,8 @@ namespace TLAC::Components static bool hookedGiveUpFunc(void* cls); + static void setSEVolume(int amount); + static const int menuX = 640; static const int menuY = 360; static const int menuItemHeight = 36; @@ -43,15 +47,38 @@ namespace TLAC::Components static bool showUI; static unsigned int menuPos; + static unsigned int mainMenuPos; // syncs to menuPos when menuSet == menuset_main (used for restoring on back) + static unsigned int menuSet; static std::chrono::time_point menuItemSelectTime; - static void unpause() { setPaused(false); }; + enum menusets + { + menuset_main = 0, + menuset_sevol = 1, + }; + + static void mainmenu() { menuSet = menuset_main; menuPos = mainMenuPos; menuItemSelectTime = std::chrono::high_resolution_clock::now(); }; + static void unpause() { pause = false; }; static void giveup() { giveUp = true; }; - std::vector> menuItems = { - std::pair(std::string("RESUME"), &unpause), - std::pair(std::string("GIVE UP"), &giveup), + static void sevolmenu() { menuSet = menuset_sevol; menuPos = 1; menuItemSelectTime = std::chrono::high_resolution_clock::now(); }; + static void sevolplus() { setSEVolume(10); }; + static void sevolminus() { setSEVolume(-10); }; + + + // defined as an array now so submenus could be added + std::vector> menuItems[2] = { + { + std::pair(std::string("RESUME"), &unpause), + std::pair(std::string("SE VOLUME"), &sevolmenu), + std::pair(std::string("GIVE UP"), &giveup), + }, + { + std::pair(std::string("+"), &sevolplus), + std::pair(std::string("XX"), &mainmenu), + std::pair(std::string("-"), &sevolminus), + } }; }; }