Skip to content

Commit 4576640

Browse files
committed
FixPegasusClopping: fixes looping clop sound effect remaining active through the session
Moves lens flare fix to bugfixes.cpp, and added INI settings for toggling all fixes
1 parent 8c9d32d commit 4576640

File tree

6 files changed

+112
-42
lines changed

6 files changed

+112
-42
lines changed

Outrun2006Tweaks.ini

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,21 @@ SkipIntroLogos = false
8080
# DisableCountdownTimer: disables the countdown timer, may be useful for modders, or those who just want to take a leisurely drive.
8181
# Can also be enabled via -OuttaTime launch parameter.
8282
DisableCountdownTimer = false
83+
84+
[Bugfixes]
85+
# FixPegasusClopping: fixes looping clop sound effect remaining active through the session.
86+
FixPegasusClopping = true
87+
88+
# FixC2CRankings: fixes C2C scoreboard rankings not updating due to incomplete anti-piracy checks.
89+
# (game still contained "SecuROM_Tripwire" checks inside it, despite Steam release not using SecuROM...)
90+
FixC2CRankings = true
91+
92+
# PreventDESTSaveCorruption: prevents the save corruption caused by trying to remap controls with many devices connected.
93+
# This usually resulted in player name replaced with "DEST" and some garbage text, along with player character model disappearing along with all unlocks/miles.
94+
# (if you got hit by this bug, you can restore name/model by replacing first 0xB0 bytes in your corrupted License.dat file with the contents of a different one)
95+
PreventDESTSaveCorruption = true
96+
97+
# FixLensFlarePath: game tries to load in lens flare data from common/, but the game files have it inside media/, causing lens flare not to be drawn.
98+
# If lens flare is still present inside media/ then this will just patch game to load it from there instead.
99+
# (if you already moved the lens flare file yourself then no change will be applied)
100+
FixLensFlarePath = true

src/dllmain.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ namespace Settings
7171

7272
spdlog::info(" - SkipIntroLogos: {}", SkipIntroLogos);
7373
spdlog::info(" - CountdownTimerDisable: {}", CountdownTimerDisable);
74+
75+
spdlog::info(" - FixPegasusClopping: {}", FixPegasusClopping);
76+
spdlog::info(" - FixC2CRankings: {}", FixC2CRankings);
77+
spdlog::info(" - PreventDESTSaveCorruption: {}", PreventDESTSaveCorruption);
78+
spdlog::info(" - FixLensFlarePath: {}", FixLensFlarePath);
7479
}
7580

7681
bool read(std::filesystem::path& iniPath)
@@ -114,6 +119,11 @@ namespace Settings
114119
SkipIntroLogos = ini.Get("Misc", "SkipIntroLogos", std::move(SkipIntroLogos));
115120
CountdownTimerDisable = ini.Get("Misc", "CountdownTimerDisable", std::move(CountdownTimerDisable));
116121

122+
FixPegasusClopping = ini.Get("Bugfixes", "FixPegasusClopping", std::move(FixPegasusClopping));
123+
FixC2CRankings = ini.Get("Bugfixes", "FixC2CRankings", std::move(FixC2CRankings));
124+
PreventDESTSaveCorruption = ini.Get("Bugfixes", "PreventDESTSaveCorruption", std::move(PreventDESTSaveCorruption));
125+
FixLensFlarePath = ini.Get("Bugfixes", "FixLensFlarePath", std::move(FixLensFlarePath));
126+
117127
return true;
118128
}
119129
};

src/game_addrs.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ namespace Game
4545
inline fn_0args GhostCarExecServer = nullptr;
4646
inline fn_0args fn4666A0 = nullptr;
4747

48+
inline fn_1arg PrjSndRequest = nullptr;
49+
4850
inline void init()
4951
{
5052
current_mode = Module::exe_ptr<GameState>(0x38026C);
@@ -82,5 +84,7 @@ namespace Game
8284
EventControl = Module::fn_ptr<fn_0args>(0x3FAB0); // EventControl
8385
GhostCarExecServer = Module::fn_ptr<fn_0args>(0x80F80); // GhostCarExecServer
8486
fn4666A0 = Module::fn_ptr<fn_0args>(0x666A0);
87+
88+
PrjSndRequest = Module::fn_ptr<fn_1arg>(0x249F0);
8589
}
8690
};

src/hooks_bugfixes.cpp

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,40 @@
55
#include "plugin.hpp"
66
#include "game_addrs.hpp"
77

