diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h
index 78ef69282126..7d83e617f081 100644
--- a/Source/Core/Core/ConfigManager.h
+++ b/Source/Core/Core/ConfigManager.h
@@ -151,6 +151,7 @@ struct SConfig
bool bPrimeNoclip = false;
bool bPrimeInvulnerability = false;
bool bPrimeSkipCutscene = false;
+ bool bPrimeRestoreDashing = false;
// Interface settings
bool bConfirmStop = false;
diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj
index 144736de4da3..54c6fb4840bd 100644
--- a/Source/Core/Core/Core.vcxproj
+++ b/Source/Core/Core/Core.vcxproj
@@ -694,6 +694,7 @@
+
diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters
index 4b4e29206b1d..9e4998461748 100644
--- a/Source/Core/Core/Core.vcxproj.filters
+++ b/Source/Core/Core/Core.vcxproj.filters
@@ -1837,6 +1837,9 @@
PrimeHack
+
+ PrimeHack\Mods
+
diff --git a/Source/Core/Core/HotkeyManager.cpp b/Source/Core/Core/HotkeyManager.cpp
index a3cbade1faea..fbc0e4a7caef 100644
--- a/Source/Core/Core/HotkeyManager.cpp
+++ b/Source/Core/Core/HotkeyManager.cpp
@@ -24,7 +24,7 @@
#include "InputCommon/GCPadStatus.h"
// clang-format off
-constexpr std::array s_hotkey_labels{{
+constexpr std::array s_hotkey_labels{{
_trans("Open"),
_trans("Change Disc"),
_trans("Eject Disc"),
@@ -196,6 +196,7 @@ constexpr std::array s_hotkey_labels{{
_trans("Toggle Noclip"),
_trans("Toggle Invulnerability"),
_trans("Toggle Skippable Cutscenes"),
+ _trans("Toggle Dashing Restoration"),
_trans("Toggle Lock Camera In Motion Puzzles")
}};
// clang-format on
@@ -354,7 +355,7 @@ constexpr std::array s_groups_info = {
{_trans("Select State"), HK_SELECT_STATE_SLOT_1, HK_SELECT_STATE_SLOT_10},
{_trans("Load Last State"), HK_LOAD_LAST_STATE_1, HK_LOAD_LAST_STATE_10},
{_trans("Other State Hotkeys"), HK_SAVE_FIRST_STATE, HK_LOAD_STATE_FILE},
- {_trans("PrimeHack Cheats"), HK_NOCLIP_TOGGLE, HK_SKIP_CUTSCENE},
+ {_trans("PrimeHack Cheats"), HK_NOCLIP_TOGGLE, HK_RESTORE_DASHING},
{_trans("PrimeHack Graphics"), HK_MOTION_LOCK, HK_MOTION_LOCK}}};
HotkeyManager::HotkeyManager()
diff --git a/Source/Core/Core/HotkeyManager.h b/Source/Core/Core/HotkeyManager.h
index 3b77e5d7aafe..27b68b1a492c 100644
--- a/Source/Core/Core/HotkeyManager.h
+++ b/Source/Core/Core/HotkeyManager.h
@@ -181,6 +181,7 @@ enum Hotkey
HK_NOCLIP_TOGGLE,
HK_INVULNERABILITY_TOGGLE,
HK_SKIP_CUTSCENE,
+ HK_RESTORE_DASHING,
HK_MOTION_LOCK,
NUM_HOTKEYS,
diff --git a/Source/Core/Core/PrimeHack/HackConfig.cpp b/Source/Core/Core/PrimeHack/HackConfig.cpp
index ddb218ee8d43..f2ebd0a1fc8d 100644
--- a/Source/Core/Core/PrimeHack/HackConfig.cpp
+++ b/Source/Core/Core/PrimeHack/HackConfig.cpp
@@ -10,6 +10,7 @@
#include "Core/PrimeHack/Mods/CutBeamFxMP1.h"
#include "Core/PrimeHack/Mods/DisableBloom.h"
#include "Core/PrimeHack/Mods/FpsControls.h"
+#include "Core/PrimeHack/Mods/RestoreDashing.h"
#include "Core/PrimeHack/Mods/Invulnerability.h"
#include "Core/PrimeHack/Mods/Noclip.h"
#include "Core/PrimeHack/Mods/SkipCutscene.h"
@@ -51,6 +52,7 @@ void InitializeHack() {
hack_mgr.add_mod("invulnerability", std::make_unique());
hack_mgr.add_mod("noclip", std::make_unique());
hack_mgr.add_mod("skip_cutscene", std::make_unique());
+ hack_mgr.add_mod("restore_dashing", std::make_unique());
hack_mgr.add_mod("springball_button", std::make_unique());
hack_mgr.add_mod("fov_modifier", std::make_unique());
hack_mgr.add_mod("context_sensitive_controls", std::make_unique());
@@ -137,6 +139,10 @@ bool GetSkipCutscene() {
return SConfig::GetInstance().bPrimeSkipCutscene;
}
+bool GetRestoreDashing() {
+ return SConfig::GetInstance().bPrimeRestoreDashing;
+}
+
bool GetEFBTexture() {
return Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM);
}
diff --git a/Source/Core/Core/PrimeHack/HackConfig.h b/Source/Core/Core/PrimeHack/HackConfig.h
index 2d95958e9b5e..8146f0c16395 100644
--- a/Source/Core/Core/PrimeHack/HackConfig.h
+++ b/Source/Core/Core/PrimeHack/HackConfig.h
@@ -31,6 +31,7 @@ bool GetBloom();
bool GetNoclip();
bool GetInvulnerability();
bool GetSkipCutscene();
+bool GetRestoreDashing();
bool GetEnableSecondaryGunFX();
diff --git a/Source/Core/Core/PrimeHack/HackManager.cpp b/Source/Core/Core/PrimeHack/HackManager.cpp
index 527442b49e0f..b5f3ea021a10 100644
--- a/Source/Core/Core/PrimeHack/HackManager.cpp
+++ b/Source/Core/Core/PrimeHack/HackManager.cpp
@@ -165,6 +165,7 @@ void HackManager::update_mod_states()
set_mod_enabled("noclip", GetNoclip());
set_mod_enabled("invulnerability", GetInvulnerability());
set_mod_enabled("skip_cutscene", GetSkipCutscene());
+ set_mod_enabled("restore_dashing", GetRestoreDashing());
// Disallow any PrimeHack control mods
if (!SConfig::GetInstance().bEnablePrimeHack) {
diff --git a/Source/Core/Core/PrimeHack/Mods/RestoreDashing.h b/Source/Core/Core/PrimeHack/Mods/RestoreDashing.h
new file mode 100644
index 000000000000..c7a0c1ef616c
--- /dev/null
+++ b/Source/Core/Core/PrimeHack/Mods/RestoreDashing.h
@@ -0,0 +1,137 @@
+#pragma once
+
+#include "Core/PrimeHack/PrimeMod.h"
+#include
+
+namespace prime {
+ class RestoreDashing : public PrimeMod {
+ public:
+ void run_mod(Game game, Region region) override {}
+ void init_mod(Game game, Region region) override {
+ // d0210014 d0010010 4b -> pattern to search for CPlayer::FinishSidewaysDash() for Prime 2 GC
+ // d0210024 d0010020 4b -> pattern to search for CPlayer::FinishSidewaysDash() for Prime 2 and 3 Wii
+
+ u8 version = PowerPC::HostRead_U8(0x80000007);
+
+ switch (game) {
+ case Game::PRIME_1:
+ if (region == Region::NTSC_U) {
+ // remove scan visor check
+ code_changes.emplace_back(0x80193334, 0x48000018);
+ // restore dashing speed
+ code_changes.emplace_back(0x80194b60, 0x4800001c);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x80192cc0, 0x801f037c); // CPlayer + 0x37c
+ }
+ else if (region == Region::PAL) {
+ // remove scan visor check
+ code_changes.emplace_back(0x801935cc, 0x48000018);
+ // restore dashing speed
+ code_changes.emplace_back(0x80194df8, 0x4800001c);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x80192f58, 0x801f037c); // CPlayer + 0x37c
+ }
+ else { // region == Region::NTSC-J
+ // remove scan visor check
+ code_changes.emplace_back(0x80193eb4, 0x48000018);
+ // restore dashing speed
+ code_changes.emplace_back(0x801956e0, 0x4800001c);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x80193840, 0x801f037c); // CPlayer + 0x37c
+ }
+ break;
+ case Game::PRIME_1_GCN:
+ if (region == Region::NTSC_U) {
+ if (version == 2) {
+ // remove scan visor check
+ code_changes.emplace_back(0x802888d0, 0x48000018);
+ }
+ }
+ else if (region == Region::NTSC_J) {
+ // remove scan visor check
+ code_changes.emplace_back(0x802770e4, 0x48000018);
+ }
+ else if (region == Region::PAL) {
+ // remove scan visor check
+ code_changes.emplace_back(0x80275328, 0x48000018);
+ }
+ break;
+ case Game::PRIME_2:
+ if (region == Region::NTSC_U) {
+ // don't slow down when finishing the dash
+ code_changes.emplace_back(0x8015d690, 0x60000000);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x8015cd1c, 0x881e0574); // CPlayer + 0x574 as u8
+ }
+ else if (region == Region::NTSC_J) {
+ // don't slow down when finishing the dash
+ code_changes.emplace_back(0x8015cc58, 0x60000000);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x8015c2e4, 0x881e0574); // CPlayer + 0x574 as u8
+ }
+ else if (region == Region::PAL) {
+ // don't slow down when finishing the dash
+ code_changes.emplace_back(0x8015ee08, 0x60000000);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x8015e494, 0x881e0574); // CPlayer + 0x574 as u8
+ }
+ break;
+ case Game::PRIME_2_GCN:
+ if (region == Region::NTSC_U) {
+ // don't slow down when finishing the dash
+ code_changes.emplace_back(0x8018961c, 0x60000000);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x80189d6c, 0x881e0588); // CPlayer + 0x588 as u8
+ }
+ else if (region == Region::NTSC_J) {
+ // don't slow down when finishing the dash
+ code_changes.emplace_back(0x8018b130, 0x60000000);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x8018b884, 0x881e0588); // CPlayer + 0x588 as u8
+ }
+ else if (region == Region::PAL) {
+ // don't slow down when finishing the dash
+ code_changes.emplace_back(0x80189914, 0x60000000);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x8018a068, 0x881e0588); // CPlayer + 0x588 as u8
+ }
+ break;
+ case Game::PRIME_3:
+ if (region == Region::NTSC_U) {
+ // don't slow down when finishing the dash
+ code_changes.emplace_back(0x80174c60, 0x60000000);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x8017432c, 0x881e06cc); // CPlayer + 0x6cc as u8
+ }
+ else if (region == Region::PAL) {
+ // don't slow down when finishing the dash
+ code_changes.emplace_back(0x801745ac, 0x60000000);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x80173c78, 0x881e06cc); // CPlayer + 0x6cc as u8
+ }
+ break;
+ case Game::PRIME_3_STANDALONE:
+ if (region == Region::NTSC_U) {
+ // don't slow down when finishing the dash
+ code_changes.emplace_back(0x80178d90, 0x60000000);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x8017845c, 0x881e06cc); // CPlayer + 0x6cc as u8
+ }
+ else if (region == Region::NTSC_J) {
+ // don't slow down when finishing the dash
+ code_changes.emplace_back(0x8017aa90, 0x60000000);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x8017a15c, 0x881e06cc); // CPlayer + 0x6cc as u8
+ }
+ else if (region == Region::PAL) {
+ // don't slow down when finishing the dash
+ code_changes.emplace_back(0x80179884, 0x60000000);
+ // stop dash when done dashing
+ code_changes.emplace_back(0x80178F50, 0x881e06cc); // CPlayer + 0x6cc as u8
+ }
+ break;
+ }
+ initialized = true;
+ }
+ };
+}
diff --git a/Source/Core/Core/PrimeHack/PrimeUtils.cpp b/Source/Core/Core/PrimeHack/PrimeUtils.cpp
index 6f24059bd597..57cb28080666 100644
--- a/Source/Core/Core/PrimeHack/PrimeUtils.cpp
+++ b/Source/Core/Core/PrimeHack/PrimeUtils.cpp
@@ -33,6 +33,7 @@ std::array(Game::MAX_VAL) + 1>,
static u32 noclip_msg_time;
static u32 invulnerability_msg_time;
static u32 cutscene_msg_time;
+static u32 restore_dashing_msg_time;
u8 read8(u32 addr) {
return PowerPC::HostRead_U8(addr);
@@ -247,9 +248,9 @@ std::string GetDevInfo()
}
// Common::Timer::GetTimeMs()
-std::tuple GetCheatsTime()
+std::tuple GetCheatsTime()
{
- return std::make_tuple(noclip_msg_time, invulnerability_msg_time, cutscene_msg_time);
+ return std::make_tuple(noclip_msg_time, invulnerability_msg_time, cutscene_msg_time, restore_dashing_msg_time);
}
void AddCheatsTime(int index, u32 time)
@@ -264,6 +265,9 @@ void AddCheatsTime(int index, u32 time)
break;
case 2:
cutscene_msg_time = Common::Timer::GetTimeMs() + 3000;
+ break;
+ case 3:
+ restore_dashing_msg_time = Common::Timer::GetTimeMs() + 3000;
}
}
diff --git a/Source/Core/Core/PrimeHack/PrimeUtils.h b/Source/Core/Core/PrimeHack/PrimeUtils.h
index 2551fc50139c..92436a401556 100644
--- a/Source/Core/Core/PrimeHack/PrimeUtils.h
+++ b/Source/Core/Core/PrimeHack/PrimeUtils.h
@@ -44,7 +44,7 @@ void set_cursor_pos(float x, float y);
void DevInfo(const char* name, const char* format, ...);
void DevInfoMatrix(const char* name, const Transform& t);
-std::tuple GetCheatsTime();
+std::tuple GetCheatsTime();
void AddCheatsTime(int index, u32 time);
std::string GetDevInfo();
diff --git a/Source/Core/DolphinQt/HotkeyScheduler.cpp b/Source/Core/DolphinQt/HotkeyScheduler.cpp
index 73687d912a80..6d5a29a0a7c6 100644
--- a/Source/Core/DolphinQt/HotkeyScheduler.cpp
+++ b/Source/Core/DolphinQt/HotkeyScheduler.cpp
@@ -613,8 +613,17 @@ void HotkeyScheduler::Run()
OSD::AddMessage(StringFromFormat("Skippable Cutscenes: %s", new_value ? "Enabled" : "Disabled"));
}
+
+ if (IsHotkey(HK_RESTORE_DASHING))
+ {
+ const bool new_value = !SConfig::GetInstance().bPrimeRestoreDashing;
+ SConfig::GetInstance().bPrimeRestoreDashing = new_value;
+
+ OSD::AddMessage(StringFromFormat("Restore Dashing: %s", new_value ? "Enabled" : "Disabled"));
+ }
}
else {
+ SConfig::GetInstance().bPrimeRestoreDashing = false;
SConfig::GetInstance().bPrimeSkipCutscene = false;
SConfig::GetInstance().bPrimeInvulnerability = false;
SConfig::GetInstance().bPrimeNoclip = false;