Skip to content

Commit e54c0d1

Browse files
committed
HudToggleKey: allow assigning a key to toggle the game HUD
also fixed issue with CDTracks getting cleared when using user.ini
1 parent 3e218f1 commit e54c0d1

File tree

9 files changed

+146
-46
lines changed

9 files changed

+146
-46
lines changed

OutRun2006Tweaks.ini

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,11 @@ DisableCountdownTimer = false
208208
# Clarissa in O2SP arcade mode uses a different model in non-JP versions, this allows restoring the original JP model
209209
RestoreJPClarissa = false
210210

211+
# Allows assigning a keyboard key to toggle the game HUD
212+
# Depends on your keyboard layout which keys can be assigned here, some might work as-is (eg. P to bind it to P, or HOME to bind to Home)
213+
# Binding to a function key such as F10 should work fine on all keyboard layouts
214+
HudToggleKey =
215+
211216
# Changes the "Not Signed In" text to also display number of OutRun miles
212217
ShowOutRunMilesOnMenu = true
213218

src/dllmain.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ namespace Settings
111111

112112
spdlog::info(" - SkipIntroLogos: {}", SkipIntroLogos);
113113
spdlog::info(" - DisableCountdownTimer: {}", DisableCountdownTimer);
114+
spdlog::info(" - HudToggleKey: {}", HudToggleKey);
114115
spdlog::info(" - RestoreJPClarissa: {}", RestoreJPClarissa);
115116
spdlog::info(" - ShowOutRunMilesOnMenu: {}", ShowOutRunMilesOnMenu);
116117
spdlog::info(" - RandomHighwayAnimSets: {}", RandomHighwayAnimSets);
@@ -225,6 +226,7 @@ namespace Settings
225226

226227
SkipIntroLogos = ini.Get("Misc", "SkipIntroLogos", std::move(SkipIntroLogos));
227228
DisableCountdownTimer = ini.Get("Misc", "DisableCountdownTimer", std::move(DisableCountdownTimer));
229+
HudToggleKey = ini.Get("Misc", "HudToggleKey", std::move(HudToggleKey));
228230
RestoreJPClarissa = ini.Get("Misc", "RestoreJPClarissa", std::move(RestoreJPClarissa));
229231
ShowOutRunMilesOnMenu = ini.Get("Misc", "ShowOutRunMilesOnMenu", std::move(ShowOutRunMilesOnMenu));
230232
RandomHighwayAnimSets = ini.Get("Misc", "RandomHighwayAnimSets", std::move(RandomHighwayAnimSets));

src/game.hpp

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -68,50 +68,14 @@ namespace Input
6868
inline XINPUT_STATE PadStateCur{ 0 };
6969
inline uint32_t PadDigitalCur{ 0 };
7070

