Skip to content

Commit ec02add

Browse files
committed
implement crouch walk game logic
1 parent c5bc27b commit ec02add

File tree

4 files changed

+176
-20
lines changed

4 files changed

+176
-20
lines changed

MGS3CrouchWalk/MGS3CrouchWalk.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
<ClInclude Include="ini.h" />
156156
<ClInclude Include="Memory.h" />
157157
<ClInclude Include="MinHook.h" />
158+
<ClInclude Include="types.h" />
158159
</ItemGroup>
159160
<ItemGroup>
160161
<ClCompile Include="dllmain.cpp" />

MGS3CrouchWalk/MGS3CrouchWalk.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
<ClInclude Include="ini.h">
2828
<Filter>Header Files</Filter>
2929
</ClInclude>
30+
<ClInclude Include="types.h">
31+
<Filter>Header Files</Filter>
32+
</ClInclude>
3033
</ItemGroup>
3134
<ItemGroup>
3235
<ClCompile Include="dllmain.cpp">

MGS3CrouchWalk/dllmain.cpp

Lines changed: 95 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,102 @@
22
#include "Memory.h"
33
#include "MinHook.h"
44
#include "ini.h"
5+
#include "types.h"
56

67
HMODULE GameModule = GetModuleHandleA("METAL GEAR SOLID3.exe");
78
uintptr_t GameBase = (uintptr_t)GameModule;
89
uintptr_t* CamoIndexData = NULL;
10+
uintptr_t ActSquatStillOffset = 0;
11+
MovementWork* plWorkGlobal = NULL;
912
float CamoIndexModifier = 1.0f;
1013
int CamoIndexValue = 0;
14+
bool CrouchWalkEnabled = false;
15+
bool CrouchMoving = false;
1116
mINI::INIStructure Config;
1217

