├── SACarCam ├── common.h ├── SACarCam.vcxproj.filters ├── Pad.h ├── Pad.cpp ├── MemoryMgr.h ├── ModuleList.hpp ├── debugmenu_public.h ├── GInputAPI.h ├── GTA.h ├── Camera.h ├── SACarCam.vcxproj └── SACarCam.cpp └── SACarCam.sln /SACarCam/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define WIN32_LEAN_AND_MEAN 3 | 4 | #define _CRT_SECURE_NO_WARNINGS 5 | #define _USE_MATH_DEFINES 6 | #pragma warning(disable: 4244) // int to float 7 | #pragma warning(disable: 4800) // int to bool 8 | #pragma warning(disable: 4305) // double to float 9 | #pragma warning(disable: 4838) // narrowing conversion 10 | #pragma warning(disable: 4996) // POSIX names 11 | 12 | #define PI 3.1415927f 13 | #define TWOPI (PI*2) 14 | #define HALFPI (PI/2) 15 | #define DEGTORAD(x) ((x) * PI / 180.0f) 16 | #define RADTODEG(x) ((x) * 180.0f / PI) 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | typedef uint8_t uint8; 27 | typedef int8_t int8; 28 | typedef uint16_t uint16; 29 | typedef int16_t int16; 30 | typedef uint32_t uint32; 31 | typedef int32_t int32; 32 | typedef uintptr_t uintptr; 33 | typedef uint64_t uint64; 34 | typedef int64_t int64; 35 | // hardcode ucs-2 36 | typedef uint16_t wchar; 37 | 38 | typedef uintptr_t addr; 39 | #define nil nullptr 40 | 41 | inline float RecipSqrt(float x, float y) { return x / sqrtf(y); } 42 | inline float RecipSqrt(float x) { return RecipSqrt(1.0f, x); } 43 | 44 | #define clamp(v, low, high) ((v)<(low) ? (low) : (v)>(high) ? (high) : (v)) 45 | -------------------------------------------------------------------------------- /SACarCam/SACarCam.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | -------------------------------------------------------------------------------- /SACarCam/Pad.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CControllerState 4 | { 5 | public: 6 | int16 LeftStickX, LeftStickY; 7 | int16 RightStickX, RightStickY; 8 | int16 LeftShoulder1, LeftShoulder2; 9 | int16 RightShoulder1, RightShoulder2; 10 | int16 DPadUp, DPadDown, DPadLeft, DPadRight; 11 | int16 Start, Select; 12 | int16 Square, Triangle, Cross, Circle; 13 | int16 LeftShock, RightShock; 14 | int16 NetworkTalk; 15 | float GetLeftStickX(void) { return LeftStickX / 32767.0f; }; 16 | float GetLeftStickY(void) { return LeftStickY / 32767.0f; }; 17 | float GetRightStickX(void) { return RightStickX / 32767.0f; }; 18 | float GetRightStickY(void) { return RightStickY / 32767.0f; }; 19 | }; 20 | 21 | class CMouseControllerState 22 | { 23 | public: 24 | //uint32 btns; // bit 0-2 button 1-3 25 | 26 | bool LMB; 27 | bool RMB; 28 | bool MMB; 29 | bool WHEELUP; 30 | bool WHEELDN; 31 | bool MXB1; 32 | bool MXB2; 33 | char _pad0; 34 | 35 | float x, y; 36 | }; 37 | 38 | class CPad 39 | { 40 | public: 41 | /* 42 | // III 43 | CControllerState NewState; 44 | CControllerState OldState; 45 | CControllerState PCTempKeyState; 46 | CControllerState PCTempJoyState; 47 | CControllerState PCTempMouseState; 48 | int16 Phase; 49 | int16 Mode; 50 | int16 ShakeDur; 51 | uint8 ShakeFreq; 52 | bool bHornHistory[5]; 53 | uint8 iCurrHornHistory; 54 | uint8 DisablePlayerControls; 55 | int8 bApplyBrakes; 56 | char _unk[12]; //int32 unk[3]; 57 | char _pad0[3]; 58 | int32 LastTimeTouched; 59 | int32 AverageWeapon; 60 | int32 AverageEntries; 61 | */ 62 | static CMouseControllerState &NewMouseControllerState; 63 | 64 | int16 LookAroundUpDown(void); 65 | int16 LookAroundLeftRight(void); 66 | int16 GetSteeringUpDown(void); 67 | int16 GetCarGunUpDown(void); 68 | int16 GetCarGunLeftRight(void); 69 | bool GetLookLeft(void); 70 | bool GetLookRight(void); 71 | bool GetLookBehindForCar(void); 72 | bool GetLookBehindForPed(void); 73 | 74 | int16 FakeCarGunUpDown(void); 75 | int16 FakeCarGunLeftRight(void); 76 | }; 77 | //static_assert(sizeof(CPad) == 0xFC, "CPad: this is broken as shit"); 78 | 79 | extern CPad &pad0; -------------------------------------------------------------------------------- /SACarCam.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29215.179 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SACarCam", "SACarCam\SACarCam.vcxproj", "{F06BC71F-1298-453C-83EA-D29C909403C5}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | DebugLCS|x64 = DebugLCS|x64 13 | DebugLCS|x86 = DebugLCS|x86 14 | DebugVC|x64 = DebugVC|x64 15 | DebugVC|x86 = DebugVC|x86 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | ReleaseLCS|x64 = ReleaseLCS|x64 19 | ReleaseLCS|x86 = ReleaseLCS|x86 20 | ReleaseVC|x64 = ReleaseVC|x64 21 | ReleaseVC|x86 = ReleaseVC|x86 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {F06BC71F-1298-453C-83EA-D29C909403C5}.Debug|x64.ActiveCfg = Debug|x64 25 | {F06BC71F-1298-453C-83EA-D29C909403C5}.Debug|x64.Build.0 = Debug|x64 26 | {F06BC71F-1298-453C-83EA-D29C909403C5}.Debug|x86.ActiveCfg = Debug|Win32 27 | {F06BC71F-1298-453C-83EA-D29C909403C5}.Debug|x86.Build.0 = Debug|Win32 28 | {F06BC71F-1298-453C-83EA-D29C909403C5}.DebugLCS|x64.ActiveCfg = DebugLCS|x64 29 | {F06BC71F-1298-453C-83EA-D29C909403C5}.DebugLCS|x64.Build.0 = DebugLCS|x64 30 | {F06BC71F-1298-453C-83EA-D29C909403C5}.DebugLCS|x86.ActiveCfg = DebugLCS|Win32 31 | {F06BC71F-1298-453C-83EA-D29C909403C5}.DebugLCS|x86.Build.0 = DebugLCS|Win32 32 | {F06BC71F-1298-453C-83EA-D29C909403C5}.DebugVC|x64.ActiveCfg = DebugVC|x64 33 | {F06BC71F-1298-453C-83EA-D29C909403C5}.DebugVC|x64.Build.0 = DebugVC|x64 34 | {F06BC71F-1298-453C-83EA-D29C909403C5}.DebugVC|x86.ActiveCfg = DebugVC|Win32 35 | {F06BC71F-1298-453C-83EA-D29C909403C5}.DebugVC|x86.Build.0 = DebugVC|Win32 36 | {F06BC71F-1298-453C-83EA-D29C909403C5}.Release|x64.ActiveCfg = Release|x64 37 | {F06BC71F-1298-453C-83EA-D29C909403C5}.Release|x64.Build.0 = Release|x64 38 | {F06BC71F-1298-453C-83EA-D29C909403C5}.Release|x86.ActiveCfg = Release|Win32 39 | {F06BC71F-1298-453C-83EA-D29C909403C5}.Release|x86.Build.0 = Release|Win32 40 | {F06BC71F-1298-453C-83EA-D29C909403C5}.ReleaseLCS|x64.ActiveCfg = ReleaseLCS|x64 41 | {F06BC71F-1298-453C-83EA-D29C909403C5}.ReleaseLCS|x64.Build.0 = ReleaseLCS|x64 42 | {F06BC71F-1298-453C-83EA-D29C909403C5}.ReleaseLCS|x86.ActiveCfg = ReleaseLCS|Win32 43 | {F06BC71F-1298-453C-83EA-D29C909403C5}.ReleaseLCS|x86.Build.0 = ReleaseLCS|Win32 44 | {F06BC71F-1298-453C-83EA-D29C909403C5}.ReleaseVC|x64.ActiveCfg = ReleaseVC|x64 45 | {F06BC71F-1298-453C-83EA-D29C909403C5}.ReleaseVC|x64.Build.0 = ReleaseVC|x64 46 | {F06BC71F-1298-453C-83EA-D29C909403C5}.ReleaseVC|x86.ActiveCfg = ReleaseVC|Win32 47 | {F06BC71F-1298-453C-83EA-D29C909403C5}.ReleaseVC|x86.Build.0 = ReleaseVC|Win32 48 | EndGlobalSection 49 | GlobalSection(SolutionProperties) = preSolution 50 | HideSolutionNode = FALSE 51 | EndGlobalSection 52 | GlobalSection(ExtensibilityGlobals) = postSolution 53 | SolutionGuid = {0868CAA7-5624-4C86-A01C-D155850F99A5} 54 | EndGlobalSection 55 | EndGlobal 56 | -------------------------------------------------------------------------------- /SACarCam/Pad.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "MemoryMgr.h" 3 | #include "Camera.h" 4 | #include "Pad.h" 5 | 6 | // These functions (which is commented out as of now) is belong to Fire_Head. 7 | 8 | CPad &pad0 = *AddressByVersion(0x6F0360, 0, 0, 0x7DBCB0, 0, 0); 9 | CMouseControllerState &CPad::NewMouseControllerState = *AddressByVersion(0x8809F0, 0, 0, 0x94D788, 0, 0); 10 | 11 | addr glcAddress = AddressByVersion(0x4932F0, 0, 0, 0x4AAC30, 0, 0); 12 | addr glpAddress = AddressByVersion(0x493320, 0, 0, 0x4AAC00, 0, 0); 13 | addr glrAddress = AddressByVersion(0x4932C0, 0, 0, 0x4AAC60, 0, 0); 14 | addr gllAddress = AddressByVersion(0x493290, 0, 0, 0x4AAC90, 0, 0); 15 | addr gcglrAddress = AddressByVersion(0x4930C0, 0, 0, 0x4AAEB0, 0, 0); 16 | addr gcgudAddress = AddressByVersion(0x493070, 0, 0, 0x4AAF00, 0, 0); 17 | addr gsudAddress = AddressByVersion(0x492FF0, 0, 0, 0x4AAF50, 0, 0); 18 | addr lalrAddress = AddressByVersion(0x493F80, 0, 0, 0x4A9A80, 0, 0); 19 | addr laudAddress = AddressByVersion(0x494130, 0, 0, 0x4A98F0, 0, 0); 20 | 21 | WRAPPER bool CPad::GetLookBehindForCar(void) { EAXJMP(glcAddress); } 22 | WRAPPER bool CPad::GetLookBehindForPed(void) { EAXJMP(glpAddress); } 23 | WRAPPER bool CPad::GetLookRight(void) { EAXJMP(glrAddress); } 24 | WRAPPER bool CPad::GetLookLeft(void) { EAXJMP(gllAddress); } 25 | WRAPPER int16 CPad::GetCarGunLeftRight(void) { EAXJMP(gcglrAddress); } 26 | WRAPPER int16 CPad::GetCarGunUpDown(void) { EAXJMP(gcgudAddress); } 27 | WRAPPER int16 CPad::GetSteeringUpDown(void) { EAXJMP(gsudAddress); } 28 | 29 | // Unused 30 | WRAPPER int16 CPad::LookAroundLeftRight(void) { EAXJMP(lalrAddress); } 31 | WRAPPER int16 CPad::LookAroundUpDown(void) { EAXJMP(laudAddress); } 32 | 33 | #if 0 34 | int16 CPad::GetSteeringUpDown(void) 35 | { 36 | if (ArePlayerControlsDisabled()) 37 | return 0; 38 | 39 | switch (Mode) 40 | { 41 | case 0: 42 | case 2: 43 | { 44 | int16 axis = NewState.LeftStickY; 45 | int16 dpad = (NewState.DPadUp - NewState.DPadDown) / 2; 46 | 47 | if (fabs(axis) > fabs(dpad)) 48 | return axis; 49 | else 50 | return dpad; 51 | 52 | break; 53 | } 54 | 55 | case 1: 56 | case 3: 57 | { 58 | return NewState.LeftStickY; 59 | 60 | break; 61 | } 62 | } 63 | 64 | return 0; 65 | } 66 | 67 | int16 CPad::GetCarGunUpDown(void) 68 | { 69 | if (ArePlayerControlsDisabled()) 70 | return 0; 71 | 72 | switch (Mode) 73 | { 74 | case 0: 75 | case 1: 76 | case 2: 77 | { 78 | return NewState.RightStickY; 79 | 80 | break; 81 | } 82 | 83 | case 3: 84 | { 85 | return (NewState.DPadUp - NewState.DPadDown) / 2; 86 | 87 | break; 88 | } 89 | } 90 | 91 | return 0; 92 | } 93 | 94 | int16 CPad::GetCarGunLeftRight(void) 95 | { 96 | if (ArePlayerControlsDisabled()) 97 | return 0; 98 | 99 | switch (Mode) 100 | { 101 | case 0: 102 | case 1: 103 | case 2: 104 | { 105 | return NewState.RightStickX; 106 | 107 | break; 108 | } 109 | 110 | case 3: 111 | { 112 | return (NewState.DPadRight - NewState.DPadLeft) / 2; 113 | 114 | break; 115 | } 116 | } 117 | 118 | return 0; 119 | } 120 | 121 | bool CPad::GetLookLeft(void) 122 | { 123 | if (ArePlayerControlsDisabled()) 124 | return false; 125 | 126 | return !!(NewState.LeftShoulder2 && !NewState.RightShoulder2); 127 | } 128 | 129 | bool CPad::GetLookRight(void) 130 | { 131 | if (ArePlayerControlsDisabled()) 132 | return false; 133 | 134 | return !!(NewState.RightShoulder2 && !NewState.LeftShoulder2); 135 | } 136 | 137 | 138 | bool CPad::GetLookBehindForCar(void) 139 | { 140 | if (ArePlayerControlsDisabled()) 141 | return false; 142 | 143 | return !!(NewState.RightShoulder2 && NewState.LeftShoulder2); 144 | } 145 | 146 | bool CPad::GetLookBehindForPed(void) 147 | { 148 | if (ArePlayerControlsDisabled()) 149 | return false; 150 | 151 | return !!NewState.RightShock; 152 | } 153 | #endif -------------------------------------------------------------------------------- /SACarCam/MemoryMgr.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEMORYMGR 2 | #define __MEMORYMGR 3 | 4 | #define WRAPPER __declspec(naked) 5 | #define DEPRECATED __declspec(deprecated) 6 | #define EAXJMP(a) { _asm mov eax, a _asm jmp eax } 7 | #define VARJMP(a) { _asm jmp a } 8 | #define WRAPARG(a) UNREFERENCED_PARAMETER(a) 9 | 10 | #define NOVMT __declspec(novtable) 11 | #define SETVMT(a) *((DWORD_PTR*)this) = (DWORD_PTR)a 12 | 13 | enum 14 | { 15 | PATCH_CALL, 16 | PATCH_JUMP, 17 | PATCH_NOTHING, 18 | }; 19 | 20 | enum 21 | { 22 | III_10 = 1, 23 | III_11, 24 | III_STEAM, 25 | VC_10, 26 | VC_11, 27 | VC_STEAM 28 | }; 29 | 30 | extern int gtaversion; 31 | 32 | template 33 | inline T AddressByVersion(addr addressIII10, addr addressIII11, addr addressIIISteam, addr addressvc10, addr addressvc11, addr addressvcSteam) 34 | { 35 | if (gtaversion == -1) { 36 | if (*(addr*)0x5C1E75 == 0xB85548EC) gtaversion = III_10; 37 | else if (*(addr*)0x5C2135 == 0xB85548EC) gtaversion = III_11; 38 | else if (*(addr*)0x5C6FD5 == 0xB85548EC) gtaversion = III_STEAM; 39 | else if (*(addr*)0x667BF5 == 0xB85548EC) gtaversion = VC_10; 40 | else if (*(addr*)0x667C45 == 0xB85548EC) gtaversion = VC_11; 41 | else if (*(addr*)0x666BA5 == 0xB85548EC) gtaversion = VC_STEAM; 42 | else gtaversion = 0; 43 | } 44 | switch (gtaversion) { 45 | case III_10: 46 | return (T)addressIII10; 47 | case III_11: 48 | return (T)addressIII11; 49 | case III_STEAM: 50 | return (T)addressIIISteam; 51 | case VC_10: 52 | return (T)addressvc10; 53 | case VC_11: 54 | return (T)addressvc11; 55 | case VC_STEAM: 56 | return (T)addressvcSteam; 57 | default: 58 | return (T)0; 59 | } 60 | } 61 | 62 | inline bool 63 | is10(void) 64 | { 65 | return gtaversion == III_10 || gtaversion == VC_10; 66 | } 67 | 68 | inline bool 69 | isIII(void) 70 | { 71 | return gtaversion >= III_10 && gtaversion <= III_STEAM; 72 | } 73 | 74 | inline bool 75 | isVC(void) 76 | { 77 | return gtaversion >= VC_10 && gtaversion <= VC_STEAM; 78 | } 79 | 80 | #define PTRFROMCALL(addr) (uint32_t)(*(uint32_t*)((uint32_t)addr+1) + (uint32_t)addr + 5) 81 | #define INTERCEPT(saved, func, a) \ 82 | { \ 83 | saved = PTRFROMCALL(a); \ 84 | InjectHook(a, func); \ 85 | } 86 | 87 | template inline void 88 | Patch(AT address, T value) 89 | { 90 | DWORD dwProtect[2]; 91 | VirtualProtect((void*)address, sizeof(T), PAGE_EXECUTE_READWRITE, &dwProtect[0]); 92 | *(T*)address = value; 93 | VirtualProtect((void*)address, sizeof(T), dwProtect[0], &dwProtect[1]); 94 | } 95 | 96 | template inline void 97 | Nop(AT address, unsigned int nCount) 98 | { 99 | DWORD dwProtect[2]; 100 | VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]); 101 | memset((void*)address, 0x90, nCount); 102 | VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]); 103 | } 104 | 105 | template inline void 106 | InjectHook(AT address, HT hook, unsigned int nType = PATCH_NOTHING) 107 | { 108 | DWORD dwProtect[2]; 109 | switch (nType) 110 | { 111 | case PATCH_JUMP: 112 | VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); 113 | *(BYTE*)address = 0xE9; 114 | break; 115 | case PATCH_CALL: 116 | VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); 117 | *(BYTE*)address = 0xE8; 118 | break; 119 | default: 120 | VirtualProtect((void*)((DWORD)address + 1), 4, PAGE_EXECUTE_READWRITE, &dwProtect[0]); 121 | break; 122 | } 123 | DWORD dwHook; 124 | _asm 125 | { 126 | mov eax, hook 127 | mov dwHook, eax 128 | } 129 | 130 | *(ptrdiff_t*)((DWORD)address + 1) = (DWORD)dwHook - (DWORD)address - 5; 131 | if (nType == PATCH_NOTHING) 132 | VirtualProtect((void*)((DWORD)address + 1), 4, dwProtect[0], &dwProtect[1]); 133 | else 134 | VirtualProtect((void*)address, 5, dwProtect[0], &dwProtect[1]); 135 | } 136 | 137 | inline void ExtractCall(void* dst, addr a) 138 | { 139 | *(addr*)dst = (addr)(*(addr*)(a + 1) + a + 5); 140 | } 141 | template 142 | inline void InterceptCall(void* dst, T func, addr a) 143 | { 144 | ExtractCall(dst, a); 145 | InjectHook(a, func); 146 | } 147 | template 148 | inline void InterceptVmethod(void* dst, T func, addr a) 149 | { 150 | *(addr*)dst = *(addr*)a; 151 | Patch(a, func); 152 | } 153 | 154 | #endif -------------------------------------------------------------------------------- /SACarCam/ModuleList.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // Stores a list of loaded modules with their names, WITHOUT extension 8 | class ModuleList 9 | { 10 | public: 11 | struct LazyEnumerateTag {}; 12 | 13 | ModuleList() 14 | { 15 | Enumerate(); 16 | } 17 | 18 | explicit ModuleList(LazyEnumerateTag) 19 | { 20 | } 21 | 22 | // Initializes module list 23 | // Needs to be called before any calls to Get or GetAll 24 | void Enumerate() 25 | { 26 | // Cannot enumerate twice without cleaing 27 | assert(m_moduleList.size() == 0); 28 | 29 | constexpr size_t INITIAL_SIZE = sizeof(HMODULE) * 256; 30 | HMODULE* modules = static_cast(malloc(INITIAL_SIZE)); 31 | if (modules != nullptr) 32 | { 33 | typedef BOOL(WINAPI * Func)(HANDLE hProcess, HMODULE * lphModule, DWORD cb, LPDWORD lpcbNeeded); 34 | 35 | HMODULE hLib = LoadLibrary(TEXT("kernel32")); 36 | assert(hLib != nullptr); // If this fails then everything is probably broken anyway 37 | 38 | Func pEnumProcessModules = reinterpret_cast(GetProcAddress(hLib, "K32EnumProcessModules")); 39 | if (pEnumProcessModules == nullptr) 40 | { 41 | // Try psapi 42 | FreeLibrary(hLib); 43 | hLib = LoadLibrary(TEXT("psapi")); 44 | if (hLib != nullptr) 45 | { 46 | pEnumProcessModules = reinterpret_cast(GetProcAddress(hLib, "EnumProcessModules")); 47 | } 48 | } 49 | 50 | if (pEnumProcessModules != nullptr) 51 | { 52 | const HANDLE currentProcess = GetCurrentProcess(); 53 | DWORD cbNeeded = 0; 54 | if (pEnumProcessModules(currentProcess, modules, INITIAL_SIZE, &cbNeeded) != 0) 55 | { 56 | if (cbNeeded > INITIAL_SIZE) 57 | { 58 | HMODULE* newModules = static_cast(realloc(modules, cbNeeded)); 59 | if (newModules != nullptr) 60 | { 61 | modules = newModules; 62 | 63 | if (pEnumProcessModules(currentProcess, modules, cbNeeded, &cbNeeded) != 0) 64 | { 65 | EnumerateInternal(modules, cbNeeded / sizeof(HMODULE)); 66 | } 67 | } 68 | else 69 | { 70 | EnumerateInternal(modules, INITIAL_SIZE / sizeof(HMODULE)); 71 | } 72 | } 73 | else 74 | { 75 | EnumerateInternal(modules, cbNeeded / sizeof(HMODULE)); 76 | } 77 | } 78 | } 79 | 80 | if (hLib != nullptr) 81 | { 82 | FreeLibrary(hLib); 83 | } 84 | 85 | free(modules); 86 | } 87 | } 88 | 89 | // Recreates module list 90 | void ReEnumerate() 91 | { 92 | Clear(); 93 | Enumerate(); 94 | } 95 | 96 | // Clears module list 97 | void Clear() 98 | { 99 | m_moduleList.clear(); 100 | } 101 | 102 | // Gets handle of a loaded module with given name, NULL otherwise 103 | HMODULE Get(const wchar_t* moduleName) const 104 | { 105 | // If vector is empty then we're trying to call it without calling Enumerate first 106 | assert(m_moduleList.size() != 0); 107 | 108 | auto it = std::find_if(m_moduleList.begin(), m_moduleList.end(), [&](const auto& e) { 109 | return _wcsicmp(moduleName, e.second.c_str()) == 0; 110 | }); 111 | return it != m_moduleList.end() ? it->first : nullptr; 112 | } 113 | 114 | // Gets handles to all loaded modules with given name 115 | std::vector GetAll(const wchar_t* moduleName) const 116 | { 117 | // If vector is empty then we're trying to call it without calling Enumerate first 118 | assert(m_moduleList.size() != 0); 119 | 120 | std::vector results; 121 | for (auto& e : m_moduleList) 122 | { 123 | if (_wcsicmp(moduleName, e.second.c_str()) == 0) 124 | { 125 | results.push_back(e.first); 126 | } 127 | } 128 | 129 | return results; 130 | } 131 | 132 | // Gets handle of a loaded module with given prefix, NULL otherwise 133 | HMODULE GetByPrefix(const wchar_t* modulePrefix) const 134 | { 135 | // If vector is empty then we're trying to call it without calling Enumerate first 136 | assert(m_moduleList.size() != 0); 137 | 138 | const size_t len = wcslen(modulePrefix); 139 | auto it = std::find_if(m_moduleList.begin(), m_moduleList.end(), [&](const auto& e) { 140 | return _wcsnicmp(modulePrefix, e.second.c_str(), len) == 0; 141 | }); 142 | return it != m_moduleList.end() ? it->first : nullptr; 143 | } 144 | 145 | // Gets handles to all loaded modules with given prefix 146 | std::vector GetAllByPrefix(const wchar_t* modulePrefix) const 147 | { 148 | // If vector is empty then we're trying to call it without calling Enumerate first 149 | assert(m_moduleList.size() != 0); 150 | 151 | const size_t len = wcslen(modulePrefix); 152 | std::vector results; 153 | for (auto& e : m_moduleList) 154 | { 155 | if (_wcsnicmp(modulePrefix, e.second.c_str(), len) == 0) 156 | { 157 | results.push_back(e.first); 158 | } 159 | } 160 | 161 | return results; 162 | } 163 | 164 | private: 165 | void EnumerateInternal(HMODULE* modules, size_t numModules) 166 | { 167 | size_t moduleNameLength = MAX_PATH; 168 | wchar_t* moduleName = static_cast(malloc(moduleNameLength * sizeof(moduleName[0]))); 169 | if (moduleName != nullptr) 170 | { 171 | m_moduleList.reserve(numModules); 172 | for (size_t i = 0; i < numModules; i++) 173 | { 174 | // Obtain module name, with resizing if necessary 175 | DWORD size; 176 | while (size = GetModuleFileNameW(*modules, moduleName, moduleNameLength), size == moduleNameLength) 177 | { 178 | wchar_t* newName = static_cast(realloc(moduleName, 2 * moduleNameLength * sizeof(moduleName[0]))); 179 | if (newName != nullptr) 180 | { 181 | moduleName = newName; 182 | moduleNameLength *= 2; 183 | } 184 | else 185 | { 186 | size = 0; 187 | break; 188 | } 189 | } 190 | 191 | if (size != 0) 192 | { 193 | const wchar_t* nameBegin = wcsrchr(moduleName, '\\') + 1; 194 | const wchar_t* dotPos = wcsrchr(nameBegin, '.'); 195 | if (dotPos != nullptr) 196 | { 197 | m_moduleList.emplace_back(*modules, std::wstring(nameBegin, dotPos)); 198 | } 199 | else 200 | { 201 | m_moduleList.emplace_back(*modules, nameBegin); 202 | } 203 | } 204 | modules++; 205 | } 206 | 207 | free(moduleName); 208 | } 209 | } 210 | 211 | std::vector< std::pair > m_moduleList; 212 | }; -------------------------------------------------------------------------------- /SACarCam/debugmenu_public.h: -------------------------------------------------------------------------------- 1 | 2 | extern "C" { 3 | 4 | typedef void (*TriggerFunc)(void); 5 | 6 | struct DebugMenuEntry; 7 | 8 | typedef DebugMenuEntry *(*DebugMenuAddInt8_TYPE)(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings); 9 | typedef DebugMenuEntry *(*DebugMenuAddInt16_TYPE)(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings); 10 | typedef DebugMenuEntry *(*DebugMenuAddInt32_TYPE)(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings); 11 | typedef DebugMenuEntry *(*DebugMenuAddInt64_TYPE)(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings); 12 | typedef DebugMenuEntry *(*DebugMenuAddUInt8_TYPE)(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings); 13 | typedef DebugMenuEntry *(*DebugMenuAddUInt16_TYPE)(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings); 14 | typedef DebugMenuEntry *(*DebugMenuAddUInt32_TYPE)(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings); 15 | typedef DebugMenuEntry *(*DebugMenuAddUInt64_TYPE)(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings); 16 | typedef DebugMenuEntry *(*DebugMenuAddFloat32_TYPE)(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound); 17 | typedef DebugMenuEntry *(*DebugMenuAddFloat64_TYPE)(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound); 18 | typedef DebugMenuEntry *(*DebugMenuAddCmd_TYPE)(const char *path, const char *name, TriggerFunc triggerFunc); 19 | typedef void (*DebugMenuEntrySetWrap_TYPE)(DebugMenuEntry *e, bool wrap); 20 | typedef void (*DebugMenuEntrySetStrings_TYPE)(DebugMenuEntry *e, const char **strings); 21 | typedef void (*DebugMenuEntrySetAddress_TYPE)(DebugMenuEntry *e, void *addr); 22 | 23 | struct DebugMenuAPI 24 | { 25 | bool isLoaded; 26 | HMODULE module; 27 | DebugMenuAddInt8_TYPE addint8; 28 | DebugMenuAddInt16_TYPE addint16; 29 | DebugMenuAddInt32_TYPE addint32; 30 | DebugMenuAddInt64_TYPE addint64; 31 | DebugMenuAddUInt8_TYPE adduint8; 32 | DebugMenuAddUInt16_TYPE adduint16; 33 | DebugMenuAddUInt32_TYPE adduint32; 34 | DebugMenuAddUInt64_TYPE adduint64; 35 | DebugMenuAddFloat32_TYPE addfloat32; 36 | DebugMenuAddFloat64_TYPE addfloat64; 37 | DebugMenuAddCmd_TYPE addcmd; 38 | DebugMenuEntrySetWrap_TYPE setwrap; 39 | DebugMenuEntrySetStrings_TYPE setstrings; 40 | DebugMenuEntrySetAddress_TYPE setaddress; 41 | }; 42 | extern DebugMenuAPI gDebugMenuAPI; 43 | 44 | inline DebugMenuEntry *DebugMenuAddInt8(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings) 45 | { return gDebugMenuAPI.addint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 46 | inline DebugMenuEntry *DebugMenuAddInt16(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings) 47 | { return gDebugMenuAPI.addint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 48 | inline DebugMenuEntry *DebugMenuAddInt32(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings) 49 | { return gDebugMenuAPI.addint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 50 | inline DebugMenuEntry *DebugMenuAddInt64(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings) 51 | { return gDebugMenuAPI.addint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 52 | inline DebugMenuEntry *DebugMenuAddUInt8(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings) 53 | { return gDebugMenuAPI.adduint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 54 | inline DebugMenuEntry *DebugMenuAddUInt16(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings) 55 | { return gDebugMenuAPI.adduint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 56 | inline DebugMenuEntry *DebugMenuAddUInt32(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings) 57 | { return gDebugMenuAPI.adduint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 58 | inline DebugMenuEntry *DebugMenuAddUInt64(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings) 59 | { return gDebugMenuAPI.adduint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 60 | inline DebugMenuEntry *DebugMenuAddFloat32(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound) 61 | { return gDebugMenuAPI.addfloat32(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } 62 | inline DebugMenuEntry *DebugMenuAddFloat64(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound) 63 | { return gDebugMenuAPI.addfloat64(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } 64 | inline DebugMenuEntry *DebugMenuAddCmd(const char *path, const char *name, TriggerFunc triggerFunc) 65 | { return gDebugMenuAPI.addcmd(path, name, triggerFunc); } 66 | inline void DebugMenuEntrySetWrap(DebugMenuEntry *e, bool wrap) 67 | { gDebugMenuAPI.setwrap(e, wrap); } 68 | inline void DebugMenuEntrySetStrings(DebugMenuEntry *e, const char **strings) 69 | { gDebugMenuAPI.setstrings(e, strings); } 70 | inline void DebugMenuEntrySetAddress(DebugMenuEntry *e, void *addr) 71 | { gDebugMenuAPI.setaddress(e, addr); } 72 | 73 | inline bool DebugMenuLoad(void) 74 | { 75 | if(gDebugMenuAPI.isLoaded) 76 | return true; 77 | HMODULE mod = LoadLibraryA("debugmenu"); 78 | if(mod == 0){ 79 | char modulePath[MAX_PATH]; 80 | HMODULE dllModule; 81 | GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR)&gDebugMenuAPI, &dllModule); 82 | GetModuleFileNameA(dllModule, modulePath, MAX_PATH); 83 | char *p = strchr(modulePath, '\\'); 84 | if(p) p[1] = '\0'; 85 | strcat(modulePath, "debugmenu"); 86 | mod = LoadLibraryA(modulePath); 87 | } 88 | if(mod == 0) 89 | return false; 90 | gDebugMenuAPI.addint8 = (DebugMenuAddInt8_TYPE)GetProcAddress(mod, "DebugMenuAddInt8"); 91 | gDebugMenuAPI.addint16 = (DebugMenuAddInt16_TYPE)GetProcAddress(mod, "DebugMenuAddInt16"); 92 | gDebugMenuAPI.addint32 = (DebugMenuAddInt32_TYPE)GetProcAddress(mod, "DebugMenuAddInt32"); 93 | gDebugMenuAPI.addint64 = (DebugMenuAddInt64_TYPE)GetProcAddress(mod, "DebugMenuAddInt64"); 94 | gDebugMenuAPI.adduint8 = (DebugMenuAddUInt8_TYPE)GetProcAddress(mod, "DebugMenuAddUInt8"); 95 | gDebugMenuAPI.adduint16 = (DebugMenuAddUInt16_TYPE)GetProcAddress(mod, "DebugMenuAddUInt16"); 96 | gDebugMenuAPI.adduint32 = (DebugMenuAddUInt32_TYPE)GetProcAddress(mod, "DebugMenuAddUInt32"); 97 | gDebugMenuAPI.adduint64 = (DebugMenuAddUInt64_TYPE)GetProcAddress(mod, "DebugMenuAddUInt64"); 98 | gDebugMenuAPI.addfloat32 = (DebugMenuAddFloat32_TYPE)GetProcAddress(mod, "DebugMenuAddFloat32"); 99 | gDebugMenuAPI.addfloat64 = (DebugMenuAddFloat64_TYPE)GetProcAddress(mod, "DebugMenuAddFloat64"); 100 | gDebugMenuAPI.addcmd = (DebugMenuAddCmd_TYPE)GetProcAddress(mod, "DebugMenuAddCmd"); 101 | gDebugMenuAPI.setwrap = (DebugMenuEntrySetWrap_TYPE)GetProcAddress(mod, "DebugMenuEntrySetWrap"); 102 | gDebugMenuAPI.setstrings = (DebugMenuEntrySetStrings_TYPE)GetProcAddress(mod, "DebugMenuEntrySetStrings"); 103 | gDebugMenuAPI.setaddress = (DebugMenuEntrySetAddress_TYPE)GetProcAddress(mod, "DebugMenuEntrySetAddress"); 104 | gDebugMenuAPI.isLoaded = true; 105 | gDebugMenuAPI.module = mod; 106 | return true; 107 | } 108 | 109 | } 110 | 111 | // Also overload them for simplicity 112 | 113 | inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings) 114 | { return gDebugMenuAPI.addint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 115 | inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings) 116 | { return gDebugMenuAPI.addint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 117 | inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings) 118 | { return gDebugMenuAPI.addint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 119 | inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings) 120 | { return gDebugMenuAPI.addint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 121 | inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings) 122 | { return gDebugMenuAPI.adduint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 123 | inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings) 124 | { return gDebugMenuAPI.adduint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 125 | inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings) 126 | { return gDebugMenuAPI.adduint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 127 | inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings) 128 | { return gDebugMenuAPI.adduint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } 129 | inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound) 130 | { return gDebugMenuAPI.addfloat32(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } 131 | inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound) 132 | { return gDebugMenuAPI.addfloat64(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } 133 | 134 | inline DebugMenuEntry *DebugMenuAddVarBool32(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc) 135 | { 136 | static const char *boolstr[] = { "Off", "On" }; 137 | DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr); 138 | DebugMenuEntrySetWrap(e, true); 139 | return e; 140 | } 141 | inline DebugMenuEntry *DebugMenuAddVarBool16(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc) 142 | { 143 | static const char *boolstr[] = { "Off", "On" }; 144 | DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr); 145 | DebugMenuEntrySetWrap(e, true); 146 | return e; 147 | } 148 | inline DebugMenuEntry *DebugMenuAddVarBool8(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc) 149 | { 150 | static const char *boolstr[] = { "Off", "On" }; 151 | DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr); 152 | DebugMenuEntrySetWrap(e, true); 153 | return e; 154 | } 155 | -------------------------------------------------------------------------------- /SACarCam/GInputAPI.h: -------------------------------------------------------------------------------- 1 | #ifndef __GINPUTAPI 2 | #define __GINPUTAPI 3 | 4 | // GInput 1.11 API file 5 | 6 | // With this little API prepared for C++, you can take advantage of some GInput features 7 | // For functions list, scroll down to the interface declaration 8 | 9 | 10 | // As this API file is compatible with GInputIII. GInputVC and GInputSA, you need to declare 11 | // whether to compile III version, VC version, SA version, or a cross-compatible version 12 | 13 | // The API doesn't target a specific game by default - you need one of those four defines in order for API to work correctly: 14 | 15 | // To target GTA III, define GINPUT_COMPILE_III_VERSION in your project settings, code headers or just 16 | // uncomment the line below 17 | //#define GINPUT_COMPILE_III_VERSION 18 | 19 | // To target GTA VC, define GINPUT_COMPILE_VC_VERSION in your project settings, code headers or just 20 | // uncomment the line below 21 | //#define GINPUT_COMPILE_VC_VERSION 22 | 23 | // To target GTA SA, define GINPUT_COMPILE_SA_VERSION in your project settings, code headers or just 24 | // uncomment the line below 25 | //#define GINPUT_COMPILE_SA_VERSION 26 | 27 | // You can also target all three games at once by defining GINPUT_COMPILE_CROSSCOMPATIBLE_VERSION - define it 28 | // in your project settings, code headers or just uncomment the line below 29 | #define GINPUT_COMPILE_CROSSCOMPATIBLE_VERSION 30 | 31 | enum eGInputEvent 32 | { 33 | GINPUT_NO_EVENT = -1, // DON'T USE, internal use only 34 | 35 | GINPUT_EVENT_CHANGE_RADIO_STATION = 0, // Returns NULL all the time, pParam specifies whether to set 36 | // next or previous radio station (0 for next station, 1 for previous) 37 | // Callable from SendEvent: YES 38 | // Callable from SendConstEvent: NO 39 | 40 | GINPUT_EVENT_CHANGE_USER_TRACK = 1, // Returns NULL all the time, pParam specifies whether to set 41 | // next or previous MP3 (0 for next MP3, 1 for previous) 42 | // Callable from SendEvent: YES 43 | // Callable from SendConstEvent: NO 44 | 45 | GINPUT_EVENT_REGISTER_SETTINGS_RELOAD_CALLBACK = 2, // Registers a callback function which gets called after GInput*.ini gets reloaded 46 | // after WM_SETFOCUS gets called. Returns NULL. pParam should be a callback function 47 | // pointer (see GInputOnSettingsReloadCallback) 48 | // Cannot be recursive - the callbacks registered from within a callback will be ignored 49 | // Callable from SendEvent: YES 50 | // Callable from SendConstEvent: NO 51 | 52 | GINPUT_EVENT_FETCH_SETTINGS = 3, // DEPRECATED EVENT, DO NOT USE 53 | 54 | GINPUT_EVENT_FETCH_CHEAT_STRING = 4, // Copies the current cheat string to a char array sent via pParam. 55 | // pParam should point to an array of at least GINPUT_CHEAT_STRING_LENGTH characters 56 | // or a buffer overflow will occur. 57 | // Returns a value of type BOOL - when set to TRUE, cheat string has been changed since 58 | // the last frame - useful for determining when to re-check for a custom cheat combo 59 | // Letters from a cheat string are assigned to buttons as follows: 60 | // U - DPad Up, D - DPad Down, L - DPad Left, R - DPad Right 61 | // T - Y/Triangle, C - B/Circle, X - A/Cross, S - X/Square 62 | // 1 - L1/LB, 2 - L2/LT, 3 - R1/RB, 4 - R2/RT 63 | // Callable from SendEvent: YES 64 | // Callable from SendConstEvent: YES 65 | 66 | GINPUT_EVENT_RELOAD_WEAPON = 5, // Reloads the weapon player is holding 67 | // Supported only in SA 68 | // Callable from SendEvent: YES 69 | // Callable from SendConstEvent: NO 70 | 71 | GINPUT_EVENT_FETCH_GENERAL_SETTINGS = 6, // Fetches a structure filled with GInput general settings 72 | // pParam should point to a GINPUT_GENERAL_SETTINGS structure 73 | // Structure's cbSize field should equal sizeof(GINPUT_GENERAL_SETTINGS) 74 | // Callable from SendEvent: YES 75 | // Callable from SendConstEvent: YES 76 | 77 | GINPUT_EVENT_FETCH_PAD_SETTINGS = 7, // Fetches a structure filled with GInput ped-specific settings 78 | // pParam should point to a GINPUT_PAD_SETTINGS structure 79 | // Structure's cbSize field should equal sizeof(GINPUT_PAD_SETTINGS) 80 | // Callable from SendEvent: YES 81 | // Callable from SendConstEvent: YES 82 | 83 | GINPUT_EVENT_FETCH_SIXAXIS_INPUT = 8, // Fetches a structure filled with last frame's Sixaxis input 84 | // pParam should point to a SIXAXIS_INPUT structure 85 | // If Sixaxis is not supported, this struct will always contain zeroes 86 | // Callable from SendEvent: YES 87 | // Callable from SendConstEvent: YES 88 | 89 | GINPUT_EVENT_REGISTER_SIXAXIS_FETCH_CALLBACK = 9, // Registers a callback function which gets called after Sixaxis sends input 90 | // pParam should be a callback function pointer (see GInputOnSixaxisFetchCallback) 91 | // Cannot be recursive - the callbacks registered from within a callback will be ignored 92 | // Callable from SendEvent: YES 93 | // Callable from SendConstEvent: NO 94 | 95 | GINPUT_EVENT_IS_USING_SCP_DRIVER_CAPABILITIES = 10, // Checks if the game uses the pressure sensitive buttons feature, exclusive to 96 | // SCP Driver Package. 97 | // Returns BOOL - if TRUE, both SCP's xinput1_3.dll and a controller with pressure sensitive 98 | // face buttons (ie. DualShock 3) is used, FALSE otherwise. 99 | // Can be also used to determine whether Sixaxis is available or not 100 | // Callable from SendEvent: YES 101 | // Callable from SendConstEvent: YES 102 | 103 | GINPUT_EVENT_OVERRIDE_SIXAXIS_SETTINGS = 11, // Overrides all Sixaxis toggles. 104 | // if pParam is set to TRUE, the override gets enabled. If pParam is set to FALSE, 105 | // the override gets disabled. 106 | // Returns NULL all the time 107 | // Callable from SendEvent: YES 108 | // Callable from SendConstEvent: NO 109 | 110 | GINPUT_EVENT_FORCE_MAP_PAD_ONE_TO_PAD_TWO = 12, // Forcibly maps XInput pad 2 to game pad 1, same as "MapPadOneToPadTwo" INI option 111 | // if pParam is set to TRUE, the override gets enabled. If pParam is set to FALSE, 112 | // the override gets disabled. 113 | // Returns NULL all the time 114 | // Callable from SendEvent: YES 115 | // Callable from SendConstEvent: NO 116 | 117 | NUM_GINPUT_EVENTS 118 | }; 119 | 120 | struct SIXAXIS_INPUT 121 | { 122 | short ACCEL_X; 123 | short ACCEL_Y; 124 | short ACCEL_Z; 125 | 126 | short GYRO; 127 | }; 128 | 129 | // Those are options from [GInput] section 130 | // The options not present in the particular game are always 0 131 | struct GINPUT_GENERAL_SETTINGS 132 | { 133 | DWORD cbSize; // Fill with sizeof(GINPUT_GENERAL_SETTINGS) 134 | 135 | bool DisableOnFocusLost : 1; 136 | bool Vibration : 1; 137 | bool CheatsFromPad : 1; 138 | bool GuideLaunchesOverlay : 1; 139 | bool ApplyMissionSpecificFixes : 1; 140 | bool ApplyGXTFixes : 1; 141 | bool PlayStationButtons : 1; 142 | bool MapPadOneToPadTwo : 1; 143 | bool FreeAim : 1; 144 | 145 | }; 146 | 147 | // Those are options from [PadX] section 148 | // The options not present in the particular game are always 0 149 | struct GINPUT_PAD_SETTINGS 150 | { 151 | DWORD cbSize; // Fill with sizeof(GINPUT_PAD_SETTINGS) 152 | 153 | BYTE ControlsSet : 4; 154 | bool Southpaw : 1; 155 | bool SAStyleSniperZoom : 1; 156 | bool SwapSticksDuringAiming : 1; 157 | bool DrivebyWithAnalog : 1; 158 | bool HotkeyToDriveby : 1; 159 | bool InvertLook : 1; 160 | 161 | bool InvertLeftXAxis : 1; 162 | bool InvertLeftYAxis : 1; 163 | bool SwapLeftAxes : 1; 164 | float LeftStickDeadzone; 165 | float LeftStickSensitivity; 166 | 167 | bool InvertRightXAxis : 1; 168 | bool InvertRightYAxis : 1; 169 | bool SwapRightAxes : 1; 170 | float RightStickDeadzone; 171 | float RightStickSensitivity; 172 | 173 | float FaceButtonsSensitivity; 174 | float SixaxisSensitivity; 175 | bool SixaxisReloading : 1; 176 | bool SixaxisCarSteering : 1; 177 | bool SixaxisBikeSteering : 1; 178 | bool SixaxisBoatSteering : 1; 179 | bool SixaxisHeliSteering : 1; 180 | bool SixaxisPlaneSteering : 1; 181 | bool SixaxisHydraulics : 1; 182 | }; 183 | 184 | // The size of a char array returned from GINPUT_FETCH_CHEAT_STRING 185 | #define GINPUT_CHEAT_STRING_LENGTH 12 186 | 187 | // Callback called on INI file reload 188 | // Note - it is NOT called the first time INIs are loaded 189 | typedef void (*GInputOnSettingsReloadCallback)(); 190 | 191 | // Callback called when Sixaxis data gets fetched and processed by GInput 192 | // Gets called ONLY on input change 193 | typedef void (CALLBACK *GInputOnSixaxisFetchCallback)(const SIXAXIS_INPUT&); 194 | 195 | 196 | 197 | // Internal declarations 198 | #ifndef GINPUT_COMPILE_CROSSCOMPATIBLE_VERSION 199 | #if defined GINPUT_COMPILE_III_VERSION 200 | #define GINPUT_FILENAMEA "GInputIII" 201 | #define GINPUT_FILENAMEW L"GInputIII" 202 | #elif defined GINPUT_COMPILE_VC_VERSION 203 | #define GINPUT_FILENAMEA "GInputVC" 204 | #define GINPUT_FILENAMEW L"GInputVC" 205 | #elif defined GINPUT_COMPILE_SA_VERSION 206 | #define GINPUT_FILENAMEA "GInputSA" 207 | #define GINPUT_FILENAMEW L"GInputSA" 208 | #endif 209 | 210 | #ifdef UNICODE 211 | #define GINPUT_FILENAME GINPUT_FILENAMEW 212 | #else 213 | #define GINPUT_FILENAME GINPUT_FILENAMEA 214 | #endif 215 | 216 | #endif 217 | 218 | #define GINPUT_MODVERSION 0x00010B00 // 1.11 219 | 220 | // The pad interface 221 | // The interface is safe to use without validating a pointer - in case of GInput loading failure, 222 | // these functions are set to return false all the time 223 | // NOTE: Do not use any of these functions before GInput_Load is called on your interface pointer! 224 | class IGInputPad 225 | { 226 | protected: 227 | virtual ~IGInputPad() { }; 228 | 229 | public: 230 | // Returns true when XInput compatible pad is connected 231 | virtual bool IsPadConnected() const =0; 232 | 233 | // Returns true when last input came from a pad, false otherwise 234 | virtual bool HasPadInHands() const =0; 235 | 236 | // Returns installed GInput version (see GINPUT_MODVERSION), -1 on failure 237 | virtual int GetVersion() const =0; 238 | 239 | // Sends an event to GInput, allowing the script to take advantage of GInput features not available 240 | // through CPad or other original GTA functions 241 | // See eGInputEvent enum for supported events and their params/return values (if any) 242 | virtual void* SendEvent(eGInputEvent eEvent, void* pParam)=0; 243 | virtual void* SendConstEvent(eGInputEvent eEvent, void* pParam) const =0; 244 | }; 245 | 246 | // GInput management functions 247 | 248 | // Use one of those functions ONCE to initialise GInput API 249 | // DO NOT use both functions in the same plugin! 250 | // DO NOT CALL THOSE IN DLLMAIN, SINCE GINPUT MIGHT NOT BE INITIALIZED YET AT THE TIME YOUR PLUGIN LOADS 251 | // Takes a pointer to pad interface pointer as an argument, returns true if succeed and false otherwise 252 | // (GInput not installed or any other error occured) 253 | bool GInput_Load(IGInputPad** pInterfacePtr); 254 | // Takes a pointer to an array of TWO interface pointers as an argument, returns true if succeed and false otherwise 255 | // (GInput not installed or any other error occured) 256 | bool GInput_Load_TwoPads(IGInputPad** pInterfacePtr); 257 | 258 | // Releases GInput API 259 | // Call it when your program terminates 260 | void GInput_Release(); 261 | 262 | 263 | // Management functions definitions - internal use only, do not change anything here 264 | #include 265 | #include "ModuleList.hpp" 266 | 267 | // GInput ASI handle 268 | inline HMODULE* _GInput_HandlePtr() 269 | { 270 | // Making it a static variable outside of the function would duplicate it for each .cpp file which uses any API funcs (bad) 271 | static HMODULE hGInputHandle = nullptr; 272 | return &hGInputHandle; 273 | } 274 | 275 | // Although these functions may not be inlined, we need to declare them as so 276 | inline IGInputPad* _GInput_SafeMode() 277 | { 278 | static class CDummyPad : public IGInputPad 279 | { 280 | public: 281 | virtual bool IsPadConnected() const { return false; }; 282 | virtual bool HasPadInHands() const { return false; }; 283 | virtual int GetVersion() const { return -1; }; 284 | virtual void* SendEvent(eGInputEvent eEvent, void* pParam) { return CDummyPad::SendConstEvent(eEvent, pParam); }; 285 | virtual void* SendConstEvent(eGInputEvent eEvent, void* pParam) const { 286 | UNREFERENCED_PARAMETER(eEvent); UNREFERENCED_PARAMETER(pParam); 287 | SetLastError(ERROR_NOT_SUPPORTED); 288 | return reinterpret_cast(GINPUT_NO_EVENT); 289 | }; 290 | } DummyClass; 291 | return &DummyClass; 292 | } 293 | 294 | inline bool GInput_Load(IGInputPad** pInterfacePtr) 295 | { 296 | static IGInputPad* pCopiedPtr = nullptr; // We keep a backup of the interface pointer in case user calls GInput_Load multiple times 297 | static bool bLoadingResult = false; // Loading result is also cached so GInput_Load always returns the same value when called multiple times 298 | 299 | // Have we attempted to load GInput already? If so, just return a valid interface pointer and return 300 | // The pointer can be either a GInput interface or a dummy, 'safe-mode' interface which got initialised 301 | // due to GInput*.asi loading failure 302 | if ( pCopiedPtr != nullptr ) 303 | { 304 | *pInterfacePtr = pCopiedPtr; 305 | return bLoadingResult; 306 | } 307 | 308 | #ifdef GINPUT_COMPILE_CROSSCOMPATIBLE_VERSION 309 | for ( const HMODULE hHandle : ModuleList().GetAllByPrefix( L"GInput" ) ) 310 | #else 311 | const HMODULE hHandle = ModuleList().Get( GINPUT_FILENAMEW ); 312 | #endif 313 | { 314 | if ( hHandle != nullptr ) 315 | { 316 | // Let's call a GInput export to get the proper interface 317 | auto ExportFunc = (IGInputPad*(*)())GetProcAddress(hHandle, "GetGInputInterface"); 318 | if ( ExportFunc == nullptr ) 319 | { 320 | ExportFunc = (IGInputPad*(*)())GetProcAddress(hHandle, (LPCSTR)1); 321 | } 322 | 323 | if ( ExportFunc != nullptr ) 324 | { 325 | *pInterfacePtr = pCopiedPtr = ExportFunc(); 326 | if ( pCopiedPtr != nullptr ) 327 | { 328 | HMODULE duplicatedHandle; 329 | if ( GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)ExportFunc, &duplicatedHandle ) != 0 ) 330 | { 331 | *_GInput_HandlePtr() = duplicatedHandle; 332 | bLoadingResult = true; 333 | return true; 334 | } 335 | } 336 | } 337 | } 338 | } 339 | 340 | *pInterfacePtr = pCopiedPtr = _GInput_SafeMode(); 341 | bLoadingResult = false; 342 | return false; 343 | } 344 | 345 | inline bool GInput_Load_TwoPads(IGInputPad** pInterfacePtr) 346 | { 347 | static IGInputPad* pCopiedPtr[2]; // We keep a backup of the interface pointer in case user calls GInput_Load multiple times 348 | static bool bLoadingResult = false; // Loading result is also cached so GInput_Load always returns the same value when called multiple times 349 | 350 | // Have we attempted to load GInput already? If so, just return a valid interface pointer and return 351 | // The pointer can be either a GInput interface or a dummy, 'safe-mode' interface which got initialised 352 | // due to GInput*.asi loading failure 353 | if ( pCopiedPtr[0] != nullptr && pCopiedPtr[1] != nullptr ) 354 | { 355 | pInterfacePtr[0] = pCopiedPtr[0]; 356 | pInterfacePtr[1] = pCopiedPtr[1]; 357 | return bLoadingResult; 358 | } 359 | 360 | #ifdef GINPUT_COMPILE_CROSSCOMPATIBLE_VERSION 361 | for ( const HMODULE hHandle : ModuleList().GetAllByPrefix( L"GInput" ) ) 362 | #else 363 | const HMODULE hHandle = ModuleList().Get( GINPUT_FILENAMEW ); 364 | #endif 365 | { 366 | if ( hHandle != nullptr ) 367 | { 368 | // Let's call a GInput export to get the proper interface 369 | auto ExportFunc = (IGInputPad**(*)())GetProcAddress(hHandle, "GetGInputInterface_2Pads"); 370 | if ( ExportFunc == nullptr ) 371 | { 372 | ExportFunc = (IGInputPad**(*)())GetProcAddress(hHandle, (LPCSTR)2); 373 | } 374 | 375 | if ( ExportFunc != nullptr ) 376 | { 377 | IGInputPad** pad = ExportFunc(); 378 | pInterfacePtr[0] = pCopiedPtr[0] = pad[0]; 379 | pInterfacePtr[1] = pCopiedPtr[1] = pad[1]; 380 | if ( pCopiedPtr[0] != nullptr && pCopiedPtr[1] != nullptr ) 381 | { 382 | HMODULE duplicatedHandle; 383 | if ( GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)ExportFunc, &duplicatedHandle ) != 0 ) 384 | { 385 | *_GInput_HandlePtr() = duplicatedHandle; 386 | bLoadingResult = true; 387 | return true; 388 | } 389 | } 390 | } 391 | } 392 | } 393 | 394 | IGInputPad* pad = _GInput_SafeMode(); 395 | pInterfacePtr[0] = pCopiedPtr[0] = pad; 396 | pInterfacePtr[1] = pCopiedPtr[1] = pad; 397 | bLoadingResult = false; 398 | return false; 399 | } 400 | 401 | inline void GInput_Release() 402 | { 403 | HMODULE* pHandle = _GInput_HandlePtr(); 404 | if ( *pHandle != nullptr ) 405 | { 406 | FreeLibrary(*pHandle); 407 | *pHandle = nullptr; 408 | } 409 | } 410 | 411 | #endif -------------------------------------------------------------------------------- /SACarCam/GTA.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Many, many thanks to GTAForums community and re3 project, all of these headers are taken from there. 4 | 5 | class CPed; 6 | class CAutomobile; 7 | 8 | extern int previousMode; 9 | 10 | class CVector 11 | { 12 | public: 13 | float x, y, z; 14 | CVector(void) {} 15 | CVector(float x, float y, float z) : x(x), y(y), z(z) {} 16 | 17 | // (0,1,0) means no rotation. So get right vector and its atan 18 | float Heading(void) const { return atan2f(-x, y); } 19 | float Magnitude(void) const { return sqrtf(x * x + y * y + z * z); } 20 | float MagnitudeSqr(void) const { return x * x + y * y + z * z; } 21 | float Magnitude2D(void) const { return sqrtf(x * x + y * y); } 22 | float MagnitudeSqr2D(void) const { return x * x + y * y; } 23 | void Normalise(void) { 24 | float sq = MagnitudeSqr(); 25 | if (sq > 0.0f) { 26 | float invsqrt = RecipSqrt(sq); 27 | x *= invsqrt; 28 | y *= invsqrt; 29 | z *= invsqrt; 30 | } 31 | else 32 | x = 1.0f; 33 | } 34 | 35 | const CVector& operator+=(CVector const& right) { 36 | x += right.x; 37 | y += right.y; 38 | z += right.z; 39 | return *this; 40 | } 41 | 42 | const CVector& operator-=(CVector const& right) { 43 | x -= right.x; 44 | y -= right.y; 45 | z -= right.z; 46 | return *this; 47 | } 48 | 49 | const CVector& operator*=(float right) { 50 | x *= right; 51 | y *= right; 52 | z *= right; 53 | return *this; 54 | } 55 | 56 | const CVector& operator/=(float right) { 57 | x /= right; 58 | y /= right; 59 | z /= right; 60 | return *this; 61 | } 62 | 63 | CVector operator-() const { 64 | return CVector(-x, -y, -z); 65 | } 66 | 67 | const bool operator==(CVector const& right) { 68 | return x == right.x && y == right.y && z == right.z; 69 | } 70 | 71 | bool IsZero(void) { return x == 0.0f && y == 0.0f && z == 0.0f; } 72 | }; 73 | 74 | inline float 75 | DotProduct(const CVector& v1, const CVector& v2) 76 | { 77 | return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; 78 | } 79 | 80 | inline CVector 81 | CrossProduct(const CVector& v1, const CVector& v2) 82 | { 83 | return CVector( 84 | v1.y * v2.z - v1.z * v2.y, 85 | v1.z * v2.x - v1.x * v2.z, 86 | v1.x * v2.y - v1.y * v2.x); 87 | } 88 | 89 | inline CVector operator+(const CVector& left, const CVector& right) 90 | { 91 | return CVector(left.x + right.x, left.y + right.y, left.z + right.z); 92 | } 93 | 94 | inline CVector operator-(const CVector& left, const CVector& right) 95 | { 96 | return CVector(left.x - right.x, left.y - right.y, left.z - right.z); 97 | } 98 | 99 | inline CVector operator*(const CVector& left, float right) 100 | { 101 | return CVector(left.x * right, left.y * right, left.z * right); 102 | } 103 | 104 | inline CVector operator*(float left, const CVector& right) 105 | { 106 | return CVector(left * right.x, left * right.y, left * right.z); 107 | } 108 | 109 | inline CVector operator/(const CVector& left, float right) 110 | { 111 | return CVector(left.x / right, left.y / right, left.z / right); 112 | } 113 | 114 | 115 | class CVector2D 116 | { 117 | public: 118 | float x, y; 119 | CVector2D(void) {} 120 | CVector2D(float x, float y) : x(x), y(y) {} 121 | CVector2D(const CVector& v) : x(v.x), y(v.y) {} 122 | float Heading(void) const { return atan2f(-x, y); } 123 | float Magnitude(void) const { return sqrtf(x * x + y * y); } 124 | float MagnitudeSqr(void) const { return x * x + y * y; } 125 | 126 | void Normalise(void) { 127 | float sq = MagnitudeSqr(); 128 | if (sq > 0.0f) { 129 | float invsqrt = RecipSqrt(sq); 130 | x *= invsqrt; 131 | y *= invsqrt; 132 | } 133 | else 134 | x = 1.0f; 135 | } 136 | const CVector2D& operator+=(CVector2D const& right) { 137 | x += right.x; 138 | y += right.y; 139 | return *this; 140 | } 141 | 142 | const CVector2D& operator-=(CVector2D const& right) { 143 | x -= right.x; 144 | y -= right.y; 145 | return *this; 146 | } 147 | 148 | const CVector2D& operator*=(float right) { 149 | x *= right; 150 | y *= right; 151 | return *this; 152 | } 153 | 154 | const CVector2D& operator/=(float right) { 155 | x /= right; 156 | y /= right; 157 | return *this; 158 | } 159 | CVector2D operator-(const CVector2D& rhs) const { 160 | return CVector2D(x - rhs.x, y - rhs.y); 161 | } 162 | CVector2D operator+(const CVector2D& rhs) const { 163 | return CVector2D(x + rhs.x, y + rhs.y); 164 | } 165 | CVector2D operator*(float t) const { 166 | return CVector2D(x * t, y * t); 167 | } 168 | CVector2D operator/(float t) const { 169 | return CVector2D(x / t, y / t); 170 | } 171 | }; 172 | 173 | struct CColSphereIII 174 | { 175 | CVector center; 176 | float radius; 177 | uint8 surface; 178 | uint8 piece; 179 | }; 180 | 181 | struct CColSphereVC 182 | { 183 | CVector center; 184 | float radius; 185 | }; 186 | 187 | struct CColBoxIII 188 | { 189 | CVector min; 190 | CVector max; 191 | uint8 surface; 192 | uint8 piece; 193 | }; 194 | 195 | struct CColBoxVC 196 | { 197 | CVector min; 198 | CVector max; 199 | }; 200 | 201 | struct CColLine 202 | { 203 | CVector p0; 204 | int pad0; 205 | CVector p1; 206 | int pad1; 207 | }; 208 | 209 | struct CColTriangle 210 | { 211 | uint16 a; 212 | uint16 b; 213 | uint16 c; 214 | uint8 surface; 215 | }; 216 | 217 | struct CColTrianglePlane 218 | { 219 | CVector normal; 220 | float dist; 221 | uint8 dir; 222 | }; 223 | 224 | struct CColPoint 225 | { 226 | CVector point; 227 | int pad1; 228 | // the surface normal on the surface of point 229 | CVector normal; 230 | int pad2; 231 | uint8 surfaceA; 232 | uint8 pieceA; 233 | uint8 surfaceB; 234 | uint8 pieceB; 235 | float depth; 236 | }; 237 | 238 | class CColModelVC { 239 | public: 240 | CColSphereVC boundingSphere; 241 | CColBoxVC boundingBox; 242 | unsigned short m_nNumSpheres; 243 | unsigned short m_nNumBoxes; 244 | unsigned short m_nNumTriangles; 245 | unsigned char m_nNumLines; 246 | unsigned char m_nColStoreIndex; 247 | bool m_bLoaded; 248 | char _pad31[3]; 249 | CColSphereVC* m_pSpheres; 250 | void* m_pLines; 251 | CColBoxVC* m_pBoxes; 252 | void* m_pVertices; 253 | void* m_pTriangles; 254 | void* m_pTrianglePlanes; 255 | }; 256 | 257 | struct CColModelIII 258 | { 259 | CColSphereIII boundingSphere; 260 | CColBoxIII boundingBox; 261 | short numSpheres; 262 | short numLines; 263 | short numBoxes; 264 | short numTriangles; 265 | int level; 266 | bool ownsCollisionVolumes; 267 | CColSphereIII* spheres; 268 | CColLine* lines; 269 | CColBoxIII* boxes; 270 | CVector* vertices; 271 | CColTriangle* triangles; 272 | CColTrianglePlane* trianglePlanes; 273 | 274 | ~CColModelIII(void) { }; 275 | }; 276 | 277 | // This is III one, not same in VC but it doesn't matter 278 | class CBaseModelInfo 279 | { 280 | public: 281 | char m_name[24]; 282 | void* m_colModel; 283 | void* m_twodEffects; 284 | int16 m_objectId; 285 | 286 | uint16 m_refCount; 287 | int16 m_txdSlot; 288 | uint8 m_type; 289 | uint8 m_num2dEffects; 290 | bool m_freeCol; 291 | 292 | virtual ~CBaseModelInfo() {}; 293 | 294 | void* GetColModel(void) { return m_colModel; } 295 | }; 296 | 297 | static_assert(sizeof(CBaseModelInfo) == 0x30, "CBaseModelInfo: error"); 298 | 299 | class CModelInfo 300 | { 301 | static CBaseModelInfo** ms_modelInfoPtrs; 302 | public: 303 | static CBaseModelInfo* GetModelInfo(int id) { 304 | return ms_modelInfoPtrs[id]; 305 | } 306 | }; 307 | 308 | struct RwMatrix 309 | { 310 | CVector right; 311 | uint32 flags; 312 | CVector up; 313 | uint32 pad1; 314 | CVector at; 315 | uint32 pad2; 316 | CVector pos; 317 | uint32 pad3; 318 | }; 319 | 320 | class CMatrix 321 | { 322 | public: 323 | RwMatrix m_matrix; 324 | RwMatrix* m_attachment; 325 | bool m_hasRwMatrix; // are we the owner? 326 | 327 | CMatrix(void) { 328 | m_attachment = nil; 329 | m_hasRwMatrix = false; 330 | } 331 | void SetRotateZOnly(float angle) { 332 | float c = cosf(angle); 333 | float s = sinf(angle); 334 | 335 | m_matrix.right.x = c; 336 | m_matrix.right.y = s; 337 | m_matrix.right.z = 0.0f; 338 | 339 | m_matrix.up.x = -s; 340 | m_matrix.up.y = c; 341 | m_matrix.up.z = 0.0f; 342 | 343 | m_matrix.at.x = 0.0f; 344 | m_matrix.at.y = 0.0f; 345 | m_matrix.at.z = 1.0f; 346 | } 347 | void SetRotateZ(float angle) { 348 | SetRotateZOnly(angle); 349 | m_matrix.pos.x = 0.0f; 350 | m_matrix.pos.y = 0.0f; 351 | m_matrix.pos.z = 0.0f; 352 | } 353 | void Attach(RwMatrix* matrix, bool owner = false); 354 | void UpdateRW(void); 355 | 356 | CVector& GetPosition(void) { return *(CVector*)& m_matrix.pos; } 357 | CVector& GetRight(void) { return *(CVector*)& m_matrix.right; } 358 | CVector& GetForward(void) { return *(CVector*)& m_matrix.up; } 359 | CVector& GetUp(void) { return *(CVector*)& m_matrix.at; } 360 | }; 361 | 362 | // Without vtbl. Used for CCameraVC 363 | class CPlaceableVC 364 | { 365 | public: 366 | CMatrix m_matrix; 367 | 368 | CVector& GetPosition(void) { return m_matrix.GetPosition(); } 369 | CVector& GetRight(void) { return m_matrix.GetRight(); } 370 | CVector& GetForward(void) { return m_matrix.GetForward(); } 371 | CVector& GetUp(void) { return m_matrix.GetUp(); } 372 | CMatrix& GetMatrix(void) { return m_matrix; } 373 | }; 374 | 375 | // Interchangable between III-VC, but the child class should also have virtual func. (Which isn't a case in CCameraVC) 376 | class CPlaceable 377 | { 378 | public: 379 | CMatrix m_matrix; 380 | 381 | virtual ~CPlaceable(void) { }; 382 | CVector& GetPosition(void) { return m_matrix.GetPosition(); } 383 | CVector& GetRight(void) { return m_matrix.GetRight(); } 384 | CVector& GetForward(void) { return m_matrix.GetForward(); } 385 | CVector& GetUp(void) { return m_matrix.GetUp(); } 386 | CMatrix& GetMatrix(void) { return m_matrix; } 387 | }; 388 | static_assert(sizeof(CPlaceable) == 0x4C, "CPlaceable: error"); 389 | 390 | struct CReference; 391 | 392 | enum eEntityType 393 | { 394 | ENTITY_TYPE_NOTHING = 0, 395 | ENTITY_TYPE_BUILDING, 396 | ENTITY_TYPE_VEHICLE, 397 | ENTITY_TYPE_PED, 398 | ENTITY_TYPE_OBJECT, 399 | ENTITY_TYPE_DUMMY, 400 | }; 401 | 402 | enum eEntityStatus 403 | { 404 | STATUS_PLAYER, 405 | STATUS_PLAYER_PLAYBACKFROMBUFFER, 406 | STATUS_SIMPLE, 407 | STATUS_PHYSICS, 408 | STATUS_ABANDONED, 409 | STATUS_WRECKED, 410 | STATUS_TRAIN_MOVING, 411 | STATUS_TRAIN_NOT_MOVING, 412 | STATUS_HELI, 413 | STATUS_PLANE, 414 | STATUS_PLAYER_REMOTE, 415 | STATUS_PLAYER_DISABLED, 416 | }; 417 | 418 | // Again, not actually same between III and VC but doesn't matter to us. 419 | class CEntity : public CPlaceable 420 | { 421 | public: 422 | void* m_rwObject; 423 | uint32 m_type : 3; 424 | uint32 m_status : 5; 425 | 426 | // flagsA 427 | uint32 bUsesCollision : 1; 428 | uint32 bCollisionProcessed : 1; 429 | uint32 bIsStatic : 1; 430 | uint32 bHasContacted : 1; 431 | uint32 bPedPhysics : 1; 432 | uint32 bIsStuck : 1; 433 | uint32 bIsInSafePosition : 1; 434 | uint32 bUseCollisionRecords : 1; 435 | 436 | // flagsB 437 | uint32 bWasPostponed : 1; 438 | uint32 bExplosionProof : 1; 439 | uint32 bIsVisible : 1; 440 | uint32 bHasCollided : 1; // 441 | uint32 bRenderScorched : 1; 442 | uint32 bHasBlip : 1; 443 | uint32 bIsBIGBuilding : 1; 444 | // VC inserts one more flag here: if drawdist <= 2000 445 | uint32 bRenderDamaged : 1; 446 | 447 | // flagsC 448 | uint32 bBulletProof : 1; 449 | uint32 bFireProof : 1; 450 | uint32 bCollisionProof : 1; 451 | uint32 bMeleeProof : 1; 452 | uint32 bOnlyDamagedByPlayer : 1; 453 | uint32 bStreamingDontDelete : 1; 454 | uint32 bZoneCulled : 1; 455 | uint32 bZoneCulled2 : 1; // only treadables+10m 456 | 457 | // flagsD 458 | uint32 bRemoveFromWorld : 1; 459 | uint32 bHasHitWall : 1; 460 | uint32 bImBeingRendered : 1; 461 | uint32 m_flagD8 : 1; // used by cBuoyancy::ProcessBuoyancy 462 | uint32 bIsSubway : 1; // set when subway, but maybe different meaning? 463 | uint32 bDrawLast : 1; 464 | uint32 bNoBrightHeadLights : 1; 465 | uint32 m_flagD80 : 1; // CObject visibility? 466 | 467 | // flagsE 468 | uint32 bDistanceFade : 1; 469 | uint32 m_flagE2 : 1; 470 | 471 | uint16 m_scanCode; 472 | int16 m_randomSeed; 473 | int16 m_modelIndex; 474 | uint16 m_level; // int16 475 | CReference* m_pFirstReference; 476 | 477 | void* GetColModel(void) { return CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(); } 478 | 479 | virtual ~CEntity(void) { }; 480 | 481 | bool IsBuilding(void) { return m_type == ENTITY_TYPE_BUILDING; } 482 | bool IsVehicle(void) { return m_type == ENTITY_TYPE_VEHICLE; } 483 | bool IsPed(void) { return m_type == ENTITY_TYPE_PED; } 484 | bool IsObject(void) { return m_type == ENTITY_TYPE_OBJECT; } 485 | bool IsDummy(void) { return m_type == ENTITY_TYPE_DUMMY; } 486 | 487 | int GetModelIndex(void) { return m_modelIndex; } 488 | }; 489 | static_assert(sizeof(CEntity) == 0x64, "CEntity: error"); 490 | 491 | class CPhysicalIII : public CEntity 492 | { 493 | public: 494 | // The not properly indented fields haven't been checked properly yet 495 | 496 | int32 m_audioEntityId; 497 | float unk1; 498 | void* m_treadable[2]; // car and ped 499 | uint32 m_nLastTimeCollided; 500 | CVector m_vecMoveSpeed; // velocity 501 | CVector m_vecTurnSpeed; // angular velocity 502 | CVector m_vecMoveFriction; 503 | CVector m_vecTurnFriction; 504 | CVector m_vecMoveSpeedAvg; 505 | CVector m_vecTurnSpeedAvg; 506 | float m_fMass; 507 | float m_fTurnMass; // moment of inertia 508 | float fForceMultiplier; 509 | float m_fAirResistance; 510 | float m_fElasticity; 511 | float m_fBuoyancy; 512 | CVector m_vecCentreOfMass; 513 | void* m_entryInfoList; 514 | void* m_movingListNode; 515 | 516 | char field_EC; 517 | uint8 m_nStaticFrames; 518 | uint8 m_nCollisionRecords; 519 | bool field_EF; 520 | CEntity* m_aCollisionRecords[6]; 521 | 522 | float m_fDistanceTravelled; 523 | 524 | // damaged piece 525 | float m_fDamageImpulse; 526 | CEntity* m_pDamageEntity; 527 | CVector m_vecDamageNormal; 528 | int16 m_nDamagePieceType; 529 | 530 | uint8 bIsHeavy : 1; 531 | uint8 bAffectedByGravity : 1; 532 | uint8 bInfiniteMass : 1; 533 | uint8 bIsInWater : 1; 534 | uint8 m_phy_flagA10 : 1; 535 | uint8 m_phy_flagA20 : 1; 536 | uint8 bHitByTrain : 1; 537 | uint8 m_phy_flagA80 : 1; 538 | 539 | uint8 m_nSurfaceTouched; 540 | int8 m_nZoneLevel; 541 | 542 | virtual ~CPhysicalIII(void) { }; 543 | }; 544 | static_assert(sizeof(CPhysicalIII) == 0x128, "CPhysicalIII: error"); 545 | 546 | struct CStoredCollPoly 547 | { 548 | CVector verts[3]; 549 | bool valid; 550 | }; 551 | 552 | enum eVehicleType { 553 | VEHICLE_TYPE_CAR, 554 | VEHICLE_TYPE_BOAT, 555 | VEHICLE_TYPE_TRAIN, 556 | VEHICLE_TYPE_HELI, 557 | VEHICLE_TYPE_PLANE, 558 | VEHICLE_TYPE_BIKE, 559 | NUM_VEHICLE_TYPES 560 | }; 561 | 562 | class CVehicleIII : public CPhysicalIII 563 | { 564 | public: 565 | // 0x128 566 | void* pHandling; 567 | char AutoPilot[112]; 568 | uint8 m_currentColour1; 569 | uint8 m_currentColour2; 570 | uint8 m_aExtras[2]; 571 | int16 m_nAlarmState; 572 | int16 m_nMissionValue; 573 | CPed* pDriver; 574 | CPed* pPassengers[8]; 575 | uint8 m_nNumPassengers; 576 | int8 m_nNumGettingIn; 577 | int8 m_nGettingInFlags; 578 | int8 m_nGettingOutFlags; 579 | uint8 m_nNumMaxPassengers; 580 | char field_1CD[19]; 581 | CEntity* m_pCurGroundEntity; 582 | void* m_pCarFire; 583 | float m_fSteerAngle; 584 | float m_fGasPedal; 585 | float m_fBrakePedal; 586 | uint8 VehicleCreatedBy; 587 | 588 | // cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CVehicle.h from R* 589 | uint8 bIsLawEnforcer : 1; // Is this guy chasing the player at the moment 590 | uint8 bIsAmbulanceOnDuty : 1; // Ambulance trying to get to an accident 591 | uint8 bIsFireTruckOnDuty : 1; // Firetruck trying to get to a fire 592 | uint8 bIsLocked : 1; // Is this guy locked by the script (cannot be removed) 593 | uint8 bEngineOn : 1; // For sound purposes. Parked cars have their engines switched off (so do destroyed cars) 594 | uint8 bIsHandbrakeOn : 1; // How's the handbrake doing ? 595 | uint8 bLightsOn : 1; // Are the lights switched on ? 596 | uint8 bFreebies : 1; // Any freebies left in this vehicle ? 597 | 598 | uint8 bIsVan : 1; // Is this vehicle a van (doors at back of vehicle) 599 | uint8 bIsBus : 1; // Is this vehicle a bus 600 | uint8 bIsBig : 1; // Is this vehicle a bus 601 | uint8 bLowVehicle : 1; // Need this for sporty type cars to use low getting-in/out anims 602 | uint8 bComedyControls : 1; // Will make the car hard to control (hopefully in a funny way) 603 | uint8 bWarnedPeds : 1; // Has scan and warn peds of danger been processed? 604 | uint8 bCraneMessageDone : 1; // A crane message has been printed for this car allready 605 | uint8 bExtendedRange : 1; // This vehicle needs to be a bit further away to get deleted 606 | 607 | uint8 bTakeLessDamage : 1; // This vehicle is stronger (takes about 1/4 of damage) 608 | uint8 bIsDamaged : 1; // This vehicle has been damaged and is displaying all its components 609 | uint8 bHasBeenOwnedByPlayer : 1;// To work out whether stealing it is a crime 610 | uint8 bFadeOut : 1; // Fade vehicle out 611 | uint8 bIsBeingCarJacked : 1; // Fade vehicle out 612 | uint8 bCreateRoadBlockPeds : 1; // If this vehicle gets close enough we will create peds (coppers or gang members) round it 613 | uint8 bCanBeDamaged : 1; // Set to FALSE during cut scenes to avoid explosions 614 | uint8 bUsingSpecialColModel : 1;// Is player vehicle using special collision model, stored in player strucure 615 | 616 | uint8 bOccupantsHaveBeenGenerated : 1; // Is true if the occupants have already been generated. (Shouldn't happen again) 617 | uint8 bGunSwitchedOff : 1; // Level designers can use this to switch off guns on boats 618 | uint8 bVehicleColProcessed : 1;// Has ProcessEntityCollision been processed for this car? 619 | uint8 bIsCarParkVehicle : 1; // Car has been created using the special CAR_PARK script command 620 | uint8 bHasAlreadyBeenRecorded : 1; // Used for replays 621 | 622 | int8 m_numPedsUseItAsCover; 623 | uint8 m_nAmmoInClip; // Used to make the guns on boat do a reload (20 by default) 624 | int8 m_nPacManPickupsCarried; 625 | uint8 m_nRoadblockType; 626 | int16 m_nRoadblockNode; 627 | float m_fHealth; // 1000.0f = full health. 250.0f = fire. 0 -> explode 628 | uint8 m_nCurrentGear; 629 | int8 field_205[3]; 630 | float m_fChangeGearTime; 631 | uint32 m_nGunFiringTime; // last time when gun on vehicle was fired (used on boats) 632 | uint32 m_nTimeOfDeath; 633 | uint16 m_nTimeBlocked; 634 | int16 m_nBombTimer; // goes down with each frame 635 | CEntity* m_pBlowUpEntity; 636 | float m_fMapObjectHeightAhead; // front Z? 637 | float m_fMapObjectHeightBehind; // rear Z? 638 | uint32 m_nDoorLock; 639 | int8 m_nLastWeaponDamage; // see eWeaponType, -1 if no damage 640 | int8 m_nRadioStation; 641 | uint8 m_bRainAudioCounter; 642 | uint8 m_bRainSamplesCounter; 643 | uint8 m_nCarHornTimer; 644 | int8 field_22D; 645 | bool m_bSirenOrAlarm; 646 | int8 m_comedyControlState; 647 | CStoredCollPoly m_aCollPolys[2]; // poly which is under front/rear part of car 648 | float m_fSteerRatio; 649 | eVehicleType m_vehType; 650 | 651 | bool IsCar(void) { return m_vehType == VEHICLE_TYPE_CAR; } 652 | bool IsBoat(void) { return m_vehType == VEHICLE_TYPE_BOAT; } 653 | bool IsBike(void) { return m_vehType == VEHICLE_TYPE_BIKE; } 654 | 655 | CBaseModelInfo* GetModelInfo() { return CModelInfo::GetModelInfo(GetModelIndex()); } 656 | }; 657 | static_assert(sizeof(CVehicleIII) == 0x288, "CVehicleIII: error"); 658 | 659 | struct CPhysicalVC : CEntity 660 | { 661 | unsigned int m_audioEntityId; 662 | float fUnknownX; 663 | float fUnknownY; 664 | CVector m_vecMoveSpeed; 665 | CVector m_vecTurnSpeed; 666 | CVector m_vecFrictionMoveForce; 667 | CVector m_vecFrictionTurnForce; 668 | CVector m_vecForce; 669 | CVector m_vecTorque; 670 | float m_fMass; 671 | float m_fTurnMass; 672 | float m_fVelocityFrequency; 673 | float m_fAirResistance; 674 | float m_fElasticity; 675 | float m_fBuoyancyConstant; 676 | CVector m_vecCentreOfMass; 677 | void* m_collisionList; 678 | void* m_pMovingListNode; 679 | unsigned char uCollideExtra; 680 | unsigned char uCollideInfo; 681 | unsigned char m_nNumCollisionRecords; 682 | char field_E7; 683 | CEntity* m_apCollisionRecords[6]; 684 | float m_fTotSpeed; 685 | float m_fCollisionPower; 686 | CPhysicalVC* m_pPhysColliding; 687 | CVector m_vecCollisionPower; 688 | unsigned short m_wComponentCol; 689 | unsigned char m_nMoveFlags; 690 | unsigned char m_nCollFlags; 691 | unsigned char m_nLastCollType; 692 | unsigned char m_nZoneLevel; 693 | char field_11E[2]; 694 | }; 695 | 696 | struct CVehicleVC : CPhysicalVC 697 | { 698 | void* pHandling; 699 | void* m_pFlyingHandling; 700 | char m_autoPilot[116]; 701 | CVehicleVC* m_pVehicleToRam; 702 | unsigned char m_nPrimaryColor; 703 | unsigned char m_nSecondaryColor; 704 | char m_anExtras[2]; 705 | short m_wWantedStarsOnEnter; 706 | short m_wMissionValue; 707 | CPed* pDriver; 708 | CPed* pPassengers[8]; 709 | unsigned char m_nNumPassengers; 710 | unsigned char m_nNumGettingIn; 711 | unsigned char m_nGettingInFlags; 712 | unsigned char m_nGettingOutFlags; 713 | unsigned char m_nMaxPassengers; 714 | char __f01CD[3]; 715 | int field_1D4; 716 | CVector field_1D8; 717 | CEntity* m_pEntityWeAreOn; 718 | void* m_pFire; 719 | float m_fSteerAngle; 720 | float m_fGasPedal; 721 | float m_fBreakPedal; 722 | unsigned char m_nCreatedBy; // see eVehicleCreatedBy 723 | char flagsAndSoOn[9]; 724 | unsigned char m_nAmmoInClip; 725 | char field_201; 726 | float m_fHealth; 727 | unsigned char m_nCurrentGear; 728 | char __f0205[3]; 729 | int field_20C; 730 | int field_210; 731 | int m_nTimeTillWeNeedThisCar; 732 | int field_218; 733 | int m_nTimeOfDeath; 734 | short field_220; 735 | short m_wBombTimer; // goes down with each frame 736 | int field_224; 737 | int field_228; 738 | int field_22C; 739 | unsigned int m_nLockStatus; 740 | unsigned char m_nLastWeaponDamage; 741 | char __f0231[3]; 742 | CEntity* pLastDamEntity; 743 | unsigned char m_nRadioStation; 744 | char field_23D; 745 | char field_23E; 746 | unsigned int m_bHornEnabled; 747 | char field_244; 748 | unsigned char m_nSirenOrAlarm; 749 | unsigned char m_nSirenExtra; 750 | char field_247; 751 | CStoredCollPoly m_aCollPolys[2]; // poly which is under front/rear part of car 752 | float m_fSteerRatio; 753 | eVehicleType m_vehType; 754 | 755 | bool IsCar(void) { return m_vehType == VEHICLE_TYPE_CAR; } 756 | bool IsBoat(void) { return m_vehType == VEHICLE_TYPE_BOAT; } 757 | bool IsBike(void) { return m_vehType == VEHICLE_TYPE_BIKE; } 758 | 759 | CBaseModelInfo* GetModelInfo() { return CModelInfo::GetModelInfo(GetModelIndex()); } 760 | }; 761 | 762 | typedef struct RsGlobalType RsGlobalType; 763 | struct RsGlobalType 764 | { 765 | const char* appName; 766 | int32 width; 767 | int32 height; 768 | int32 maximumWidth; 769 | int32 maximumHeight; 770 | int32 maxFPS; 771 | bool quit; 772 | 773 | void* ps; /* platform specific data */ 774 | 775 | // Removed the fields we don't use 776 | }; 777 | 778 | class CWorldIII 779 | { 780 | public: 781 | static bool ProcessLineOfSight(const CVector& point1, const CVector& point2, CColPoint& point, CEntity*& entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false); 782 | static CEntity* TestSphereAgainstWorld(CVector centre, float distance, CEntity* entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects); 783 | }; 784 | 785 | class CWorldVC 786 | { 787 | public: 788 | static bool ProcessLineOfSight(const CVector& point1, const CVector& point2, CColPoint& point, CEntity*& entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false, bool ignoreShootThrough = true); 789 | static CEntity* TestSphereAgainstWorld(CVector centre, float distance, CEntity* entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects); 790 | }; 791 | 792 | class CWaterLevel 793 | { 794 | public: 795 | static bool GetWaterLevelNoWaves(float fX, float fY, float fZ, float* pfOutLevel); 796 | }; 797 | 798 | class cDMAudio 799 | { 800 | public: 801 | void PlayOneShot(int32 audioEntity, uint16 oneShot, float volume); 802 | }; 803 | extern cDMAudio &DMAudio; -------------------------------------------------------------------------------- /SACarCam/Camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GTA.h" 3 | 4 | // Many, many thanks to GTAForums community and re3 project, all of these headers are taken from there. 5 | 6 | #define NUMBER_OF_VECTORS_FOR_AVERAGE 2 7 | 8 | enum 9 | { 10 | MODE_TOPDOWN1 = 1, 11 | MODE_TOPDOWN2, 12 | MODE_BEHINDCAR, 13 | MODE_FOLLOWPED, 14 | MODE_AIMING, 15 | MODE_DEBUG, 16 | MODE_SNIPER, 17 | MODE_ROCKET, 18 | MODE_MODELVIEW, 19 | MODE_BILL, 20 | MODE_SYPHON, 21 | MODE_CIRCLE, 22 | MODE_CHEESYZOOM, 23 | MODE_WHEELCAM, 24 | MODE_FIXED, 25 | MODE_FIRSTPERSON, 26 | MODE_FLYBY, 27 | MODE_CAMONASTRING, 28 | MODE_REACTIONCAM, 29 | MODE_FOLLOWPEDWITHBINDING, 30 | MODE_CHRISWITHBINDINGPLUSROTATION, 31 | MODE_BEHINDBOAT, 32 | MODE_PLAYERFALLENWATER, 33 | MODE_CAMONTRAINROOF, 34 | MODE_CAMRUNNINGSIDETRAIN, 35 | MODE_BLOODONTHETRACKS, 36 | MODE_IMTHEPASSENGERWOOWOO, 37 | MODE_SYPHONCRIMINFRONT, 38 | MODE_PEDSDEADBABY, 39 | MODE_CUSHYPILLOWSARSE, 40 | MODE_LOOKATCARS, 41 | MODE_ARRESTCAMONE, 42 | MODE_ARRESTCAMTWO, 43 | MODE_M16FIRSTPERSON_34, 44 | MODE_SPECIALFIXEDFORSYPHON, 45 | MODE_FIGHT, 46 | MODE_TOPDOWNPED, 47 | MODE_SNIPER_RUN_AROUND, 48 | MODE_ROCKET_RUN_AROUND, 49 | MODE_FIRSTPERSONPEDONPC_40, 50 | MODE_FIRSTPERSONPEDONPC_41, 51 | MODE_FIRSTPERSONPEDONPC_42, 52 | MODE_EDITOR, 53 | MODE_M16FIRSTPERSON_44 54 | }; 55 | 56 | class CCamVC { 57 | public: 58 | bool bBelowMinDist; //used for follow ped mode 59 | bool bBehindPlayerDesired; //used for follow ped mode 60 | bool m_bCamLookingAtVector; 61 | bool m_bCollisionChecksOn; 62 | bool m_bFixingBeta; //used for camera on a string 63 | bool m_bTheHeightFixerVehicleIsATrain; 64 | bool LookBehindCamWasInFront; 65 | bool LookingBehind; 66 | bool LookingLeft; // 32 67 | bool LookingRight; 68 | bool ResetStatics; //for interpolation type stuff to work 69 | bool Rotating; 70 | 71 | short Mode; // CameraMode 72 | unsigned int m_uiFinishTime; // 52 73 | 74 | int m_iDoCollisionChecksOnFrameNum; 75 | int m_iDoCollisionCheckEveryNumOfFrames; 76 | int m_iFrameNumWereAt; // 64 77 | int m_iRunningVectorArrayPos; 78 | int m_iRunningVectorCounter; 79 | int DirectionWasLooking; 80 | 81 | float f_max_role_angle; //=DEGTORAD(5.0f); 82 | float f_Roll; //used for adding a slight roll to the camera in the 83 | float f_rollSpeed; //camera on a string mode 84 | float m_fSyphonModeTargetZOffSet; 85 | float m_fAmountFractionObscured; 86 | float m_fAlphaSpeedOverOneFrame; // 100 87 | float m_fBetaSpeedOverOneFrame; 88 | float m_fBufferedTargetBeta; 89 | float m_fBufferedTargetOrientation; 90 | float m_fBufferedTargetOrientationSpeed; 91 | float m_fCamBufferedHeight; 92 | float m_fCamBufferedHeightSpeed; 93 | float m_fCloseInPedHeightOffset; 94 | float m_fCloseInPedHeightOffsetSpeed; // 132 95 | float m_fCloseInCarHeightOffset; 96 | float m_fCloseInCarHeightOffsetSpeed; 97 | float m_fDimensionOfHighestNearCar; 98 | float m_fDistanceBeforeChanges; 99 | float m_fFovSpeedOverOneFrame; 100 | float m_fMinDistAwayFromCamWhenInterPolating; 101 | float m_fPedBetweenCameraHeightOffset; 102 | float m_fPlayerInFrontSyphonAngleOffSet; // 164 103 | float m_fRadiusForDead; 104 | float m_fRealGroundDist; //used for follow ped mode 105 | float m_fTargetBeta; 106 | float m_fTimeElapsedFloat; 107 | float m_fTilt; 108 | float m_fTiltSpeed; 109 | 110 | float m_fTransitionBeta; 111 | float m_fTrueBeta; 112 | float m_fTrueAlpha; // 200 113 | float m_fInitialPlayerOrientation; //used for first person 114 | 115 | float Alpha; 116 | float AlphaSpeed; 117 | float FOV; 118 | float FOVSpeed; 119 | float Beta; 120 | float BetaSpeed; 121 | float Distance; // 232 122 | float DistanceSpeed; 123 | float CA_MIN_DISTANCE; 124 | float CA_MAX_DISTANCE; 125 | float SpeedVar; 126 | 127 | // ped onfoot zoom distance 128 | float m_fTargetZoomGroundOne; 129 | float m_fTargetZoomGroundTwo; // 256 130 | float m_fTargetZoomGroundThree; 131 | // ped onfoot alpha angle offset 132 | float m_fTargetZoomOneZExtra; 133 | float m_fTargetZoomTwoZExtra; 134 | float m_fTargetZoomThreeZExtra; 135 | 136 | float m_fTargetZoomZCloseIn; 137 | float m_fMinRealGroundDist; 138 | float m_fTargetCloseInDist; 139 | 140 | CVector m_cvecSourceSpeedOverOneFrame; // 324 141 | CVector m_cvecTargetSpeedOverOneFrame; // 336 142 | CVector m_cvecUpOverOneFrame; // 348 143 | 144 | CVector m_cvecTargetCoorsForFudgeInter; // 360 145 | CVector m_cvecCamFixedModeVector; // 372 146 | CVector m_cvecCamFixedModeSource; // 384 147 | CVector m_cvecCamFixedModeUpOffSet; // 396 148 | CVector m_vecLastAboveWaterCamPosition; //408 //helper for when the player has gone under the water 149 | 150 | CVector m_vecBufferedPlayerBodyOffset; // 420 151 | 152 | // The three vectors that determine this camera for this frame 153 | CVector Front; // 432 // Direction of looking in 154 | CVector Source; // Coors in world space 155 | CVector SourceBeforeLookBehind; 156 | CVector Up; // Just that 157 | CVector m_arrPreviousVectors[NUMBER_OF_VECTORS_FOR_AVERAGE]; // used to average stuff 158 | CEntity* CamTargetEntity; 159 | 160 | float m_fCameraDistance; 161 | float m_fIdealAlpha; 162 | float m_fPlayerVelocity; 163 | CAutomobile* m_pLastCarEntered; // So interpolation works 164 | CPed* m_pLastPedLookedAt;// So interpolation works 165 | bool m_bFirstPersonRunAboutActive; 166 | 167 | void GetVectorsReadyForRW(void); 168 | void Process_FollowCar_SA_VC(const CVector&, float, float, float); 169 | }; 170 | 171 | class CCamIII 172 | { 173 | public: 174 | bool bBelowMinDist; //used for follow ped mode 175 | bool bBehindPlayerDesired; //used for follow ped mode 176 | bool m_bCamLookingAtVector; 177 | bool m_bCollisionChecksOn; 178 | bool m_bFixingBeta; //used for camera on a string 179 | bool m_bTheHeightFixerVehicleIsATrain; 180 | bool LookBehindCamWasInFront; 181 | bool LookingBehind; 182 | bool LookingLeft; // 32 183 | bool LookingRight; 184 | bool ResetStatics; //for interpolation type stuff to work 185 | bool Rotating; 186 | 187 | int16 Mode; // CameraMode 188 | uint32 m_uiFinishTime; // 52 189 | 190 | int m_iDoCollisionChecksOnFrameNum; 191 | int m_iDoCollisionCheckEveryNumOfFrames; 192 | int m_iFrameNumWereAt; // 64 193 | int m_iRunningVectorArrayPos; 194 | int m_iRunningVectorCounter; 195 | int DirectionWasLooking; 196 | 197 | float f_max_role_angle; //=DEGTORAD(5.0f); 198 | float f_Roll; //used for adding a slight roll to the camera in the 199 | float f_rollSpeed; 200 | float m_fSyphonModeTargetZOffSet; 201 | float m_fUnknownZOffSet; 202 | float m_fAmountFractionObscured; 203 | float m_fAlphaSpeedOverOneFrame; // 100 204 | float m_fBetaSpeedOverOneFrame; 205 | float m_fBufferedTargetBeta; 206 | float m_fBufferedTargetOrientation; 207 | float m_fBufferedTargetOrientationSpeed; 208 | float m_fCamBufferedHeight; 209 | float m_fCamBufferedHeightSpeed; 210 | float m_fCloseInPedHeightOffset; 211 | float m_fCloseInPedHeightOffsetSpeed; // 132 212 | float m_fCloseInCarHeightOffset; 213 | float m_fCloseInCarHeightOffsetSpeed; 214 | float m_fDimensionOfHighestNearCar; 215 | float m_fDistanceBeforeChanges; 216 | float m_fFovSpeedOverOneFrame; 217 | float m_fMinDistAwayFromCamWhenInterPolating; 218 | float m_fPedBetweenCameraHeightOffset; 219 | float m_fPlayerInFrontSyphonAngleOffSet; // 164 220 | float m_fRadiusForDead; 221 | float m_fRealGroundDist; //used for follow ped mode 222 | float m_fTargetBeta; 223 | float m_fTimeElapsedFloat; 224 | 225 | float m_fTransitionBeta; 226 | float m_fTrueBeta; 227 | float m_fTrueAlpha; // 200 228 | float m_fInitialPlayerOrientation; //used for first person 229 | 230 | float Alpha; 231 | float AlphaSpeed; 232 | float FOV; 233 | float FOVSpeed; 234 | float Beta; 235 | float BetaSpeed; 236 | float Distance; // 232 237 | float DistanceSpeed; 238 | float CA_MIN_DISTANCE; 239 | float CA_MAX_DISTANCE; 240 | float SpeedVar; 241 | 242 | // ped onfoot zoom distance 243 | float m_fTargetZoomGroundOne; 244 | float m_fTargetZoomGroundTwo; // 256 245 | float m_fTargetZoomGroundThree; 246 | // ped onfoot alpha angle offset 247 | float m_fTargetZoomOneZExtra; 248 | float m_fTargetZoomTwoZExtra; 249 | float m_fTargetZoomThreeZExtra; 250 | 251 | float m_fTargetZoomZCloseIn; 252 | float m_fMinRealGroundDist; 253 | float m_fTargetCloseInDist; 254 | 255 | CVector m_cvecTargetCoorsForFudgeInter; // 360 256 | CVector m_cvecCamFixedModeVector; // 372 257 | CVector m_cvecCamFixedModeSource; // 384 258 | CVector m_cvecCamFixedModeUpOffSet; // 396 259 | CVector m_vecLastAboveWaterCamPosition; //408 //helper for when the player has gone under the water 260 | CVector m_vecBufferedPlayerBodyOffset; // 420 261 | 262 | // The three vectors that determine this camera for this frame 263 | CVector Front; // 432 // Direction of looking in 264 | CVector Source; // Coors in world space 265 | CVector SourceBeforeLookBehind; 266 | CVector Up; // Just that 267 | CVector m_arrPreviousVectors[NUMBER_OF_VECTORS_FOR_AVERAGE]; // used to average stuff 268 | CEntity* CamTargetEntity; 269 | 270 | float m_fCameraDistance; 271 | float m_fIdealAlpha; 272 | float m_fPlayerVelocity; 273 | CAutomobile* m_pLastCarEntered; // So interpolation works 274 | CPed* m_pLastPedLookedAt;// So interpolation works 275 | bool m_bFirstPersonRunAboutActive; 276 | 277 | void GetVectorsReadyForRW(void); 278 | void Process_FollowCar_SA_III(const CVector&, float, float, float); 279 | }; 280 | static_assert(sizeof(CCamIII) == 0x1A4, "CCam: wrong size"); 281 | 282 | struct CCamPathSplines 283 | { 284 | float m_arr_PathData[800]; 285 | }; 286 | 287 | struct CTrainCamNode 288 | { 289 | CVector m_cvecCamPosition; 290 | CVector m_cvecPointToLookAt; 291 | CVector m_cvecMinPointInRange; 292 | CVector m_cvecMaxPointInRange; 293 | float m_fDesiredFOV; 294 | float m_fNearClip; 295 | }; 296 | 297 | struct CQueuedMode 298 | { 299 | int16 Mode; 300 | float Duration; 301 | int16 MinZoom; 302 | int16 MaxZoom; 303 | }; 304 | 305 | enum 306 | { 307 | LOOKING_BEHIND, 308 | LOOKING_LEFT, 309 | LOOKING_RIGHT, 310 | LOOKING_FORWARD, 311 | }; 312 | 313 | enum 314 | { 315 | // TODO: figure out 316 | FADE_0, 317 | FADE_1, // mid fade 318 | FADE_2, 319 | 320 | FADE_OUT = 0, 321 | FADE_IN, 322 | }; 323 | 324 | enum 325 | { 326 | MBLUR_NONE, 327 | MBLUR_SNIPER, 328 | MBLUR_NORMAL, 329 | MBLUR_INTRO1, // green camera 330 | MBLUR_INTRO2, // unused 331 | MBLUR_INTRO3, // bank scene 332 | MBLUR_INTRO4, // jail break scene 333 | MBLUR_INTRO5, // explosion 334 | MBLUR_INTRO6, // player shot 335 | MBLUR_UNUSED, // pinkish 336 | }; 337 | 338 | struct CCameraVC : public CPlaceableVC 339 | { 340 | bool m_bAboveGroundTrainNodesLoaded; 341 | bool m_bBelowGroundTrainNodesLoaded; 342 | bool m_bCamDirectlyBehind; 343 | bool m_bCamDirectlyInFront; 344 | bool m_bCameraJustRestored; 345 | bool m_bcutsceneFinished; 346 | bool m_bCullZoneChecksOn; 347 | bool m_bFirstPersonBeingUsed; // To indicate if the m_bFirstPersonBeingUsed viewer is being used. 348 | bool m_bJustJumpedOutOf1stPersonBecauseOfTarget; 349 | bool m_bIdleOn; 350 | bool m_bInATunnelAndABigVehicle; 351 | bool m_bInitialNodeFound; 352 | bool m_bInitialNoNodeStaticsSet; 353 | bool m_bIgnoreFadingStuffForMusic; 354 | bool m_bPlayerIsInGarage; 355 | bool m_bPlayerWasOnBike; 356 | bool m_bJustCameOutOfGarage; 357 | bool m_bJustInitalised; //Just so the speed thingy doesn't go mad right at the start 358 | bool m_bJust_Switched; //Variable to indicate that we have jumped somewhere 359 | bool m_bLookingAtPlayer; 360 | bool m_bLookingAtVector; 361 | bool m_bMoveCamToAvoidGeom; 362 | bool m_bObbeCinematicPedCamOn; 363 | bool m_bObbeCinematicCarCamOn; 364 | bool m_bRestoreByJumpCut; 365 | bool m_bUseNearClipScript; 366 | bool m_bStartInterScript; 367 | bool m_bStartingSpline; 368 | bool m_bTargetJustBeenOnTrain; //this variable is needed to be able to restore the camera 369 | bool m_bTargetJustCameOffTrain; 370 | bool m_bUseSpecialFovTrain; 371 | bool m_bUseTransitionBeta; 372 | bool m_bUseScriptZoomValuePed; 373 | bool m_bUseScriptZoomValueCar; 374 | bool m_bWaitForInterpolToFinish; 375 | bool m_bItsOkToLookJustAtThePlayer; //Used when interpolating 376 | bool m_bWantsToSwitchWidescreenOff; 377 | bool m_WideScreenOn; 378 | bool m_1rstPersonRunCloseToAWall; 379 | bool m_bHeadBob; 380 | bool m_bVehicleSuspenHigh; 381 | bool m_bEnable1rstPersonCamCntrlsScript; 382 | 383 | bool m_bAllow1rstPersonWeaponsCamera; 384 | bool m_bFailedCullZoneTestPreviously; 385 | bool m_FadeTargetIsSplashScreen; //used as hack for fading 386 | bool WorldViewerBeingUsed; // To indicate if the world viewer is being used. 387 | unsigned char ActiveCam; 388 | uint8 somePad; 389 | unsigned int m_uiCamShakeStart; // When did the camera shake start. 390 | unsigned int m_uiFirstPersonCamLastInputTime; 391 | unsigned int m_uiLongestTimeInMill; 392 | unsigned int m_uiNumberOfTrainCamNodes; 393 | 394 | unsigned char m_uiTransitionJUSTStarted; // This is the first frame of a transition. 395 | unsigned char m_uiTransitionState; // 0:one mode 1:transition 396 | uint8 somePad2; 397 | uint8 somePad3; 398 | unsigned int m_uiTimeLastChange; 399 | unsigned int m_uiTimeWeLeftIdle_StillNoInput; 400 | unsigned int m_uiTimeWeEnteredIdle; 401 | unsigned int m_uiTimeTransitionStart; // When was the transition started ? 402 | unsigned int m_uiTransitionDuration; // How long does the transition take ? 403 | unsigned int m_uiTransitionDurationTargetCoors; 404 | int m_BlurBlue; 405 | int m_BlurGreen; 406 | int m_BlurRed; 407 | int m_BlurType; 408 | int m_iWorkOutSpeedThisNumFrames; 409 | int m_iNumFramesSoFar; //counter 410 | int m_iCurrentTrainCamNode; //variable indicating which camera node we are at for the train 411 | int m_motionBlur; //to indicate that we are fading 412 | 413 | int m_imotionBlurAddAlpha; 414 | int m_iCheckCullZoneThisNumFrames; 415 | int m_iZoneCullFrameNumWereAt; 416 | int WhoIsInControlOfTheCamera; //to discern between obbe and scripts 417 | float CamFrontXNorm, CamFrontYNorm; 418 | float CarZoomIndicator; // m_nCarZoom in SA 419 | float CarZoomValue; // m_nCarZoomBase in SA 420 | float CarZoomValueSmooth; // m_fCarZoomSmoothed in SA 421 | float DistanceToWater; 422 | float FOVDuringInter; 423 | float LODDistMultiplier; // This takes into account the FOV and the standard LOD multiplier Smaller aperture->bigger LOD multipliers. 424 | float GenerationDistMultiplier; // This takes into account the FOV but noy the standard LOD multiplier 425 | 426 | float m_fAlphaSpeedAtStartInter; 427 | float m_fAlphaWhenInterPol; 428 | float m_fAlphaDuringInterPol; 429 | float m_fBetaDuringInterPol; 430 | float m_fBetaSpeedAtStartInter; 431 | float m_fBetaWhenInterPol; 432 | float m_fFOVWhenInterPol; 433 | float m_fFOVSpeedAtStartInter; 434 | float m_fStartingBetaForInterPol; 435 | float m_fStartingAlphaForInterPol; 436 | float m_PedOrientForBehindOrInFront; 437 | 438 | float m_CameraAverageSpeed; //this is an average depending on how many frames we work it out 439 | float m_CameraSpeedSoFar; //this is a running total 440 | float m_fCamShakeForce; // How severe is the camera shake. 441 | float m_fCarZoomValueScript; // m_fCarZoomValueScript in SA 442 | float m_fFovForTrain; 443 | float m_fFOV_Wide_Screen; 444 | float m_fNearClipScript; 445 | float m_fOldBetaDiff; // Needed for interpolation between 2 modes 446 | float m_fPedZoomValue; 447 | float m_fPedZoomValueSmooth; 448 | float m_fPedZoomValueScript; 449 | float m_fPositionAlongSpline; //Variable used to indicate how far along the spline we are 0-1 for started to completed respectively 450 | float m_ScreenReductionPercentage; 451 | float m_ScreenReductionSpeed; 452 | float m_AlphaForPlayerAnim1rstPerson; 453 | float Orientation; // The orientation of the camera. Used for peds walking. 454 | float PedZoomIndicator; 455 | float PlayerExhaustion; // How tired is player (inaccurate sniping) 0.0f-1.0f 456 | // The following things are used by the sound code to 457 | // play reverb depending on the surroundings. From a point 458 | // in front of the camera the disance is measured to the 459 | // nearest obstacle (building) 460 | float SoundDistUp; //, SoundDistLeft, SoundDistRight; // These ones are buffered and should be used by the audio 461 | float SoundDistUpAsRead; //, SoundDistLeftAsRead, SoundDistRightAsRead; 462 | float SoundDistUpAsReadOld; //, SoundDistLeftAsReadOld, SoundDistRightAsReadOld; 463 | // Very rough distance to the nearest water for the sound to use 464 | // Front vector X&Y normalised to 1. Used by loads of stuff. 465 | 466 | 467 | float m_fAvoidTheGeometryProbsTimer; 468 | short m_nAvoidTheGeometryProbsDirn; 469 | 470 | float m_fWideScreenReductionAmount; //0 for not reduced 1 for fully reduced (Variable for Les) 471 | float m_fStartingFOVForInterPol; 472 | 473 | CCamVC Cams[3]; // The actual cameras (usually only one of the two is active) 474 | // And to complicate this we have a third camera, this camera is 475 | // used for debugging when we want to have a look at the world. 476 | // We can't change the camera mode because other objects depend on their 477 | 478 | void* pToGarageWeAreIn; 479 | void* pToGarageWeAreInForHackAvoidFirstPerson; 480 | CQueuedMode m_PlayerMode; 481 | 482 | // The higher priority player camera mode. This one is used 483 | // for the sniper mode and rocket launcher mode. 484 | // This one overwrites the m_PlayerMode above. 485 | CQueuedMode PlayerWeaponMode; 486 | CVector m_PreviousCameraPosition; //needed to work out speed 487 | CVector m_RealPreviousCameraPosition; // This cane be used by stuff outside the camera code. The one above is the same as the current coordinates outwidth the camera code. 488 | // an active camera for range finding etc 489 | CVector m_cvecAimingTargetCoors; // Coors to look at with Gordons aiming thing 490 | // The player camera that is waiting to be used 491 | 492 | 493 | CVector m_vecFixedModeVector; 494 | CVector m_vecFixedModeSource; 495 | CVector m_vecFixedModeUpOffSet; 496 | CVector m_vecCutSceneOffset; 497 | 498 | CVector m_cvecStartingSourceForInterPol; 499 | CVector m_cvecStartingTargetForInterPol; 500 | CVector m_cvecStartingUpForInterPol; 501 | CVector m_cvecSourceSpeedAtStartInter; 502 | CVector m_cvecTargetSpeedAtStartInter; 503 | CVector m_cvecUpSpeedAtStartInter; 504 | CVector m_vecSourceWhenInterPol; 505 | CVector m_vecTargetWhenInterPol; 506 | CVector m_vecUpWhenInterPol; 507 | CVector m_vecClearGeometryVec; 508 | CVector m_vecGameCamPos; 509 | 510 | CVector SourceDuringInter, TargetDuringInter, UpDuringInter; 511 | // RenderWare camera pointer 512 | void* m_pRwCamera; 513 | 514 | CEntity* pTargetEntity; 515 | // removed the fields we don't use 516 | }; 517 | extern CCameraVC *TheCameraVC; 518 | 519 | struct CCameraIII : public CPlaceable 520 | { 521 | bool m_bAboveGroundTrainNodesLoaded; 522 | bool m_bBelowGroundTrainNodesLoaded; 523 | bool m_bCamDirectlyBehind; 524 | bool m_bCamDirectlyInFront; 525 | bool m_bCameraJustRestored; 526 | bool m_bcutsceneFinished; 527 | bool m_bCullZoneChecksOn; 528 | bool m_bFirstPersonBeingUsed; 529 | bool m_bJustJumpedOutOf1stPersonBecauseOfTarget; 530 | bool m_bIdleOn; 531 | bool m_bInATunnelAndABigVehicle; 532 | bool m_bInitialNodeFound; 533 | bool m_bInitialNoNodeStaticsSet; 534 | bool m_bIgnoreFadingStuffForMusic; 535 | bool m_bPlayerIsInGarage; 536 | bool m_bJustCameOutOfGarage; 537 | bool m_bJustInitalised; 538 | bool m_bJust_Switched; 539 | bool m_bLookingAtPlayer; 540 | bool m_bLookingAtVector; 541 | bool m_bMoveCamToAvoidGeom; 542 | bool m_bObbeCinematicPedCamOn; 543 | bool m_bObbeCinematicCarCamOn; 544 | bool m_bRestoreByJumpCut; 545 | bool m_bUseNearClipScript; 546 | bool m_bStartInterScript; 547 | bool m_bStartingSpline; 548 | bool m_bTargetJustBeenOnTrain; 549 | bool m_bTargetJustCameOffTrain; 550 | bool m_bUseSpecialFovTrain; 551 | bool m_bUseTransitionBeta; 552 | bool m_bUseScriptZoomValuePed; 553 | bool m_bUseScriptZoomValueCar; 554 | bool m_bWaitForInterpolToFinish; 555 | bool m_bItsOkToLookJustAtThePlayer; 556 | bool m_bWantsToSwitchWidescreenOff; 557 | bool m_WideScreenOn; 558 | bool m_1rstPersonRunCloseToAWall; 559 | bool m_bHeadBob; 560 | bool m_bFailedCullZoneTestPreviously; 561 | 562 | bool m_FadeTargetIsSplashScreen; 563 | 564 | bool WorldViewerBeingUsed; 565 | uint8 ActiveCam; 566 | uint32 m_uiCamShakeStart; 567 | uint32 m_uiFirstPersonCamLastInputTime; 568 | // where are those? 569 | //bool m_bVehicleSuspenHigh; 570 | //bool m_bEnable1rstPersonCamCntrlsScript; 571 | //bool m_bAllow1rstPersonWeaponsCamera; 572 | 573 | uint32 m_uiLongestTimeInMill; 574 | uint32 m_uiNumberOfTrainCamNodes; 575 | uint8 m_uiTransitionJUSTStarted; 576 | uint8 m_uiTransitionState; // 0:one mode 1:transition 577 | 578 | uint32 m_uiTimeLastChange; 579 | uint32 m_uiTimeWeEnteredIdle; 580 | uint32 m_uiTimeTransitionStart; 581 | uint32 m_uiTransitionDuration; 582 | int m_BlurBlue; 583 | int m_BlurGreen; 584 | int m_BlurRed; 585 | int m_BlurType; 586 | 587 | uint32 unknown; 588 | int m_iWorkOutSpeedThisNumFrames; 589 | int m_iNumFramesSoFar; 590 | 591 | 592 | int m_iCurrentTrainCamNode; 593 | int m_motionBlur; 594 | int m_imotionBlurAddAlpha; 595 | int m_iCheckCullZoneThisNumFrames; 596 | int m_iZoneCullFrameNumWereAt; 597 | int WhoIsInControlOfTheCamera; 598 | 599 | float CamFrontXNorm; 600 | float CamFrontYNorm; 601 | float CarZoomIndicator; // m_nCarZoom in SA 602 | float CarZoomValue; // m_nCarZoomBase in SA 603 | float CarZoomValueSmooth; // m_fCarZoomSmoothed in SA 604 | 605 | float DistanceToWater; 606 | float FOVDuringInter; 607 | float LODDistMultiplier; 608 | float GenerationDistMultiplier; 609 | float m_fAlphaSpeedAtStartInter; 610 | float m_fAlphaWhenInterPol; 611 | float m_fAlphaDuringInterPol; 612 | float m_fBetaDuringInterPol; 613 | float m_fBetaSpeedAtStartInter; 614 | float m_fBetaWhenInterPol; 615 | float m_fFOVWhenInterPol; 616 | float m_fFOVSpeedAtStartInter; 617 | float m_fStartingBetaForInterPol; 618 | float m_fStartingAlphaForInterPol; 619 | float m_PedOrientForBehindOrInFront; 620 | float m_CameraAverageSpeed; 621 | float m_CameraSpeedSoFar; 622 | float m_fCamShakeForce; 623 | float m_fCarZoomValueScript; // m_fCarZoomValueScript in SA 624 | float m_fFovForTrain; 625 | float m_fFOV_Wide_Screen; 626 | float m_fNearClipScript; 627 | float m_fOldBetaDiff; 628 | float m_fPedZoomValue; 629 | 630 | float m_fPedZoomValueScript; 631 | float m_fPedZoomValueSmooth; 632 | float m_fPositionAlongSpline; 633 | float m_ScreenReductionPercentage; 634 | float m_ScreenReductionSpeed; 635 | float m_AlphaForPlayerAnim1rstPerson; 636 | float Orientation; 637 | float PedZoomIndicator; 638 | float PlayerExhaustion; 639 | float SoundDistUp, SoundDistLeft, SoundDistRight; 640 | float SoundDistUpAsRead, SoundDistLeftAsRead, SoundDistRightAsRead; 641 | float SoundDistUpAsReadOld, SoundDistLeftAsReadOld, SoundDistRightAsReadOld; 642 | float m_fWideScreenReductionAmount; 643 | float m_fStartingFOVForInterPol; 644 | 645 | // not static yet 646 | float m_fMouseAccelHorzntl;// acceleration multiplier for 1st person controls 647 | float m_fMouseAccelVertical;// acceleration multiplier for 1st person controls 648 | float m_f3rdPersonCHairMultX; 649 | float m_f3rdPersonCHairMultY; 650 | 651 | 652 | CCamIII Cams[3]; 653 | void* pToGarageWeAreIn; 654 | void* pToGarageWeAreInForHackAvoidFirstPerson; 655 | CQueuedMode m_PlayerMode; 656 | CQueuedMode PlayerWeaponMode; 657 | CVector m_PreviousCameraPosition; 658 | CVector m_RealPreviousCameraPosition; 659 | CVector m_cvecAimingTargetCoors; 660 | CVector m_vecFixedModeVector; 661 | CVector m_vecFixedModeSource; 662 | CVector m_vecFixedModeUpOffSet; 663 | CVector m_vecCutSceneOffset; 664 | 665 | // one of those has to go 666 | CVector m_cvecStartingSourceForInterPol; 667 | CVector m_cvecStartingTargetForInterPol; 668 | CVector m_cvecStartingUpForInterPol; 669 | CVector m_cvecSourceSpeedAtStartInter; 670 | CVector m_cvecTargetSpeedAtStartInter; 671 | CVector m_cvecUpSpeedAtStartInter; 672 | CVector m_vecSourceWhenInterPol; 673 | CVector m_vecTargetWhenInterPol; 674 | CVector m_vecUpWhenInterPol; 675 | //CVector m_vecClearGeometryVec; 676 | 677 | CVector m_vecGameCamPos; 678 | CVector SourceDuringInter; 679 | CVector TargetDuringInter; 680 | CVector UpDuringInter; 681 | void* m_pRwCamera; 682 | CEntity* pTargetEntity; 683 | CCamPathSplines m_arrPathArray[4]; 684 | CTrainCamNode m_arrTrainCamNode[800]; 685 | CMatrix m_cameraMatrix; 686 | bool m_bGarageFixedCamPositionSet; 687 | bool m_vecDoingSpecialInterPolation; 688 | bool m_bScriptParametersSetForInterPol; 689 | bool m_bFading; 690 | bool m_bMusicFading; 691 | CMatrix m_viewMatrix; 692 | CVector m_vecFrustumNormals[4]; 693 | CVector m_vecOldSourceForInter; 694 | CVector m_vecOldFrontForInter; 695 | CVector m_vecOldUpForInter; 696 | 697 | float m_vecOldFOVForInter; 698 | float m_fFLOATingFade; 699 | float m_fFLOATingFadeMusic; 700 | float m_fTimeToFadeOut; 701 | float m_fTimeToFadeMusic; 702 | float m_fFractionInterToStopMovingTarget; 703 | float m_fFractionInterToStopCatchUpTarget; 704 | float m_fGaitSwayBuffer; 705 | float m_fScriptPercentageInterToStopMoving; 706 | float m_fScriptPercentageInterToCatchUp; 707 | 708 | uint32 m_fScriptTimeForInterPolation; 709 | 710 | 711 | int16 m_iFadingDirection; 712 | int m_iModeObbeCamIsInForCar; 713 | int16 m_iModeToGoTo; 714 | int16 m_iMusicFadingDirection; 715 | int16 m_iTypeOfSwitch; 716 | 717 | uint32 m_uiFadeTimeStarted; 718 | uint32 m_uiFadeTimeStartedMusic; 719 | 720 | virtual ~CCameraIII() { }; 721 | }; 722 | static_assert(sizeof(CCameraIII) == 0xE9D8, "CCameraIII: wrong size"); 723 | extern CCameraIII *TheCameraIII; 724 | -------------------------------------------------------------------------------- /SACarCam/SACarCam.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DebugLCS 6 | Win32 7 | 8 | 9 | DebugLCS 10 | x64 11 | 12 | 13 | DebugVC 14 | Win32 15 | 16 | 17 | DebugVC 18 | x64 19 | 20 | 21 | Debug 22 | Win32 23 | 24 | 25 | ReleaseLCS 26 | Win32 27 | 28 | 29 | ReleaseLCS 30 | x64 31 | 32 | 33 | ReleaseVC 34 | Win32 35 | 36 | 37 | ReleaseVC 38 | x64 39 | 40 | 41 | Release 42 | Win32 43 | 44 | 45 | Debug 46 | x64 47 | 48 | 49 | Release 50 | x64 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 16.0 68 | {F06BC71F-1298-453C-83EA-D29C909403C5} 69 | Win32Proj 70 | SACarCam 71 | 10.0 72 | 73 | 74 | 75 | DynamicLibrary 76 | true 77 | v142 78 | Unicode 79 | 80 | 81 | DynamicLibrary 82 | true 83 | v142 84 | Unicode 85 | 86 | 87 | DynamicLibrary 88 | true 89 | v142 90 | Unicode 91 | 92 | 93 | DynamicLibrary 94 | false 95 | v142 96 | true 97 | Unicode 98 | 99 | 100 | DynamicLibrary 101 | false 102 | v142 103 | true 104 | Unicode 105 | 106 | 107 | DynamicLibrary 108 | false 109 | v142 110 | true 111 | Unicode 112 | 113 | 114 | DynamicLibrary 115 | true 116 | v142 117 | Unicode 118 | 119 | 120 | DynamicLibrary 121 | true 122 | v142 123 | Unicode 124 | 125 | 126 | DynamicLibrary 127 | true 128 | v142 129 | Unicode 130 | 131 | 132 | DynamicLibrary 133 | false 134 | v142 135 | true 136 | Unicode 137 | 138 | 139 | DynamicLibrary 140 | false 141 | v142 142 | true 143 | Unicode 144 | 145 | 146 | DynamicLibrary 147 | false 148 | v142 149 | true 150 | Unicode 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | true 196 | .dll 197 | 198 | 199 | true 200 | .asi 201 | 202 | 203 | true 204 | .asi 205 | 206 | 207 | true 208 | 209 | 210 | true 211 | 212 | 213 | true 214 | 215 | 216 | false 217 | 218 | 219 | false 220 | .asi 221 | 222 | 223 | false 224 | .asi 225 | 226 | 227 | false 228 | 229 | 230 | false 231 | 232 | 233 | false 234 | 235 | 236 | 237 | NotUsing 238 | Level3 239 | Disabled 240 | true 241 | WIN32;_DEBUG;SACARCAM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 242 | true 243 | pch.h 244 | stdcpp14 245 | 246 | 247 | Windows 248 | true 249 | false 250 | 251 | 252 | set "path=C:/Users/Ecuner/Downloads/gta3/plugins/" 253 | setlocal EnableDelayedExpansion 254 | set file=$(TargetPath) 255 | FOR %%i IN ("%file%") DO ( 256 | set filename=%%~ni 257 | set fileextension=%%~xi 258 | set target=!path!!filename!!fileextension! 259 | if exist "!target!" copy /y "!file!" "!target!" 260 | ) 261 | 262 | 263 | 264 | 265 | NotUsing 266 | Level3 267 | Disabled 268 | true 269 | WIN32;_DEBUG;SACARCAM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 270 | true 271 | pch.h 272 | stdcpp14 273 | 274 | 275 | Windows 276 | true 277 | false 278 | 279 | 280 | 281 | set "path=C:/Users/Ecuner/Downloads/gta vc/scripts/" 282 | setlocal EnableDelayedExpansion 283 | set file=$(TargetPath) 284 | FOR %%i IN ("%file%") DO ( 285 | set filename=%%~ni 286 | set fileextension=%%~xi 287 | set target=!path!!filename!!fileextension! 288 | if exist "!target!" copy /y "!file!" "!target!" 289 | ) 290 | 291 | 292 | 293 | 294 | NotUsing 295 | Level3 296 | Disabled 297 | true 298 | WIN32;_DEBUG;SACARCAM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 299 | true 300 | pch.h 301 | stdcpp14 302 | 303 | 304 | Windows 305 | true 306 | false 307 | 308 | 309 | 310 | set "path=C:/Users/Ecuner/Downloads/gta lcs/scripts/" 311 | setlocal EnableDelayedExpansion 312 | set file=$(TargetPath) 313 | FOR %%i IN ("%file%") DO ( 314 | set filename=%%~ni 315 | set fileextension=%%~xi 316 | set target=!path!!filename!!fileextension! 317 | if exist "!target!" copy /y "!file!" "!target!" 318 | ) 319 | 320 | 321 | 322 | 323 | Use 324 | Level3 325 | Disabled 326 | true 327 | _DEBUG;SACARCAM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 328 | true 329 | pch.h 330 | 331 | 332 | Windows 333 | true 334 | false 335 | 336 | 337 | 338 | 339 | Use 340 | Level3 341 | Disabled 342 | true 343 | _DEBUG;SACARCAM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 344 | true 345 | pch.h 346 | 347 | 348 | Windows 349 | true 350 | false 351 | 352 | 353 | 354 | 355 | Use 356 | Level3 357 | Disabled 358 | true 359 | _DEBUG;SACARCAM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 360 | true 361 | pch.h 362 | 363 | 364 | Windows 365 | true 366 | false 367 | 368 | 369 | 370 | 371 | NotUsing 372 | Level3 373 | MaxSpeed 374 | true 375 | true 376 | true 377 | WIN32;NDEBUG;SACARCAM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 378 | true 379 | pch.h 380 | stdcpp14 381 | 382 | 383 | Windows 384 | true 385 | true 386 | true 387 | false 388 | 389 | 390 | set "path=C:/Users/Ecuner/Downloads/gta3/plugins/" 391 | setlocal EnableDelayedExpansion 392 | set file=$(TargetPath) 393 | FOR %%i IN ("%file%") DO ( 394 | set filename=%%~ni 395 | set fileextension=%%~xi 396 | set target=!path!!filename!!fileextension! 397 | if exist "!target!" copy /y "!file!" "!target!" 398 | ) 399 | 400 | 401 | 402 | 403 | NotUsing 404 | Level3 405 | MaxSpeed 406 | true 407 | true 408 | true 409 | WIN32;NDEBUG;SACARCAM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 410 | true 411 | pch.h 412 | stdcpp14 413 | 414 | 415 | Windows 416 | true 417 | true 418 | true 419 | false 420 | 421 | 422 | set "path=C:/Users/Ecuner/Downloads/gta vc/scripts/" 423 | setlocal EnableDelayedExpansion 424 | set file=$(TargetPath) 425 | FOR %%i IN ("%file%") DO ( 426 | set filename=%%~ni 427 | set fileextension=%%~xi 428 | set target=!path!!filename!!fileextension! 429 | if exist "!target!" copy /y "!file!" "!target!" 430 | ) 431 | 432 | 433 | 434 | 435 | NotUsing 436 | Level3 437 | MaxSpeed 438 | true 439 | true 440 | true 441 | WIN32;NDEBUG;SACARCAM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 442 | true 443 | pch.h 444 | stdcpp14 445 | 446 | 447 | Windows 448 | true 449 | true 450 | true 451 | false 452 | 453 | 454 | set "path=C:/Users/Ecuner/Downloads/gta lcs/scripts/" 455 | setlocal EnableDelayedExpansion 456 | set file=$(TargetPath) 457 | FOR %%i IN ("%file%") DO ( 458 | set filename=%%~ni 459 | set fileextension=%%~xi 460 | set target=!path!!filename!!fileextension! 461 | if exist "!target!" copy /y "!file!" "!target!" 462 | ) 463 | 464 | 465 | 466 | 467 | Use 468 | Level3 469 | MaxSpeed 470 | true 471 | true 472 | true 473 | NDEBUG;SACARCAM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 474 | true 475 | pch.h 476 | 477 | 478 | Windows 479 | true 480 | true 481 | true 482 | false 483 | 484 | 485 | 486 | 487 | Use 488 | Level3 489 | MaxSpeed 490 | true 491 | true 492 | true 493 | NDEBUG;SACARCAM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 494 | true 495 | pch.h 496 | 497 | 498 | Windows 499 | true 500 | true 501 | true 502 | false 503 | 504 | 505 | 506 | 507 | Use 508 | Level3 509 | MaxSpeed 510 | true 511 | true 512 | true 513 | NDEBUG;SACARCAM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 514 | true 515 | pch.h 516 | 517 | 518 | Windows 519 | true 520 | true 521 | true 522 | false 523 | 524 | 525 | 526 | 527 | 528 | -------------------------------------------------------------------------------- /SACarCam/SACarCam.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "MemoryMgr.h" 3 | #include "GTA.h" 4 | #include "Camera.h" 5 | #include "Pad.h" 6 | 7 | #include "ModuleList.hpp" 8 | #include "GInputAPI.h" 9 | #include "debugmenu_public.h" 10 | 11 | // Uncomment to make it LCS vehicle camera - defined or not, it will always be compatible with III / VC / Re:LCS 12 | // #define LCS_CAM 13 | 14 | #define DefaultFOV 70.0f 15 | 16 | HMODULE dllModule, hDummyHandle; 17 | int gtaversion = -1; 18 | 19 | // Reminder: isVC() will also return true for Re:LCS 20 | bool isReLCS = false; 21 | 22 | #define MI_III_YARDIE 135 23 | #define MI_III_RCBANDIT 131 24 | #define MI_III_RHINO 122 25 | #define MI_III_DODO 126 26 | #define MI_III_FIRETRUCK 97 27 | 28 | #define MI_VC_VOODOO 142 29 | #define MI_VC_FIRETRUCK 137 30 | #define MI_VC_RHINO 162 31 | #define MI_VC_RCBANDIT 171 32 | #define MI_VC_RCBARON 194 33 | #define MI_VC_RCRAIDER 195 34 | #define MI_VC_RCGOBLIN 231 35 | 36 | #define MI_RELCS_FIRETRUCK 138 37 | #define MI_RELCS_RHINO 162 38 | #define MI_RELCS_DODO 164 39 | #define MI_RELCS_RCBANDIT 169 // original LCS didn't use this though, RC vehicles have same camera distance as normal veh - Ryadica926 40 | #define MI_RELCS_YARDIE 173 41 | #define MI_RELCS_RCGOBLIN 211 // same as rc bandit 42 | #define MI_RELCS_RCRAIDER 212 // same as above 43 | 44 | #define Tank (isIII() ? MI_III_RHINO : (isReLCS ? MI_RELCS_RHINO : MI_VC_RHINO)) 45 | #define FireTruk (isIII() ? MI_III_FIRETRUCK : (isReLCS ? MI_RELCS_FIRETRUCK : MI_VC_FIRETRUCK)) 46 | #define CarWithHydraulics (isIII() ? MI_III_YARDIE : (isReLCS ? MI_RELCS_YARDIE : MI_VC_VOODOO)) 47 | #define RcBandit (isIII() ? MI_III_RCBANDIT : (isReLCS ? MI_RELCS_RCBANDIT : MI_VC_RCBANDIT)) 48 | 49 | // These are being used only if isVC() is true 50 | #define RcGoblin (isReLCS ? MI_RELCS_RCGOBLIN : MI_VC_RCGOBLIN) 51 | #define RcRaider (isReLCS ? MI_RELCS_RCRAIDER : MI_VC_RCRAIDER) 52 | 53 | IGInputPad* ginputPad; 54 | int ginputLoaded = 0; // 1: not installed 2: installed 55 | int debugMenuLoaded = 0; // 1: not installed 2: installed 56 | GINPUT_PAD_SETTINGS padSettings = {}; 57 | DebugMenuAPI gDebugMenuAPI; 58 | 59 | // Car zoom modes per veh. types doesn't exist in III, so we will emulate it :) We're just injecting them for VC. 60 | // Original values from SA / LCS as of r6 61 | #ifdef LCS_CAM 62 | float CarZoomModes[] = { 63 | -1.0f, -0.2f, -3.2f, 0.05f, -2.41f, // near 64 | 2.0f, 2.2f, 1.65f, 2.9f, 6.49f, // mid 65 | 6.0f, 6.0f, 15.9f, 15.9f, 15.0f // far 66 | }; 67 | #else 68 | float CarZoomModes[] = { 69 | -1.0f, -0.2f, -3.2f, 0.05f, -2.41f, // near 70 | 1.0f, 1.4f, 0.65f, 1.9f, 6.49f, // mid 71 | 6.0f, 6.0f, 15.9f, 15.9f, 15.0f // far 72 | }; 73 | #endif 74 | 75 | // Alpha angles (up-down) 76 | float ZmOneAlphaOffset[] = { 0.08f, 0.08f, 0.15f, 0.08f, 0.08f }; 77 | float ZmTwoAlphaOffset[] = { 0.07f, 0.08f, 0.3f, 0.08f, 0.08f }; 78 | float ZmThreeAlphaOffset[] = { 0.055f, 0.05f, 0.15f, 0.06f, 0.08f }; 79 | 80 | float ZmOneAlphaOffsetLCS[] = { 0.12f, 0.08f, 0.15f, 0.08f, 0.08f }; 81 | float ZmTwoAlphaOffsetLCS[] = { 0.1f, 0.08f, 0.3f, 0.08f, 0.08f }; 82 | float ZmThreeAlphaOffsetLCS[] = { 0.065f, 0.05f, 0.15f, 0.06f, 0.08f }; 83 | 84 | // Debug menu toggles 85 | #ifdef LCS_CAM 86 | bool heightIncreaseOnBike = false; // Not exists on LCS 87 | bool useLCSalphaValues = true; 88 | bool zoomOnWidescreen = true; // Because this is how we remember LCS, not needed if you're not using the widescreen fix 89 | #else 90 | bool heightIncreaseOnBike = true; 91 | bool useLCSalphaValues = false; 92 | bool zoomOnWidescreen = false; 93 | #endif 94 | bool fixTheBug = true; 95 | bool seeUnderwater = false; 96 | 97 | // ----- 98 | 99 | void(*&RwCamera) = *AddressByVersion(0x72676C, 0, 0, 0x8100BC, 0, 0); 100 | 101 | CCameraIII *TheCameraIII = (CCameraIII*)0x6FACF8; 102 | CCameraVC *TheCameraVC = (CCameraVC*)0x7E4688; 103 | 104 | // Actually static member of CCamera 105 | bool& m_bUseMouse3rdPerson = *AddressByVersion(0x5F03D8, 0, 0, 0xA10B4C, 0, 0); 106 | 107 | cDMAudio &DMAudio = *AddressByVersion(0x95CDBE, 0, 0, 0xA10B8A, 0, 0); 108 | 109 | // These are static members of CWorld 110 | CColPoint& ms_testSpherePoint = *AddressByVersion(0x6E64C0, 0, 0, 0x7D18C0, 0, 0); 111 | CEntity*& pIgnoreEntity = *AddressByVersion(0x8F6494, 0, 0, 0x9B6E58, 0, 0); 112 | 113 | addr plosAddress = AddressByVersion(0x4AF970, 0, 0, 0x4D92D0, 0, 0); 114 | WRAPPER bool CWorldIII::ProcessLineOfSight(const CVector& point1, const CVector& point2, CColPoint& point, CEntity*& entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects) { EAXJMP(plosAddress); } 115 | WRAPPER bool CWorldVC::ProcessLineOfSight(const CVector& point1, const CVector& point2, CColPoint& point, CEntity*& entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects, bool sth) { EAXJMP(plosAddress); } 116 | 117 | addr tsawAddress = AddressByVersion(0x4B4710, 0, 0, 0x4D3F40, 0, 0); 118 | WRAPPER CEntity* CWorldIII::TestSphereAgainstWorld(CVector centre, float distance, CEntity* entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects) { EAXJMP(tsawAddress); } 119 | WRAPPER CEntity* CWorldVC::TestSphereAgainstWorld(CVector centre, float distance, CEntity* entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects) { EAXJMP(tsawAddress); } 120 | 121 | addr gwlnwAddress = AddressByVersion(0x555440, 0, 0, 0x5C2BE0, 0, 0); 122 | WRAPPER bool CWaterLevel::GetWaterLevelNoWaves(float fX, float fY, float fZ, float* pfOutLevel) { EAXJMP(gwlnwAddress); } 123 | 124 | addr rcsncpAddress = AddressByVersion(0x5A5070, 0, 0, 0x64A860, 0, 0); 125 | WRAPPER void* RwCameraSetNearClipPlane(void* camera, float nearClip) { EAXJMP(rcsncpAddress); } 126 | 127 | addr posAddress = AddressByVersion(0x57C840, 0, 0, 0x5F9DA0, 0, 0); 128 | WRAPPER void cDMAudio::PlayOneShot(int32 audioEntity, uint16 oneShot, float volume) { EAXJMP(posAddress); } 129 | 130 | CBaseModelInfo** CModelInfo::ms_modelInfoPtrs = AddressByVersion(0x83D408, 0, 0, 0x92D4C8, 0, 0); 131 | 132 | addr attachAddress = AddressByVersion(0x4B8DD0, 0, 0, 0x4DFA40, 0, 0); 133 | addr updateRwAddress = AddressByVersion(0x4B8EC0, 0, 0, 0x4DF8F0, 0, 0); 134 | WRAPPER void CMatrix::Attach(RwMatrix* matrix, bool owner) { EAXJMP(attachAddress); } 135 | WRAPPER void CMatrix::UpdateRW(void) { EAXJMP(updateRwAddress); } 136 | 137 | addr ditbAddress = AddressByVersion(0x48BFB0, 0, 0, 0x4A4C02, 0, 0); 138 | void (*DebugInitTextBuffer)(); 139 | 140 | // Actually static member of CVehicle 141 | bool &m_bDisableMouseSteering = *AddressByVersion(0x60252C, 0, 0, 0x69C610, 0, 0); 142 | 143 | uint32 &m_snTimeInMilliseconds = *AddressByVersion(0x885B48, 0, 0, 0x974B2C, 0, 0); 144 | float &ms_fTimeStep = *AddressByVersion(0x8E2CB4, 0, 0, 0x975424, 0, 0); 145 | 146 | #define RwFrameGetMatrix(frame) (RwMatrix*)((addr)frame + 0x10) 147 | #define GetVehicleComponent(car, comp) *(void**)((addr)car + (isIII() ? 0x37C : 0x394) + comp*4) // In CAutomobile. normally returns RwFrame* 148 | 149 | #define GetDisablePlayerControls(pad) *((uint8*)((addr)pad + (isIII() ? 0xDF : 0xF0))) 150 | #define GetHandlingFlags(veh) *((uint32*)((addr)veh->pHandling + (isIII() ? 0xC8 : 0xCC))) 151 | #define GetWheelsOnGround(veh) *((uint8*)((addr)veh + (isIII() ? 0x591 : 0x5C4))) // In CAutomobile 152 | #define GetMysteriousWheelRelatedThingBike(veh) *((uint8*)((addr)veh + 0x4DC)) // In CBike, VC 153 | #define GetDoomAnglePtrLR(veh) (float*)((addr)veh + (isIII() ? 0x580 : 0x5B0)) // In CAutomobile 154 | #define GetDoomAnglePtrUD(veh) (float*)((addr)veh + (isIII() ? 0x584 : 0x5B4)) // In CAutomobile 155 | #define GetPedObjective(ped) *((uint32*)((addr)ped + (isIII() ? 0x164 : 0x160))) 156 | #define GetNearPlane() *(float*)((addr)RwCamera + 0x80) 157 | 158 | // Virtual func. in GTA 159 | #define GetHeightAboveRoad(veh, classToCast) (veh->IsCar() ? *((float*)((addr)veh + (isIII() ? 0x50C : 0x530))) : \ 160 | -1.0f * ((classToCast*)veh->GetColModel())->boundingBox.min.z) 161 | 162 | float aspectRatio; 163 | bool gotTheAR = false; 164 | float GetAspectRatio() { 165 | if (isVC()) 166 | return *(float*)0x94DD38; // CDraw::ms_fAspectRatio 167 | else { 168 | if (!gotTheAR) { 169 | gotTheAR = true; 170 | 171 | RsGlobalType& RsGlobal = *(RsGlobalType*)0x8F4360; 172 | return aspectRatio = ((float)RsGlobal.width) / ((float)RsGlobal.height); 173 | } else 174 | return aspectRatio; 175 | } 176 | } 177 | 178 | float GetMouseAccel(CCameraVC *camera) { 179 | return *(float*)0x94DBD0; // CCamera::m_fMouseAccelHorzntl 180 | } 181 | 182 | float GetMouseAccel(CCameraIII *camera) { 183 | return camera->m_fMouseAccelHorzntl; 184 | } 185 | 186 | float GetATanOfXY(float x, float y) { 187 | if (x == 0.0f && y == 0.0f) 188 | return 0.0f; 189 | 190 | float xabs = fabsf(x); 191 | float yabs = fabsf(y); 192 | 193 | if (xabs < yabs) { 194 | if (y > 0.0f) { 195 | if (x > 0.0f) 196 | return 0.5f * PI - atan2f(x / y, 1.0f); 197 | else 198 | return 0.5f * PI + atan2f(-x / y, 1.0f); 199 | } 200 | else { 201 | if (x > 0.0f) 202 | return 1.5f * PI + atan2f(x / -y, 1.0f); 203 | else 204 | return 1.5f * PI - atan2f(-x / -y, 1.0f); 205 | } 206 | } 207 | else { 208 | if (y > 0.0f) { 209 | if (x > 0.0f) 210 | return atan2f(y / x, 1.0f); 211 | else 212 | return PI - atan2f(y / -x, 1.0f); 213 | } 214 | else { 215 | if (x > 0.0f) 216 | return 2.0f * PI - atan2f(-y / x, 1.0f); 217 | else 218 | return PI + atan2f(-y / -x, 1.0f); 219 | } 220 | } 221 | } 222 | 223 | const CVector 224 | Multiply3x3(const CMatrix& mat, const CVector& vec) 225 | { 226 | return CVector( 227 | mat.m_matrix.right.x * vec.x + mat.m_matrix.up.x * vec.y + mat.m_matrix.at.x * vec.z, 228 | mat.m_matrix.right.y * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.at.y * vec.z, 229 | mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z); 230 | } 231 | 232 | const CVector 233 | Multiply3x3(const CVector& vec, const CMatrix& mat) 234 | { 235 | return CVector( 236 | mat.m_matrix.right.x * vec.x + mat.m_matrix.right.y * vec.y + mat.m_matrix.right.z * vec.z, 237 | mat.m_matrix.up.x * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.up.z * vec.z, 238 | mat.m_matrix.at.x * vec.x + mat.m_matrix.at.y * vec.y + mat.m_matrix.at.z * vec.z); 239 | } 240 | 241 | int previousMode = 0; 242 | 243 | static void OnGInputSettingsReload() 244 | { 245 | padSettings.cbSize = sizeof(padSettings); 246 | ginputPad->SendConstEvent(GINPUT_EVENT_FETCH_PAD_SETTINGS, &padSettings); 247 | } 248 | 249 | void registerDebugMenu() { 250 | if (!debugMenuLoaded) { 251 | if (DebugMenuLoad()) { 252 | #ifdef LCS_CAM 253 | DebugMenuAddCmd("SACarCam", "You're using r6-LCS version, which has hardcoded LCS features.", nil); 254 | #else 255 | DebugMenuAddCmd("SACarCam", "You're using r6-regular version.", nil); 256 | #endif 257 | DebugMenuAddVarBool8("SACarCam", "Zoom on widescreen", (int8*)&zoomOnWidescreen, nil); 258 | DebugMenuAddVarBool8("SACarCam", "SA bikes cam raise with passenger", (int8*)&heightIncreaseOnBike, nil); 259 | DebugMenuAddVarBool8("SACarCam", "Use LCS alpha angles", (int8*)&useLCSalphaValues, nil); 260 | DebugMenuAddVarBool8("SACarCam", "Fix Camera clipping through the model bug", (int8*)&fixTheBug, nil); 261 | DebugMenuAddVarBool8("SACarCam", "Don't keep camera over water", (int8*)&seeUnderwater, nil); 262 | debugMenuLoaded = 2; 263 | } else 264 | debugMenuLoaded = 1; 265 | } 266 | DebugInitTextBuffer(); 267 | } 268 | 269 | template 270 | void 271 | Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation, CamClass* cam, CameraClass* TheCamera) // bool sthForScript) 272 | { 273 | // Reminder: SA vehicle subclass 3 is heli, 4 is plane, class 9 is bike 274 | 275 | // Missing things on III CCam 276 | static CVector m_aTargetHistoryPosOne; 277 | static CVector m_aTargetHistoryPosTwo; 278 | static CVector m_aTargetHistoryPosThree; 279 | static int m_nCurrentHistoryPoints = 0; 280 | static float lastBeta = -9999.0f; 281 | static float lastAlpha = -9999.0f; 282 | static float stepsLeftToChangeBetaByMouse; 283 | static float flt_9BF250; 284 | static bool alphaCorrected; 285 | static float heightIncreaseMult; 286 | 287 | if (!cam->CamTargetEntity->IsVehicle()) 288 | return; 289 | 290 | if (!ginputLoaded) { 291 | if (GInput_Load(&ginputPad)) { 292 | OnGInputSettingsReload(); 293 | ginputPad->SendEvent(GINPUT_EVENT_REGISTER_SETTINGS_RELOAD_CALLBACK, OnGInputSettingsReload); 294 | ginputLoaded = 2; 295 | } else 296 | ginputLoaded = 1; 297 | } 298 | 299 | VehicleClass* car = (VehicleClass*)cam->CamTargetEntity; 300 | CVector TargetCoors = CameraTarget; 301 | uint8 camSetArrPos = 0; 302 | 303 | // For compatibility with III with Aircraft mod and VC 304 | bool isPlane = isIII() && car->m_modelIndex == MI_III_DODO || GetHandlingFlags(car) & 0x40000; 305 | bool isHeli = GetHandlingFlags(car) & 0x20000; 306 | bool isBike = (GetHandlingFlags(car) & 0x10000) || car->IsBike(); 307 | bool isCar = car->IsCar() && !isPlane && !isHeli && !isBike; 308 | 309 | CPad* pad = &pad0; 310 | 311 | // Next direction is 0x8CC384 in SA, non-existent in III 312 | uint8 nextDirectionIsForward = !(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight()) && 313 | cam->DirectionWasLooking == LOOKING_FORWARD; 314 | 315 | #ifdef LCS_CAM 316 | if (car->m_modelIndex == FireTruk) { 317 | camSetArrPos = 7; 318 | } else 319 | #endif 320 | if (car->m_modelIndex == RcBandit || (isVC() && !isReLCS && car->m_modelIndex == MI_VC_RCBARON)) { 321 | camSetArrPos = 5; 322 | } 323 | else if (isVC() && (car->m_modelIndex == RcRaider || car->m_modelIndex == RcGoblin)) { 324 | camSetArrPos = 6; 325 | } 326 | else if (car->IsBoat()) { 327 | camSetArrPos = 4; 328 | } 329 | else if (isBike) { 330 | camSetArrPos = 1; 331 | } 332 | else if (isPlane) { 333 | camSetArrPos = 3; 334 | } 335 | else if (isHeli) { 336 | camSetArrPos = 2; 337 | } 338 | 339 | #ifdef LCS_CAM 340 | // LCS one but index 1(firetruck) moved to last 341 | float CARCAM_SET[][15] = { 342 | {1.3f, 1.0f, 0.4f, 10.0f, 15.0f, 0.5f, 1.0f, 1.0f, 0.85f, 0.2f, 0.075f, 0.05f, 0.8f, 0.7854f, 1.5533f}, // cars 343 | {1.1f, 1.0f, 0.1f, 10.0f, 11.0f, 0.5f, 1.0f, 1.0f, 0.85f, 0.2f, 0.075f, 0.05f, 0.75f, 0.7854f, 1.5533f}, // bike 344 | {1.1f, 1.0f, 0.2f, 10.0f, 15.0f, 0.05f, 0.05f, 0.0f, 0.9f, 0.05f, 0.01f, 0.05f, 1.0f, 0.17453294f, 1.2217305f}, // heli (SA values) 345 | {1.1f, 3.5f, 0.2f, 10.0f, 25.0f, 0.5f, 1.0f, 1.0f, 0.75f, 0.1f, 0.005f, 0.2f, 1.0f, 1.5533431f, 1.5533431f}, // plane (SA values) 346 | {0.9f, 1.0f, 0.1f, 10.0f, 15.0f, 0.5f, 1.0f, 0.0f, 0.9f, 0.05f, 0.005f, 0.05f, 1.0f, -0.2f, 1.2217305f}, // boat 347 | {1.1f, 1.0f, 0.2f, 10.0f, 5.0f, 0.5f, 1.0f, 1.0f, 0.75f, 0.1f, 0.005f, 0.2f, 1.0f, 0.7854f, 1.5533f}, // rc cars 348 | {1.1f, 1.0f, 0.2f, 10.0f, 5.0f, 0.5f, 1.0f, 1.0f, 0.75f, 0.1f, 0.005f, 0.2f, 1.0f, 0.34906587f, 1.2217305f}, // rc heli/planes 349 | {1.3f, 1.0f, 0.4f, 10.0f, 15.0f, 0.5f, 1.0f, 1.0f, 0.85f, 0.2f, 0.075f, 0.05f, 0.8f, -0.18f, 0.7f}, // firetruck... 350 | }; 351 | #else 352 | float CARCAM_SET[][15] = { 353 | {1.3f, 1.0f, 0.4f, 10.0f, 15.0f, 0.5f, 1.0f, 1.0f, 0.85f, 0.2f, 0.075f, 0.05f, 0.8f, 0.785398f, 1.5533431f}, 354 | {1.1f, 1.0f, 0.1f, 10.0f, 11.0f, 0.5f, 1.0f, 1.0f, 0.85f, 0.2f, 0.075f, 0.05f, 0.75f, 0.78539819f, 1.5533431f}, 355 | {1.1f, 1.0f, 0.2f, 10.0f, 15.0f, 0.05f, 0.05f, 0.0f, 0.9f, 0.05f, 0.01f, 0.05f, 1.0f, 0.17453294f, 1.2217305f}, 356 | {1.1f, 3.5f, 0.2f, 10.0f, 25.0f, 0.5f, 1.0f, 1.0f, 0.75f, 0.1f, 0.005f, 0.2f, 1.0f, 1.5533431f, 1.5533431f}, 357 | {1.3f, 1.0f, 0.4f, 10.0f, 15.0f, 0.5f, 1.0f, 0.0f, 0.9f, 0.05f, 0.005f, 0.05f, 1.0f, 0.34906587f, 1.2217305f}, 358 | {1.1f, 1.0f, 0.2f, 10.0f, 5.0f, 0.5f, 1.0f, 1.0f, 0.75f, 0.1f, 0.005f, 0.2f, 1.0f, 0.78539819f, 1.5533431f}, // rc cars 359 | {1.1f, 1.0f, 0.2f, 10.0f, 5.0f, 0.5f, 1.0f, 1.0f, 0.75f, 0.1f, 0.005f, 0.2f, 1.0f, 0.34906587f, 1.2217305f} // rc heli/planes 360 | }; 361 | #endif 362 | 363 | // RC Heli/planes use same alpha values with heli/planes (LCS firetruck will fallback to 0) 364 | uint8 alphaArrPos = (camSetArrPos > 4 ? (isPlane ? 3 : (isHeli ? 2 : 0)) : camSetArrPos); 365 | float zoomModeAlphaOffset = 0.0f; 366 | 367 | if (isHeli && car->m_status == STATUS_PLAYER_REMOTE) 368 | zoomModeAlphaOffset = (useLCSalphaValues ? ZmTwoAlphaOffsetLCS[alphaArrPos] : ZmTwoAlphaOffset[alphaArrPos]); 369 | else { 370 | switch ((int)TheCamera->CarZoomIndicator) { 371 | // near 372 | case 1: 373 | zoomModeAlphaOffset = (useLCSalphaValues ? ZmOneAlphaOffsetLCS[alphaArrPos] : ZmOneAlphaOffset[alphaArrPos]); 374 | break; 375 | // mid 376 | case 2: 377 | zoomModeAlphaOffset = (useLCSalphaValues ? ZmTwoAlphaOffsetLCS[alphaArrPos] : ZmTwoAlphaOffset[alphaArrPos]); 378 | break; 379 | // far 380 | case 3: 381 | zoomModeAlphaOffset = (useLCSalphaValues ? ZmThreeAlphaOffsetLCS[alphaArrPos] : ZmThreeAlphaOffset[alphaArrPos]); 382 | break; 383 | default: 384 | break; 385 | } 386 | } 387 | 388 | ColModelClass* carCol = (ColModelClass*)car->GetColModel(); 389 | float colMaxZ = carCol->boundingBox.max.z; // As opposed to LCS and SA, VC does this: carCol->boundingBox.max.z - carCol->boundingBox.min.z; 390 | float approxCarLength = 2.0f * fabsf(carCol->boundingBox.min.y); // SA taxi min.y = -2.95, max.z = 0.883502f 391 | 392 | // Turned off by default on LCS_CAM 393 | if(heightIncreaseOnBike) { 394 | if (!isBike) { 395 | heightIncreaseMult = 0.0f; 396 | } else { 397 | // Increase colMaxZ slowly when there is a passenger on bike 398 | if (car->pPassengers[0]) 399 | { 400 | if (heightIncreaseMult < 1.0f) { 401 | heightIncreaseMult = min(1.0f, ms_fTimeStep * 0.02f + heightIncreaseMult); 402 | } 403 | } 404 | else 405 | { 406 | if (heightIncreaseMult > 0.0f) { 407 | heightIncreaseMult = max(0.0f, heightIncreaseMult - ms_fTimeStep * 0.02f); 408 | } 409 | } 410 | colMaxZ += 0.4f * heightIncreaseMult; 411 | } 412 | } 413 | 414 | float hackedZoomValue = TheCamera->CarZoomValueSmooth; 415 | 416 | // Emulate the zoom values per veh. type in III! 417 | // Original values: 3.9 - far, 1.9 - mid, 0.05 - near 418 | // Reminder: We don't have near to far transitions, only far to near. 419 | if (isIII()) { 420 | if ((int)TheCamera->CarZoomIndicator == 3) 421 | hackedZoomValue = CarZoomModes[alphaArrPos + 2 * 5]; 422 | else if ((int)TheCamera->CarZoomIndicator == 2) { 423 | hackedZoomValue = (CarZoomModes[alphaArrPos + 1 * 5]) + 424 | (hackedZoomValue - 1.9f) * (CarZoomModes[alphaArrPos + 2 * 5] - CarZoomModes[alphaArrPos + 1 * 5]) / (3.9f - 1.9f); 425 | } else if ((int)TheCamera->CarZoomIndicator == 1) { 426 | hackedZoomValue = (CarZoomModes[alphaArrPos + 0 * 5]) + 427 | (hackedZoomValue - 0.05f) * (CarZoomModes[alphaArrPos + 1 * 5] - CarZoomModes[alphaArrPos + 0 * 5]) / (1.9f - 0.05f); 428 | } 429 | 430 | // Had to put this condition to prevent zooming even more in tunnels etc. 431 | if (hackedZoomValue < CarZoomModes[alphaArrPos]) 432 | hackedZoomValue = CarZoomModes[alphaArrPos]; 433 | } 434 | 435 | float newDistance = hackedZoomValue + CARCAM_SET[camSetArrPos][1] + approxCarLength; 436 | 437 | // Because the widescreen fixes we use today changes FOV and it's nowhere near original car cam. zoom. 438 | if (zoomOnWidescreen && GetAspectRatio() > 0.4f) 439 | newDistance -= 1.0f; 440 | 441 | // Taken from VC CCam::Cam_On_A_String_Unobscured. If we don't this, we will end up seeing the world from the inside of RC Goblin/Raider. 442 | // I couldn't find where SA does that. It's possible that they've increased the size of these veh.'s collision bounding box. 443 | if (isVC()) { 444 | if (car->m_modelIndex != RcRaider && car->m_modelIndex != RcGoblin) { 445 | if (!isReLCS && car->m_modelIndex == MI_VC_RCBARON) 446 | newDistance += 9.5f; 447 | } else 448 | newDistance += 6.0f; 449 | } 450 | float minDistForThisCar = approxCarLength * CARCAM_SET[camSetArrPos][3]; 451 | 452 | if (!isHeli || car->m_status == STATUS_PLAYER_REMOTE) { 453 | float radiusToStayOutside = colMaxZ * CARCAM_SET[camSetArrPos][0] - CARCAM_SET[camSetArrPos][2]; 454 | if (radiusToStayOutside > 0.0f) { 455 | TargetCoors.z += radiusToStayOutside; 456 | newDistance += radiusToStayOutside; 457 | zoomModeAlphaOffset += 0.3f / newDistance * radiusToStayOutside; 458 | } 459 | } 460 | else { 461 | // 0.6f = fTestShiftHeliCamTarget 462 | TargetCoors.x += 0.6f * car->GetUp().x * colMaxZ; 463 | TargetCoors.y += 0.6f * car->GetUp().y * colMaxZ; 464 | TargetCoors.z += 0.6f * car->GetUp().z * colMaxZ; 465 | } 466 | 467 | // SA sets CurrentTweakAngle to this value for RCGOBLIN. VC also adds 0.2f to it 468 | if (isVC() && car->m_modelIndex == RcGoblin) 469 | zoomModeAlphaOffset += 0.178997f; 470 | 471 | float minDistForVehType = CARCAM_SET[camSetArrPos][4]; 472 | #ifdef LCS_CAM 473 | if ((int)TheCamera->CarZoomIndicator == 1 && (camSetArrPos < 2 || camSetArrPos == 7)) { 474 | #else 475 | if ((int)TheCamera->CarZoomIndicator == 1 && (camSetArrPos < 2)) { 476 | #endif 477 | minDistForVehType = minDistForVehType * 0.65f; 478 | } 479 | 480 | float nextDistance = max(newDistance, minDistForVehType); 481 | 482 | cam->CA_MAX_DISTANCE = newDistance; 483 | cam->CA_MIN_DISTANCE = 3.5f; 484 | 485 | if (cam->ResetStatics) { 486 | cam->FOV = DefaultFOV; 487 | 488 | if (isIII()) { 489 | // GTA 3 has this in veh. camera 490 | if (TheCamera->m_bIdleOn) 491 | TheCamera->m_uiTimeWeEnteredIdle = m_snTimeInMilliseconds; 492 | } 493 | } 494 | else { 495 | if (isCar || isBike) { 496 | // 0.4f: CAR_FOV_START_SPEED 497 | if (DotProduct(car->GetForward(), car->m_vecMoveSpeed) > 0.4f) 498 | cam->FOV += (DotProduct(car->GetForward(), car->m_vecMoveSpeed) - 0.4f) * ms_fTimeStep; 499 | } 500 | 501 | if (cam->FOV > DefaultFOV) 502 | // 0.98f: CAR_FOV_FADE_MULT 503 | cam->FOV = pow(0.98f, ms_fTimeStep) * (cam->FOV - DefaultFOV) + DefaultFOV; 504 | 505 | if (cam->FOV <= DefaultFOV + 30.0f) 506 | { 507 | if (cam->FOV < DefaultFOV) 508 | cam->FOV = DefaultFOV; 509 | } else 510 | cam->FOV = DefaultFOV + 30.0f; 511 | } 512 | 513 | // WORKAROUND: I still don't know how looking behind works (m_bCamDirectlyInFront is unused in III, they seem to use m_bUseTransitionBeta) 514 | if (pad->GetLookBehindForCar()) 515 | if (cam->DirectionWasLooking == LOOKING_FORWARD || !cam->LookingBehind) 516 | TheCamera->m_bCamDirectlyInFront = true; 517 | 518 | // Taken from RotCamIfInFrontCar, because we don't call it anymore 519 | if (!(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight())) 520 | if (cam->DirectionWasLooking != LOOKING_FORWARD) 521 | TheCamera->m_bCamDirectlyBehind = true; 522 | 523 | // Called when we just entered the car, just started to look behind or returned back from looking left, right or behind 524 | if (cam->ResetStatics || TheCamera->m_bCamDirectlyBehind || TheCamera->m_bCamDirectlyInFront) { 525 | cam->ResetStatics = false; 526 | cam->Rotating = false; 527 | cam->m_bCollisionChecksOn = true; 528 | // TheCamera.m_bResetOldMatrix = 1; 529 | 530 | // Garage exit cam is not working well in III... 531 | if (isIII() || !TheCamera->m_bJustCameOutOfGarage) // && !sthForScript) 532 | { 533 | cam->Alpha = 0.0f; 534 | cam->Beta = car->GetForward().Heading() - HALFPI; 535 | if (TheCamera->m_bCamDirectlyInFront) { 536 | cam->Beta += PI; 537 | } 538 | } 539 | 540 | cam->BetaSpeed = 0.0; 541 | cam->AlphaSpeed = 0.0; 542 | cam->Distance = 1000.0; 543 | 544 | cam->Front.x = -(cos(cam->Beta) * cos(cam->Alpha)); 545 | cam->Front.y = -(sin(cam->Beta) * cos(cam->Alpha)); 546 | cam->Front.z = sin(cam->Alpha); 547 | 548 | m_aTargetHistoryPosOne = TargetCoors - nextDistance * cam->Front; 549 | 550 | m_aTargetHistoryPosTwo = TargetCoors - newDistance * cam->Front; 551 | 552 | m_nCurrentHistoryPoints = 0; 553 | if (!TheCamera->m_bJustCameOutOfGarage) // && !sthForScript) 554 | cam->Alpha = -zoomModeAlphaOffset; 555 | } 556 | 557 | cam->Front = TargetCoors - m_aTargetHistoryPosOne; 558 | cam->Front.Normalise(); 559 | 560 | // Code that makes cam rotate around the car 561 | float camRightHeading = cam->Front.Heading() - HALFPI; 562 | if (camRightHeading < -PI) 563 | camRightHeading = camRightHeading + TWOPI; 564 | 565 | float velocityRightHeading; 566 | if (car->m_vecMoveSpeed.Magnitude2D() <= 0.02f) 567 | velocityRightHeading = camRightHeading; 568 | else 569 | velocityRightHeading = car->m_vecMoveSpeed.Heading() - HALFPI; 570 | 571 | if (velocityRightHeading < camRightHeading - PI) 572 | velocityRightHeading = velocityRightHeading + TWOPI; 573 | else if (velocityRightHeading > camRightHeading + PI) 574 | velocityRightHeading = velocityRightHeading - TWOPI; 575 | 576 | float v70 = ms_fTimeStep * CARCAM_SET[camSetArrPos][10]; 577 | float v153 = ms_fTimeStep * CARCAM_SET[camSetArrPos][11]; 578 | 579 | float a6f = (car->m_vecMoveSpeed - DotProduct(car->m_vecMoveSpeed, cam->Front) * cam->Front).Magnitude(); 580 | 581 | float v76 = min(1.0f, v70 * a6f) * (velocityRightHeading - camRightHeading); 582 | if (v76 <= v153) 583 | { 584 | if (v76 < -v153) 585 | v76 = -v153; 586 | } 587 | else 588 | { 589 | v76 = v153; 590 | } 591 | float targetBeta = camRightHeading + v76; 592 | 593 | if (targetBeta < cam->Beta - HALFPI) 594 | targetBeta += TWOPI; 595 | else if (targetBeta > cam->Beta + PI) 596 | targetBeta -= TWOPI; 597 | 598 | float carPosChange = (TargetCoors - m_aTargetHistoryPosTwo).Magnitude(); 599 | if (carPosChange < newDistance && newDistance > minDistForThisCar) { 600 | newDistance = max(minDistForThisCar, carPosChange); 601 | } 602 | float maxAlphaAllowed = CARCAM_SET[camSetArrPos][13]; 603 | 604 | // Originally this is to prevent camera enter into car while we're standing, but what about moving??? 605 | // This is also original LCS and SA bug, or some attempt to fix lag. We'll never know 606 | 607 | // Fix camera enters into car bug by default 608 | if (fixTheBug || car->m_vecMoveSpeed.MagnitudeSqr() < 0.04f) 609 | #ifdef LCS_CAM 610 | if (car->m_modelIndex != FireTruk) 611 | #endif 612 | if (!isBike || GetMysteriousWheelRelatedThingBike(car) > 3) 613 | if (!isHeli && (!isPlane || GetWheelsOnGround(car))) { 614 | CVector out = CrossProduct(car->GetForward(), CVector(0.0f, 0.0f, 1.0f)); 615 | out.Normalise(); 616 | CVector v173 = CrossProduct(out, car->GetForward()); 617 | v173.Normalise(); 618 | float v83 = DotProduct(v173, cam->Front); 619 | if (v83 > 0.0) 620 | { 621 | float v88 = asinf(fabsf(sinf(cam->Beta - (car->GetForward().Heading() - HALFPI)))); 622 | float v200; 623 | if (v88 <= atan2f(carCol->boundingBox.max.x, -carCol->boundingBox.min.y)) 624 | { 625 | v200 = (1.5f - carCol->boundingBox.min.y) / cosf(v88); 626 | } 627 | else 628 | { 629 | float a6g = 1.2f + carCol->boundingBox.max.x; 630 | v200 = a6g / cos(max(0.0f, HALFPI - v88)); 631 | } 632 | maxAlphaAllowed = cos(cam->Beta - (car->GetForward().Heading() - HALFPI)) * atan2f(car->GetForward().z, car->GetForward().Magnitude2D()) 633 | + atan2f(TargetCoors.z - car->GetPosition().z + GetHeightAboveRoad(car, ColModelClass), v200 * 1.2f); 634 | if (isCar && GetWheelsOnGround(car) > 1 635 | && fabsf(DotProduct(car->m_vecTurnSpeed, car->GetForward())) < 0.05f) 636 | { 637 | maxAlphaAllowed += cosf(cam->Beta - (car->GetForward().Heading() - HALFPI) + HALFPI) * atan2f(car->GetRight().z, car->GetRight().Magnitude2D()); 638 | } 639 | } 640 | } 641 | 642 | float targetAlpha = asinf(clamp(cam->Front.z, -1.0f, 1.0f)) - zoomModeAlphaOffset; 643 | if (targetAlpha <= maxAlphaAllowed) 644 | { 645 | if (targetAlpha < -CARCAM_SET[camSetArrPos][14]) 646 | targetAlpha = -CARCAM_SET[camSetArrPos][14]; 647 | } 648 | else 649 | { 650 | targetAlpha = maxAlphaAllowed; 651 | } 652 | float maxAlphaBlendAmount = ms_fTimeStep * CARCAM_SET[camSetArrPos][6]; 653 | float targetAlphaBlendAmount = (1.0f - pow(CARCAM_SET[camSetArrPos][5], ms_fTimeStep)) * (targetAlpha - cam->Alpha); 654 | if (targetAlphaBlendAmount <= maxAlphaBlendAmount) 655 | { 656 | if (targetAlphaBlendAmount < -maxAlphaBlendAmount) 657 | targetAlphaBlendAmount = -maxAlphaBlendAmount; 658 | } 659 | else 660 | { 661 | targetAlphaBlendAmount = maxAlphaBlendAmount; 662 | } 663 | 664 | // Using GetCarGun(LR/UD) with Y-axis invert check will give us same unprocessed RightStick value as SA 665 | float stickX = -(pad->GetCarGunLeftRight()); 666 | float stickY = pad->GetCarGunUpDown(); 667 | 668 | // In SA this checks for m_bUseMouse3rdPerson so num2/num8 do not move camera 669 | // when Keyboard & Mouse controls are used. To work best with GInput, check for actual pad state instead 670 | const bool ginputHasPad = ginputPad->HasPadInHands(); 671 | if (ginputLoaded == 2 ? !ginputHasPad : m_bUseMouse3rdPerson) 672 | stickY = 0.0f; 673 | else { 674 | // Added in r4. GInput doesn't hook VC's Y-axis invert option, so that was needed 675 | if (ginputHasPad && padSettings.InvertLook) 676 | stickY = -stickY; 677 | 678 | // Hidden Y-axis invert option in VC. just in case 679 | if (isVC()) 680 | if (*(bool*)0xA10AF7) 681 | stickY = -stickY; 682 | } 683 | 684 | float v103 = cam->FOV * 0.0125f; 685 | 686 | float xMovement = fabsf(stickX) * (v103 * 0.071428575) * stickX * 0.007f * 0.007f; 687 | float yMovement = fabsf(stickY) * (v103 * 0.042857144) * stickY * 0.007f * 0.007f; 688 | 689 | bool correctAlpha = true; 690 | // if (SA checks if we aren't in work car, why?) { 691 | if (!isCar || car->m_modelIndex != CarWithHydraulics) { 692 | correctAlpha = false; 693 | } else { 694 | xMovement = 0.0f; 695 | yMovement = 0.0f; 696 | } 697 | // } else 698 | // yMovement = 0.0; 699 | 700 | if (!nextDirectionIsForward) { 701 | yMovement = 0.0; 702 | xMovement = 0.0; 703 | } 704 | 705 | #ifdef LCS_CAM 706 | if (camSetArrPos == 0 || camSetArrPos == 7) { 707 | #else 708 | if (camSetArrPos == 0) { 709 | #endif 710 | // This is not working on cars as SA 711 | // Because III/VC doesn't have any buttons tied to LeftStick if you're not in Classic Configuration, using Dodo or using GInput/Pad, so :shrug: 712 | if (fabsf(pad->GetSteeringUpDown()) > 120.0f) { 713 | 714 | // OBJECTIVE_LEAVE_VEHICLE 715 | if (car->pDriver && GetPedObjective(car->pDriver) != (isIII() ? 13 : 16)) { 716 | yMovement += fabsf(pad->GetSteeringUpDown()) * (cam->FOV * 0.0125 * 0.042857144) * pad->GetSteeringUpDown() * 0.007f * 0.007f * 0.5; 717 | } 718 | } 719 | } 720 | 721 | if (yMovement > 0.0) 722 | yMovement = yMovement * 0.5; 723 | 724 | bool mouseChangesBeta = false; 725 | 726 | // FIX: Disable mouse movement in drive-by, it's buggy. Original SA bug. 727 | if (m_bUseMouse3rdPerson && !GetDisablePlayerControls(pad) && nextDirectionIsForward) 728 | { 729 | float mouseY = CPad::NewMouseControllerState.y * 2.0f; 730 | float mouseX = CPad::NewMouseControllerState.x * -2.0f; 731 | 732 | // If you want an ability to toggle free cam while steering with mouse, you can add an OR after DisableMouseSteering. 733 | // There was a pad->NewState.m_bVehicleMouseLook in SA, which doesn't exists in III. 734 | 735 | if ((mouseX != 0.0 || mouseY != 0.0) && (m_bDisableMouseSteering)) 736 | { 737 | float v113 = cam->FOV * 0.0125; 738 | yMovement = mouseY * v113 * GetMouseAccel(TheCamera); // Same as SA, horizontal sensitivity. 739 | cam->BetaSpeed = 0.0; 740 | cam->AlphaSpeed = 0.0; 741 | xMovement = mouseX * v113 * GetMouseAccel(TheCamera); 742 | targetAlpha = cam->Alpha; 743 | stepsLeftToChangeBetaByMouse = 1.0f * 50.0f; 744 | mouseChangesBeta = true; 745 | } 746 | else if (stepsLeftToChangeBetaByMouse > 0.0f) 747 | { 748 | // Finish rotation by decreasing speed when we stopped moving mouse 749 | cam->BetaSpeed = 0.0; 750 | cam->AlphaSpeed = 0.0; 751 | yMovement = 0.0; 752 | xMovement = 0.0; 753 | targetAlpha = cam->Alpha; 754 | stepsLeftToChangeBetaByMouse = max(0.0f, stepsLeftToChangeBetaByMouse - ms_fTimeStep); 755 | mouseChangesBeta = true; 756 | } 757 | } 758 | 759 | /* 760 | // That doesn't exist on LCS, and I didn't put much thought into it 761 | if (car->pPassengers[0] && car->pPassengers[0]->m_objective == OBJECTIVE_SOLICIT) 762 | { 763 | if (BYTE1(CTaskManager::GetActiveTask(&car->__parent.__parent.m_apPassengers[0]->intelligence->m_taskManager)[5].m_pParentTask) & 1) 764 | { 765 | if (maxAlphaAllowed - flt_8CCEC8 <= v7->Alpha) 766 | yMovement = 0.0; 767 | else 768 | yMovement = ms_fTimeStep * flt_8CCEC4; 769 | } 770 | } */ 771 | if (correctAlpha) { 772 | if (previousMode != MODE_CAMONASTRING) 773 | alphaCorrected = false; 774 | 775 | if (!alphaCorrected && fabsf(zoomModeAlphaOffset + cam->Alpha) > 0.05f) { 776 | yMovement = (-zoomModeAlphaOffset - cam->Alpha) * 0.05f; 777 | } else 778 | alphaCorrected = true; 779 | } 780 | float alphaSpeedFromStickY = yMovement * CARCAM_SET[camSetArrPos][12]; 781 | float betaSpeedFromStickX = xMovement * CARCAM_SET[camSetArrPos][12]; 782 | float v117 = CARCAM_SET[camSetArrPos][9]; 783 | float angleChangeStep = pow(CARCAM_SET[camSetArrPos][8], ms_fTimeStep); 784 | float targetBetaWithStickBlendAmount = betaSpeedFromStickX + (targetBeta - cam->Beta) / max(ms_fTimeStep, 1.0f); 785 | 786 | if (targetBetaWithStickBlendAmount < -v117) 787 | targetBetaWithStickBlendAmount = -v117; 788 | else if (targetBetaWithStickBlendAmount > v117) 789 | targetBetaWithStickBlendAmount = v117; 790 | 791 | float angleChangeStepLeft = 1.0 - angleChangeStep; 792 | cam->BetaSpeed = targetBetaWithStickBlendAmount * angleChangeStepLeft + angleChangeStep * cam->BetaSpeed; 793 | if (fabsf(cam->BetaSpeed) < 0.0001f) 794 | cam->BetaSpeed = 0.0; 795 | 796 | float v121; 797 | if (mouseChangesBeta) 798 | v121 = betaSpeedFromStickX; 799 | else 800 | v121 = ms_fTimeStep * cam->BetaSpeed; 801 | cam->Beta = v121 + cam->Beta; 802 | 803 | // SA: 804 | if (TheCamera->m_bJustCameOutOfGarage) 805 | cam->Beta = GetATanOfXY(cam->Front.x, cam->Front.y) + PI; 806 | 807 | if (cam->Beta < -PI) 808 | cam->Beta += TWOPI; 809 | else if (cam->Beta > PI) 810 | cam->Beta -= TWOPI; 811 | 812 | /* LCS: 813 | if (TheCamera->m_bJustCameOutOfGarage) { 814 | float v168 = atan2f(cam->Front.y, cam->Front.x); 815 | if (v168 < 0.0f) 816 | v168 = v168 + TWOPI; 817 | 818 | cam->Beta = v168 + PI; 819 | } 820 | 821 | cam->Beta = LimitRadianAngle(cam->Beta); 822 | if (cam->Beta < 0.0f) 823 | cam->Beta += TWOPI; 824 | */ 825 | 826 | #ifdef LCS_CAM 827 | if ((camSetArrPos <= 1 || camSetArrPos == 7) && targetAlpha < cam->Alpha && carPosChange >= newDistance) { 828 | #else 829 | if (camSetArrPos <= 1 && targetAlpha < cam->Alpha && carPosChange >= newDistance) { 830 | #endif 831 | if (isCar && GetWheelsOnGround(car) > 1 || 832 | isBike && GetMysteriousWheelRelatedThingBike(car) > 1) 833 | alphaSpeedFromStickY += (targetAlpha - cam->Alpha) * 0.075f; 834 | } 835 | 836 | cam->AlphaSpeed = angleChangeStepLeft * alphaSpeedFromStickY + angleChangeStep * cam->AlphaSpeed; 837 | float maxAlphaSpeed = v117; 838 | if (alphaSpeedFromStickY > 0.0f) 839 | maxAlphaSpeed = maxAlphaSpeed * 0.5; 840 | 841 | if (cam->AlphaSpeed <= maxAlphaSpeed) 842 | { 843 | float minAlphaSpeed = -maxAlphaSpeed; 844 | if (cam->AlphaSpeed < minAlphaSpeed) 845 | cam->AlphaSpeed = minAlphaSpeed; 846 | } 847 | else 848 | { 849 | cam->AlphaSpeed = maxAlphaSpeed; 850 | } 851 | 852 | if (fabsf(cam->AlphaSpeed) < 0.0001f) 853 | cam->AlphaSpeed = 0.0f; 854 | 855 | float alphaWithSpeedAccounted; 856 | if (mouseChangesBeta) 857 | { 858 | alphaWithSpeedAccounted = alphaSpeedFromStickY + targetAlpha; 859 | cam->Alpha += alphaSpeedFromStickY; 860 | } 861 | else 862 | { 863 | alphaWithSpeedAccounted = ms_fTimeStep * cam->AlphaSpeed + targetAlpha; 864 | cam->Alpha += targetAlphaBlendAmount; 865 | } 866 | 867 | if (cam->Alpha <= maxAlphaAllowed) 868 | { 869 | float minAlphaAllowed = -CARCAM_SET[camSetArrPos][14]; 870 | if (minAlphaAllowed > cam->Alpha) 871 | { 872 | cam->Alpha = minAlphaAllowed; 873 | cam->AlphaSpeed = 0.0; 874 | } 875 | } 876 | else 877 | { 878 | cam->Alpha = maxAlphaAllowed; 879 | cam->AlphaSpeed = 0.0; 880 | } 881 | 882 | // Prevent unsignificant angle changes 883 | if (fabsf(lastAlpha - cam->Alpha) < 0.0001f) 884 | cam->Alpha = lastAlpha; 885 | 886 | lastAlpha = cam->Alpha; 887 | 888 | if (fabsf(lastBeta - cam->Beta) < 0.0001f) 889 | cam->Beta = lastBeta; 890 | 891 | lastBeta = cam->Beta; 892 | 893 | cam->Front.x = -(cos(cam->Beta) * cos(cam->Alpha)); 894 | cam->Front.y = -(sin(cam->Beta) * cos(cam->Alpha)); 895 | cam->Front.z = sin(cam->Alpha); 896 | cam->GetVectorsReadyForRW(); 897 | TheCamera->m_bCamDirectlyBehind = false; 898 | TheCamera->m_bCamDirectlyInFront = false; 899 | 900 | cam->Source = TargetCoors - newDistance * cam->Front; 901 | 902 | 903 | cam->m_cvecTargetCoorsForFudgeInter = TargetCoors; 904 | m_aTargetHistoryPosThree = m_aTargetHistoryPosOne; 905 | float v140 = alphaWithSpeedAccounted + zoomModeAlphaOffset; 906 | float v144 = -(cos(cam->Beta) * cos(v140)); 907 | float v145 = -(sin(cam->Beta) * cos(v140)); 908 | float v146 = sin(v140); 909 | 910 | m_aTargetHistoryPosOne.x = TargetCoors.x - v144 * nextDistance; 911 | m_aTargetHistoryPosOne.y = TargetCoors.y - v145 * nextDistance; 912 | m_aTargetHistoryPosOne.z = TargetCoors.z - v146 * nextDistance; 913 | 914 | m_aTargetHistoryPosTwo.x = TargetCoors.x - v144 * newDistance; 915 | m_aTargetHistoryPosTwo.y = TargetCoors.y - v145 * newDistance; 916 | m_aTargetHistoryPosTwo.z = TargetCoors.z - v146 * newDistance; 917 | 918 | // SA calls SetColVarsVehicle in here 919 | if (nextDirectionIsForward) { 920 | /* SA 921 | CWorld::pIgnoreEntity = car; 922 | TheCamera.m_nExtraEntitiesCount = 0; 923 | TheCamera.sub_50CDE0(car); 924 | CCamera::CameraColDetAndReact(Source, TargetCoors); 925 | TheCamera->ImproveNearClip(car, 0, Source, TargetCoors); 926 | CWorld::pIgnoreEntity = 0; 927 | */ 928 | // Instead of above code (because it's rather impossible) I will use LCS FollowCar and SA FollowPedWithMouse col. detection 929 | 930 | 931 | // Move cam if there are collisions 932 | float v206 = powf(0.99, ms_fTimeStep); 933 | flt_9BF250 = (v206 * flt_9BF250) + ((1.0f - v206) * car->m_vecMoveSpeed.Magnitude()); 934 | 935 | CColPoint foundCol; 936 | CEntity* foundEnt; 937 | pIgnoreEntity = cam->CamTargetEntity; 938 | if (WorldClass::ProcessLineOfSight(TargetCoors, cam->Source, foundCol, foundEnt, true, flt_9BF250 < 0.1f, false, true, false, true, false)) 939 | { 940 | float obstacleTargetDist = (TargetCoors - foundCol.point).Magnitude(); 941 | float obstacleCamDist = newDistance - obstacleTargetDist; 942 | if (!foundEnt->IsPed() || obstacleCamDist <= 1.0f) 943 | { 944 | cam->Source = foundCol.point; 945 | if (obstacleTargetDist < 1.2f) 946 | { 947 | RwCameraSetNearClipPlane(RwCamera, max(0.05f, obstacleTargetDist - 0.3f)); 948 | } 949 | } 950 | else 951 | { 952 | if (!WorldClass::ProcessLineOfSight(foundCol.point, cam->Source, foundCol, foundEnt, true, flt_9BF250 < 0.1f, false, true, false, true, false)) 953 | { 954 | float lessClip = obstacleCamDist - 0.35f; 955 | if (lessClip <= 0.9f) 956 | RwCameraSetNearClipPlane(RwCamera, lessClip); 957 | else 958 | RwCameraSetNearClipPlane(RwCamera, 0.9f); 959 | } else { 960 | obstacleTargetDist = (TargetCoors - foundCol.point).Magnitude(); 961 | cam->Source = foundCol.point; 962 | if (obstacleTargetDist < 1.2f) 963 | { 964 | float lessClip = obstacleTargetDist - 0.3f; 965 | if (lessClip >= 0.05f) 966 | RwCameraSetNearClipPlane(RwCamera, lessClip); 967 | else 968 | RwCameraSetNearClipPlane(RwCamera, 0.05f); 969 | } 970 | } 971 | } 972 | } 973 | pIgnoreEntity = nil; 974 | float nearClip = GetNearPlane(); 975 | float radius = tanf(cam->FOV * 0.017453292f * 0.5f) * GetAspectRatio() * 1.1f; 976 | 977 | // If we're seeing blue hell due to camera intersects some surface, fix it. 978 | // SA and LCS have this unrolled. 979 | for (int i = 0; 980 | i <= 5 && WorldClass::TestSphereAgainstWorld((nearClip * cam->Front) + cam->Source, radius * nearClip, nil, true, true, false, true, false, false); 981 | i++) { 982 | 983 | CVector surfaceCamDist = ms_testSpherePoint.point - cam->Source; 984 | CVector v52 = DotProduct(surfaceCamDist, cam->Front) * cam->Front; 985 | float v86 = (surfaceCamDist - v52).Magnitude() / radius; 986 | 987 | if (v86 > nearClip) 988 | v86 = nearClip; 989 | if (v86 < 0.1) 990 | v86 = 0.1; 991 | if (nearClip > v86) 992 | RwCameraSetNearClipPlane(RwCamera, v86); 993 | 994 | if (v86 == 0.1f) 995 | cam->Source += (TargetCoors - cam->Source) * 0.3f; 996 | 997 | nearClip = GetNearPlane(); 998 | radius = tanf(cam->FOV * 0.017453292f * 0.5f) * GetAspectRatio() * 1.1f; 999 | } 1000 | } 1001 | TheCamera->m_bCamDirectlyBehind = false; 1002 | TheCamera->m_bCamDirectlyInFront = false; 1003 | 1004 | // ------- LCS specific part starts 1005 | 1006 | if (camSetArrPos == 5 && cam->Source.z < 1.0f) // RC Bandit and Baron 1007 | cam->Source.z = 1.0f; 1008 | 1009 | // Obviously some specific place in LC 1010 | if (isReLCS || isIII()) 1011 | if (cam->Source.x > 11.0f && cam->Source.x < 91.0f) { 1012 | if (cam->Source.y > -680.0f && cam->Source.y < -600.0f && cam->Source.z < 24.4f) 1013 | cam->Source.z = 24.4f; 1014 | } 1015 | 1016 | if (!seeUnderwater) { 1017 | // CCam::FixSourceAboveWaterLevel 1018 | if (CameraTarget.z >= -2.0f) { 1019 | float level = -6000.0; 1020 | // +0.5f is needed for III 1021 | if (CWaterLevel::GetWaterLevelNoWaves(cam->Source.x, cam->Source.y, cam->Source.z, &level)) { 1022 | if (cam->Source.z < level + 0.5f) 1023 | cam->Source.z = level + 0.5f; 1024 | } 1025 | } 1026 | } 1027 | 1028 | cam->Front = TargetCoors - cam->Source; 1029 | 1030 | // -------- LCS specific part ends 1031 | 1032 | cam->GetVectorsReadyForRW(); 1033 | // SA 1034 | // gTargetCoordsForLookingBehind = TargetCoors; 1035 | 1036 | // SA code from CAutomobile::TankControl/FireTruckControl. 1037 | if (car->m_modelIndex == Tank || car->m_modelIndex == FireTruk) { 1038 | CVector hi = Multiply3x3(cam->Front, car->GetMatrix()); 1039 | 1040 | // III/VC's firetruck turret angle is reversed 1041 | float angleToFace = (car->m_modelIndex == FireTruk ? -hi.Heading() : hi.Heading()); 1042 | 1043 | if (angleToFace <= *GetDoomAnglePtrLR(car) + PI) { 1044 | if (angleToFace < *GetDoomAnglePtrLR(car) - PI) 1045 | angleToFace = angleToFace + TWOPI; 1046 | } else { 1047 | angleToFace = angleToFace - TWOPI; 1048 | } 1049 | 1050 | float neededTurn = angleToFace - *GetDoomAnglePtrLR(car); 1051 | float turnPerFrame = ms_fTimeStep * (car->m_modelIndex == FireTruk ? 0.05f : 0.015f); 1052 | if (neededTurn <= turnPerFrame) { 1053 | if (neededTurn < -turnPerFrame) 1054 | angleToFace = *GetDoomAnglePtrLR(car) - turnPerFrame; 1055 | } else { 1056 | angleToFace = turnPerFrame + *GetDoomAnglePtrLR(car); 1057 | } 1058 | 1059 | if (car->m_modelIndex == Tank && *GetDoomAnglePtrLR(car) != angleToFace) { 1060 | DMAudio.PlayOneShot(car->m_audioEntityId, (isIII() ? 26 : 28), fabsf(angleToFace - *GetDoomAnglePtrLR(car))); 1061 | } 1062 | *GetDoomAnglePtrLR(car) = angleToFace; 1063 | 1064 | if (*GetDoomAnglePtrLR(car) < -PI) { 1065 | *GetDoomAnglePtrLR(car) += TWOPI; 1066 | } else if (*GetDoomAnglePtrLR(car) > PI) { 1067 | *GetDoomAnglePtrLR(car) -= TWOPI; 1068 | } 1069 | 1070 | // Because firetruk turret also has Y movement 1071 | if (car->m_modelIndex == FireTruk) { 1072 | float alphaToFace = atan2f(hi.z, hi.Magnitude2D()) + 0.2617994f; 1073 | float neededAlphaTurn = alphaToFace - *GetDoomAnglePtrUD(car); 1074 | float alphaTurnPerFrame = ms_fTimeStep * 0.02f; 1075 | 1076 | if (neededAlphaTurn > alphaTurnPerFrame) { 1077 | neededTurn = alphaTurnPerFrame; 1078 | *GetDoomAnglePtrUD(car) = neededTurn + *GetDoomAnglePtrUD(car); 1079 | } else { 1080 | if (neededAlphaTurn >= -alphaTurnPerFrame) { 1081 | *GetDoomAnglePtrUD(car) = alphaToFace; 1082 | } else { 1083 | *GetDoomAnglePtrUD(car) = *GetDoomAnglePtrUD(car) - alphaTurnPerFrame; 1084 | } 1085 | } 1086 | 1087 | float turretMinY = -0.34906587f; 1088 | float turretMaxY = 0.34906587f; 1089 | if (turretMinY <= *GetDoomAnglePtrUD(car)) { 1090 | if (*GetDoomAnglePtrUD(car) > turretMaxY) 1091 | *GetDoomAnglePtrUD(car) = turretMaxY; 1092 | } else { 1093 | *GetDoomAnglePtrUD(car) = turretMinY; 1094 | } 1095 | 1096 | if (isReLCS) { 1097 | // Actual rotating turret for RE:LCS 1098 | // CAR_BUMP_REAR (firetruck turret lol) = 8 1099 | if (GetVehicleComponent(car, 8)) { 1100 | CMatrix mat; 1101 | CVector pos; 1102 | 1103 | mat.Attach(RwFrameGetMatrix(GetVehicleComponent(car, 8))); 1104 | pos = mat.GetPosition(); 1105 | mat.SetRotateZ(-(*GetDoomAnglePtrLR(car))); 1106 | mat.GetPosition() = pos; 1107 | mat.UpdateRW(); 1108 | } 1109 | } 1110 | } 1111 | } 1112 | 1113 | previousMode = cam->Mode; 1114 | } 1115 | 1116 | void 1117 | CCamVC::GetVectorsReadyForRW(void) 1118 | { 1119 | CVector right; 1120 | Up = CVector(0.0f, 0.0f, 1.0f); 1121 | Front.Normalise(); 1122 | if (Front.x == 0.0f && Front.y == 0.0f) { 1123 | Front.x = 0.0001f; 1124 | Front.y = 0.0001f; 1125 | } 1126 | right = CrossProduct(Front, Up); 1127 | right.Normalise(); 1128 | Up = CrossProduct(right, Front); 1129 | } 1130 | 1131 | void 1132 | CCamIII::GetVectorsReadyForRW(void) 1133 | { 1134 | CVector right; 1135 | Up = CVector(0.0f, 0.0f, 1.0f); 1136 | Front.Normalise(); 1137 | if (Front.x == 0.0f && Front.y == 0.0f) { 1138 | Front.x = 0.0001f; 1139 | Front.y = 0.0001f; 1140 | } 1141 | right = CrossProduct(Front, Up); 1142 | right.Normalise(); 1143 | Up = CrossProduct(right, Front); 1144 | } 1145 | 1146 | #define currentMode (isIII() ? TheCameraIII->Cams[TheCameraIII->ActiveCam].Mode : TheCameraVC->Cams[TheCameraVC->ActiveCam].Mode) 1147 | 1148 | // Needed for storing previous mode for some unknown alpha angle effect. 1149 | // Credits goes to The Hero - aap for reversing it (comments are belong to him) 1150 | void 1151 | WellBufferMe(float Target, float* CurrentValue, float* CurrentSpeed, float MaxSpeed, float Acceleration, bool IsAngle) 1152 | { 1153 | // MaxSpeed is a limit of how fast the value is allowed to change. 1.0 = to Target in up to 1ms 1154 | // Acceleration is how fast the speed will change to MaxSpeed. 1.0 = to MaxSpeed in 1ms 1155 | 1156 | float Delta = Target - *CurrentValue; 1157 | 1158 | if (IsAngle) { 1159 | while (Delta >= PI) Delta -= 2 * PI; 1160 | while (Delta < -PI) Delta += 2 * PI; 1161 | } 1162 | 1163 | float TargetSpeed = Delta * MaxSpeed; 1164 | *CurrentSpeed += Acceleration * (TargetSpeed - *CurrentSpeed) * ms_fTimeStep; 1165 | 1166 | // Clamp speed if we overshot 1167 | if (TargetSpeed < 0.0f && *CurrentSpeed < TargetSpeed) 1168 | * CurrentSpeed = TargetSpeed; 1169 | else if (TargetSpeed > 0.0f && *CurrentSpeed > TargetSpeed) 1170 | * CurrentSpeed = TargetSpeed; 1171 | 1172 | *CurrentValue += *CurrentSpeed * min(10.0f, ms_fTimeStep); 1173 | 1174 | previousMode = currentMode; 1175 | } 1176 | 1177 | int16 1178 | CPad::FakeCarGunLeftRight(void) 1179 | { 1180 | if (currentMode == MODE_CAMONASTRING) 1181 | return 0; 1182 | else 1183 | return pad0.GetCarGunLeftRight(); 1184 | } 1185 | 1186 | int16 1187 | CPad::FakeCarGunUpDown(void) 1188 | { 1189 | if (currentMode == MODE_CAMONASTRING) 1190 | return 0; 1191 | else 1192 | return pad0.GetCarGunUpDown(); 1193 | } 1194 | #undef currentMode 1195 | 1196 | void 1197 | CCamIII::Process_FollowCar_SA_III(const CVector &CameraTarget, float TargetOrientation, float, float) 1198 | { 1199 | Process_FollowCar_SA(CameraTarget, TargetOrientation, this, TheCameraIII); 1200 | } 1201 | 1202 | void 1203 | CCamVC::Process_FollowCar_SA_VC(const CVector &CameraTarget, float TargetOrientation, float, float) 1204 | { 1205 | Process_FollowCar_SA(CameraTarget, TargetOrientation, this, TheCameraVC); 1206 | } 1207 | 1208 | BOOL WINAPI 1209 | DllMain(HINSTANCE hInst, DWORD reason, LPVOID) 1210 | { 1211 | if (reason == DLL_PROCESS_ATTACH) { 1212 | dllModule = hInst; 1213 | 1214 | /* Taken from SkyGFX 1215 | if (GetAsyncKeyState(VK_F8) & 0x8000) { 1216 | AllocConsole(); 1217 | freopen("CONIN$", "r", stdin); 1218 | freopen("CONOUT$", "w", stdout); 1219 | freopen("CONOUT$", "w", stderr); 1220 | } 1221 | */ 1222 | 1223 | GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)& DllMain, &hDummyHandle); 1224 | 1225 | // III 1226 | if (*(DWORD*)0x5C1E70 == 0x53E58955) { 1227 | InjectHook(0x456F40, &WellBufferMe, PATCH_JUMP); 1228 | InjectHook(0x459A54, &CCamIII::Process_FollowCar_SA_III, PATCH_NOTHING); 1229 | InjectHook(0x459B36, &CCamIII::Process_FollowCar_SA_III, PATCH_NOTHING); 1230 | 1231 | // To block original rhino-firetruck turret movement 1232 | InjectHook(0x52260E, &CPad::FakeCarGunUpDown, PATCH_NOTHING); 1233 | InjectHook(0x53D628, &CPad::FakeCarGunLeftRight, PATCH_NOTHING); 1234 | InjectHook(0x5225D2, &CPad::FakeCarGunLeftRight, PATCH_NOTHING); 1235 | // VC 1236 | } else if (*(DWORD*)0x667BF5 == 0xB85548EC) { 1237 | 1238 | // checks for settings file name (gta_lcs.set in this case) 1239 | isReLCS = *(DWORD*)0x68CFCC == 0x2E73636C; 1240 | 1241 | InjectHook(0x4864E3, &WellBufferMe, PATCH_JUMP); 1242 | InjectHook(0x483B3B, &CCamVC::Process_FollowCar_SA_VC, PATCH_NOTHING); 1243 | InjectHook(0x483B79, &CCamVC::Process_FollowCar_SA_VC, PATCH_NOTHING); 1244 | InjectHook(0x483C3C, &CCamVC::Process_FollowCar_SA_VC, PATCH_NOTHING); 1245 | 1246 | // To block original rhino-firetruck turret movement 1247 | InjectHook(0x57ABAE, &CPad::FakeCarGunUpDown, PATCH_NOTHING); 1248 | InjectHook(0x57AB72, &CPad::FakeCarGunLeftRight, PATCH_NOTHING); 1249 | InjectHook(0x5865B8, &CPad::FakeCarGunLeftRight, PATCH_NOTHING); 1250 | 1251 | // Patch zoom modes 1252 | // Only for VC atm., III doesn't have zoom values per veh. types 1253 | for (int i = 0; i < sizeof(CarZoomModes) / sizeof(CarZoomModes[0]); i++) { 1254 | addr a = 0x68AB70 + i*sizeof(CarZoomModes[0]); 1255 | Patch(a, CarZoomModes[i]); 1256 | } 1257 | } 1258 | else return FALSE; 1259 | 1260 | InterceptCall(&DebugInitTextBuffer, registerDebugMenu, ditbAddress); 1261 | } 1262 | return TRUE; 1263 | } 1264 | --------------------------------------------------------------------------------