71-
inline void PadUpdate(int controllerIndex)
72-
{
73-
PadStatePrev = PadStateCur;
74-
PadDigitalPrev = PadDigitalCur;
75-
76-
if (XInputGetState(controllerIndex, &PadStateCur) != ERROR_SUCCESS)
77-
PadStateCur = { 0 };
78-
79-
PadDigitalCur = PadStateCur.Gamepad.wButtons;
80-
81-
// Convert analog inputs to digital bitfield
82-
{
83-
if (PadStateCur.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
84-
PadDigitalCur |= XINPUT_DIGITAL_LEFT_TRIGGER;
85-
if (PadStateCur.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
86-
PadDigitalCur |= XINPUT_DIGITAL_RIGHT_TRIGGER;
87-
88-
// Check left stick
89-
if (PadStateCur.Gamepad.sThumbLY > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
90-
PadDigitalCur |= XINPUT_DIGITAL_LS_UP;
91-
if (PadStateCur.Gamepad.sThumbLY < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
92-
PadDigitalCur |= XINPUT_DIGITAL_LS_DOWN;
93-
if (PadStateCur.Gamepad.sThumbLX < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
94-
PadDigitalCur |= XINPUT_DIGITAL_LS_LEFT;
95-
if (PadStateCur.Gamepad.sThumbLX > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
96-
PadDigitalCur |= XINPUT_DIGITAL_LS_RIGHT;
97-
98-
// Check right stick
99-
if (PadStateCur.Gamepad.sThumbRY > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
100-
PadDigitalCur |= XINPUT_DIGITAL_RS_UP;
101-
if (PadStateCur.Gamepad.sThumbRY < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
102-
PadDigitalCur |= XINPUT_DIGITAL_RS_DOWN;
103-
if (PadStateCur.Gamepad.sThumbRX < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
104-
PadDigitalCur |= XINPUT_DIGITAL_RS_LEFT;
105-
if (PadStateCur.Gamepad.sThumbRX > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
106-
PadDigitalCur |= XINPUT_DIGITAL_RS_RIGHT;
107-
}
108-
}
109-
11071
inline bool PadReleased(uint32_t buttons)
11172
{
11273
return (PadDigitalPrev & buttons) == buttons &&
113-
(PadDigitalCur & buttons) != buttons;
74+
(PadDigitalCur & buttons) != buttons;
11475
}
76+
77+
// hooks_input.cpp
78+
void Update();
11579
};
11680

11781
enum GameState

src/game_addrs.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ namespace Game
3535
return *DirectInput8_ptr;
3636
}
3737

38+
inline uint32_t* navipub_disp_flg = nullptr;
39+
3840
inline int* sel_bgm_kind_buf = nullptr;
3941

4042
inline int* app_time = nullptr; // used by SetTweeningTable etc
@@ -122,6 +124,8 @@ namespace Game
122124
D3DDevice_ptr = Module::exe_ptr<IDirect3DDevice9*>(0x49BD60);
123125
DirectInput8_ptr = Module::exe_ptr<IDirectInput8A*>(0x4606E8);
124126

127+
navipub_disp_flg = Module::exe_ptr<uint32_t>(0x4447F8);
128+
125129
sel_bgm_kind_buf = Module::exe_ptr<int>(0x430364);
126130

127131
app_time = Module::exe_ptr<int>(0x49EDB8);

src/hooks_audio.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@ class CDSwitcher : public Hook
150150
PadStatePrev = false;
151151
}
152152

153-
bool KeyStateNext = (GetAsyncKeyState('X') || PadStateNext);
154-
bool KeyStatePrev = (GetAsyncKeyState('Z') || PadStatePrev);
153+
bool KeyStateNext = ((GetAsyncKeyState('X') & 1) || PadStateNext);
154+
bool KeyStatePrev = ((GetAsyncKeyState('Z') & 1) || PadStatePrev);
155155

156156
bool BGMChanged = false;
157157

@@ -189,8 +189,15 @@ class CDSwitcher : public Hook
189189

190190
static void __cdecl PettyAutosceneCmdTblAnalysis_adxPlay_dest(int a1, uint32_t bgmIdx, int a3)
191191
{
192+
if (!Settings::CDTracks.size())
193+
{
194+
Game::adxPlay(a1, bgmIdx, a3);
195+
return;
196+
}
197+
192198
if (bgmIdx >= Settings::CDTracks.size())
193199
bgmIdx = 0;
200+
194201
BGMOverridePath = Settings::CDTracks[bgmIdx].first;
195202
Game::adxPlay(0, 0, 0);
196203
}
@@ -283,8 +290,6 @@ void AudioHooks_Update(int numUpdates)
283290

284291
void CDSwitcher_ReadIni(const std::filesystem::path& iniPath)
285292
{
286-
Settings::CDTracks.clear();
287-
288293
if (!std::filesystem::exists(iniPath))
289294
{
290295
// TODO: fill in defaults if no INI found? for now we'll just disable switcher

src/hooks_framerate.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ class ReplaceGameUpdateLoop : public Hook
209209
{
210210
// Fetch latest input state
211211
// (do this inside our update-loop so that any hooked game funcs have accurate state...)
212-
Input::PadUpdate(Settings::VibrationControllerId);
212+
Input::Update();
213213

214214
Game::ReadIO();
215215
Game::SoundControl_mb();

src/hooks_input.cpp

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,125 @@
1010
#include "plugin.hpp"
1111
#include "game_addrs.hpp"
1212

13+
namespace Input
14+
{
15+
void PadUpdate(int controllerIndex)
16+
{
17+
PadStatePrev = PadStateCur;
18+
PadDigitalPrev = PadDigitalCur;
19+
20+
if (XInputGetState(controllerIndex, &PadStateCur) != ERROR_SUCCESS)
21+
PadStateCur = { 0 };
22+
23+
PadDigitalCur = PadStateCur.Gamepad.wButtons;
24+
25+
// Convert analog inputs to digital bitfield
26+
{
27+
if (PadStateCur.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
28+
PadDigitalCur |= XINPUT_DIGITAL_LEFT_TRIGGER;
29+
if (PadStateCur.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
30+
PadDigitalCur |= XINPUT_DIGITAL_RIGHT_TRIGGER;
31+
32+
// Check left stick
33+
if (PadStateCur.Gamepad.sThumbLY > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
34+
PadDigitalCur |= XINPUT_DIGITAL_LS_UP;
35+
if (PadStateCur.Gamepad.sThumbLY < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
36+
PadDigitalCur |= XINPUT_DIGITAL_LS_DOWN;
37+
if (PadStateCur.Gamepad.sThumbLX < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
38+
PadDigitalCur |= XINPUT_DIGITAL_LS_LEFT;
39+
if (PadStateCur.Gamepad.sThumbLX > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
40+
PadDigitalCur |= XINPUT_DIGITAL_LS_RIGHT;
41+
42+
// Check right stick
43+
if (PadStateCur.Gamepad.sThumbRY > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
44+
PadDigitalCur |= XINPUT_DIGITAL_RS_UP;
45+
if (PadStateCur.Gamepad.sThumbRY < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
46+
PadDigitalCur |= XINPUT_DIGITAL_RS_DOWN;
47+
if (PadStateCur.Gamepad.sThumbRX < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
48+
PadDigitalCur |= XINPUT_DIGITAL_RS_LEFT;
49+
if (PadStateCur.Gamepad.sThumbRX > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
50+
PadDigitalCur |= XINPUT_DIGITAL_RS_RIGHT;
51+
}
52+
}
53+
54+
static int HudToggleVKey = 0;
55+
56+
void HudToggleUpdate()
57+
{
58+
static bool HudTogglePrevState = false;
59+
bool hudToggleKeyState = (GetAsyncKeyState(HudToggleVKey) & 0x8000);
60+
if (HudTogglePrevState != hudToggleKeyState)
61+
{
62+
HudTogglePrevState = hudToggleKeyState;
63+
if (!hudToggleKeyState) // if key is being released, toggle the hud flag
64+
*Game::navipub_disp_flg = (*Game::navipub_disp_flg == 0 ? 1 : 0);
65+
}
66+
}
67+
68+
int StringToVK(std::string_view key)
69+
{
70+
// Convert key to uppercase
71+
std::string keyUpper(key);
72+
std::transform(keyUpper.begin(), keyUpper.end(), keyUpper.begin(),
73+
[](unsigned char c) { return std::toupper(c); });
74+
75+
static const std::unordered_map<std::string_view, int> vkMap = {
76+
{"LBUTTON", VK_LBUTTON}, {"RBUTTON", VK_RBUTTON}, {"CANCEL", VK_CANCEL}, {"MBUTTON", VK_MBUTTON},
77+
{"XBUTTON1", VK_XBUTTON1}, {"XBUTTON2", VK_XBUTTON2}, {"BACK", VK_BACK}, {"TAB", VK_TAB},
78+
{"CLEAR", VK_CLEAR}, {"RETURN", VK_RETURN}, {"SHIFT", VK_SHIFT}, {"CONTROL", VK_CONTROL},
79+
{"MENU", VK_MENU}, {"PAUSE", VK_PAUSE}, {"CAPITAL", VK_CAPITAL}, {"ESCAPE", VK_ESCAPE},
80+
{"SPACE", VK_SPACE}, {"PRIOR", VK_PRIOR}, {"NEXT", VK_NEXT}, {"END", VK_END},
81+
{"HOME", VK_HOME}, {"LEFT", VK_LEFT}, {"UP", VK_UP}, {"RIGHT", VK_RIGHT},
82+
{"DOWN", VK_DOWN}, {"SELECT", VK_SELECT}, {"PRINT", VK_PRINT}, {"EXECUTE", VK_EXECUTE},
83+
{"SNAPSHOT", VK_SNAPSHOT}, {"INSERT", VK_INSERT}, {"DELETE", VK_DELETE}, {"HELP", VK_HELP},
84+
{"LWIN", VK_LWIN}, {"RWIN", VK_RWIN}, {"APPS", VK_APPS}, {"SLEEP", VK_SLEEP},
85+
{"NUMPAD0", VK_NUMPAD0}, {"NUMPAD1", VK_NUMPAD1}, {"NUMPAD2", VK_NUMPAD2}, {"NUMPAD3", VK_NUMPAD3},
86+
{"NUMPAD4", VK_NUMPAD4}, {"NUMPAD5", VK_NUMPAD5}, {"NUMPAD6", VK_NUMPAD6}, {"NUMPAD7", VK_NUMPAD7},
87+
{"NUMPAD8", VK_NUMPAD8}, {"NUMPAD9", VK_NUMPAD9}, {"MULTIPLY", VK_MULTIPLY}, {"ADD", VK_ADD},
88+
{"SEPARATOR", VK_SEPARATOR}, {"SUBTRACT", VK_SUBTRACT}, {"DECIMAL", VK_DECIMAL}, {"DIVIDE", VK_DIVIDE},
89+
{"F1", VK_F1}, {"F2", VK_F2}, {"F3", VK_F3}, {"F4", VK_F4}, {"F5", VK_F5},
90+
{"F6", VK_F6}, {"F7", VK_F7}, {"F8", VK_F8}, {"F9", VK_F9}, {"F10", VK_F10},
91+
{"F11", VK_F11}, {"F12", VK_F12}, {"F13", VK_F13}, {"F14", VK_F14}, {"F15", VK_F15},
92+
{"F16", VK_F16}, {"F17", VK_F17}, {"F18", VK_F18}, {"F19", VK_F19}, {"F20", VK_F20},
93+
{"F21", VK_F21}, {"F22", VK_F22}, {"F23", VK_F23}, {"F24", VK_F24}, {"NUMLOCK", VK_NUMLOCK},
94+
{"SCROLL", VK_SCROLL}
95+
// TODO: are there any others worth adding here?
96+
};
97+
98+
// Check if key is a single character
99+
if (keyUpper.size() == 1)
100+
{
101+
char ch = keyUpper[0];
102+
if (std::isalnum(ch))
103+
return std::toupper(ch);
104+
}
105+
106+
// Search in the vkMap
107+
auto it = vkMap.find(keyUpper);
108+
if (it != vkMap.end())
109+
return it->second;
110+
111+
// If not found, return -1 or some invalid value
112+
return 0;
113+
}
114+
115+
void Update()
116+
{
117+
static bool inited = false;
118+
if (!inited)
119+
{
120+
HudToggleVKey = StringToVK(Settings::HudToggleKey);
121+
inited = true;
122+
}
123+
124+
// Update gamepad for main controller id
125+
PadUpdate(Settings::VibrationControllerId);
126+
127+
if (HudToggleVKey)
128+
HudToggleUpdate();
129+
}
130+
};
131+
13132
// Hooks into XINPUT1_4's DeviceIoControl via undocumented DriverHook(0xBAAD0001) call
14133
// Allows us to detect SET_GAMEPAD_STATE ioctl and send the GIP HID command for trigger impulses
15134
// Hopefully will work for most series controller connection types...

src/plugin.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ namespace Settings
102102

103103
inline bool SkipIntroLogos = false;
104104
inline bool DisableCountdownTimer = false;
105+
inline std::string HudToggleKey = "";
105106
inline bool RestoreJPClarissa = false;
106107
inline bool ShowOutRunMilesOnMenu = true;
107108
inline bool RandomHighwayAnimSets = false;

src/resource.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
#define MODULE_VERSION_MAJOR 0
1717
#define MODULE_VERSION_MINOR 5
18-
#define MODULE_VERSION_BUILD 0
18+
#define MODULE_VERSION_BUILD 1
1919
#define MODULE_VERSION_REVISION 0
2020

2121
#define STR(value) #value

0 commit comments

Comments
 (0)