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