13-
typedef uintptr_t* __fastcall InitializeCamoIndexDelegate(uintptr_t a1, int a2);
1418
InitializeCamoIndexDelegate* InitializeCamoIndex;
15-
16-
typedef uintptr_t __fastcall CalculateCamoIndexDelegate(uintptr_t a1, int a2);
1719
CalculateCamoIndexDelegate* CalculateCamoIndex;
18-
uintptr_t __fastcall CalculateCamoIndexHook(uintptr_t a1, int a2)
20+
ActionSquatStillDelegate* ActionSquatStill;
21+
PlayerSetMotionDelegate* PlayerSetMotionInternal;
22+
SetMotionDataDelegate* SetMotionData;
23+
PlayerStatusCheckDelegate* PlayerStatusCheck;
24+
ActMovementDelegate* ActMovement;
25+
26+
uintptr_t PlayerSetMotion(__int64 work, PlayerMotion motion)
27+
{
28+
int motionIndex = (int)motion;
29+
30+
if (motionIndex > 0)
31+
{
32+
motionIndex--;
33+
}
34+
35+
return PlayerSetMotionInternal(work, (PlayerMotion)motionIndex);
36+
}
37+
38+
int* __fastcall ActionSquatStillHook(__int64 work, MovementWork* plWork, __int64 a3, __int64 a4)
1939
{
20-
uintptr_t result = CalculateCamoIndex(a1, a2);
40+
// we store this here so we don't have to hardcode another address that
41+
// needs to be updated with each new game patch
42+
plWorkGlobal = plWork;
2143

22-
if (CamoIndexData != NULL)
44+
int* result = ActionSquatStill(work, plWork, a3, a4);
45+
int16_t padForce = *(int16_t*)(work + 2016);
46+
47+
CrouchMoving = padForce > plWork->padForceLimit;
48+
49+
// 0xDE seems to make sure we aren't in first person mode
50+
if (CrouchMoving && !PlayerStatusCheck(0xDE))
51+
{
52+
if (!CrouchWalkEnabled)
53+
plWork->motion = PlayerSetMotion(work, PlayerMotion::RunUpwards); // we must set the motion to something unusable on the first run, otherwise the anim won't reset properly
54+
else
55+
plWork->motion = PlayerSetMotion(work, PlayerMotion::StandMoveStalk); // hijack the stalking motion
56+
57+
CrouchWalkEnabled = true;
58+
}
59+
60+
if (CrouchWalkEnabled && (plWork->flag & MovementFlag::FlagStand) != 0)
61+
CrouchWalkEnabled = false;
62+
63+
return result;
64+
}
65+
66+
void __fastcall SetMotionDataHook(int* m_ctrl, int layer, PlayerMotion motion, int time, __int64 a5)
67+
{
68+
if (motion == PlayerMotion::StandMoveStalk && CrouchWalkEnabled)
69+
motion = PlayerMotion::SquatMove;
70+
71+
SetMotionData(m_ctrl, layer, motion, time, a5);
72+
}
73+
74+
__int64 __fastcall ActMovementHook(MovementWork* plWork, __int64 work, int flag)
75+
{
76+
if (plWorkGlobal != NULL && plWorkGlobal->action != ActSquatStillOffset)
77+
CrouchWalkEnabled = false;
78+
79+
return ActMovement(plWork, work, flag);
80+
}
81+
82+
int* __fastcall CalculateCamoIndexHook(int* a1, int a2)
83+
{
84+
int* result = CalculateCamoIndex(a1, a2);
85+
86+
if (CamoIndexData != NULL && CrouchWalkEnabled)
2387
{
2488
int index = a2 << 7;
2589
auto camoIndex = (int*)((char*)&CamoIndexData[4] + index + 4);
2690
auto movementState = (int*)((char*)&CamoIndexData[4] + index + 8);
2791

28-
if (*camoIndex >= 1000) // ignore if stealth is equipped
92+
if (*camoIndex >= 1000) // ignore if stealth is equipped (todo: properly check item for ezgun and spider camo)
2993
{
3094
return result;
3195
}
3296

33-
if (*movementState == 0x6002)
97+
if (CrouchMoving)
3498
{
35-
*camoIndex = *camoIndex < 0 ? *camoIndex / CamoIndexModifier : *camoIndex * CamoIndexModifier;
36-
*camoIndex += CamoIndexValue;
99+
*camoIndex = *camoIndex < 0 ? *camoIndex / CamoIndexModifier : *camoIndex * CamoIndexModifier;
100+
*camoIndex -= CamoIndexValue;
37101

38102
if (*camoIndex > 950) *camoIndex = 950;
39103
if (*camoIndex < -1000) *camoIndex = -1000;
@@ -42,18 +106,30 @@ uintptr_t __fastcall CalculateCamoIndexHook(uintptr_t a1, int a2)
42106

43107
return result;
44108
}
45-
46-
void InstallHooks()
109+
void InstallHooks()
47110
{
48111
int status = MH_Initialize();
49112

113+
uintptr_t actMovementOffset = (uintptr_t)Memory::PatternScan(GameModule, "40 53 56 57 48 81 EC F0 00 00 00 48 8B 05 96 ?? ?? 00 48 33 C4 48 89 84 24 B0 00 00 00 48 8B F9");
114+
uintptr_t setMotionDataOffset = (uintptr_t)Memory::PatternScan(GameModule, "48 85 C9 0F 84 42 03 00 00 4C 8B DC 55 53 56 41");
50115
uintptr_t calcuateCamoIndexOffset = (uintptr_t)Memory::PatternScan(GameModule, "48 83 EC 30 0F 29 74 24 20 48 8B F9 48 63 F2 E8") - 0x10;
51-
uintptr_t initializeCamoIndexOffset = (uintptr_t)Memory::PatternScan(GameModule, "85 D2 75 33 0F 57 C0 48 63 C2 48 C1 E0 07 48 8D");
116+
uint8_t* disableCrouchProneOffset = Memory::PatternScan(GameModule, "00 00 7E 19 83 4F 68 10");
117+
118+
ActSquatStillOffset = (uintptr_t)Memory::PatternScan(GameModule, "4C 8B DC 55 57 41 56 49 8D 6B A1 48 81 EC 00 01");
119+
InitializeCamoIndex = (InitializeCamoIndexDelegate*)Memory::PatternScan(GameModule, "85 D2 75 33 0F 57 C0 48 63 C2 48 C1 E0 07 48 8D");
120+
PlayerSetMotionInternal = (PlayerSetMotionDelegate*)(Memory::PatternScan(GameModule, "B9 0F 01 00 00 E8 ?? 36 FF FF 85 C0 74 2A BA FF") - 0x10);
121+
PlayerStatusCheck = (PlayerStatusCheckDelegate*)Memory::PatternScan(GameModule, "8B D1 B8 01 00 00 00 83 E1 1F D3 E0 8B CA 48 C1");
52122

123+
Memory::DetourFunction(actMovementOffset, (LPVOID)ActMovementHook, (LPVOID*)&ActMovement);
124+
Memory::DetourFunction(setMotionDataOffset, (LPVOID)SetMotionDataHook, (LPVOID*)&SetMotionData);
53125
Memory::DetourFunction(calcuateCamoIndexOffset, (LPVOID)CalculateCamoIndexHook, (LPVOID*)&CalculateCamoIndex);
126+
Memory::DetourFunction(ActSquatStillOffset, (LPVOID)ActionSquatStillHook, (LPVOID*)&ActionSquatStill);
54127

55-
InitializeCamoIndex = (InitializeCamoIndexDelegate*)initializeCamoIndexOffset;
56128
CamoIndexData = InitializeCamoIndex(0, 0);
129+
130+
DWORD oldProtect;
131+
VirtualProtect((LPVOID)disableCrouchProneOffset, 8, PAGE_EXECUTE_READWRITE, &oldProtect);
132+
disableCrouchProneOffset[7] = 0x00;
57133
}
58134

59135
void ReadConfig()
@@ -71,20 +147,19 @@ DWORD WINAPI MainThread(LPVOID lpParam)
71147
WCHAR* filename = PathFindFileName(exePath);
72148

73149
if (wcsncmp(filename, L"launcher.exe", 13) == 0)
74-
{
75150
return true;
76-
}
77151

78152
Sleep(3000); // delay, just in case
79153
ReadConfig();
80154
InstallHooks();
155+
81156
return true;
82157
}
83158

84-
BOOL APIENTRY DllMain( HMODULE hModule,
85-
DWORD ul_reason_for_call,
86-
LPVOID lpReserved
87-
)
159+
BOOL APIENTRY DllMain(HMODULE hModule,
160+
DWORD ul_reason_for_call,
161+
LPVOID lpReserved
162+
)
88163
{
89164
switch (ul_reason_for_call)
90165
{

MGS3CrouchWalk/types.h

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
5+
const enum PlayerMotion
6+
{
7+
Stand = 0,
8+
Squat = 2,
9+
StandMoveSlow = 3,
10+
StandMoveStalk = 4,
11+
Run = 5,
12+
RunUpwards = 6,
13+
Ground = 9,
14+
GroundMove = 10,
15+
RunToRolling = 21,
16+
RollingToStand = 22,
17+
RollingToGround = 23,
18+
StandCover = 97,
19+
SquatCover = 98,
20+
SquatMove = 199
21+
};
22+
23+
const enum MovementFlag
24+
{
25+
FlagWalk = 0x20u,
26+
FlagSquatToGround = 0x30u,
27+
FlagStand = 0x40u,
28+
};
29+
30+
struct MovementWork
31+
{
32+
uint32_t field00;
33+
uint32_t field04;
34+
uint32_t field08;
35+
uint32_t field0C;
36+
uint32_t field10;
37+
uint32_t field14;
38+
uint32_t field18;
39+
uint32_t field1C;
40+
uint32_t field20;
41+
uint32_t field24;
42+
uint32_t field28;
43+
uint32_t field2C;
44+
uint32_t field30;
45+
uint32_t field34;
46+
uint32_t field38;
47+
uint32_t field3C;
48+
uint32_t field40;
49+
uint32_t field44;
50+
uint32_t field48;
51+
uint32_t field4C;
52+
uint32_t field50;
53+
uint32_t field54;
54+
uintptr_t action;
55+
uint32_t motion;
56+
uint32_t field64;
57+
uint32_t flag;
58+
uint16_t padCount;
59+
uint16_t field6C;
60+
uint16_t turnDir;
61+
uint32_t field70;
62+
uint32_t field74;
63+
uint32_t field78;
64+
uint32_t field7C;
65+
uint32_t field80;
66+
uint32_t field84;
67+
uint32_t field88;
68+
uint32_t padForceLimit;
69+
};
70+
71+
typedef uintptr_t* __fastcall InitializeCamoIndexDelegate(int* a1, int a2);
72+
typedef int* __fastcall CalculateCamoIndexDelegate(int* a1, int a2);
73+
typedef int* __fastcall ActionSquatStillDelegate(__int64 work, MovementWork* plWork, __int64 a3, __int64 a4);
74+
typedef uint32_t __fastcall PlayerSetMotionDelegate(__int64 work, PlayerMotion motion);
75+
typedef void __fastcall SetMotionDataDelegate(int* m_ctrl, int layer, int motion, int time, __int64 a5);
76+
typedef __int64 __fastcall PlayerStatusCheckDelegate(unsigned int a1);
77+
typedef __int64 __fastcall ActMovementDelegate(MovementWork* plWork, __int64 work, int flag);

0 commit comments

Comments
 (0)