8+
class FixPegasusClopping : public Hook
9+
{
10+
const static int SndOff_PEGA_Addr = 0x4BCC0;
11+
12+
inline static SafetyHookInline SndOff_PEGA = {};
13+
static void destination()
14+
{
15+
SndOff_PEGA.call();
16+
17+
const int SND_STOP = 0x8000;
18+
Game::PrjSndRequest(SND_STOP | 0x8D); // 0x8D = clop
19+
}
20+
21+
public:
22+
std::string_view description() override
23+
{
24+
return "FixPegasusClopping";
25+
}
26+
27+
bool validate() override
28+
{
29+
return Settings::FixPegasusClopping;
30+
}
31+
32+
bool apply() override
33+
{
34+
SndOff_PEGA = safetyhook::create_inline(Module::exe_ptr(SndOff_PEGA_Addr), destination);
35+
return !!SndOff_PEGA;
36+
}
37+
38+
static FixPegasusClopping instance;
39+
};
40+
FixPegasusClopping FixPegasusClopping::instance;
41+
842
class FixC2CRankings : public Hook
943
{
1044
// A lot of the C2C ranking code has a strange check that tries to OpenEventA an existing named event based on current process ID
@@ -23,7 +57,7 @@ class FixC2CRankings : public Hook
2357

2458
bool validate() override
2559
{
26-
return true;
60+
return Settings::FixC2CRankings;
2761
}
2862

2963
bool apply() override
@@ -67,7 +101,7 @@ class PreventDESTSaveCorruption : public Hook
67101

68102
bool validate() override
69103
{
70-
return true;
104+
return Settings::PreventDESTSaveCorruption;
71105
}
72106

73107
bool apply() override
@@ -79,3 +113,42 @@ class PreventDESTSaveCorruption : public Hook
79113
static PreventDESTSaveCorruption instance;
80114
};
81115
PreventDESTSaveCorruption PreventDESTSaveCorruption::instance;
116+
117+
class FixLensFlarePath : public Hook
118+
{
119+
// Game tries to load in lens flare data from common/, but the game files have it inside media/, causing lens flare not to be drawn.
120+
// We'll just patch code to load from media/ instead
121+
// (only patch it if file actually exists inside media/ though, some may have already moved it to common/)
122+
123+
const static int LoadLensFlareOffset_StringAddr = 0x1A29F8;
124+
125+
public:
126+
std::string_view description() override
127+
{
128+
return "FixLensFlarePath";
129+
}
130+
131+
bool validate() override
132+
{
133+
return Settings::FixLensFlarePath;
134+
}
135+
136+
bool apply() override
137+
{
138+
std::string NewPath = "\\media\\lens_flare_offset.bin";
139+
if (std::filesystem::exists("." + NewPath))
140+
{
141+
auto* patch_addr = Module::exe_ptr<char>(LoadLensFlareOffset_StringAddr);
142+
143+
DWORD dwProtect;
144+
VirtualProtect((void*)patch_addr, NewPath.length(), PAGE_EXECUTE_READWRITE, &dwProtect);
145+
strcpy(patch_addr, NewPath.c_str());
146+
VirtualProtect((void*)patch_addr, NewPath.length(), dwProtect, &dwProtect);
147+
}
148+
149+
return true;
150+
}
151+
152+
static FixLensFlarePath instance;
153+
};
154+
FixLensFlarePath FixLensFlarePath::instance;

src/hooks_graphics.cpp

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -27,46 +27,6 @@ class DisableDPIScaling : public Hook
2727
};
2828
DisableDPIScaling DisableDPIScaling::instance;
2929

30-
class LensFlarePathFix : public Hook
31-
{
32-
const static int LoadLensFlareOffset_StringAddr = 0x1A29F8;
33-
34-
public:
35-
std::string_view description() override
36-
{
37-
return "LensFlarePathFix";
38-
}
39-
40-
bool validate() override
41-
{
42-
return true;
43-
}
44-
45-
bool apply() override
46-
{
47-
// Game code tries to load lens_flare_offset.bin from the wrong path
48-
// Code tries loading from common/, but game files have it inside media/
49-
// We'll just patch code to load from media/ instead
50-
// (only patch it if file actually exists inside media/ though, some fix guides already told people to move it to common/)
51-
52-
std::string NewPath = "\\media\\lens_flare_offset.bin";
53-
if (std::filesystem::exists("." + NewPath))
54-
{
55-
auto* patch_addr = Module::exe_ptr<char>(LoadLensFlareOffset_StringAddr);
56-
57-
DWORD dwProtect;
58-
VirtualProtect((void*)patch_addr, NewPath.length(), PAGE_EXECUTE_READWRITE, &dwProtect);
59-
strcpy(patch_addr, NewPath.c_str());
60-
VirtualProtect((void*)patch_addr, NewPath.length(), dwProtect, &dwProtect);
61-
}
62-
63-
return true;
64-
}
65-
66-
static LensFlarePathFix instance;
67-
};
68-
LensFlarePathFix LensFlarePathFix::instance;
69-
7030
class ScreenEdgeCullFix : public Hook
7131
{
7232
const static int CalcBall3D2D_Addr = 0x49E70;

src/plugin.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ namespace Settings
5656

5757
inline bool SkipIntroLogos = false;
5858
inline bool CountdownTimerDisable = false;
59+
60+
inline bool FixPegasusClopping = true;
61+
inline bool FixC2CRankings = true;
62+
inline bool PreventDESTSaveCorruption = true;
63+
inline bool FixLensFlarePath = true;
5964
}
6065

6166
namespace Util

0 commit comments

Comments
 (0)