diff --git a/NewClassics.vcxproj b/NewClassics.vcxproj index 2a21812..22d0781 100644 --- a/NewClassics.vcxproj +++ b/NewClassics.vcxproj @@ -29,26 +29,26 @@ DynamicLibrary true - v145 + v143 Unicode DynamicLibrary false - v145 + v143 true Unicode DynamicLibrary true - v145 + v143 Unicode DynamicLibrary false - v145 + v143 true Unicode diff --git a/src/exports.cpp b/src/exports.cpp index df3a901..2d653f5 100644 --- a/src/exports.cpp +++ b/src/exports.cpp @@ -1,5 +1,6 @@ #include "build_info.h" #include "nc_state.h" +#include extern "C" { @@ -32,4 +33,9 @@ extern "C" GetState()->nc_song_entry.reset(); GetState()->nc_chart_entry.reset(); } + + __declspec(dllexport) int32_t GetSharedTechZoneStyle() + { + return nc::GetSharedData().tech_zone_style; + } } \ No newline at end of file diff --git a/src/game/game.cpp b/src/game/game.cpp index 7dd9413..d94399e 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -479,10 +479,11 @@ HOOK(void, __fastcall, ExecuteModeSelect, 0x1503B04A0, PVGamePvData* pv_data, in switch (mode) { case ModeSelect_ChallengeStart: - PatchFrmBtmHeight(ChallengeTimeHeight); + if (!isXtraSkn) + PatchFrmBtmHeight(ChallengeTimeHeight); break; case ModeSelect_ChanceStart: - SaveAndPatchCTHeight(); + if (!isXtraSkn) SaveAndPatchCTHeight(); SetChanceTimeMode(&pv_data->pv_game->ui, ModeSelect_ChanceStart); break; case ModeSelect_ChanceEnd: diff --git a/src/game/tech_zone.cpp b/src/game/tech_zone.cpp index 1b555fa..ecb21a4 100644 --- a/src/game/tech_zone.cpp +++ b/src/game/tech_zone.cpp @@ -75,13 +75,16 @@ void TechZoneDispState::Ctrl() if (scene == 0 || layer_name.empty()) { - // TODO: Implement song's default style (?) - // Detect BricOOtaku's X UI mode and set the style accordingly in 'Match' mode int32_t style = nc::GetSharedData().tech_zone_style; + uint32_t skinType = GetResolvedSkinType(); + if (style == TechZoneStyle_Match) { - if (style == TechZoneStyle_Match) - style = game::IsFutureToneMode() ? TechZoneStyle_FT : TechZoneStyle_M39; - + if (skinType != (uint32_t)-1) + style = static_cast(skinType); + else + style = game::IsFutureToneMode() ? TechZoneStyle_FT : TechZoneStyle_M39; + } + switch (style) { case TechZoneStyle_F: @@ -103,6 +106,11 @@ void TechZoneDispState::Ctrl() case TechZoneStyle_M39: layer_name = "bonus_zone"; scene = 14010085; + break; + default : + layer_name = "bonus_zone"; + scene = 14010081; + break; } } diff --git a/src/mod.cpp b/src/mod.cpp index f347e98..94175ee 100644 --- a/src/mod.cpp +++ b/src/mod.cpp @@ -379,5 +379,6 @@ extern "C" { InstallPvSelHooks(); InstallCustomizeSelHooks(); + XtraCompatibility(); } }; \ No newline at end of file diff --git a/src/nc_state.cpp b/src/nc_state.cpp index 6645f54..bde8e82 100644 --- a/src/nc_state.cpp +++ b/src/nc_state.cpp @@ -4,6 +4,135 @@ #include "game/hit_state.h" #include "nc_state.h" +#include + +typedef const diva::vec3* (*FnGetBtnLongScale)(); +static FnGetBtnLongScale GetBtnLongScale = nullptr; + +typedef const diva::vec3* (*FnGetBtnScale)(); +static FnGetBtnScale GetBtnScale = nullptr; + +typedef int32_t(*FnGetSkinType)(); +static FnGetSkinType GetSkinType = nullptr; + +typedef bool (*FnGetIsXtraSkn)(); +static FnGetIsXtraSkn GetIsXtraSkn = nullptr; + +diva::vec3 noteScale = { 1.0f, 1.0f, 1.0f }; +bool isXtraSkn = false; + +static HMODULE FindModuleWithExport(const char* exportName) +{ + HMODULE modules[512]; + DWORD needed = 0; + + if (!EnumProcessModules(GetCurrentProcess(), modules, sizeof(modules), &needed)) + return nullptr; + + size_t count = needed / sizeof(HMODULE); + + for (size_t i = 0; i < count; i++) + { + FARPROC proc = GetProcAddress(modules[i], exportName); + if (proc) + return modules[i]; + } + + return nullptr; +} + +void ResolveBtnScale() +{ + HMODULE mod = FindModuleWithExport("GetBtnScale"); + if (!mod) { + GetBtnScale = nullptr; + return; + } + + GetBtnScale = reinterpret_cast( + GetProcAddress(mod, "GetBtnScale")); + + if (!GetBtnScale) + GetBtnScale = nullptr; +} + +void ResolveBtnLongScale() +{ + HMODULE mod = FindModuleWithExport("GetBtnLongScale"); + if (!mod) { + GetBtnLongScale = nullptr; + return; + } + + GetBtnLongScale = reinterpret_cast( + GetProcAddress(mod, "GetBtnLongScale")); + + if (!GetBtnLongScale) + GetBtnLongScale = nullptr; +} + +diva::vec3 ResolveScale( + FnGetBtnScale getter, + int idx, + const diva::vec3& fallback, + const char* logTag) +{ + diva::vec3 scale = fallback; + + if (getter) { + const diva::vec3* arr = getter(); + if (arr && idx >= 0) + scale = arr[idx]; + } + + return scale; +} + +void ResolveSkinType() +{ + HMODULE mod = FindModuleWithExport("GetSkinType"); + if (!mod) { + GetSkinType = nullptr; + return; + } + + FARPROC proc = GetProcAddress(mod, "GetSkinType"); + if (!proc) { + GetSkinType = nullptr; + return; + } + + GetSkinType = reinterpret_cast(proc); +} + +uint32_t GetResolvedSkinType() +{ + if (!GetSkinType) + return -1; + + return GetSkinType(); +} + +void ResolveIsXtraSkn() +{ + HMODULE mod = FindModuleWithExport("GetIsXtraSkn"); + if (!mod) + { + isXtraSkn = false; + return; + } + + FARPROC proc = GetProcAddress(mod, "GetIsXtraSkn"); + if (!proc) + { + isXtraSkn = false; + return; + } + + GetIsXtraSkn = reinterpret_cast(proc); + isXtraSkn = GetIsXtraSkn(); +} + void TargetStateEx::ResetPlayState() { hold_button = nullptr; @@ -85,7 +214,21 @@ bool TargetStateEx::SetLongNoteAet() aet::SetPlay(target_aet, false); aet::SetFrame(target_aet, 360.0f); - diva::vec3 scale = { 1.0f, 1.0f, 1.0f }; + int idx = -1; + switch (target_type) { + case TargetType_TriangleLong: idx = 0; break; + case TargetType_CircleLong: idx = 1; break; + case TargetType_CrossLong: idx = 2; break; + case TargetType_SquareLong: idx = 3; break; + } + + diva::vec3 scale = ResolveScale( + GetBtnLongScale, + idx, + noteScale, + "LongAet" + ); + aet::SetScale(target_aet, &scale); // NOTE: Free original aets @@ -125,7 +268,22 @@ bool TargetStateEx::SetRushNoteAet() diva::vec3 pos = { scaled_pos.x, scaled_pos.y, 0.0f }; aet::SetPosition(button_aet, &pos); - diva::vec3 scale = { 1.0f, 1.0f, 1.0f }; + int idx = -1; + switch (target_type) { + case TargetType_TriangleRush: idx = 0; break; + case TargetType_CircleRush: idx = 1; break; + case TargetType_CrossRush: idx = 2; break; + case TargetType_SquareRush: idx = 3; break; + case TargetType_StarRush: idx = 4; break; + } + + diva::vec3 scale = ResolveScale( + GetBtnScale, + idx, + noteScale, + "RushAet" + ); + aet::SetScale(button_aet, &scale); org->button_aet = 0; @@ -347,11 +505,18 @@ TargetStateEx* GetTargetStateEx(const PvGameTarget* org) int32_t sub_index = 0; for (PvGameTarget* prev = org->prev; prev && prev->multi_count == org->multi_count; prev = prev->prev) sub_index++; - + return GetTargetStateEx(org->target_index, sub_index); } extern "C" __declspec(dllexport) StateEx* GetState() { return &state; +} + +void XtraCompatibility() { + ResolveBtnLongScale(); + ResolveBtnScale(); + ResolveSkinType(); + ResolveIsXtraSkn(); } \ No newline at end of file diff --git a/src/nc_state.h b/src/nc_state.h index b9cf534..a3528bc 100644 --- a/src/nc_state.h +++ b/src/nc_state.h @@ -351,4 +351,8 @@ inline StateEx state = { }; TargetStateEx* GetTargetStateEx(int32_t index, int32_t sub_index); TargetStateEx* GetTargetStateEx(const PvGameTarget* org); -extern "C" __declspec(dllexport) StateEx* GetState(); \ No newline at end of file +uint32_t GetResolvedSkinType(); + +extern "C" __declspec(dllexport) StateEx* GetState(); +extern bool isXtraSkn; +void XtraCompatibility(); \ No newline at end of file