mirror of
https://github.com/CookiePLMonster/SilentPatch.git
synced 2024-12-29 23:33:02 +05:00
Compare commits
21 commits
ea13429022
...
202101e4f7
Author | SHA1 | Date | |
---|---|---|---|
|
202101e4f7 | ||
|
52deecd5ac | ||
|
7d055f9264 | ||
|
fd67cb4064 | ||
|
7d1bd8a9ac | ||
|
75a3f16ffb | ||
|
2f79eb1c8f | ||
|
3017790d44 | ||
|
9f705a3dc3 | ||
|
5aaec719ed | ||
|
cdcf979a54 | ||
|
2de40406d2 | ||
|
09bb67220e | ||
|
6a524dcf46 | ||
|
17baa64613 | ||
|
f1d85b825b | ||
|
4cb6edad7c | ||
|
6e5b41c958 | ||
|
a07d7936da | ||
|
e8b3d3f531 | ||
|
d74b104473 |
20 changed files with 761 additions and 228 deletions
|
@ -48,6 +48,8 @@ All the remaining, non-critical fixes.
|
|||
* The radar's horizontal position and its disc texture now scale to resolution correctly, resolving color bleed issues at high resolutions.
|
||||
* Credits now scale to resolution correctly, and they don't cut to an empty screen at the very end anymore.
|
||||
* Mission title and 'Mission Passed' texts now stay on screen for the same duration, regardless of screen resolution.
|
||||
* The inner padding of the text boxes with a background now scales to resolution correctly.
|
||||
* The position of the dialog question text in the main menu now scales to resolution correctly.
|
||||
* `FILE_FLAG_NO_BUFFERING` flag has been removed from IMG reading functions - speeding up streaming.
|
||||
* Free resprays will not carry on a New Game now.
|
||||
* Fixed ambulance and firetruck dispatch timers - they reset on New Game now.
|
||||
|
@ -63,7 +65,7 @@ All the remaining, non-critical fixes.
|
|||
* Drivers now behave correctly when shot at. In the PC versions, they would always speed away, but now they can also do nothing, like in the PS2 version. Additionally, a third, previously inaccessible behavior where drivers abandon the car and flee on foot is now working correctly.
|
||||
* Dodo keyboard controls are now active when the All Cars Fly cheat is enabled.
|
||||
* Temporary pickups (like money) are now properly cleaned up if there are too many of them, fixing a possible object leak.
|
||||
* Car reflections are now displayed correctly in the Steam version (integrated Steam Car Colour Fix from **Sergenaur**).
|
||||
* Car reflections are now displayed correctly in the Steam version (integrated Steam Car Colour Fix from **Sergeanur**).
|
||||
* Made Claude sit when riding in a Speeder, the same as **Fire_Head**'s SitInBoat. This change also applies to Skimmer if III Aircraft is installed.
|
||||
* All FBI Kurumas now spawn in a dark grey color with unpainted bumpers, rather than pitch black.
|
||||
* Detached limbs now have properly working LODs, instead of rendering the normal and low-detail models at the same time.
|
||||
|
|
|
@ -102,6 +102,7 @@ All the remaining, non-critical fixes.
|
|||
* ➕ The boundaries of the cursor on the Map screen, and the cursor itself now scale to resolution correctly (contributed by **Wesser**).
|
||||
* ➕ The inner padding of the text boxes with a background now scales to resolution correctly (contributed by **Wesser**).
|
||||
* ➕ Nitrous will no longer regenerate faster when reversing the car (contributed by **Wesser**).
|
||||
* ➕ Hydra's jet thrusters no longer randomly fail to appear (contributed by **B1ack_Wh1te**).
|
||||
* Detached vehicle parts will now keep the same color and lighting as the vehicle they came from.
|
||||
* Detached vehicle parts are now rendered from both sides.
|
||||
* Resolved single-pixel wide seams showing on the Map screen with Anti-Aliasing enabled.
|
||||
|
|
|
@ -44,6 +44,9 @@ All the remaining, non-critical fixes.
|
|||
* The radar's horizontal position, the disc texture, and the shadow now scale to resolution correctly. The radar disc was also shrunk slightly to fix gaps and make the icons sit better on the edge.
|
||||
* Credits now scale to resolution correctly.
|
||||
* Mission title and 'Mission Passed' texts now stay on screen for the same duration, regardless of screen resolution.
|
||||
* The inner padding of the text boxes with a background now scales to resolution correctly.
|
||||
* The vertical offset of the weapon name text in Ammu-Nation now scales to resolution correctly.
|
||||
* The downward-pointing destination blip in the Map Legend now displays with a correct outline.
|
||||
* `FILE_FLAG_NO_BUFFERING` flag has been removed from IMG reading functions - speeding up streaming.
|
||||
* Free resprays will not carry on a New Game now.
|
||||
* Fixed ambulance and firetruck dispatch timers - they reset on New Game now.
|
||||
|
@ -63,7 +66,7 @@ All the remaining, non-critical fixes.
|
|||
* Fixed an issue where Tommy wouldn't shake his fist at incoming traffic when holding Brass Knuckles, yet would do it when holding a chainsaw.
|
||||
* Fixed an issue where Tommy wouldn't shake his fist at stopped traffic when holding any weapons introduced in Vice City.
|
||||
* Hitting vehicles and objects with a screwdriver now produces an impact sound.
|
||||
* Pedestrians and Tommy are now much more talkative, like in the PS2 version (integrated Ped Speech Patch from **Sergenaur**).
|
||||
* Pedestrians and Tommy are now much more talkative, like in the PS2 version (integrated Ped Speech Patch from **Sergeanur**).
|
||||
* Tear gas can now deal damage to Tommy and other mission characters, like in the PS2 version.
|
||||
* ⚙️ Fixed siren corona placements in Police, Firetruck, Ambulance, Enforcer, Vice Cheetah, and FBI Washington.
|
||||
* ⚙️ Added siren corona to FBI Washington.
|
||||
|
|
|
@ -56,17 +56,30 @@ carsontrack
|
|||
car_fucko03
|
||||
chairsntable
|
||||
chairsntableml
|
||||
ci_alights1_01
|
||||
ci_astudlights
|
||||
ci_backlot1
|
||||
ci_backlot2
|
||||
ci_backlot3
|
||||
ci_backlotprops1
|
||||
ci_backlotprops2
|
||||
ci_backlotprops3
|
||||
ci_blights1_01
|
||||
ci_camera1_01
|
||||
ci_flatprop01
|
||||
ci_flatprop02
|
||||
ci_fountain
|
||||
ci_industrial1
|
||||
ci_lander
|
||||
ci_lights1_01
|
||||
ci_manintstuff
|
||||
ci_mansion1
|
||||
ci_offices
|
||||
ci_redhead1_01
|
||||
ci_setshad1
|
||||
ci_tankship
|
||||
ci_watertank
|
||||
ci_windmach
|
||||
cl_curtains
|
||||
cl_tbl_chait_tmp
|
||||
cl_tbl_chait_tmpb
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# SilentPatch
|
||||
|
||||
<p align="center">
|
||||
<img height="350" src="https://i.imgur.com/sCDzq12.png" alt="Logo">
|
||||
<img src="https://i.imgur.com/sCDzq12.png" alt="Logo">
|
||||
</p>
|
||||
|
||||
SilentPatch for the 3D-era Grand Theft Auto games is the first and flagship release of the "SilentPatch family", providing numerous fixes for this beloved franchise.
|
||||
|
@ -36,10 +36,11 @@ for both first-time players and the old guard returning for yet another playthro
|
|||
|
||||
SilentPatch includes code contributions from:
|
||||
* aap
|
||||
* B1ack_Wh1te
|
||||
* DK22Pac
|
||||
* Fire_Head
|
||||
* Nick007J
|
||||
* NTAuthority
|
||||
* Sergenaur
|
||||
* Sergeanur
|
||||
* spaceeinstein
|
||||
* Wesser
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "SVF.h"
|
||||
#include "ParseUtils.hpp"
|
||||
#include "Random.h"
|
||||
#include "RWGTA.h"
|
||||
|
||||
#include "Utils/DelimStringReader.h"
|
||||
|
||||
|
@ -195,6 +196,8 @@ namespace Common {
|
|||
using namespace Memory;
|
||||
using namespace hook::txn;
|
||||
|
||||
const bool HasRwD3D8 = RWGTA::Patches::TryLocateRwD3D8();
|
||||
|
||||
// Delayed patching
|
||||
try
|
||||
{
|
||||
|
@ -249,7 +252,7 @@ namespace Common {
|
|||
|
||||
|
||||
// Fixed static shadows not rendering under fire and pickups
|
||||
try
|
||||
if (HasRwD3D8) try
|
||||
{
|
||||
using namespace StaticShadowAlphaFix;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#define RwEngineInstance (*rwengine)
|
||||
|
||||
#include <rwcore.h>
|
||||
#include "RWGTA.h"
|
||||
|
||||
// GTA versions of RenderWare functions/macros for GTA III/Vice City
|
||||
// since we cannot use RwEngineInstance directly
|
||||
|
@ -39,14 +40,16 @@ void** rwengine = []() -> void** {
|
|||
return nullptr;
|
||||
}();
|
||||
|
||||
static void* varRwD3D8SetRenderState = Memory::ReadCallFrom( hook::get_pattern( "0F 8C ? ? ? ? 6A 05 6A 19", 10 ) );
|
||||
WRAPPER RwBool RwD3D8SetRenderState(RwUInt32 state, RwUInt32 value) { VARJMP(varRwD3D8SetRenderState); }
|
||||
static decltype(::RwD3D8SetRenderState)* fnRwD3D8SetRenderState;
|
||||
RwBool RwD3D8SetRenderState(RwUInt32 state, RwUInt32 value)
|
||||
{
|
||||
return fnRwD3D8SetRenderState(state, value);
|
||||
}
|
||||
|
||||
static RwUInt32* _rwD3D8RenderStates = *static_cast<RwUInt32**>(Memory::ReadCallFrom( hook::get_pattern( "0F 8C ? ? ? ? 6A 05 6A 19", 10 ), 8 + 3 ));
|
||||
static decltype(::RwD3D8GetRenderState)* fnRwD3D8GetRenderState;
|
||||
void RwD3D8GetRenderState(RwUInt32 state, void* value)
|
||||
{
|
||||
RwUInt32* valuePtr = static_cast<RwUInt32*>(value);
|
||||
*valuePtr = _rwD3D8RenderStates[ 2 * state ];
|
||||
fnRwD3D8GetRenderState(state, value);
|
||||
}
|
||||
|
||||
RwReal RwIm2DGetNearScreenZ()
|
||||
|
@ -65,4 +68,37 @@ RwBool RwRenderStateSet(RwRenderState state, void *value)
|
|||
}
|
||||
|
||||
// Unreachable stub
|
||||
RwBool RwMatrixDestroy(RwMatrix* mpMat) { assert(!"Unreachable!"); return TRUE; }
|
||||
RwBool RwMatrixDestroy(RwMatrix* /*mpMat*/) { assert(!"Unreachable!"); return TRUE; }
|
||||
|
||||
bool RWGTA::Patches::TryLocateRwD3D8() try
|
||||
{
|
||||
using namespace Memory;
|
||||
using namespace hook::txn;
|
||||
|
||||
auto pfnRwD3D8SetRenderState = [] {
|
||||
try {
|
||||
// Everything except for III Steam
|
||||
return static_cast<decltype(RwD3D8SetRenderState)*>(get_pattern("39 0C C5 ? ? ? ? 74 31", -8));
|
||||
} catch (const hook::txn_exception&) {
|
||||
// III Steam
|
||||
return static_cast<decltype(RwD3D8SetRenderState)*>(get_pattern("8B 0C C5 ? ? ? ? 3B CA", -8));
|
||||
}
|
||||
}();
|
||||
auto pfnRwD3D8GetRenderState = [] {
|
||||
try {
|
||||
// Everything except for III Steam
|
||||
return static_cast<decltype(RwD3D8GetRenderState)*>(get_pattern("8B 0C C5 ? ? ? ? 89 0A C3", -8));
|
||||
} catch (const hook::txn_exception&) {
|
||||
// III Steam
|
||||
return static_cast<decltype(RwD3D8GetRenderState)*>(get_pattern("8B 04 C5 ? ? ? ? 89 02 C3", -8));
|
||||
}
|
||||
}();
|
||||
|
||||
fnRwD3D8SetRenderState = pfnRwD3D8SetRenderState;
|
||||
fnRwD3D8GetRenderState = pfnRwD3D8GetRenderState;
|
||||
return true;
|
||||
}
|
||||
catch (const hook::txn_exception&)
|
||||
{
|
||||
return false;
|
||||
}
|
6
SilentPatch/RWGTA.h
Normal file
6
SilentPatch/RWGTA.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace RWGTA::Patches
|
||||
{
|
||||
bool TryLocateRwD3D8();
|
||||
}
|
|
@ -1 +1 @@
|
|||
Subproject commit d70ae68a8e20c4cbd43f60e45586ce65304c1741
|
||||
Subproject commit 0c6cb62fbee9ff278cc9ff61b4b8b39403812945
|
|
@ -1099,6 +1099,84 @@ namespace BrakelightsDummy
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// ============= Fix text background padding not scaling to resolution =============
|
||||
namespace TextRectPaddingScalingFixes
|
||||
{
|
||||
template<std::size_t Index>
|
||||
static const float* orgPaddingXSize;
|
||||
|
||||
template<std::size_t Index>
|
||||
static float PaddingXSize_Recalculated;
|
||||
|
||||
template<std::size_t... I>
|
||||
static void RecalculateXSize(std::index_sequence<I...>)
|
||||
{
|
||||
const float multiplier = GetWidthMult() * RsGlobal->MaximumWidth;
|
||||
((PaddingXSize_Recalculated<I> = *orgPaddingXSize<I> * multiplier), ...);
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static const float* orgPaddingYSize;
|
||||
|
||||
template<std::size_t Index>
|
||||
static float PaddingYSize_Recalculated;
|
||||
|
||||
template<std::size_t... I>
|
||||
static void RecalculateYSize(std::index_sequence<I...>)
|
||||
{
|
||||
const float multiplier = GetHeightMult() * RsGlobal->MaximumHeight;
|
||||
((PaddingYSize_Recalculated<I> = *orgPaddingYSize<I> * multiplier), ...);
|
||||
}
|
||||
|
||||
static void (*orgGetTextRect)(CRect*, float, float, void*);
|
||||
template<std::size_t NumXPadding, std::size_t NumYPadding>
|
||||
static void GetTextRect_Recalculate(CRect* a1, float a2, float a3, void* a4)
|
||||
{
|
||||
RecalculateXSize(std::make_index_sequence<NumXPadding>{});
|
||||
RecalculateYSize(std::make_index_sequence<NumYPadding>{});
|
||||
orgGetTextRect(a1, a2, a3, a4);
|
||||
}
|
||||
|
||||
HOOK_EACH_INIT(PaddingXSize, orgPaddingXSize, PaddingXSize_Recalculated);
|
||||
HOOK_EACH_INIT(PaddingYSize, orgPaddingYSize, PaddingYSize_Recalculated);
|
||||
|
||||
template<std::size_t Index>
|
||||
static const float* orgWrapX;
|
||||
|
||||
template<std::size_t Index>
|
||||
static float WrapX_Recalculated;
|
||||
|
||||
template<std::size_t... I>
|
||||
static void RecalculateWrapX(std::index_sequence<I...>)
|
||||
{
|
||||
const float multiplier = GetWidthMult() * RsGlobal->MaximumWidth;
|
||||
((WrapX_Recalculated<I> = *orgWrapX<I> * multiplier), ...);
|
||||
}
|
||||
|
||||
static void (*orgSetJustifyOff)();
|
||||
template<std::size_t NumXWrap>
|
||||
static void SetJustifyOff_Recalculate()
|
||||
{
|
||||
RecalculateWrapX(std::make_index_sequence<NumXWrap>{});
|
||||
orgSetJustifyOff();
|
||||
}
|
||||
|
||||
HOOK_EACH_INIT(WrapX, orgWrapX, WrapX_Recalculated);
|
||||
}
|
||||
|
||||
|
||||
// ============= Fix menu texts not scaling to resolution =============
|
||||
namespace MenuManagerScalingFixes
|
||||
{
|
||||
static void (*orgPrintString)(float,float,const wchar_t*);
|
||||
static void PrintString_Scale(float fX, float fY, const wchar_t* pText)
|
||||
{
|
||||
orgPrintString(fX * GetWidthMult() * RsGlobal->MaximumWidth, fY * GetHeightMult() * RsGlobal->MaximumHeight, pText);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace ModelIndicesReadyHook
|
||||
{
|
||||
static void (*orgInitialiseObjectData)(const char*);
|
||||
|
@ -1493,6 +1571,65 @@ void InjectDelayedPatches_III_Common( bool bHasDebugMenu, const wchar_t* wcModul
|
|||
}
|
||||
TXN_CATCH();
|
||||
|
||||
|
||||
// Fix text background padding not scaling to resolution
|
||||
try
|
||||
{
|
||||
using namespace TextRectPaddingScalingFixes;
|
||||
|
||||
auto getTextRect = get_pattern("FF 74 24 54 FF 74 24 54 50 E8 ? ? ? ? 83 C4 10", 9);
|
||||
auto rectWidth1 = pattern("D8 25 ? ? ? ? D9 18 89 54 24 18 8B 44 24 34 DB 44 24 18 D8 44 24 38 D8 05").get_one();
|
||||
auto rectWidth2 = pattern("D8 25 ? ? ? ? D9 18 D9 05 ? ? ? ? D8 0D ? ? ? ? 8B 44 24 34 D8 44 24 38 D8 05").get_one();
|
||||
auto rectWidth3 = get_pattern<float*>("D8 25 ? ? ? ? 8B 44 24 34 D9 18", 2);
|
||||
|
||||
auto rectHeight1 = pattern("D8 05 ? ? ? ? D9 58 04 D9 44 24 3C D8 25").count(2);
|
||||
auto rectHeight2 = pattern("D9 05 ? ? ? ? D8 44 24 3C DE C1 D8 05").get_one();
|
||||
|
||||
// SetWrapx on the help boxes includes an unscaled -4.0f probably to work together with this padding,
|
||||
// so treat it as part of the same fix
|
||||
auto setJustifyOff_helpBox = get_pattern("59 E8 ? ? ? ? D9 EE", 1);
|
||||
|
||||
std::array<float**, 5> paddingXSizes = {
|
||||
rectWidth1.get<float*>(2),
|
||||
rectWidth1.get<float*>(0x18 + 2),
|
||||
rectWidth2.get<float*>(2),
|
||||
rectWidth2.get<float*>(0x1C + 2),
|
||||
rectWidth3
|
||||
};
|
||||
|
||||
std::array<float**, 6> paddingYSizes = {
|
||||
rectHeight1.get(0).get<float*>(2),
|
||||
rectHeight1.get(0).get<float*>(0xD + 2),
|
||||
rectHeight1.get(1).get<float*>(2),
|
||||
rectHeight1.get(1).get<float*>(0xD + 2),
|
||||
rectHeight2.get<float*>(2),
|
||||
rectHeight2.get<float*>(0xC + 2),
|
||||
};
|
||||
|
||||
std::array<float**, 1> wrapxWidth = {
|
||||
get_pattern<float*>("D8 25 ? ? ? ? D9 1C 24 DD D8", 2),
|
||||
};
|
||||
|
||||
HookEach_PaddingXSize(paddingXSizes, PatchFloat);
|
||||
HookEach_PaddingYSize(paddingYSizes, PatchFloat);
|
||||
InterceptCall(getTextRect, orgGetTextRect, GetTextRect_Recalculate<paddingXSizes.size(), paddingYSizes.size()>);
|
||||
|
||||
HookEach_WrapX(wrapxWidth, PatchFloat);
|
||||
InterceptCall(setJustifyOff_helpBox, orgSetJustifyOff, SetJustifyOff_Recalculate<wrapxWidth.size()>);
|
||||
}
|
||||
TXN_CATCH();
|
||||
|
||||
|
||||
// ============= Fix menu texts not scaling to resolution =============
|
||||
try
|
||||
{
|
||||
using namespace MenuManagerScalingFixes;
|
||||
|
||||
auto printStringMenuText = get_pattern("E8 ? ? ? ? 83 C4 0C DB 05 ? ? ? ? 50");
|
||||
InterceptCall(printStringMenuText, orgPrintString, PrintString_Scale);
|
||||
}
|
||||
TXN_CATCH();
|
||||
|
||||
FLAUtils::Init(moduleList);
|
||||
}
|
||||
|
||||
|
@ -2276,10 +2413,10 @@ void Patch_III_Common()
|
|||
|
||||
|
||||
// Fix dark car reflections in the Steam EXE
|
||||
// Based off Sergenaur's fix
|
||||
// Based off Sergeanur's fix
|
||||
try
|
||||
{
|
||||
// This will only pass on the Steam EXE, and if Sergenaur's standalone fix isn't present
|
||||
// This will only pass on the Steam EXE, and if Sergeanur's standalone fix isn't present
|
||||
auto reflection = pattern("A1 ? ? ? ? 85 C0 74 34").get_one();
|
||||
|
||||
// xor eax, eax \ nop
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
<ClInclude Include="..\SilentPatch\Maths.h" />
|
||||
<ClInclude Include="..\SilentPatch\ParseUtils.hpp" />
|
||||
<ClInclude Include="..\SilentPatch\Random.h" />
|
||||
<ClInclude Include="..\SilentPatch\RWGTA.h" />
|
||||
<ClInclude Include="..\SilentPatch\StdAfx.h" />
|
||||
<ClInclude Include="..\SilentPatch\StoredCar.h" />
|
||||
<ClInclude Include="..\SilentPatch\SVF.h" />
|
||||
|
|
|
@ -113,6 +113,9 @@
|
|||
<ClInclude Include="..\SilentPatch\Random.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\SilentPatch\RWGTA.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\SilentPatch\SilentPatch.rc">
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<SILENTPATCH_EXT>.asi</SILENTPATCH_EXT>
|
||||
<SILENTPATCH_FULL_NAME>SilentPatch for GTA III</SILENTPATCH_FULL_NAME>
|
||||
<SILENTPATCH_REVISION_ID>9</SILENTPATCH_REVISION_ID>
|
||||
<SILENTPATCH_BUILD_ID>0</SILENTPATCH_BUILD_ID>
|
||||
<SILENTPATCH_BUILD_ID>1</SILENTPATCH_BUILD_ID>
|
||||
<SILENTPATCH_COPYRIGHT>2013-2024</SILENTPATCH_COPYRIGHT>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup />
|
||||
|
|
|
@ -603,7 +603,7 @@ static hook::pattern MakeScriptPattern(bool isMission, std::string_view bytes)
|
|||
begin = uintptr_t(ScriptSpace);
|
||||
end = begin + ScriptFileSize;
|
||||
}
|
||||
return hook::make_range_pattern(begin, end, bytes).count_hint(100);
|
||||
return hook::make_range_pattern(begin, end, bytes);
|
||||
}
|
||||
|
||||
static void MountainCloudBoysFix()
|
||||
|
@ -631,7 +631,10 @@ static void SupplyLinesFix( bool isBeefyBaron )
|
|||
static void DrivingSchoolConesFix()
|
||||
{
|
||||
auto pattern = MakeScriptPattern(true, "04 00 02 20 03 04 00 D6 00 04 00 1A 00 04 2E 02 20 03 4D 00 01 60 75 FF FF BE 00 08 01 07 24 03 20 03 2E 80 08 00 02 20 03 04 01");
|
||||
if (pattern.size() == 1) // Only destroy as many cones as were created
|
||||
auto coneCoilConeCount = MakeScriptPattern(true, "1A 00 04 17 02 20 03");
|
||||
auto burnAndLapConeCount = MakeScriptPattern(true, "1A 00 04 23 02 20 03");
|
||||
// Only destroy as many cones as were created, and correct trafficcone_counter for "Cone Coil" and "Burn and Lap"
|
||||
if (pattern.size() == 1 && coneCoilConeCount.size() == 1 && burnAndLapConeCount.size() == 1)
|
||||
{
|
||||
const uint8_t gotoSkipAssignment[] = { 0x02, 0x00, 0x01, 0x8B, 0x75, 0xFF, 0xFF };
|
||||
memcpy(pattern.get(0).get<void>(0), gotoSkipAssignment, sizeof(gotoSkipAssignment));
|
||||
|
@ -646,6 +649,15 @@ static void DrivingSchoolConesFix()
|
|||
// Also set trafficcone_counter to 0 so the first destruction doesn't happen
|
||||
int32_t* trafficcone_counter = reinterpret_cast<int32_t*>(ScriptSpace+800);
|
||||
*trafficcone_counter = 0;
|
||||
|
||||
// Correct the final trafficcone_counter in Cone Coil
|
||||
// 23 -> 30
|
||||
*coneCoilConeCount.get(0).get<int8_t>(3) = 30;
|
||||
|
||||
|
||||
// Correct the final trafficcone_counter in Burn and Lap
|
||||
// 35 -> 42
|
||||
*burnAndLapConeCount.get(0).get<int8_t>(3) = 42;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1167,10 +1179,10 @@ void DrawScriptSpritesAndRectangles( uint8_t arg )
|
|||
bool ReadDoubleRearWheels(const wchar_t* pPath);
|
||||
bool __stdcall CheckDoubleRWheelsList( void* modelInfo, uint8_t* handlingData );
|
||||
|
||||
CVehicleModelInfo* (__thiscall *orgVehicleModelInfoCtor)(CVehicleModelInfo*);
|
||||
CVehicleModelInfo* __fastcall VehicleModelInfoCtor(CVehicleModelInfo* me)
|
||||
CVehicleModelInfo* (__thiscall *orgVehicleModelInfoInit)(CVehicleModelInfo*);
|
||||
CVehicleModelInfo* __fastcall VehicleModelInfoInit(CVehicleModelInfo* me)
|
||||
{
|
||||
orgVehicleModelInfoCtor(me);
|
||||
orgVehicleModelInfoInit(me);
|
||||
|
||||
// Hack to satisfy some null checks
|
||||
static uintptr_t DUMMY;
|
||||
|
@ -2629,16 +2641,23 @@ namespace NewResolutionSelectionDialog
|
|||
}
|
||||
}
|
||||
|
||||
static RwSubSystemInfo* (*orgRwEngineGetSubSystemInfo)(RwSubSystemInfo *subSystemInfo, RwInt32 subSystemIndex);
|
||||
static RwSubSystemInfo *RwEngineGetSubSystemInfo_GetFriendlyNames(RwSubSystemInfo *subSystemInfo, RwInt32 subSystemIndex)
|
||||
{
|
||||
static const auto friendlyNames = FriendlyMonitorNames::GetNamesForDevicePaths();
|
||||
// If we can't do any our work, fall back to the original game functions that may already by customized by other mods
|
||||
if (*ppRWD3D9 == nullptr)
|
||||
{
|
||||
return orgRwEngineGetSubSystemInfo(subSystemInfo, subSystemIndex);
|
||||
}
|
||||
|
||||
D3DADAPTER_IDENTIFIER9 identifier;
|
||||
if (FAILED((*ppRWD3D9)->GetAdapterIdentifier(subSystemIndex, 0, &identifier)))
|
||||
{
|
||||
return nullptr;
|
||||
return orgRwEngineGetSubSystemInfo(subSystemInfo, subSystemIndex);
|
||||
}
|
||||
|
||||
static const auto friendlyNames = FriendlyMonitorNames::GetNamesForDevicePaths();
|
||||
|
||||
// If we can't find the friendly name, either because it doesn't exist or we're on an ancient Windows, fall back to the device name
|
||||
auto it = friendlyNames.find(identifier.DeviceName);
|
||||
if (it != friendlyNames.end())
|
||||
|
@ -2654,8 +2673,15 @@ namespace NewResolutionSelectionDialog
|
|||
}
|
||||
|
||||
static size_t MenuManagerAdapterOffset = 0xDC;
|
||||
static RwInt32 (*orgRwEngineGetCurrentSubSystem)();
|
||||
static RwInt32 RwEngineGetCurrentSubSystem_FromSettings()
|
||||
{
|
||||
// If we can't do any our work, fall back to the original game functions that may already by customized by other mods
|
||||
if (*ppRWD3D9 == nullptr)
|
||||
{
|
||||
return orgRwEngineGetCurrentSubSystem();
|
||||
}
|
||||
|
||||
RwInt32 subSystem = *reinterpret_cast<RwInt32*>(static_cast<char*>(FrontEndMenuManager) + MenuManagerAdapterOffset);
|
||||
if (subSystem > 0)
|
||||
{
|
||||
|
@ -2705,7 +2731,7 @@ namespace NewResolutionSelectionDialog
|
|||
if (msg == WM_INITDIALOG)
|
||||
{
|
||||
const WrappedDialocFunc* data = reinterpret_cast<WrappedDialocFunc*>(lParam);
|
||||
SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(data->lpDialogFunc));
|
||||
SetWindowLongPtr(window, DWLP_USER, reinterpret_cast<LONG_PTR>(data->lpDialogFunc));
|
||||
|
||||
data->lpDialogFunc(window, msg, wParam, data->dwInitParam);
|
||||
|
||||
|
@ -2716,14 +2742,15 @@ namespace NewResolutionSelectionDialog
|
|||
// The game inits the selected resolution weirdly, and corrects it in the IDOK handler
|
||||
// so let's invoke it manually (bleh)
|
||||
data->lpDialogFunc(window, WM_COMMAND, IDOK, 0);
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HMODULE hGameModule = GetModuleHandle(nullptr);
|
||||
SendMessage(window, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(LoadIcon(hGameModule, MAKEINTRESOURCE(100))));
|
||||
CreateNewButtonTooltip(hGameModule, window);
|
||||
|
||||
// Return TRUE instead of FALSE on init, we want keyboard focus
|
||||
// Return TRUE instead of FALSE on init, as we removed a manual SetFocus from the init function
|
||||
// and we want to rely on Windows to give us focus.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -2743,7 +2770,7 @@ namespace NewResolutionSelectionDialog
|
|||
}
|
||||
}
|
||||
|
||||
DLGPROC origProc = reinterpret_cast<DLGPROC>(GetWindowLongPtr(window, GWLP_USERDATA));
|
||||
DLGPROC origProc = reinterpret_cast<DLGPROC>(GetWindowLongPtr(window, DWLP_USER));
|
||||
if (origProc != nullptr)
|
||||
{
|
||||
return origProc(window, msg, wParam, lParam);
|
||||
|
@ -2806,6 +2833,12 @@ namespace NewResolutionSelectionDialog
|
|||
return result;
|
||||
}
|
||||
static auto* const pDialogBoxParamA_New = &DialogBoxParamA_New;
|
||||
|
||||
static HWND WINAPI SetFocus_NOP(HWND)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
static auto* const pSetFocus_NOP = &SetFocus_NOP;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3052,9 +3085,7 @@ namespace MapScreenScalingFixes
|
|||
((CursorYSize_Recalculated<I> = ScaleY(*orgCursorYSize<I>)), ...);
|
||||
}
|
||||
|
||||
static void (*orgLimitToMap)(float* x, float* y);
|
||||
|
||||
template<std::size_t NumXSize, std::size_t NumYSize>
|
||||
static void (*orgLimitToMap_Scale)(float* x, float* y);
|
||||
static void LimitToMap_Scale(float* x, float* y)
|
||||
{
|
||||
// LimitToMap assumes it's given scaled coordinates, but then the caller assumes it returns unscaled coordinates.
|
||||
|
@ -3064,12 +3095,17 @@ namespace MapScreenScalingFixes
|
|||
|
||||
*x *= XScale;
|
||||
*y *= YScale;
|
||||
orgLimitToMap(x, y);
|
||||
orgLimitToMap_Scale(x, y);
|
||||
|
||||
*x /= XScale;
|
||||
*y /= YScale;
|
||||
}
|
||||
|
||||
// This is also a comfortable spot to scale the cursor dimensions
|
||||
static void (*orgLimitToMap_RecalculateSizes)(float* x, float* y);
|
||||
template<std::size_t NumXSize, std::size_t NumYSize>
|
||||
static void LimitToMap_RecalculateSizes(float* x, float* y)
|
||||
{
|
||||
orgLimitToMap_RecalculateSizes(x, y);
|
||||
RecalculateXSize(std::make_index_sequence<NumXSize>{});
|
||||
RecalculateYSize(std::make_index_sequence<NumYSize>{});
|
||||
}
|
||||
|
@ -3186,6 +3222,30 @@ namespace NitrousReverseRechargeFix
|
|||
}
|
||||
|
||||
|
||||
// ============= Fix Hydra's jet thrusters not displaying due to an uninitialized variable in RwMatrix =============
|
||||
// By B1ack_Wh1te
|
||||
namespace JetThrustersFix
|
||||
{
|
||||
// These are technically CMatrix, but for simplicity we use RwMatrix here
|
||||
template<std::size_t Index>
|
||||
static RwMatrix* (*orgMatrixMultiply)(RwMatrix* out, const RwMatrix* lhs, const RwMatrix* rhs);
|
||||
|
||||
template<std::size_t Index>
|
||||
static RwMatrix* MatrixMultiply_ZeroFlags(RwMatrix* out, const RwMatrix* lhs, const RwMatrix* rhs)
|
||||
{
|
||||
RwMatrix* result = orgMatrixMultiply<Index>(out, lhs, rhs);
|
||||
|
||||
// Technically, this should be the same as RwMatrixUpdate, but this variable is on the stack
|
||||
// and completely uninitialized, so zero it completely for consistent results.
|
||||
rwMatrixSetFlags(result, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
HOOK_EACH_INIT(MatrixMultiply, orgMatrixMultiply, MatrixMultiply_ZeroFlags);
|
||||
}
|
||||
|
||||
|
||||
// ============= LS-RP Mode stuff =============
|
||||
namespace LSRPMode
|
||||
{
|
||||
|
@ -3418,25 +3478,25 @@ void InstallMemValidator()
|
|||
using namespace Memory;
|
||||
|
||||
// TEST: Validate memory
|
||||
InjectHook( 0x824257, malloc_validator, HookType::Jump );
|
||||
InjectHook( 0x824269, realloc_validator, HookType::Jump );
|
||||
InjectHook( 0x824416, calloc_validator, HookType::Jump );
|
||||
InjectHook( 0x82413F, free_validator, HookType::Jump );
|
||||
InjectHook( 0x828C4A, _msize_validator, HookType::Jump );
|
||||
InjectHook( AddressByRegion_10(0x824257), malloc_validator, HookType::Jump );
|
||||
InjectHook( AddressByRegion_10(0x824269), realloc_validator, HookType::Jump );
|
||||
InjectHook( AddressByRegion_10(0x824416), calloc_validator, HookType::Jump );
|
||||
InjectHook( AddressByRegion_10(0x82413F), free_validator, HookType::Jump );
|
||||
InjectHook( AddressByRegion_10(0x828C4A), _msize_validator, HookType::Jump );
|
||||
|
||||
InjectHook( 0x82119A, _new, HookType::Jump );
|
||||
InjectHook( 0x8214BD, _delete, HookType::Jump );
|
||||
InjectHook( AddressByRegion_10(0x82119A), _new, HookType::Jump );
|
||||
InjectHook( AddressByRegion_10(0x8214BD), _delete, HookType::Jump );
|
||||
|
||||
InjectHook( 0x72F420, &CDebugMemoryMgr::Malloc, HookType::Jump );
|
||||
InjectHook( 0x72F430, &CDebugMemoryMgr::Free, HookType::Jump );
|
||||
InjectHook( 0x72F440, &CDebugMemoryMgr::Realloc, HookType::Jump );
|
||||
InjectHook( 0x72F460, &CDebugMemoryMgr::Calloc, HookType::Jump );
|
||||
InjectHook( 0x72F4C0, &CDebugMemoryMgr::MallocAlign, HookType::Jump );
|
||||
InjectHook( 0x72F4F0, &CDebugMemoryMgr::AlignedFree, HookType::Jump );
|
||||
InjectHook( AddressByRegion_10(0x72F420), &CDebugMemoryMgr::Malloc, HookType::Jump );
|
||||
InjectHook( AddressByRegion_10(0x72F430), &CDebugMemoryMgr::Free, HookType::Jump );
|
||||
InjectHook( AddressByRegion_10(0x72F440), &CDebugMemoryMgr::Realloc, HookType::Jump );
|
||||
InjectHook( AddressByRegion_10(0x72F460), &CDebugMemoryMgr::Calloc, HookType::Jump );
|
||||
InjectHook( AddressByRegion_10(0x72F4C0), &CDebugMemoryMgr::MallocAlign, HookType::Jump );
|
||||
InjectHook( AddressByRegion_10(0x72F4F0), &CDebugMemoryMgr::AlignedFree, HookType::Jump );
|
||||
|
||||
|
||||
PutStaticValidator( 0xAAE950, 0xB4C310 ); // CStore
|
||||
PutStaticValidator( 0xA9AE00, 0xA9AE58 ); // fx_c
|
||||
PutStaticValidator( AddressByRegion_10(0xAAE950), AddressByRegion_10(0xB4C310) ); // CStore
|
||||
PutStaticValidator( AddressByRegion_10(0xA9AE00), AddressByRegion_10(0xA9AE58) ); // fx_c
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -4160,6 +4220,16 @@ BOOL InjectDelayedPatches_10()
|
|||
|
||||
const bool bHasDebugMenu = DebugMenuLoad();
|
||||
|
||||
auto PatchFloat = [](float** address, const float*& org, float& replaced)
|
||||
{
|
||||
org = *address;
|
||||
Patch(address, &replaced);
|
||||
};
|
||||
|
||||
const std::initializer_list<uint8_t> fadd = { 0xD8, 0x05 };
|
||||
const std::initializer_list<uint8_t> fsub = { 0xD8, 0x25 };
|
||||
const std::initializer_list<uint8_t> fld = { 0xD9, 0x05 };
|
||||
|
||||
#ifdef _DEBUG
|
||||
if ( bHasDebugMenu )
|
||||
{
|
||||
|
@ -4622,6 +4692,63 @@ BOOL InjectDelayedPatches_10()
|
|||
}
|
||||
|
||||
|
||||
// Fix Map screen boundaries and the cursor not scaling to resolution
|
||||
// Debugged by Wesser
|
||||
// Moved here for compatibility with wshps.asi
|
||||
{
|
||||
using namespace MapScreenScalingFixes;
|
||||
|
||||
// Even though those two patch the same function, treating them as separate patches makes retaining compatibility
|
||||
// with the widescreen fix easy.
|
||||
if (MemEquals(0x588251, fld) && MemEquals(0x588265, fadd) && MemEquals(0x5882A8, fld) && MemEquals(0x5882C6, fadd))
|
||||
{
|
||||
std::array<float**, 2> cursorXSizes = { (float**)(0x588251 + 2), (float**)(0x588265 + 2) };
|
||||
std::array<float**, 2> cursorYSizes = { (float**)(0x5882A8 + 2), (float**)(0x5882C6 + 2) };
|
||||
|
||||
HookEach_CursorXSize(cursorXSizes, PatchFloat);
|
||||
HookEach_CursorYSize(cursorYSizes, PatchFloat);
|
||||
InterceptCall(0x58822D, orgLimitToMap_RecalculateSizes, LimitToMap_RecalculateSizes<cursorXSizes.size(), cursorYSizes.size()>);
|
||||
}
|
||||
|
||||
// Only patch this function if wshps.asi hasn't changed the way it's being called
|
||||
// The expected code:
|
||||
// lea edx, [esp+70h+a1.y]
|
||||
// push edx
|
||||
// lea eax, [esp+74h+a1]
|
||||
// push eax
|
||||
if (MemEquals(0x588223, {0x8D, 0x54, 0x24, 0x4C, 0x52, 0x8D, 0x44, 0x24, 0x4C, 0x50 }))
|
||||
{
|
||||
InterceptCall(0x58822D, orgLimitToMap_Scale, LimitToMap_Scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Fix text background padding not scaling to resolution
|
||||
// Debugged by Wesser
|
||||
// Moved here for compatibility with wshps.asi
|
||||
{
|
||||
using namespace TextRectPaddingScalingFixes;
|
||||
|
||||
// Verify that all fadd and fsub instructions are intact
|
||||
// Patterns would do it for us for free, but 1.0 does not use them...
|
||||
if (MemEquals(0x71A653, fadd) && MemEquals(0x71A66B, fadd) && MemEquals(0x71A69D, fsub) && MemEquals(0x71A6AB, fadd) &&
|
||||
MemEquals(0x71A6BF, fsub) && MemEquals(0x71A6EC, fadd))
|
||||
{
|
||||
std::array<float**, 4> paddingXSizes = {
|
||||
(float**)(0x71A653 + 2), (float**)(0x71A66B + 2),
|
||||
(float**)(0x71A69D + 2), (float**)(0x71A6AB + 2),
|
||||
};
|
||||
std::array<float**, 2> paddingYSizes = {
|
||||
(float**)(0x71A6BF + 2), (float**)(0x71A6EC + 2),
|
||||
};
|
||||
|
||||
HookEach_PaddingXSize(paddingXSizes, PatchFloat);
|
||||
HookEach_PaddingYSize(paddingYSizes, PatchFloat);
|
||||
InterceptCall(0x71A631, orgProcessCurrentString, ProcessCurrentString_Scale<paddingXSizes.size(), paddingYSizes.size()>);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
if ( const int QPCDays = GetPrivateProfileIntW(L"Debug", L"AddDaysToQPC", 0, wcModulePath); QPCDays != 0 )
|
||||
{
|
||||
|
@ -4643,11 +4770,16 @@ BOOL InjectDelayedPatches_10()
|
|||
BOOL InjectDelayedPatches_11()
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
MessageBoxW( nullptr, L"You're using a 1.01 executable which is no longer supported by SilentPatch!\n\n"
|
||||
const int messageResult = MessageBoxW( nullptr, L"You're using a 1.01 executable which is no longer supported by SilentPatch!\n\n"
|
||||
L"Since this EXE is used by only a few people, I recommend downgrading back to 1.0 - you gain full compatibility with mods "
|
||||
L"and any relevant fixes 1.01 brings are backported to 1.0 by SilentPatch anyway.\n\n"
|
||||
L"To downgrade to 1.0, find a 1.0 EXE online and replace your current game executable with it.",
|
||||
L"To downgrade to 1.0, find a 1.0 EXE online and replace your current game executable with it. Do you want to continue?\n\n"
|
||||
L"Pressing No will close the game. Press Yes to proceed to the game anyway.",
|
||||
L"SilentPatch", MB_OK | MB_ICONWARNING );
|
||||
if (messageResult == IDNO)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( !IsAlreadyRunning() )
|
||||
|
@ -4815,11 +4947,10 @@ BOOL InjectDelayedPatches_Steam()
|
|||
{
|
||||
const int messageResult = MessageBoxW( nullptr, L"You're using a 3.0 executable which is no longer supported by SilentPatch!\n\n"
|
||||
L"Since this is an old Steam EXE, by now you should have either downgraded to 1.0 or started using an up to date version. It is recommended to "
|
||||
L"verify your game's cache on Steam and then downgrade it to 1.0. Do you want to download San Andreas Downgrader now?\n\n"
|
||||
L"Pressing Yes will close the game and open your web browser. Press No to proceed to the game anyway.", L"SilentPatch", MB_YESNO | MB_ICONWARNING );
|
||||
if ( messageResult == IDYES )
|
||||
L"verify your game's cache on Steam and then downgrade it to 1.0. Do you want to continue?\n\n"
|
||||
L"Pressing No will close the game. Press Yes to proceed to the game anyway.", L"SilentPatch", MB_YESNO | MB_ICONWARNING );
|
||||
if (messageResult == IDNO)
|
||||
{
|
||||
ShellExecuteW( nullptr, L"open", L"http://gtaforums.com/topic/753764-/", nullptr, nullptr, SW_SHOWNORMAL );
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -5002,6 +5133,12 @@ BOOL InjectDelayedPatches_NewBinaries()
|
|||
|
||||
const bool bHasDebugMenu = DebugMenuLoad();
|
||||
|
||||
auto PatchDouble = [](double** address, const double*& org, double& replaced)
|
||||
{
|
||||
org = *address;
|
||||
Patch(address, &replaced);
|
||||
};
|
||||
|
||||
// Race condition in CdStream fixed
|
||||
// Not taking effect with modloader
|
||||
//if ( !ModCompat::ModloaderCdStreamRaceConditionAware( modloaderModule ) )
|
||||
|
@ -5098,6 +5235,61 @@ BOOL InjectDelayedPatches_NewBinaries()
|
|||
TXN_CATCH();
|
||||
|
||||
|
||||
// Fix Map screen boundaries and the cursor not scaling to resolution
|
||||
// Debugged by Wesser
|
||||
// Moved here for compatibility with wshps.asi
|
||||
{
|
||||
using namespace MapScreenScalingFixes;
|
||||
|
||||
// These two are entirely separate fixes
|
||||
try
|
||||
{
|
||||
// Updated the pattern to also ensure this function's arguments are not changed by other mods
|
||||
auto limitToMap = get_pattern("8D 45 F0 50 8B CA 51 E8 ? ? ? ? DB 05 ? ? ? ? 83 C4 1C", 7);
|
||||
InterceptCall(limitToMap, orgLimitToMap_Scale, LimitToMap_Scale);
|
||||
}
|
||||
TXN_CATCH();
|
||||
|
||||
// Cursor X/Y scaling need to be done differently than in 1.0, as the game has one fld1 for width and one fld1 for height
|
||||
try
|
||||
{
|
||||
auto scaleX = pattern("D9 E8 DC E9 D9 C9 D9 5D 94").get_one();
|
||||
auto scaleY = pattern("D9 E8 DC E9 D9 C9 D9 5D B0").get_one();
|
||||
|
||||
Nop(scaleX.get<void>(), 1);
|
||||
InjectHook(scaleX.get<void>(1), ScaleX_NewBinaries, HookType::Call);
|
||||
|
||||
Nop(scaleY.get<void>(), 1);
|
||||
InjectHook(scaleY.get<void>(1), ScaleY_NewBinaries, HookType::Call);
|
||||
}
|
||||
TXN_CATCH();
|
||||
}
|
||||
|
||||
|
||||
// Fix text background padding not scaling to resolution
|
||||
// Debugged by Wesser
|
||||
// Moved here for compatibility with wshps.asi
|
||||
try
|
||||
{
|
||||
using namespace TextRectPaddingScalingFixes;
|
||||
|
||||
auto processCurrentString = get_pattern("E8 ? ? ? ? DD 05 ? ? ? ? 8B 4D 08");
|
||||
|
||||
// In new binaries, 4.0f is shared for width and height.
|
||||
// Make height determine the scale, so it works nicer in widescreen.
|
||||
auto paddingSize = pattern("DD 05 ? ? ? ? DC E9 D9 C9 D9 19").count(2);
|
||||
std::array<double**, 3> paddingYSizes = {
|
||||
get_pattern<double*>("D8 CA DD 05 ? ? ? ? DC C1", 2 + 2),
|
||||
paddingSize.get(0).get<double*>(2),
|
||||
paddingSize.get(1).get<double*>(2),
|
||||
};
|
||||
|
||||
HookEach_PaddingYSize_Double(paddingYSizes, PatchDouble);
|
||||
InterceptCall(processCurrentString, orgProcessCurrentString, ProcessCurrentString_Scale_NewBinaries<paddingYSizes.size()>);
|
||||
}
|
||||
TXN_CATCH();
|
||||
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
|
@ -5579,9 +5771,7 @@ void Patch_SA_10(HINSTANCE hInstance)
|
|||
|
||||
|
||||
// Properly initialize all CVehicleModelInfo fields
|
||||
ReadCall( 0x4C75E4, orgVehicleModelInfoCtor );
|
||||
InjectHook( 0x4C75E4, VehicleModelInfoCtor );
|
||||
|
||||
InterceptCall(0x4C7633, orgVehicleModelInfoInit, VehicleModelInfoInit);
|
||||
|
||||
// Animated Phoenix hood scoop
|
||||
{
|
||||
|
@ -6140,15 +6330,16 @@ void Patch_SA_10(HINSTANCE hInstance)
|
|||
{
|
||||
using namespace NewResolutionSelectionDialog;
|
||||
|
||||
ppRWD3D9 = *(IDirect3D9***)(0x7F6312 + 1);
|
||||
ppRWD3D9 = *AddressByRegion_10<IDirect3D9***>(0x7F6312 + 1);
|
||||
FrontEndMenuManager = *(void**)(0x4054DB + 1);
|
||||
|
||||
orgGetDocumentsPath = (char*(*)())0x744FB0;
|
||||
orgGetDocumentsPath = AddressByRegion_10<char*(*)()>(0x744FB0);
|
||||
|
||||
Patch(0x0746241 + 2, &pDialogBoxParamA_New);
|
||||
Patch(AddressByRegion_10(0x746241 + 2), &pDialogBoxParamA_New);
|
||||
Patch(AddressByRegion_10(0x745DB3 + 2), &pSetFocus_NOP);
|
||||
|
||||
InjectHook(0x7461D8, RwEngineGetSubSystemInfo_GetFriendlyNames);
|
||||
InjectHook(0x7461ED, RwEngineGetCurrentSubSystem_FromSettings);
|
||||
InterceptCall(AddressByRegion_10(0x7461D8), orgRwEngineGetSubSystemInfo, RwEngineGetSubSystemInfo_GetFriendlyNames);
|
||||
InterceptCall(AddressByRegion_10(0x7461ED), orgRwEngineGetCurrentSubSystem, RwEngineGetCurrentSubSystem_FromSettings);
|
||||
}
|
||||
|
||||
|
||||
|
@ -6229,14 +6420,14 @@ void Patch_SA_10(HINSTANCE hInstance)
|
|||
};
|
||||
|
||||
// Triangular gamepad crosshairs - their size needs to scale to screen *height*
|
||||
std::array<float**, 11> triangleSizes = {
|
||||
std::array<float**, 13> triangleSizes = {
|
||||
// Co-op offscreen crosshair
|
||||
(float**)(0x7436F1 + 2), (float**)(0x7436FF + 2), (float**)(0x74370D + 2), (float**)(0x74374B + 2),
|
||||
(float**)(0x743797 + 2), (float**)(0x7437D0 + 2), (float**)(0x7437FB + 2), (float**)(0x743819 + 2),
|
||||
(float**)(0x74386F + 2),
|
||||
|
||||
// Regular crosshair
|
||||
(float**)(0x743259 + 2), (float**)(0x743266 + 2),
|
||||
(float**)(0x743212 + 2), (float**)(0x74321E + 2), (float**)(0x743259 + 2), (float**)(0x743266 + 2),
|
||||
};
|
||||
|
||||
HookEach_RenderOneXLUSprite_Rotate_Aspect(renderRotateAspect, InterceptCall);
|
||||
|
@ -6246,39 +6437,6 @@ void Patch_SA_10(HINSTANCE hInstance)
|
|||
}
|
||||
|
||||
|
||||
// Fix Map screen boundaries and the cursor not scaling to resolution
|
||||
// Debugged by Wesser
|
||||
{
|
||||
using namespace MapScreenScalingFixes;
|
||||
|
||||
std::array<float**, 2> cursorXSizes = { (float**)(0x588251 + 2), (float**)(0x588265 + 2) };
|
||||
std::array<float**, 2> cursorYSizes = { (float**)(0x5882A8 + 2), (float**)(0x5882C6 + 2) };
|
||||
|
||||
HookEach_CursorXSize(cursorXSizes, PatchFloat);
|
||||
HookEach_CursorYSize(cursorYSizes, PatchFloat);
|
||||
InterceptCall(0x58822D, orgLimitToMap, LimitToMap_Scale<cursorXSizes.size(), cursorYSizes.size()>);
|
||||
}
|
||||
|
||||
|
||||
// Fix text background padding not scaling to resolution
|
||||
// Debugged by Wesser
|
||||
{
|
||||
using namespace TextRectPaddingScalingFixes;
|
||||
|
||||
std::array<float**, 4> paddingXSizes = {
|
||||
(float**)(0x71A653 + 2), (float**)(0x71A66B + 2),
|
||||
(float**)(0x71A69D + 2), (float**)(0x71A6AB + 2),
|
||||
};
|
||||
std::array<float**, 2> paddingYSizes = {
|
||||
(float**)(0x71A6BF + 2), (float**)(0x71A6EC + 2),
|
||||
};
|
||||
|
||||
HookEach_PaddingXSize(paddingXSizes, PatchFloat);
|
||||
HookEach_PaddingYSize(paddingYSizes, PatchFloat);
|
||||
InterceptCall(0x71A631, orgProcessCurrentString, ProcessCurrentString_Scale<paddingXSizes.size(), paddingYSizes.size()>);
|
||||
}
|
||||
|
||||
|
||||
// Fix nitrous recharging faster when reversing the car
|
||||
// By Wesser
|
||||
{
|
||||
|
@ -6289,6 +6447,16 @@ void Patch_SA_10(HINSTANCE hInstance)
|
|||
}
|
||||
|
||||
|
||||
// Fix Hydra's jet thrusters not displaying due to an uninitialized variable in RwMatrix
|
||||
// By B1ack_Wh1te
|
||||
{
|
||||
using namespace JetThrustersFix;
|
||||
|
||||
std::array<uintptr_t, 4> matrixMult = { 0x6CA09F, 0x6CA122, 0x6CA1B2, 0x6CA242 };
|
||||
HookEach_MatrixMultiply(matrixMult, InterceptCall);
|
||||
}
|
||||
|
||||
|
||||
#if FULL_PRECISION_D3D
|
||||
// Test - full precision D3D device
|
||||
Patch<uint8_t>( 0x7F672B+1, *(uint8_t*)(0x7F672B+1) | D3DCREATE_FPU_PRESERVE );
|
||||
|
@ -8308,6 +8476,7 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance)
|
|||
return get_pattern("53 FF 15 ? ? ? ? 85 C0", 1 + 2);
|
||||
}
|
||||
}();
|
||||
auto setFocus = get_pattern("53 FF 15 ? ? ? ? 5F", 1 + 2);
|
||||
|
||||
auto rRwEngineGetSubSystemInfo = get_pattern("E8 ? ? ? ? 46 83 C4 08 83 C7 50");
|
||||
auto rwEngineGetCurrentSubSystem = get_pattern("7C EA E8 ? ? ? ? A3", 2);
|
||||
|
@ -8319,9 +8488,10 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance)
|
|||
orgGetDocumentsPath = static_cast<char*(*)()>(get_pattern( "8D 45 FC 50 68 19 00 02 00", -6 ));
|
||||
|
||||
Patch(dialogBoxParam, &pDialogBoxParamA_New);
|
||||
Patch(setFocus, &pSetFocus_NOP);
|
||||
|
||||
InjectHook(rRwEngineGetSubSystemInfo, RwEngineGetSubSystemInfo_GetFriendlyNames);
|
||||
InjectHook(rwEngineGetCurrentSubSystem, RwEngineGetCurrentSubSystem_FromSettings);
|
||||
InterceptCall(rRwEngineGetSubSystemInfo, orgRwEngineGetSubSystemInfo, RwEngineGetSubSystemInfo_GetFriendlyNames);
|
||||
InterceptCall(rwEngineGetCurrentSubSystem, orgRwEngineGetCurrentSubSystem, RwEngineGetCurrentSubSystem_FromSettings);
|
||||
}
|
||||
TXN_CATCH();
|
||||
|
||||
|
@ -8432,6 +8602,7 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance)
|
|||
|
||||
// Triangular gamepad crosshairs - their size needs to scale to screen *height*
|
||||
auto regularCrosshair = pattern("D8 0D ? ? ? ? D9 5D F4 D9 46 08 DC 0D ? ? ? ? D8 45 F4").get_one();
|
||||
auto defaultCrosshairSize = pattern("DD 05 ? ? ? ? D8 C9 D9 5D F4 DC 0D ? ? ? ? D9 5D E8").get_one();
|
||||
std::array<float**, 3> triangleSizes = {
|
||||
// Co-op offscreen crosshair
|
||||
get_pattern<float*>("D9 5D CC D9 05 ? ? ? ? D9 C0 D9 45 FC", 3 + 2),
|
||||
|
@ -8440,8 +8611,10 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance)
|
|||
// Regular crosshair (float)
|
||||
regularCrosshair.get<float*>(2),
|
||||
};
|
||||
std::array<double**, 1> triangleSizesDouble = {
|
||||
std::array<double**, 3> triangleSizesDouble = {
|
||||
regularCrosshair.get<double*>(0xC + 2),
|
||||
defaultCrosshairSize.get<double*>(2),
|
||||
defaultCrosshairSize.get<double*>(0xB + 2),
|
||||
};
|
||||
|
||||
HookEach_RenderOneXLUSprite_Rotate_Aspect(renderRotateAspect, InterceptCall);
|
||||
|
@ -8453,52 +8626,6 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance)
|
|||
TXN_CATCH();
|
||||
|
||||
|
||||
// Fix Map screen boundaries and the cursor not scaling to resolution
|
||||
// Debugged by Wesser
|
||||
try
|
||||
{
|
||||
using namespace MapScreenScalingFixes;
|
||||
|
||||
auto limitToMap = get_pattern("E8 ? ? ? ? DB 05 ? ? ? ? 83 C4 1C");
|
||||
|
||||
// Cursor X/Y scaling need to be done differently than in 1.0, as the game has one fld1 for width and one fld1 for height
|
||||
auto scaleX = pattern("D9 E8 DC E9 D9 C9 D9 5D 94").get_one();
|
||||
auto scaleY = pattern("D9 E8 DC E9 D9 C9 D9 5D B0").get_one();
|
||||
|
||||
InterceptCall(limitToMap, orgLimitToMap, LimitToMap_Scale<0, 0>);
|
||||
|
||||
Nop(scaleX.get<void>(), 1);
|
||||
InjectHook(scaleX.get<void>(1), ScaleX_NewBinaries, HookType::Call);
|
||||
|
||||
Nop(scaleY.get<void>(), 1);
|
||||
InjectHook(scaleY.get<void>(1), ScaleY_NewBinaries, HookType::Call);
|
||||
}
|
||||
TXN_CATCH();
|
||||
|
||||
|
||||
// Fix text background padding not scaling to resolution
|
||||
// Debugged by Wesser
|
||||
try
|
||||
{
|
||||
using namespace TextRectPaddingScalingFixes;
|
||||
|
||||
auto processCurrentString = get_pattern("E8 ? ? ? ? DD 05 ? ? ? ? 8B 4D 08");
|
||||
|
||||
// In new binaries, 4.0f is shared for width and height.
|
||||
// Make height determine the scale, so it works nicer in widescreen.
|
||||
auto paddingSize = pattern("DD 05 ? ? ? ? DC E9 D9 C9 D9 19").count(2);
|
||||
std::array<double**, 3> paddingYSizes = {
|
||||
get_pattern<double*>("D8 CA DD 05 ? ? ? ? DC C1", 2 + 2),
|
||||
paddingSize.get(0).get<double*>(2),
|
||||
paddingSize.get(1).get<double*>(2),
|
||||
};
|
||||
|
||||
HookEach_PaddingYSize_Double(paddingYSizes, PatchDouble);
|
||||
InterceptCall(processCurrentString, orgProcessCurrentString, ProcessCurrentString_Scale_NewBinaries<paddingYSizes.size()>);
|
||||
}
|
||||
TXN_CATCH();
|
||||
|
||||
|
||||
// Fix nitrous recharging faster when reversing the car
|
||||
// By Wesser
|
||||
try
|
||||
|
@ -8510,6 +8637,25 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance)
|
|||
InjectHook(getGasPedal.get<void>(1), &NitrousControl_DontRechargeWhenReversing_NewBinaries, HookType::Call);
|
||||
}
|
||||
TXN_CATCH();
|
||||
|
||||
|
||||
// Fix Hydra's jet thrusters not displaying due to an uninitialized variable in RwMatrix
|
||||
// By B1ack_Wh1te
|
||||
try
|
||||
{
|
||||
using namespace JetThrustersFix;
|
||||
|
||||
auto thrust = pattern("D9 5D DC E8 ? ? ? ? 83 C4 0C").count(4);
|
||||
|
||||
std::array<void*, 4> matrixMult = {
|
||||
thrust.get(0).get<void>(3),
|
||||
thrust.get(1).get<void>(3),
|
||||
thrust.get(2).get<void>(3),
|
||||
thrust.get(3).get<void>(3),
|
||||
};
|
||||
HookEach_MatrixMultiply(matrixMult, InterceptCall);
|
||||
}
|
||||
TXN_CATCH();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -582,66 +582,56 @@ void CAutomobile::AfterPreRender()
|
|||
}
|
||||
}
|
||||
|
||||
void CAutomobile::HideDestroyedWheels_SilentPatch(void (CAutomobile::*spawnFlyingComponentCB)(int, unsigned int), int nodeID, unsigned int modelID)
|
||||
void CAutomobile::HideDestroyedWheels_SilentPatch(void (CAutomobile::*spawnFlyingComponentCB)(int, unsigned int), int, unsigned int modelID)
|
||||
{
|
||||
auto hideWheel = [this](int nodeID)
|
||||
auto trySpawnAndHideWheel = [this, spawnFlyingComponentCB, modelID](int nodeID)
|
||||
{
|
||||
bool bHasWheel = false;
|
||||
|
||||
RwFrame* wheelNode = m_pCarNode[nodeID];
|
||||
if (wheelNode != nullptr)
|
||||
{
|
||||
RwFrameForAllObjects(wheelNode, [&bHasWheel](RwObject* object)
|
||||
bool bWheelVisible = false;
|
||||
RwFrameForAllObjects(wheelNode, [&bWheelVisible](RwObject* object) -> RwObject*
|
||||
{
|
||||
if ((rwObjectGetFlags(object) & rpATOMICRENDER) != 0)
|
||||
{
|
||||
rwObjectSetFlags(object, 0);
|
||||
bHasWheel = true;
|
||||
bWheelVisible = true;
|
||||
return nullptr;
|
||||
}
|
||||
return object;
|
||||
});
|
||||
|
||||
if (bWheelVisible)
|
||||
{
|
||||
std::invoke(spawnFlyingComponentCB, this, nodeID, modelID);
|
||||
RwFrameForAllObjects(wheelNode, [](RwObject* object)
|
||||
{
|
||||
rwObjectSetFlags(object, 0);
|
||||
return object;
|
||||
});
|
||||
}
|
||||
}
|
||||
return bHasWheel;
|
||||
};
|
||||
|
||||
|
||||
if (m_DamageManager.GetWheelStatus(0) == 2)
|
||||
{
|
||||
if (hideWheel(5))
|
||||
{
|
||||
std::invoke(spawnFlyingComponentCB, this, 5, modelID);
|
||||
}
|
||||
trySpawnAndHideWheel(5);
|
||||
}
|
||||
if (m_DamageManager.GetWheelStatus(2) == 2)
|
||||
{
|
||||
if (hideWheel(2))
|
||||
{
|
||||
std::invoke(spawnFlyingComponentCB, this, 2, modelID);
|
||||
}
|
||||
trySpawnAndHideWheel(2);
|
||||
}
|
||||
|
||||
// For rear wheels, also hide and spawn the middle wheel (if it exists)
|
||||
if (m_DamageManager.GetWheelStatus(1) == 2)
|
||||
{
|
||||
if (hideWheel(6))
|
||||
{
|
||||
std::invoke(spawnFlyingComponentCB, this, 6, modelID);
|
||||
}
|
||||
if (hideWheel(7))
|
||||
{
|
||||
std::invoke(spawnFlyingComponentCB, this, 7, modelID);
|
||||
}
|
||||
trySpawnAndHideWheel(6);
|
||||
trySpawnAndHideWheel(7);
|
||||
}
|
||||
if (m_DamageManager.GetWheelStatus(3) == 2)
|
||||
{
|
||||
if (hideWheel(3))
|
||||
{
|
||||
std::invoke(spawnFlyingComponentCB, this, 3, modelID);
|
||||
}
|
||||
if (hideWheel(4))
|
||||
{
|
||||
std::invoke(spawnFlyingComponentCB, this, 4, modelID);
|
||||
}
|
||||
trySpawnAndHideWheel(3);
|
||||
trySpawnAndHideWheel(4);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<SILENTPATCH_EXT>.asi</SILENTPATCH_EXT>
|
||||
<SILENTPATCH_FULL_NAME>SilentPatch for San Andreas</SILENTPATCH_FULL_NAME>
|
||||
<SILENTPATCH_REVISION_ID>33</SILENTPATCH_REVISION_ID>
|
||||
<SILENTPATCH_BUILD_ID>0</SILENTPATCH_BUILD_ID>
|
||||
<SILENTPATCH_BUILD_ID>1</SILENTPATCH_BUILD_ID>
|
||||
<SILENTPATCH_COPYRIGHT>2014-2024</SILENTPATCH_COPYRIGHT>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup />
|
||||
|
|
|
@ -211,32 +211,9 @@ namespace PrintStringShadows
|
|||
namespace RadardiscFixes
|
||||
{
|
||||
static const float RADARDISC_SHRINK = 2.0f; // We are shrinking the radardisc by that
|
||||
|
||||
template<std::size_t Index>
|
||||
static const float* orgRadarXPos;
|
||||
|
||||
template<std::size_t Index>
|
||||
static float RadarXPos_Recalculated;
|
||||
|
||||
template<std::size_t... I>
|
||||
static void RecalculateXPositions(std::index_sequence<I...>)
|
||||
{
|
||||
const float multiplier = GetWidthMult() * RsGlobal->MaximumWidth;
|
||||
((RadarXPos_Recalculated<I> = *orgRadarXPos<I> * multiplier), ...);
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static const float* orgRadarYPos;
|
||||
|
||||
template<std::size_t Index>
|
||||
static float RadarYPos_Recalculated;
|
||||
|
||||
template<std::size_t... I>
|
||||
static void RecalculateYPositions(std::index_sequence<I...>)
|
||||
{
|
||||
const float multiplier = GetHeightMult() * RsGlobal->MaximumHeight;
|
||||
((RadarYPos_Recalculated<I> = *orgRadarYPos<I> * multiplier), ...);
|
||||
}
|
||||
static float orgRadarXPosVal;
|
||||
static float* orgRadarXPosPtr;
|
||||
|
||||
template<std::size_t Index>
|
||||
static const float* orgRadarXPos_RadardiscShrink;
|
||||
|
@ -265,18 +242,15 @@ namespace RadardiscFixes
|
|||
}
|
||||
|
||||
static void (*orgDrawMap)();
|
||||
template<std::size_t NumXPos, std::size_t NumYPos, std::size_t NumXPosRadardisc, std::size_t NumYPosRadardisc>
|
||||
template<std::size_t NumXPosRadardisc, std::size_t NumYPosRadardisc>
|
||||
static void DrawMap_RecalculatePositions()
|
||||
{
|
||||
RecalculateXPositions(std::make_index_sequence<NumXPos>{});
|
||||
RecalculateYPositions(std::make_index_sequence<NumYPos>{});
|
||||
*orgRadarXPosPtr = orgRadarXPosVal * GetWidthMult() * RsGlobal->MaximumWidth;
|
||||
RecalculateXPositions_RadardiscShrink(std::make_index_sequence<NumXPosRadardisc>{});
|
||||
RecalculateYPositions_RadardiscShrink(std::make_index_sequence<NumYPosRadardisc>{});
|
||||
orgDrawMap();
|
||||
}
|
||||
|
||||
HOOK_EACH_INIT(CalculateRadarXPos, orgRadarXPos, RadarXPos_Recalculated);
|
||||
HOOK_EACH_INIT(CalculateRadarYPos, orgRadarYPos, RadarYPos_Recalculated);
|
||||
HOOK_EACH_INIT(CalculateRadarXPos_RadardiscShrink, orgRadarXPos_RadardiscShrink, RadarXPos_Recalculated_RadardiscShrink);
|
||||
HOOK_EACH_INIT(CalculateRadarYPos_RadardiscShrink, orgRadarYPos_RadardiscShrink, RadarYPos_Recalculated_RadardiscShrink);
|
||||
|
||||
|
@ -579,6 +553,117 @@ namespace MinimalHUD
|
|||
}
|
||||
|
||||
|
||||
// ============= Fix text background padding not scaling to resolution =============
|
||||
namespace TextRectPaddingScalingFixes
|
||||
{
|
||||
template<std::size_t Index>
|
||||
static const float* orgPaddingXSize;
|
||||
|
||||
template<std::size_t Index>
|
||||
static float PaddingXSize_Recalculated;
|
||||
|
||||
template<std::size_t... I>
|
||||
static void RecalculateXSize(std::index_sequence<I...>)
|
||||
{
|
||||
const float multiplier = GetWidthMult() * RsGlobal->MaximumWidth;
|
||||
((PaddingXSize_Recalculated<I> = *orgPaddingXSize<I> * multiplier), ...);
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static const float* orgPaddingYSize;
|
||||
|
||||
template<std::size_t Index>
|
||||
static float PaddingYSize_Recalculated;
|
||||
|
||||
template<std::size_t... I>
|
||||
static void RecalculateYSize(std::index_sequence<I...>)
|
||||
{
|
||||
const float multiplier = GetHeightMult() * RsGlobal->MaximumHeight;
|
||||
((PaddingYSize_Recalculated<I> = *orgPaddingYSize<I> * multiplier), ...);
|
||||
}
|
||||
|
||||
static void (*orgGetTextRect)(CRect*, float, float, void*);
|
||||
template<std::size_t NumXPadding, std::size_t NumYPadding>
|
||||
static void GetTextRect_Recalculate(CRect* a1, float a2, float a3, void* a4)
|
||||
{
|
||||
RecalculateXSize(std::make_index_sequence<NumXPadding>{});
|
||||
RecalculateYSize(std::make_index_sequence<NumYPadding>{});
|
||||
orgGetTextRect(a1, a2, a3, a4);
|
||||
}
|
||||
|
||||
HOOK_EACH_INIT(PaddingXSize, orgPaddingXSize, PaddingXSize_Recalculated);
|
||||
HOOK_EACH_INIT(PaddingYSize, orgPaddingYSize, PaddingYSize_Recalculated);
|
||||
|
||||
template<std::size_t Index>
|
||||
static const float* orgWrapX;
|
||||
|
||||
template<std::size_t Index>
|
||||
static float WrapX_Recalculated;
|
||||
|
||||
template<std::size_t... I>
|
||||
static void RecalculateWrapX(std::index_sequence<I...>)
|
||||
{
|
||||
const float multiplier = GetWidthMult() * RsGlobal->MaximumWidth;
|
||||
((WrapX_Recalculated<I> = *orgWrapX<I> * multiplier), ...);
|
||||
}
|
||||
|
||||
static void (*orgSetJustifyOff)();
|
||||
template<std::size_t NumXWrap>
|
||||
static void SetJustifyOff_Recalculate()
|
||||
{
|
||||
RecalculateWrapX(std::make_index_sequence<NumXWrap>{});
|
||||
orgSetJustifyOff();
|
||||
}
|
||||
|
||||
HOOK_EACH_INIT(WrapX, orgWrapX, WrapX_Recalculated);
|
||||
}
|
||||
|
||||
|
||||
// ============= Fix ammunation text (big message type 3) Y position offset not scaling to resolution =============
|
||||
namespace BigMessage3ScalingFixes
|
||||
{
|
||||
template<std::size_t Index>
|
||||
static const float* orgOffsetY;
|
||||
|
||||
template<std::size_t Index>
|
||||
static float OffsetY_Recalculated;
|
||||
|
||||
template<std::size_t... I>
|
||||
static void RecalculateYOffset(std::index_sequence<I...>)
|
||||
{
|
||||
const float multiplier = GetHeightMult() * RsGlobal->MaximumHeight;
|
||||
((OffsetY_Recalculated<I> = *orgOffsetY<I> * multiplier), ...);
|
||||
}
|
||||
|
||||
static void (*orgSetDropColor)(const CRGBA&);
|
||||
|
||||
template<std::size_t NumXOffsets>
|
||||
static void SetDropColor_Scale(const CRGBA& color)
|
||||
{
|
||||
RecalculateYOffset(std::make_index_sequence<NumXOffsets>{});
|
||||
orgSetDropColor(color);
|
||||
}
|
||||
|
||||
HOOK_EACH_INIT(MessageYOffset, orgOffsetY, OffsetY_Recalculated);
|
||||
}
|
||||
|
||||
|
||||
// ============= Fix an incorrect vertex setup for the outline of a destination blip in the Map Legend =============
|
||||
namespace LegendBlipFix
|
||||
{
|
||||
static void (*orgDraw2DPolygon)(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, const CRGBA& color);
|
||||
static void Draw2DPolygon_FixVertices(float x1, float y1, float x2, float y2, float /*x3*/, float y3, float x4, float y4, const CRGBA& color)
|
||||
{
|
||||
// In this setup, x3 is incorrect - it should have been (X + scaleX(14.0f)) but is (X + scaleX(2.0f)), same as x4
|
||||
// We can recover the correct dimensions from x1 (bottom center) and x4 (top left):
|
||||
// x3 = x1 + (x1 - x4)
|
||||
// Write it out in full like this (without simplifying), so we know (x1 - x4) is done at a correct floating point precision.
|
||||
const float x3 = x1 + (x1 - x4);
|
||||
orgDraw2DPolygon(x1, y1, x2, y2, x3, y3, x4, y4, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float FixedRefValue()
|
||||
{
|
||||
return 1.0f;
|
||||
|
@ -884,6 +969,9 @@ namespace RemoveDriverStatusFix
|
|||
// ============= Apply the environment mapping on extra components =============
|
||||
namespace EnvMapsOnExtras
|
||||
{
|
||||
static RpMaterial* (*RpMatFXMaterialSetEnvMapCoefficient)(RpMaterial* material, RwReal coef);
|
||||
static int (*RpMatFXMaterialGetEffects)(const RpMaterial* material);
|
||||
|
||||
static void RemoveSpecularityFromAtomic(RpAtomic* atomic)
|
||||
{
|
||||
RpGeometry* geometry = RpAtomicGetGeometry(atomic);
|
||||
|
@ -907,6 +995,10 @@ namespace EnvMapsOnExtras
|
|||
|
||||
if (bRemoveSpecularity)
|
||||
{
|
||||
if (RpMatFXMaterialGetEffects(material) == 2) // rpMATFXEFFECTENVMAP
|
||||
{
|
||||
RpMatFXMaterialSetEnvMapCoefficient(material, 0.0f);
|
||||
}
|
||||
RpMaterialGetSurfaceProperties(material)->specular = 0.0f;
|
||||
}
|
||||
return material;
|
||||
|
@ -1530,21 +1622,9 @@ void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModule
|
|||
{
|
||||
using namespace RadardiscFixes;
|
||||
|
||||
auto draw_entity_coord_blip = pattern("D8 0D ? ? ? ? D8 05 ? ? ? ? DE C1 D9 5C 24 18").count(2);
|
||||
auto draw_radar_disc1 = pattern("D8 25 ? ? ? ? DD DB D9 C2 D9 9C 24 ? ? ? ? DB 05 ? ? ? ? D8 0D ? ? ? ? D8 0D ? ? ? ? D8 05 ? ? ? ? D8 05").count(2);
|
||||
auto draw_radar_disc2 = pattern("D8 C1 D8 05 ? ? ? ? D9 9C 24 ? ? ? ? DE D9 DD D8").count(2);
|
||||
|
||||
std::array<float**, 8> radarXPos = {
|
||||
get_pattern<float*>("D8 05 ? ? ? ? DE C1 D9 5C 24 28", 2),
|
||||
get_pattern<float*>("D8 05 ? ? ? ? DE C1 D9 5C EC 30", 2),
|
||||
get_pattern<float*>("D8 0D ? ? ? ? D8 05 ? ? ? ? DE C1 D9 9C C4", 6 + 2),
|
||||
get_pattern<float*>("D8 0D ? ? ? ? D8 05 ? ? ? ? DE C1 D9 5C 24 08", 6 + 2),
|
||||
get_pattern<float*>("D8 0D ? ? ? ? D8 05 ? ? ? ? DE C1 DD D9 DB 44 24 18", 6 + 2),
|
||||
get_pattern<float*>("D8 0D ? ? ? ? D8 05 ? ? ? ? DE C1 DD DB DB 44 24 18", 6 + 2),
|
||||
draw_entity_coord_blip.get(0).get<float*>(6 + 2),
|
||||
draw_entity_coord_blip.get(1).get<float*>(6 + 2),
|
||||
};
|
||||
|
||||
std::array<float**, 4> radarXPos_RadardiscShrink = {
|
||||
draw_radar_disc1.get(0).get<float*>(35 + 2),
|
||||
draw_radar_disc1.get(0).get<float*>(35 + 6 + 2),
|
||||
|
@ -1567,13 +1647,18 @@ void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModule
|
|||
drawRadarDiscSprite.get(1).get<void>(17),
|
||||
};
|
||||
|
||||
// Use exactly the same patterns as widescreen fix
|
||||
float* radarPos = *get_pattern<float*>("D8 05 ? ? ? ? DE C1 D9 5C 24 28", 2);
|
||||
std::array<float**, 2> youAreHereSize = {
|
||||
get_pattern<float*>("DD D9 D9 05 ? ? ? ? D8 C9 D9 7C 24 04", 2 + 2),
|
||||
get_pattern<float*>("8B 5C 24 18 D8 0D ? ? ? ? D8 0D ? ? ? ? D9 7C 24 04", 10 + 2),
|
||||
};
|
||||
|
||||
// Undo the damage caused by IVRadarScaling from the widescreen fix moving the radar way too far to the right
|
||||
// It's moved from 40.0f to 71.0f, which is way too much now that we're scaling the horizontal placement correctly!
|
||||
// This is removed from the most up-to-date widescreen fix, but keep it so we don't break with older builds.
|
||||
try
|
||||
{
|
||||
// Use exactly the same patterns as widescreen fix
|
||||
float* radarPos = *get_pattern<float*>("D8 05 ? ? ? ? DE C1 D9 5C 24 28", 2);
|
||||
// No need to undo CRadar::DrawYouAreHereSprite, as wsfix keeps it as 40.0f
|
||||
|
||||
// This hardcodes a patched constant inside so the pattern will fail to match without IV radar scaling
|
||||
|
@ -1597,11 +1682,33 @@ void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModule
|
|||
}
|
||||
TXN_CATCH();
|
||||
|
||||
HookEach_CalculateRadarXPos(radarXPos, PatchFloat);
|
||||
HookEach_CalculateRadarXPos_RadardiscShrink(radarXPos_RadardiscShrink, PatchFloat);
|
||||
HookEach_CalculateRadarYPos_RadardiscShrink(radarYPos_RadardiscShrink, PatchFloat);
|
||||
HookEach_DrawRadarDisc(spriteDraw, InterceptCall);
|
||||
InterceptCall(drawMap, orgDrawMap, DrawMap_RecalculatePositions<radarXPos.size(), 0, radarXPos_RadardiscShrink.size(), radarYPos_RadardiscShrink.size()>);
|
||||
// Normally we would "wrap" the global variable 40.0f used as a X radar position, but that causes issues with plugin-sdk.
|
||||
// Vice City inlined CRadar::TransformRadarPointToScreenSpace and plugin-sdk reimplements it using this global directly, so we need to patch it.
|
||||
// Therefore, we instead do the following:
|
||||
// 1. Patch the float directly, reading the original value once and rescaling as usual in-place.
|
||||
// 2. If CRadar::DrawYouAreHereSprite still points at the same global variable, give it a dedicated one.
|
||||
// Otherwise do nothing, as some other mod (like the wsfix above) may have already done it.
|
||||
// 3. If we can't safely change the radar position because it was relocated, bail out of the fix entirely, just to be safe.
|
||||
// Missing out on a fix is better than breaking something.
|
||||
if (hGameModule == ModCompat::Utils::GetModuleHandleFromAddress(radarPos))
|
||||
{
|
||||
static float fYouAreHereSize;
|
||||
orgRadarXPosVal = fYouAreHereSize = *radarPos;
|
||||
orgRadarXPosPtr = radarPos;
|
||||
|
||||
for (float** val : youAreHereSize)
|
||||
{
|
||||
if (*val == radarPos)
|
||||
{
|
||||
Patch(val, &fYouAreHereSize);
|
||||
}
|
||||
}
|
||||
|
||||
HookEach_CalculateRadarXPos_RadardiscShrink(radarXPos_RadardiscShrink, PatchFloat);
|
||||
HookEach_CalculateRadarYPos_RadardiscShrink(radarYPos_RadardiscShrink, PatchFloat);
|
||||
HookEach_DrawRadarDisc(spriteDraw, InterceptCall);
|
||||
InterceptCall(drawMap, orgDrawMap, DrawMap_RecalculatePositions<radarXPos_RadardiscShrink.size(), radarYPos_RadardiscShrink.size()>);
|
||||
}
|
||||
}
|
||||
TXN_CATCH();
|
||||
|
||||
|
@ -1912,6 +2019,70 @@ void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModule
|
|||
}
|
||||
TXN_CATCH();
|
||||
|
||||
|
||||
// Fix text background padding not scaling to resolution
|
||||
try
|
||||
{
|
||||
using namespace TextRectPaddingScalingFixes;
|
||||
|
||||
auto getTextRect = get_pattern("FF 74 24 54 FF 74 24 54 50 E8 ? ? ? ? 83 C4 10", 9);
|
||||
auto rectWidth1 = pattern("D8 25 ? ? ? ? D9 1E D9 44 24 38 D8 05 ? ? ? ? D8 05").get_one();
|
||||
auto rectWidth2 = pattern("D8 25 ? ? ? ? D9 1E D9 05 ? ? ? ? D8 0D ? ? ? ? D8 44 24 38 D8 05").get_one();
|
||||
auto rectWidth3 = get_pattern<float*>("D8 25 ? ? ? ? 0F BF C5 D9 1E", 2);
|
||||
|
||||
auto rectHeight1 = pattern("D8 05 ? ? ? ? D9 5E 04 D9 44 24 3C D8 25").count(2);
|
||||
auto rectHeight2 = pattern("D9 05 ? ? ? ? D8 44 24 3C DE C1 D8 05").get_one();
|
||||
|
||||
// SetWrapx on the help boxes includes an unscaled -4.0f probably to work together with this padding,
|
||||
// so treat it as part of the same fix
|
||||
auto setJustifyOff_helpBox = get_pattern("59 E8 ? ? ? ? D9 EE", 1);
|
||||
|
||||
std::array<float**, 5> paddingXSizes = {
|
||||
rectWidth1.get<float*>(2),
|
||||
rectWidth1.get<float*>(0x12 + 2),
|
||||
rectWidth2.get<float*>(2),
|
||||
rectWidth2.get<float*>(0x18 + 2),
|
||||
rectWidth3
|
||||
};
|
||||
|
||||
std::array<float**, 6> paddingYSizes = {
|
||||
rectHeight1.get(0).get<float*>(2),
|
||||
rectHeight1.get(0).get<float*>(0xD + 2),
|
||||
rectHeight1.get(1).get<float*>(2),
|
||||
rectHeight1.get(1).get<float*>(0xD + 2),
|
||||
rectHeight2.get<float*>(2),
|
||||
rectHeight2.get<float*>(0xC + 2),
|
||||
};
|
||||
|
||||
std::array<float**, 1> wrapxWidth = {
|
||||
get_pattern<float*>("D8 25 ? ? ? ? D9 1C 24 DD D8", 2),
|
||||
};
|
||||
|
||||
HookEach_PaddingXSize(paddingXSizes, PatchFloat);
|
||||
HookEach_PaddingYSize(paddingYSizes, PatchFloat);
|
||||
InterceptCall(getTextRect, orgGetTextRect, GetTextRect_Recalculate<paddingXSizes.size(), paddingYSizes.size()>);
|
||||
|
||||
HookEach_WrapX(wrapxWidth, PatchFloat);
|
||||
InterceptCall(setJustifyOff_helpBox, orgSetJustifyOff, SetJustifyOff_Recalculate<wrapxWidth.size()>);
|
||||
}
|
||||
TXN_CATCH();
|
||||
|
||||
|
||||
// Fix ammunation text (big message type 3) Y position offset not scaling to resolution
|
||||
try
|
||||
{
|
||||
using namespace BigMessage3ScalingFixes;
|
||||
|
||||
auto setDropColor = get_pattern("E8 ? ? ? ? 59 8D 4C 24 40");
|
||||
std::array<float**, 1> YOffset = {
|
||||
get_pattern<float*>("D8 25 ? ? ? ? D9 1C 24 A1", 2),
|
||||
};
|
||||
|
||||
HookEach_MessageYOffset(YOffset, PatchFloat);
|
||||
InterceptCall(setDropColor, orgSetDropColor, SetDropColor_Scale<YOffset.size()>);
|
||||
}
|
||||
TXN_CATCH();
|
||||
|
||||
FLAUtils::Init(moduleList);
|
||||
}
|
||||
|
||||
|
@ -2495,10 +2666,15 @@ void Patch_VC_Common()
|
|||
using namespace EnvMapsOnExtras;
|
||||
|
||||
auto forAllAtomics = pattern("50 E8 ? ? ? ? 66 8B 4B 44").get_one();
|
||||
auto setEnvMapCoefficient = reinterpret_cast<decltype(RpMatFXMaterialSetEnvMapCoefficient)>(get_pattern("8B 44 24 14 81 E2 FF 00 00 00 8D 14 52 8D 0C D6 89 41 08", -0x48));
|
||||
auto getEffects = reinterpret_cast<decltype(RpMatFXMaterialGetEffects)>(get_pattern("8B 04 01 85 C0 75 01", -0xA));
|
||||
|
||||
// push eax -> push ebx
|
||||
Patch<uint8_t>(forAllAtomics.get<void>(), 0x53);
|
||||
InterceptCall(forAllAtomics.get<void>(1), orgRpClumpForAllAtomics, RpClumpForAllAtomics_ExtraComps);
|
||||
|
||||
RpMatFXMaterialSetEnvMapCoefficient = setEnvMapCoefficient;
|
||||
RpMatFXMaterialGetEffects = getEffects;
|
||||
}
|
||||
TXN_CATCH();
|
||||
|
||||
|
@ -2634,7 +2810,7 @@ void Patch_VC_Common()
|
|||
|
||||
|
||||
// Ped speech fix
|
||||
// Based off Sergenaur's fix
|
||||
// Based off Sergeanur's fix
|
||||
try
|
||||
{
|
||||
// Remove the artificial 6s delay between any ped speech samples
|
||||
|
@ -2755,6 +2931,17 @@ void Patch_VC_Common()
|
|||
Nop(set_peds_choking, 6);
|
||||
}
|
||||
TXN_CATCH();
|
||||
|
||||
|
||||
// Fix an incorrect vertex setup for the outline of a destination blip in the Map Legend
|
||||
try
|
||||
{
|
||||
using namespace LegendBlipFix;
|
||||
|
||||
auto draw2dPolygon = get_pattern("E8 ? ? ? ? D9 EE D9 EE D9 EE DB 05 ? ? ? ? 89 5C 24 24");
|
||||
InterceptCall(draw2dPolygon, orgDraw2DPolygon, Draw2DPolygon_FixVertices);
|
||||
}
|
||||
TXN_CATCH();
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
|
|
|
@ -166,6 +166,7 @@
|
|||
<ClInclude Include="..\SilentPatch\Maths.h" />
|
||||
<ClInclude Include="..\SilentPatch\ParseUtils.hpp" />
|
||||
<ClInclude Include="..\SilentPatch\Random.h" />
|
||||
<ClInclude Include="..\SilentPatch\RWGTA.h" />
|
||||
<ClInclude Include="..\SilentPatch\RWUtils.hpp" />
|
||||
<ClInclude Include="..\SilentPatch\StdAfx.h" />
|
||||
<ClInclude Include="..\SilentPatch\StoredCar.h" />
|
||||
|
|
|
@ -75,6 +75,9 @@
|
|||
<ClInclude Include="EntityVC.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\SilentPatch\RWGTA.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\SilentPatch\Timer.cpp">
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<SILENTPATCH_EXT>.asi</SILENTPATCH_EXT>
|
||||
<SILENTPATCH_FULL_NAME>SilentPatch for Vice City</SILENTPATCH_FULL_NAME>
|
||||
<SILENTPATCH_REVISION_ID>11</SILENTPATCH_REVISION_ID>
|
||||
<SILENTPATCH_BUILD_ID>0</SILENTPATCH_BUILD_ID>
|
||||
<SILENTPATCH_BUILD_ID>1</SILENTPATCH_BUILD_ID>
|
||||
<SILENTPATCH_COPYRIGHT>2013-2024</SILENTPATCH_COPYRIGHT>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup />
|
||||
|
|
Loading…
Reference in a new issue