Compare commits

..

9 Commits

Author SHA1 Message Date
Skyth 762dbe0419 Update version milestone to Release Candidate 3. 2025-02-25 23:59:03 +03:00
Skyth (Asilkan) 0128377ad9 Implement installer music. (#463) 2025-02-25 23:00:51 +03:00
ĐeäTh 98daa27c14 Added exceptions for specific hint messages being allowed/blocked by the Hints option (#462)
* Fix Windmill Isle Act 1 (Night) chip 'hint' not being shown

* code style adjustments

* Fix Apotos entrance gate first time Chip hint appearing with hints disabled

---------

Co-authored-by: Hyper <34012267+hyperbx@users.noreply.github.com>
2025-02-25 18:34:57 +03:00
ĐeäTh 0b16633ee1 fix options menu reset to default logic getting executed when setting is already default (#461) 2025-02-24 17:17:47 +01:00
Skyth (Asilkan) 388a86e866 Fix shader recompiler not depending on the patched executable. (#453) 2025-02-23 18:07:11 +03:00
Skyth fef357062d Update version milestone to Release Candidate 2. 2025-02-22 17:04:46 +03:00
Darío 03ef34ffe8 Dpi fixes (#449)
* Potential fix for DPI scaling.

* Show window size in pixels while in Fullscreen mode.
2025-02-22 16:12:56 +03:00
Darío c90d1fcb7b Fix typo in Spanish translation. (#447) 2025-02-21 22:14:00 +03:00
Hyper ae3dfb12df options_menu: append inaccessible reason to description (#446) 2025-02-21 21:10:00 +03:00
17 changed files with 176 additions and 44 deletions
+1
View File
@@ -553,6 +553,7 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/ga
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon_night.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon_night.bmp" ARRAY_NAME "g_game_icon_night")
## Audio ##
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/music/installer.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/music/installer.ogg" ARRAY_NAME "g_installer_music")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_worldmap_cursor.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_worldmap_cursor.ogg" ARRAY_NAME "g_sys_worldmap_cursor")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_worldmap_finaldecide.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_worldmap_finaldecide.ogg" ARRAY_NAME "g_sys_worldmap_finaldecide")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_actstg_pausecansel.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_actstg_pausecansel.ogg" ARRAY_NAME "g_sys_actstg_pausecansel")
+1
View File
@@ -87,6 +87,7 @@
#include "SWA/Inspire/InspireTextureOverlay.h"
#include "SWA/Inspire/InspireTextureOverlayInfo.h"
#include "SWA/Menu/MenuWindowBase.h"
#include "SWA/Message/MsgRequestHelp.h"
#include "SWA/Movie/MovieDisplayer.h"
#include "SWA/Movie/MovieManager.h"
#include "SWA/Object/Common/DashPanel/ObjDashPanel.h"
@@ -0,0 +1,13 @@
#pragma once
#include <SWA.inl>
namespace SWA::Message
{
class MsgRequestHelp
{
public:
SWA_INSERT_PADDING(0x1C);
Hedgehog::Base::CSharedString m_Name;
};
}
+24 -1
View File
@@ -2,6 +2,7 @@
#include <apu/embedded_player.h>
#include <user/config.h>
#include <res/music/installer.ogg.h>
#include <res/sounds/sys_worldmap_cursor.ogg.h>
#include <res/sounds/sys_worldmap_finaldecide.ogg.h>
#include <res/sounds/sys_actstg_pausecansel.ogg.h>
@@ -87,13 +88,17 @@ static void PlayEmbeddedSound(EmbeddedSound s)
data.chunk = Mix_LoadWAV_RW(SDL_RWFromConstMem(soundData, soundDataSize), 1);
}
Mix_VolumeChunk(data.chunk, Config::MasterVolume * Config::EffectsVolume * MIX_MAX_VOLUME);
Mix_PlayChannel(g_channelIndex % MIX_CHANNELS, data.chunk, 0);
++g_channelIndex;
}
static Mix_Music* g_installerMusic;
void EmbeddedPlayer::Init()
{
Mix_OpenAudio(XAUDIO_SAMPLES_HZ, AUDIO_F32SYS, 2, 256);
Mix_OpenAudio(XAUDIO_SAMPLES_HZ, AUDIO_F32SYS, 2, 2048);
g_installerMusic = Mix_LoadMUS_RW(SDL_RWFromConstMem(g_installer_music, sizeof(g_installer_music)), 1);
s_isActive = true;
}
@@ -111,6 +116,21 @@ void EmbeddedPlayer::Play(const char *name)
PlayEmbeddedSound(it->second);
}
void EmbeddedPlayer::PlayMusic()
{
if (!Mix_PlayingMusic())
{
Mix_PlayMusic(g_installerMusic, INT_MAX);
Mix_VolumeMusic(Config::MasterVolume * Config::MusicVolume * MUSIC_VOLUME * MIX_MAX_VOLUME);
}
}
void EmbeddedPlayer::FadeOutMusic()
{
if (Mix_PlayingMusic())
Mix_FadeOutMusic(1000);
}
void EmbeddedPlayer::Shutdown()
{
for (EmbeddedSoundData &data : g_embeddedSoundData)
@@ -119,6 +139,9 @@ void EmbeddedPlayer::Shutdown()
Mix_FreeChunk(data.chunk);
}
Mix_HaltMusic();
Mix_FreeMusic(g_installerMusic);
Mix_CloseAudio();
Mix_Quit();
+6 -1
View File
@@ -2,9 +2,14 @@
struct EmbeddedPlayer
{
inline static bool s_isActive = false;
// Arbitrarily picked volume to match the mixing in the original game.
static constexpr float MUSIC_VOLUME = 0.25f;
static inline bool s_isActive = false;
static void Init();
static void Play(const char *name);
static void PlayMusic();
static void FadeOutMusic();
static void Shutdown();
};
+1 -1
View File
@@ -2344,7 +2344,7 @@ namespace plume {
dstWidth = rect.right - rect.left;
dstHeight = rect.bottom - rect.top;
# elif defined(SDL_VULKAN_ENABLED)
SDL_GetWindowSize(renderWindow, (int *)(&dstWidth), (int *)(&dstHeight));
SDL_GetWindowSizeInPixels(renderWindow, (int *)(&dstWidth), (int *)(&dstHeight));
# elif defined(__ANDROID__)
dstWidth = ANativeWindow_getWidth(renderWindow);
dstHeight = ANativeWindow_getHeight(renderWindow);
+16 -10
View File
@@ -2415,19 +2415,25 @@ static void DrawImGui()
// we can adjust the mouse events before ImGui processes them.
uint32_t width = g_swapChain->getWidth();
uint32_t height = g_swapChain->getHeight();
if (width != Video::s_viewportWidth || height != Video::s_viewportHeight)
float mousePosScaleX = float(width) / float(GameWindow::s_width);
float mousePosScaleY = float(height) / float(GameWindow::s_height);
float mousePosOffsetX = (width - Video::s_viewportWidth) / 2.0f;
float mousePosOffsetY = (height - Video::s_viewportHeight) / 2.0f;
for (int i = 0; i < io.Ctx->InputEventsQueue.Size; i++)
{
float mousePosOffsetX = (width - Video::s_viewportWidth) / 2.0f;
float mousePosOffsetY = (height - Video::s_viewportHeight) / 2.0f;
for (int i = 0; i < io.Ctx->InputEventsQueue.Size; i++)
auto& e = io.Ctx->InputEventsQueue[i];
if (e.Type == ImGuiInputEventType_MousePos)
{
auto& e = io.Ctx->InputEventsQueue[i];
if (e.Type == ImGuiInputEventType_MousePos)
if (e.MousePos.PosX != -FLT_MAX)
{
if (e.MousePos.PosX != -FLT_MAX) e.MousePos.PosX -= mousePosOffsetX;
if (e.MousePos.PosY != -FLT_MAX) e.MousePos.PosY -= mousePosOffsetY;
e.MousePos.PosX *= mousePosScaleX;
e.MousePos.PosX -= mousePosOffsetX;
}
if (e.MousePos.PosY != -FLT_MAX)
{
e.MousePos.PosY *= mousePosScaleY;
e.MousePos.PosY -= mousePosOffsetY;
}
}
}
+1 -1
View File
@@ -213,7 +213,7 @@ std::unordered_map<std::string_view, std::unordered_map<ELanguage, std::string>>
{ ELanguage::Japanese, "この\u200Bオプションは\u200B[現在:げんざい]の\u200BOSで\u200B[変更:へんこう]\u200Bできません" },
{ ELanguage::German, "Diese Option wird von diesem Betriebssystem nicht unterstützt." },
{ ELanguage::French, "Cette option n'est pas prise en charge par votre système d'exploitation." },
{ ELanguage::Spanish, "Está opción no está soportada por tu sistema operativo." },
{ ELanguage::Spanish, "Esta opción no está soportada por tu sistema operativo." },
{ ELanguage::Italian, "Questa opzione non è disponibile con il tuo sistema operativo." }
}
},
+39
View File
@@ -108,3 +108,42 @@ PPC_FUNC(sub_82586698)
__imp__sub_82586698(ctx, base);
}
// SWA::CObjHint::MsgNotifyObjectEvent::Impl
// Disable only certain hints from hint volumes.
// This hook should be used to allow hint volumes specifically to also prevent them from affecting the player.
PPC_FUNC_IMPL(__imp__sub_82736E80);
PPC_FUNC(sub_82736E80)
{
// GroupID parameter text
auto* groupId = (const char*)(base + PPC_LOAD_U32(ctx.r3.u32 + 0x100));
if (!Config::Hints)
{
// WhiteIsland_ACT1_001 (Windmill Isle Act 1 Night, Start)
// Your friend went off that way, Sonic. Quick, let's go after him!
if (strcmp(groupId, "WhiteIsland_ACT1_001") != 0)
return;
}
__imp__sub_82736E80(ctx, base);
}
// SWA::CHelpWindow::MsgRequestHelp::Impl
// Disable only certain hints from other sequences.
// This hook should be used to block hint messages from unknown sources.
PPC_FUNC_IMPL(__imp__sub_824C1E60);
PPC_FUNC(sub_824C1E60)
{
auto pMsgRequestHelp = (SWA::Message::MsgRequestHelp*)(base + ctx.r4.u32);
if (!Config::Hints)
{
// s10d_mykETF_c_navi (Town Mykonos Entrance, First Entry)
// Looks like we can get to a bunch of places in the village from here!
if (strcmp(pMsgRequestHelp->m_Name.c_str(), "s10d_mykETF_c_navi") == 0)
return;
}
__imp__sub_824C1E60(ctx, base);
}
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION_MILESTONE="Release Candidate 1"
VERSION_MILESTONE="Release Candidate 3"
VERSION_MAJOR=1
VERSION_MINOR=0
VERSION_REVISION=0
+5
View File
@@ -378,6 +378,11 @@ SDL_Rect GameWindow::GetDimensions()
return rect;
}
void GameWindow::GetSizeInPixels(int *w, int *h)
{
SDL_GetWindowSizeInPixels(s_pWindow, w, h);
}
void GameWindow::SetDimensions(int w, int h, int x, int y)
{
s_width = w;
+1
View File
@@ -37,6 +37,7 @@ public:
static bool IsMaximised();
static EWindowState SetMaximised(bool isEnabled);
static SDL_Rect GetDimensions();
static void GetSizeInPixels(int *w, int *h);
static void SetDimensions(int w, int h, int x = SDL_WINDOWPOS_CENTERED, int y = SDL_WINDOWPOS_CENTERED);
static void ResetDimensions();
static uint32_t GetWindowFlags();
+19
View File
@@ -1721,6 +1721,24 @@ static void PickerCheckResults()
g_currentPickerVisible = false;
}
static bool g_fadingOutMusic;
static void ProcessMusic()
{
if (g_isDisappearing)
{
if (!g_fadingOutMusic)
{
EmbeddedPlayer::FadeOutMusic();
g_fadingOutMusic = true;
}
}
else
{
EmbeddedPlayer::PlayMusic();
}
}
void InstallerWizard::Init()
{
auto &io = ImGui::GetIO();
@@ -1850,6 +1868,7 @@ bool InstallerWizard::Run(std::filesystem::path installPath, bool skipGame)
while (s_isVisible)
{
Video::WaitOnSwapChain();
ProcessMusic();
SDL_PumpEvents();
SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
GameWindow::Update();
+27 -17
View File
@@ -859,16 +859,19 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
if (g_canReset && padState.IsTapped(SWA::eKeyState_X))
{
config->MakeDefault();
if (!config->IsDefaultValue())
{
config->MakeDefault();
VideoConfigValueChangedCallback(config);
XAudioConfigValueChangedCallback(config);
VideoConfigValueChangedCallback(config);
XAudioConfigValueChangedCallback(config);
if (config->Callback)
config->Callback(config);
if (config->Callback)
config->Callback(config);
if (config->ApplyCallback)
config->ApplyCallback(config);
if (config->ApplyCallback)
config->ApplyCallback(config);
}
Game_PlaySound("sys_worldmap_decide");
}
@@ -1121,17 +1124,25 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
{
if (config == &Config::WindowSize)
{
auto displayModes = GameWindow::GetDisplayModes();
if (config->Value >= 0 && config->Value < displayModes.size())
if (Config::Fullscreen)
{
auto& displayMode = displayModes[config->Value];
valueText = fmt::format("{}x{}", displayMode.w, displayMode.h);
int displayW, displayH;
GameWindow::GetSizeInPixels(&displayW, &displayH);
valueText = fmt::format("{}x{}", displayW, displayH);
}
else
{
valueText = fmt::format("{}x{}", GameWindow::s_width, GameWindow::s_height);
auto displayModes = GameWindow::GetDisplayModes();
if (config->Value >= 0 && config->Value < displayModes.size())
{
auto& displayMode = displayModes[config->Value];
valueText = fmt::format("{}x{}", displayMode.w, displayMode.h);
}
else
{
valueText = fmt::format("{}x{}", GameWindow::s_width, GameWindow::s_height);
}
}
}
else if (config == &Config::Monitor)
@@ -1458,7 +1469,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
if (g_inaccessibleReason)
{
desc = *g_inaccessibleReason;
desc += "\n\n" + *g_inaccessibleReason;
}
else
{
@@ -1476,10 +1487,9 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
}
const auto& valueDescription = g_selectedItem->GetValueDescription(Config::Language);
if (!valueDescription.empty())
{
desc += "\n\n" + valueDescription;
}
}
clipRectMin = { clipRectMin.x, thumbnailMax.y };
+14 -5
View File
@@ -26,8 +26,11 @@ foreach(i RANGE 0 260)
endforeach()
add_custom_command(
OUTPUT ${UNLEASHED_RECOMP_PPC_RECOMPILED_SOURCES}
COMMAND $<TARGET_FILE:XenonRecomp>
OUTPUT
"${CMAKE_CURRENT_SOURCE_DIR}/private/default_patched.xex"
${UNLEASHED_RECOMP_PPC_RECOMPILED_SOURCES}
COMMAND
$<TARGET_FILE:XenonRecomp>
DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/private/default.xex"
"${CMAKE_CURRENT_SOURCE_DIR}/private/default.xexp"
@@ -49,9 +52,15 @@ file(GLOB XENOS_RECOMP_SOURCES
)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/shader/shader_cache.cpp"
COMMAND $<TARGET_FILE:XenosRecomp>
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/private/shader.ar" ${XENOS_RECOMP_SOURCES} ${XENOS_RECOMP_INCLUDE}
OUTPUT
"${CMAKE_CURRENT_SOURCE_DIR}/shader/shader_cache.cpp"
COMMAND
$<TARGET_FILE:XenosRecomp>
DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/private/default_patched.xex"
"${CMAKE_CURRENT_SOURCE_DIR}/private/shader.ar"
${XENOS_RECOMP_SOURCES}
${XENOS_RECOMP_INCLUDE}
)
add_library(UnleashedRecompLib
+6 -6
View File
@@ -106,18 +106,18 @@ jump_address = 0x82468EE0
name = "ResetScoreOnRestartMidAsmHook"
address = 0x82304374
# Disable hint volumes
[[midasm_hook]]
name = "DisableHintsMidAsmHook"
address = 0x827A2504
jump_address_on_true = 0x827A251C
# Disable hint rings
[[midasm_hook]]
name = "DisableHintsMidAsmHook"
address = 0x827A2E34
jump_address_on_true = 0x827A2E4C
# Disable Tornado Defense hints
[[midasm_hook]]
name = "DisableHintsMidAsmHook"
address = 0x82AF52BC
jump_address_on_true = 0x82AF52E4
# Disable Egg Dragoon hint "V_WHG_083" ("That lit-up part on the bottom looks fishy. I'll try aiming for that.")
[[midasm_hook]]
name = "DisableHintsMidAsmHook"