diff options
author | erorcun <erayorcunus@gmail.com> | 2020-10-04 22:18:33 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-04 22:18:33 +0300 |
commit | ea4007a13c844007b5b5ad06b6e01941cbd66e10 (patch) | |
tree | 32195602f9ba72f90ff2dbe4a2a1447f339012e1 | |
parent | 39678ba5cad61067547771e4a3037e4944f6a5c5 (diff) | |
parent | fae97f29c4f14cba0d37695d67e959defbe7ea75 (diff) |
Merge pull request #738 from erorcun/master
Fixes, mouse AUX buttons, joystick detect menu, INI
-rw-r--r-- | src/audio/MusicManager.cpp | 2 | ||||
-rw-r--r-- | src/core/Frontend.cpp | 50 | ||||
-rw-r--r-- | src/core/Game.cpp | 6 | ||||
-rw-r--r-- | src/core/Pad.h | 2 | ||||
-rw-r--r-- | src/core/common.h | 4 | ||||
-rw-r--r-- | src/core/config.h | 6 | ||||
-rw-r--r-- | src/core/main.h | 5 | ||||
-rw-r--r-- | src/core/re3.cpp | 148 | ||||
-rw-r--r-- | src/core/timebars.cpp | 2 | ||||
-rw-r--r-- | src/extras/frontendoption.cpp | 16 | ||||
-rw-r--r-- | src/extras/frontendoption.h | 16 | ||||
-rw-r--r-- | src/extras/ini_parser.hpp | 314 | ||||
-rw-r--r-- | src/render/Hud.cpp | 8 | ||||
-rw-r--r-- | src/skel/crossplatform.cpp | 10 | ||||
-rw-r--r-- | src/skel/crossplatform.h | 4 | ||||
-rw-r--r-- | src/skel/glfw/glfw.cpp | 91 | ||||
-rw-r--r-- | src/skel/win/win.cpp | 2 | ||||
-rw-r--r-- | src/text/Text.cpp | 2 | ||||
-rw-r--r-- | src/vehicles/CarGen.cpp | 10 |
19 files changed, 583 insertions, 115 deletions
diff --git a/src/audio/MusicManager.cpp b/src/audio/MusicManager.cpp index 9cf092b3..5519d899 100644 --- a/src/audio/MusicManager.cpp +++ b/src/audio/MusicManager.cpp @@ -161,7 +161,7 @@ cMusicManager::DisplayRadioStationName() CFont::SetPropOn(); CFont::SetFontStyle(FONT_HEADING); CFont::SetCentreOn(); - CFont::SetCentreSize(SCREEN_STRETCH_X(640.0f)); + CFont::SetCentreSize(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH)); CFont::SetColor(CRGBA(0, 0, 0, 255)); CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(22.0f) + SCREEN_SCALE_Y(2.0f), pCurrentStation); diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 9ead2a0a..db3774a7 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -854,6 +854,13 @@ CMenuManager::Draw() str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName); break; default: +#ifdef CUSTOM_FRONTEND_OPTIONS + if (aScreens[m_nCurrScreen].m_aEntries[0].m_SaveSlot == SAVESLOT_CFO) { + FrontendOption& option = customFrontendOptions[aScreens[m_nCurrScreen].m_aEntries[0].m_TargetMenu]; + str = (wchar*)option.leftText; + } + else +#endif str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName); break; } @@ -3443,19 +3450,6 @@ CMenuManager::LoadSettings() CFileMgr::Read(fileHandle, m_PrefsSkinFile, 256); CFileMgr::Read(fileHandle, (char*)&m_ControlMethod, 1); CFileMgr::Read(fileHandle, (char*)&m_PrefsLanguage, 1); -#ifdef CUSTOM_FRONTEND_OPTIONS - for (int i = 0; i < numCustomFrontendOptions; i++) { - FrontendOption& option = customFrontendOptions[i]; - if (option.save) { - CFileMgr::Read(fileHandle, (char*)option.value, 1); - option.lastSavedValue = option.displayedValue = *option.value; - } - } -#endif -#ifdef NO_ISLAND_LOADING - CFileMgr::Read(fileHandle, (char *)&CMenuManager::m_PrefsIslandLoading, 1); - CMenuManager::m_DisplayIslandLoading = CMenuManager::m_PrefsIslandLoading; -#endif } } @@ -3472,8 +3466,11 @@ CMenuManager::LoadSettings() m_bLanguageLoaded = false; else { m_bLanguageLoaded = true; + // Already called in InitialiseChangedLanguageSettings + /* TheText.Unload(); TheText.Load(); + */ m_bFrontEnd_ReloadObrTxtGxt = true; InitialiseChangedLanguageSettings(); @@ -3546,21 +3543,14 @@ CMenuManager::SaveSettings() CFileMgr::Write(fileHandle, m_PrefsSkinFile, 256); CFileMgr::Write(fileHandle, (char*)&m_ControlMethod, 1); CFileMgr::Write(fileHandle, (char*)&m_PrefsLanguage, 1); -#ifdef CUSTOM_FRONTEND_OPTIONS - for (int i = 0; i < numCustomFrontendOptions; i++) { - FrontendOption &option = customFrontendOptions[i]; - if (option.save) { - CFileMgr::Write(fileHandle, (char*)option.value, 1); - } - } -#endif -#ifdef NO_ISLAND_LOADING - CFileMgr::Write(fileHandle, (char *)&CMenuManager::m_PrefsIslandLoading, 1); -#endif } CFileMgr::CloseFile(fileHandle); CFileMgr::SetDir(""); + +#ifdef LOAD_INI_SETTINGS + SaveINISettings(); +#endif } bool DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha); @@ -3880,7 +3870,10 @@ CMenuManager::Process(void) MouseButtonJustClicked = 4; else if (CPad::GetPad(0)->GetMouseWheelDownJustUp()) MouseButtonJustClicked = 5; - // TODO two more buttons + else if (CPad::GetPad(0)->GetMouseX1JustUp()) + MouseButtonJustClicked = 6; + else if (CPad::GetPad(0)->GetMouseX2JustUp()) + MouseButtonJustClicked = 7; JoyButtonJustClicked = ControlsManager.GetJoyButtonJustDown(); @@ -5106,7 +5099,8 @@ CMenuManager::ProcessButtonPresses(void) *option.value = option.lastSavedValue = option.displayedValue; } else if (option.type == FEOPTION_DYNAMIC) { - option.buttonPressFunc(FEOPTION_ACTION_SELECT); + if (option.buttonPressFunc) + option.buttonPressFunc(FEOPTION_ACTION_SELECT); } else if (option.type == FEOPTION_REDIRECT) { ChangeScreen(option.to, option.option, true, option.fadeIn); } else if (option.type == FEOPTION_GOBACK) { @@ -5349,7 +5343,7 @@ CMenuManager::ProcessButtonPresses(void) option.changeFunc(option.displayedValue); *option.value = option.lastSavedValue = option.displayedValue; } - } else if (option.type == FEOPTION_DYNAMIC) { + } else if (option.type == FEOPTION_DYNAMIC && option.buttonPressFunc) { option.buttonPressFunc(changeValueBy > 0 ? FEOPTION_ACTION_RIGHT : FEOPTION_ACTION_LEFT); } DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0); @@ -6317,4 +6311,4 @@ CMenuManager::ConstructStatLine(int rowIdx) #undef GetBackJustDown #undef ChangeScreen -#endif
\ No newline at end of file +#endif diff --git a/src/core/Game.cpp b/src/core/Game.cpp index e944512a..93f0d1b0 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -295,11 +295,15 @@ bool CGame::InitialiseOnceAfterRW(void) CWorld::Players[0].SetPlayerSkin(CMenuManager::m_PrefsSkinFile); #ifdef CUSTOM_FRONTEND_OPTIONS + // Apparently this func. can be run multiple times at the start. if (numCustomFrontendOptions == 0 && numCustomFrontendScreens == 0) { + // needs stored language and TheText to be loaded, and last TheText reload is at the start of here CustomFrontendOptionsPopulate(); - FrontEndMenuManager.LoadSettings(); } #endif +#ifdef LOAD_INI_SETTINGS + LoadINISettings(); // needs frontend options to be loaded +#endif return true; } diff --git a/src/core/Pad.h b/src/core/Pad.h index 8c3bc752..8c5d7ba3 100644 --- a/src/core/Pad.h +++ b/src/core/Pad.h @@ -277,6 +277,8 @@ public: bool GetMiddleMouseJustUp() { return !!(!NewMouseControllerState.MMB && OldMouseControllerState.MMB); } bool GetMouseWheelUpJustUp() { return !!(!NewMouseControllerState.WHEELUP && OldMouseControllerState.WHEELUP); } bool GetMouseWheelDownJustUp() { return !!(!NewMouseControllerState.WHEELDN && OldMouseControllerState.WHEELDN); } + bool GetMouseX1JustUp() { return !!(!NewMouseControllerState.MXB1 && OldMouseControllerState.MXB1); } + bool GetMouseX2JustUp() { return !!(!NewMouseControllerState.MXB2 && OldMouseControllerState.MXB2); } bool GetLeftMouse() { return NewMouseControllerState.LMB; } bool GetRightMouse() { return NewMouseControllerState.RMB; } diff --git a/src/core/common.h b/src/core/common.h index 9b5c2369..ef3da265 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -219,6 +219,8 @@ public: extern int strcasecmp(const char *str1, const char *str2); #endif +extern wchar *AllocUnicode(const char*src); + #define clamp(v, low, high) ((v)<(low) ? (low) : (v)>(high) ? (high) : (v)) inline float sq(float x) { return x*x; } @@ -444,4 +446,4 @@ inline T *WriteSaveBuf(uint8 *&buf, const T &value) assert(ReadSaveBuf<uint32>(buf) == size); -void cprintf(char*, ...);
\ No newline at end of file +void cprintf(char*, ...); diff --git a/src/core/config.h b/src/core/config.h index e8e15ebe..171c6be9 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -198,6 +198,7 @@ enum Config { #define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more #define MORE_LANGUAGES // Add more translations to the game #define COMPATIBLE_SAVES // this allows changing structs while keeping saves compatible +#define LOAD_INI_SETTINGS // Rendering/display #define ASPECT_RATIO_SCALE // Not just makes everything scale with aspect ratio, also adds support for all aspect ratios @@ -226,6 +227,9 @@ enum Config { #if !defined(RW_GL3) && defined(_WIN32) #define XINPUT #endif +#if !defined(_WIN32) && !defined(__SWITCH__) +#define DONT_TRUST_RECOGNIZED_JOYSTICKS // Then we'll only rely on GLFW gamepad DB, and expect user to enter Controller->Detect joysticks if his joystick isn't on that list. +#endif #define DETECT_PAD_INPUT_SWITCH // Adds automatic switch of pad related stuff between controller and kb/m #define KANGAROO_CHEAT #define ALLCARSHELI_CHEAT @@ -306,4 +310,4 @@ enum Config { #undef NO_ISLAND_LOADING #define PC_PARTICLE #define VC_PED_PORTS // To not process collisions always. But should be tested if that's really beneficial -#endif
\ No newline at end of file +#endif diff --git a/src/core/main.h b/src/core/main.h index 96fbef05..7eb080cb 100644 --- a/src/core/main.h +++ b/src/core/main.h @@ -36,3 +36,8 @@ void ResetLoadingScreenBar(void); #ifndef MASTER void TheModelViewer(void); #endif + +#ifdef LOAD_INI_SETTINGS +void LoadINISettings(); +void SaveINISettings(); +#endif diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 13cb6283..069320ec 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -1,6 +1,7 @@ #include <csignal> #define WITHWINDOWS #include "common.h" +#include "platform.h" #include "crossplatform.h" #include "Renderer.h" #include "Credits.h" @@ -16,7 +17,6 @@ #include "Heli.h" #include "Automobile.h" #include "Ped.h" -#include "Particle.h" #include "Console.h" #include "Debug.h" #include "Hud.h" @@ -38,8 +38,6 @@ #include <stdarg.h> #endif -#include <list> - #ifdef RWLIBS extern "C" int vsprintf(char* const _Buffer, char const* const _Format, va_list _ArgList); #endif @@ -73,7 +71,6 @@ mysrand(unsigned int seed) #ifdef CUSTOM_FRONTEND_OPTIONS #include "frontendoption.h" -#include "platform.h" #include "Font.h" void ReloadFrontendOptions(void) @@ -195,6 +192,7 @@ wchar* MultiSamplingDraw(bool *disabled, bool userHovering) { return unicodeTemp; } } +const char* multisamplingKey = "MultiSampling"; #endif #ifdef MORE_LANGUAGES @@ -247,6 +245,7 @@ void FreeCamChange(int8 displayedValue) TheCamera.bFreeCam = !!displayedValue; FrontEndMenuManager.SaveSettings(); } +const char* freeCamKey = "FreeCam"; #endif #ifdef CUTSCENE_BORDERS_SWITCH @@ -255,6 +254,7 @@ void BorderModeChange(int8 displayedValue) CMenuManager::m_PrefsCutsceneBorders = !!displayedValue; FrontEndMenuManager.SaveSettings(); } +const char* cutsceneBordersKey = "CutsceneBorders"; #endif #ifdef PS2_ALPHA_TEST @@ -263,11 +263,52 @@ void PS2AlphaTestChange(int8 displayedValue) gPS2alphaTest = !!displayedValue; FrontEndMenuManager.SaveSettings(); } +const char* ps2alphaKey = "PS2AlphaTest"; #endif +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS +wchar selectedJoystickUnicode[128]; + +wchar* DetectJoystickDraw(bool* disabled, bool userHovering) { + int numButtons; + int found = -1; + const char *joyname; + if (userHovering) { + for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) { + if (joyname = glfwGetJoystickName(i)) { + const uint8* buttons = glfwGetJoystickButtons(i, &numButtons); + for (int j = 0; j < numButtons; j++) { + if (buttons[j]) { + found = i; + break; + } + } + if (found != -1) + break; + } + } + + if (found != -1 && PSGLOBAL(joy1id) != found) { + if (PSGLOBAL(joy1id) != -1 && PSGLOBAL(joy1id) != found) + PSGLOBAL(joy2id) = PSGLOBAL(joy1id); + else + PSGLOBAL(joy2id) = -1; + + strcpy(gSelectedJoystickName, joyname); + PSGLOBAL(joy1id) = found; + } + } + if (PSGLOBAL(joy1id) == -1) + AsciiToUnicode("Not found", selectedJoystickUnicode); + else + AsciiToUnicode(gSelectedJoystickName, selectedJoystickUnicode); + + return selectedJoystickUnicode; +} +#endif // Important: Make sure to read the warnings/informations in frontendoption.h!! -// For texts: Either use TheText.Get, or use wcsdup(wchar version of strdup) +// If you will hardcode any text, please use AllocUnicode! wchar_t size differs between platforms void CustomFrontendOptionsPopulate(void) { @@ -342,14 +383,14 @@ CustomFrontendOptionsPopulate(void) #ifdef MULTISAMPLING SWITCH_TO_GRAPHICS_MENU - FrontendOptionAddDynamic(TheText.Get("FED_AAS"), MultiSamplingDraw, (int8*)&FrontEndMenuManager.m_nPrefsMSAALevel, MultiSamplingButtonPress, MultiSamplingGoBack, true); + FrontendOptionAddDynamic(TheText.Get("FED_AAS"), MultiSamplingDraw, (int8*)&FrontEndMenuManager.m_nPrefsMSAALevel, MultiSamplingButtonPress, MultiSamplingGoBack, multisamplingKey); #endif CLONE_OPTION(TheText.Get("FED_TRA"), MENUACTION_TRAILS, nil, nil); #ifdef PS2_ALPHA_TEST SWITCH_TO_GRAPHICS_MENU - FrontendOptionAddSelect(TheText.Get("FEM_2PR"), off_on, 2, (int8*)&gPS2alphaTest, false, PS2AlphaTestChange, nil, true); + FrontendOptionAddSelect(TheText.Get("FEM_2PR"), off_on, 2, (int8*)&gPS2alphaTest, false, PS2AlphaTestChange, nil, ps2alphaKey); #endif ADD_RESTORE_DEFAULTS(RestoreDefGraphics) @@ -365,13 +406,12 @@ CustomFrontendOptionsPopulate(void) #ifdef CUTSCENE_BORDERS_SWITCH SWITCH_TO_DISPLAY_MENU - FrontendOptionAddSelect(TheText.Get("FEM_CSB"), off_on, 2, (int8 *)&CMenuManager::m_PrefsCutsceneBorders, false, BorderModeChange, nil, true); + FrontendOptionAddSelect(TheText.Get("FEM_CSB"), off_on, 2, (int8 *)&CMenuManager::m_PrefsCutsceneBorders, false, BorderModeChange, nil, cutsceneBordersKey); #endif #ifdef FREE_CAM SWITCH_TO_DISPLAY_MENU - static const wchar* text = (wchar*)wcsdup(L"FREE CAM"); - FrontendOptionAddSelect(text, off_on, 2, (int8*)&TheCamera.bFreeCam, false, FreeCamChange, nil, true); + FrontendOptionAddSelect(TheText.Get("FEC_FRC"), off_on, 2, (int8*)&TheCamera.bFreeCam, false, FreeCamChange, nil, freeCamKey); #endif CLONE_OPTION(TheText.Get("FED_SUB"), MENUACTION_SUBTITLES, nil, nil); @@ -389,9 +429,95 @@ CustomFrontendOptionsPopulate(void) ADD_RESTORE_DEFAULTS(RestoreDefDisplay) ADD_BACK + +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS + int detectJoystickMenu = FrontendScreenAdd("FEC_JOD", MENUSPRITE_MAINMENU, MENUPAGE_CONTROLLER_PC, 40, 60, 20, + FONT_BANK, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE, FESCREEN_LEFT_ALIGN, false); + + FrontendOptionSetCursor(detectJoystickMenu, 0); + + FrontendOptionAddBuiltinAction(TheText.Get("FEC_JPR"), MENUACTION_LABEL, nil, nil); + FrontendOptionAddDynamic(TheText.Get("FEC_JDE"), DetectJoystickDraw, nil, nil, nil); + FrontendOptionAddBackButton(TheText.Get("FEDS_TB")); + + FrontendOptionSetCursor(MENUPAGE_CONTROLLER_PC, 2); + FrontendOptionAddRedirect(TheText.Get("FEC_JOD"), detectJoystickMenu, 1); +#endif } #endif +#ifdef LOAD_INI_SETTINGS +#include "ini_parser.hpp" +void LoadINISettings() +{ + linb::ini cfg; + cfg.load_file("re3.ini"); + char defaultStr[4]; + +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS + strcpy(gSelectedJoystickName, cfg.get("DetectJoystick", "JoystickName", "").c_str()); + _InputInitialiseJoys(); +#endif + +#ifdef CUSTOM_FRONTEND_OPTIONS + for (int i = 0; i < numCustomFrontendOptions; i++) { + FrontendOption& option = customFrontendOptions[i]; + if (option.save) { + // CFO only supports saving uint8 right now + sprintf(defaultStr, "%u", *option.value); + option.lastSavedValue = option.displayedValue = *option.value = atoi(cfg.get("FrontendOptions", option.save, defaultStr).c_str()); + } + } +#endif + +#ifdef NO_ISLAND_LOADING + sprintf(defaultStr, "%u", CMenuManager::m_PrefsIslandLoading); + CMenuManager::m_PrefsIslandLoading = atoi(cfg.get("FrontendOptions", "NoIslandLoading", defaultStr).c_str()); + CMenuManager::m_DisplayIslandLoading = CMenuManager::m_PrefsIslandLoading; +#endif + +} + +void SaveINISettings() +{ + linb::ini cfg; + cfg.load_file("re3.ini"); + bool changed = false; + char temp[4]; + +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS + if (strncmp(cfg.get("DetectJoystick", "JoystickName", "").c_str(), gSelectedJoystickName, strlen(gSelectedJoystickName)) != 0) { + changed = true; + cfg.set("DetectJoystick", "JoystickName", gSelectedJoystickName); + } +#endif +#ifdef CUSTOM_FRONTEND_OPTIONS + for (int i = 0; i < numCustomFrontendOptions; i++) { + FrontendOption &option = customFrontendOptions[i]; + if (option.save) { + if (atoi(cfg.get("FrontendOptions", option.save, "xxx").c_str()) != *option.value) { // if .ini doesn't have that key compare with xxx, so we can add it + changed = true; + sprintf(temp, "%u", *option.value); + cfg.set("FrontendOptions", option.save, temp); + } + } + } +#endif +#ifdef NO_ISLAND_LOADING + if (atoi(cfg.get("FrontendOptions", "NoIslandLoading", "xxx").c_str()) != CMenuManager::m_PrefsIslandLoading) { + changed = true; + sprintf(temp, "%u", CMenuManager::m_PrefsIslandLoading); + cfg.set("FrontendOptions", "NoIslandLoading", temp); + } +#endif + + if (changed) + cfg.write_file("re3.ini"); +} + +#endif + + #ifdef DEBUGMENU void WeaponCheat(); void HealthCheat(); @@ -539,6 +665,8 @@ static const char *carnames[] = { "yankee", "escape", "borgnine", "toyz", "ghost", }; +//#include <list> + static CTweakVar** TweakVarsList; static int TweakVarsListSize = -1; static bool bAddTweakVarsNow = false; diff --git a/src/core/timebars.cpp b/src/core/timebars.cpp index 5ac5565d..94051b25 100644 --- a/src/core/timebars.cpp +++ b/src/core/timebars.cpp @@ -89,7 +89,7 @@ void tbDisplay() CFont::SetScale(0.48f, 1.12f); CFont::SetCentreOff(); CFont::SetJustifyOff(); - CFont::SetWrapx(640.0f); + CFont::SetWrapx(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH)); CFont::SetRightJustifyOff(); CFont::SetPropOn(); CFont::SetFontStyle(FONT_BANK); diff --git a/src/extras/frontendoption.cpp b/src/extras/frontendoption.cpp index b365a3fe..ed8aa2a9 100644 --- a/src/extras/frontendoption.cpp +++ b/src/extras/frontendoption.cpp @@ -213,10 +213,10 @@ void FrontendOptionAddBuiltinAction(const wchar* leftText, int action, ButtonPre TextCopy(option.leftText, leftText); option.screenOptionOrder = screenOptionOrder; option.returnPrevPageFunc = returnPrevPageFunc; - option.save = false; + option.save = nil; } -void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save) +void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName) { int8 screenOptionOrder = RegisterNewOption(); @@ -229,14 +229,14 @@ void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, in option.value = var; option.displayedValue = *var; option.lastSavedValue = *var; - option.save = save; + option.save = saveName; option.onlyApplyOnEnter = onlyApplyOnEnter; option.changeFunc = changeFunc; option.screenOptionOrder = screenOptionOrder; option.returnPrevPageFunc = returnPrevPageFunc; } -void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save) +void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName) { int8 screenOptionOrder = RegisterNewOption(); @@ -246,7 +246,7 @@ void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc drawFunc, int8 *va option.buttonPressFunc = buttonPressFunc; TextCopy(option.leftText, leftText); option.value = var; - option.save = save; + option.save = saveName; option.screenOptionOrder = screenOptionOrder; option.returnPrevPageFunc = returnPrevPageFunc; } @@ -263,7 +263,7 @@ void FrontendOptionAddRedirect(const wchar* text, int to, int8 selectedOption, b TextCopy(option.leftText, text); option.screenOptionOrder = screenOptionOrder; option.returnPrevPageFunc = nil; - option.save = false; + option.save = nil; } void FrontendOptionAddBackButton(const wchar* text, bool fadeIn) @@ -276,7 +276,7 @@ void FrontendOptionAddBackButton(const wchar* text, bool fadeIn) TextCopy(option.leftText, text); option.screenOptionOrder = screenOptionOrder; option.returnPrevPageFunc = nil; - option.save = false; + option.save = nil; } uint8 FrontendScreenAdd(const char* gxtKey, eMenuSprites sprite, int prevPage, int columnWidth, int headerHeight, int lineHeight, @@ -300,4 +300,4 @@ uint8 FrontendScreenAdd(const char* gxtKey, eMenuSprites sprite, int prevPage, i return screenOrder; } -#endif
\ No newline at end of file +#endif diff --git a/src/extras/frontendoption.h b/src/extras/frontendoption.h index b2bfbf5e..dac6be62 100644 --- a/src/extras/frontendoption.h +++ b/src/extras/frontendoption.h @@ -10,7 +10,7 @@ // About texts: // All text parameters accept wchar(including hardcoded wchar* and TheText.Get) -// except FrontendScreenAdd(it's char[8] by the design of Frontend). +// except FrontendScreenAdd(it's char[8] GXT key by the design of Frontend). // All texts reload if custom options reloaded too, which includes language changes and via live reload feature in debug menu! // Execute direction: @@ -26,7 +26,7 @@ // // Static/select: You allocate the variable, pass it to function and game sets it from user input among the strings given to function, // then you can handle ChangeFunc(only called on enter if onlyApplyOnEnter set, or set immediately) -// and ReturnPrevPageFunc optionally. You can store the option in gta3.set if you pass true to corresponding parameter. +// and ReturnPrevPageFunc optionally. You can store the option in an INI file if you pass the key(as a char array) to corresponding parameter. // // Dynamic: Passing variable to function is only needed if you want to store it, otherwise you should do // all the operations with ButtonPressFunc, this includes allocating the variable. @@ -91,11 +91,11 @@ struct FrontendOption int8 type; int8 screenOptionOrder; int32 screen; - wchar leftText[64]; + wchar leftText[128]; ReturnPrevPageFunc returnPrevPageFunc; int8* value; int8 displayedValue; // only if onlyApplyOnEnter enabled for now - bool save; + const char* save; int32 ogOptionId; // for replacements, see overwrite parameter of SetCursor union { @@ -151,12 +151,12 @@ uint8 GetNumberOfMenuOptions(int screen); void FrontendOptionSetCursor(int screen, int8 option, bool overwrite = false); -// var is optional in AddDynamic, you can enable save parameter if you pass one, otherwise pass nil/0 +// var is optional in AddDynamic, enables you to save them in an INI file(also needs passing char array to saveName param. obv), otherwise pass nil/0 void FrontendOptionAddBuiltinAction(const wchar* leftText, int action, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc); -void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save = false); -void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save = false); +void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName = nil); +void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName = nil); void FrontendOptionAddRedirect(const wchar* text, int to, int8 selectedOption = 0, bool fadeIn = true); void FrontendOptionAddBackButton(const wchar* text, bool fadeIn = true); uint8 FrontendScreenAdd(const char* gxtKey, eMenuSprites sprite, int prevPage, int columnWidth, int headerHeight, int lineHeight, int8 font, float fontScaleX, float fontScaleY, int8 alignment, bool showLeftRightHelper, ReturnPrevPageFunc returnPrevPageFunc = nil); -#endif
\ No newline at end of file +#endif diff --git a/src/extras/ini_parser.hpp b/src/extras/ini_parser.hpp new file mode 100644 index 00000000..99acf1ee --- /dev/null +++ b/src/extras/ini_parser.hpp @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2013-2015 Denilson das Mercês Amorim <dma_2012@hotmail.com> + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + */ +#ifndef LINB_INI_PARSER_HPP +#define LINB_INI_PARSER_HPP + +/* + * STL-like INI Container + */ + +#include <string> // for std::string +#include <map> // for std::map +#include <cstdio> // for std::FILE +#include <algorithm> // for std::find_if +#include <functional> // for std::function + +namespace linb +{ + template< + class CharT = char, /* Not compatible with other type here, since we're using C streams */ + class StringType = std::basic_string<CharT>, + class KeyContainer = std::map<StringType, StringType>, + class SectionContainer = std::map<StringType, KeyContainer> + > class basic_ini + { + public: + typedef CharT char_type; + typedef StringType string_type; + typedef KeyContainer key_container; + typedef SectionContainer section_container; + + // Typedef container values types + typedef typename section_container::value_type value_type; + typedef typename section_container::key_type key_type; + typedef typename section_container::mapped_type mapped_type; + + // Typedef common types + typedef typename section_container::size_type size_type; + typedef typename section_container::difference_type difference_type; + + // Typedef iterators + typedef typename section_container::iterator iterator; + typedef typename section_container::const_iterator const_iterator; + typedef typename section_container::reverse_iterator reverse_iterator; + typedef typename section_container::const_reverse_iterator const_reverse_iterator; + + // typedef References and pointers + typedef typename section_container::reference reference; + typedef typename section_container::const_reference const_reference; + typedef typename section_container::pointer pointer; + typedef typename section_container::const_pointer const_pointer; + + private: + section_container data; + + public: + + basic_ini() + { } + + basic_ini(const char_type* filename) + { this->read_file(filename); } + + /* Iterator methods */ + iterator begin() + { return data.begin(); } + const_iterator begin() const + { return data.begin(); } + iterator end() + { return data.end(); } + const_iterator end() const + { return data.end(); } + const_iterator cbegin() const + { return data.cbegin(); } + const_iterator cend() const + { return data.cend(); } + + /* Reverse iterator methods */ + reverse_iterator rbegin() + { return data.rbegin(); } + const_reverse_iterator rbegin() const + { return data.rbegin(); } + reverse_iterator rend() + { return data.rend(); } + const_reverse_iterator rend() const + { return data.rend(); } + const_reverse_iterator crbegin() const + { return data.crbegin(); } + const_reverse_iterator crend() const + { return data.crend(); } + + /* Acessing index methods */ + mapped_type& operator[](const string_type& sect) + { return data[sect]; } + mapped_type& operator[](string_type&& sect) + { return data[std::forward<string_type>(sect)]; } + mapped_type& at( const string_type& sect) + { return data.at(sect); } + const mapped_type& at(const string_type& sect) const + { return data.at(sect); } + + /* Capacity information */ + bool empty() const + { return data.empty(); } + size_type size() const + { return data.size(); } + size_type max_size() const + { return data.max_size(); } + + /* Modifiers */ + void clear() + { return data.clear(); } + + /* Lookup */ + size_type count(const string_type& sect) + { return data.count(sect); } + iterator find(const string_type& sect) + { return data.find(sect); } + + /* Gets a value from the specified section & key, default_value is returned if the sect & key doesn't exist */ + string_type get(const string_type& sect, const key_type& key, const string_type& default_value) + { + auto it = this->find(sect); + if(it != this->end()) + { + auto itv = it->second.find(key); + if(itv != it->second.end()) + return itv->second; + } + return default_value; + } + + /* Sets the value of a value in the ini */ + void set(const string_type& sect, const key_type& key, const string_type& value) + { + (*this)[sect][key] = value; // no emplace since overwrite! + } + + /* Too lazy to continue this container... If you need more methods, just add it */ + + +#if 1 + bool read_file(const char_type* filename) + { + /* Using C stream in a STL-like container, funny? + */ + if(FILE* f = fopen(filename, "r")) + { + key_container* keys = nullptr; + char_type buf[2048]; + string_type line; + string_type key; + string_type value; + string_type null_string; + size_type pos; + + // Trims an string + auto trim = [](string_type& s, bool trimLeft, bool trimRight) -> string_type& + { + if(s.size()) + { + // Ignore UTF-8 BOM + while(s.size() >= 3 && s[0] == (char)(0xEF) && s[1] == (char)(0xBB) && s[2] == (char)(0xBF)) + s.erase(s.begin(), s.begin() + 3); + + if(trimLeft) + s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::function<int(int)>(::isspace)))); + if(trimRight) + s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::function<int(int)>(::isspace))).base(), s.end()); + } + return s; + }; + + // Start parsing + while(fgets(buf, sizeof(buf), f)) + { + // What a thing, reading into a char buffer and then putting in the string... + line = buf; + + // Find comment and remove anything after it from the line + if((pos = line.find_first_of(';')) != line.npos) + line.erase(pos); + + // Trim the string, and if it gets empty, skip this line + if(trim(line, true, true).empty()) + continue; + + // Find section name + if(line.front() == '[' && line.back() == ']') + { + pos = line.length() - 1; //line.find_first_of(']'); + if(pos != line.npos) + { + trim(key.assign(line, 1, pos-1), true, true); + keys = &data[std::move(key)]; // Create section + } + else + keys = nullptr; + } + else + { + // Find key and value positions + pos = line.find_first_of('='); + if(pos == line.npos) + { + // There's only the key + key = line; // No need for trim, line is already trimmed + value.clear(); + } + else + { + // There's the key and the value + trim(key.assign(line, 0, pos), false, true); // trim the right + trim(value.assign(line, pos + 1, line.npos), true, false); // trim the left + } + + // Put the key/value into the current keys object, or into the section "" if no section has been found + #if __cplusplus >= 201103L || _MSC_VER >= 1800 + (keys ? *keys : data[null_string]).emplace(std::move(key), std::move(value)); + #else + (keys ? *keys : data[null_string])[key] = value; + key.clear(); value.clear(); + #endif + } + } + + fclose(f); + return true; + } + return false; + } + + /* + * Dumps the content of this container into an ini file + */ + bool write_file(const char_type* filename) + { + if(FILE* f = fopen(filename, "w")) + { + bool first = true; + for(auto& sec : this->data) + { + fprintf(f, first? "[%s]\n" : "\n[%s]\n", sec.first.c_str()); + first = false; + for(auto& kv : sec.second) + { + if(kv.second.empty()) + fprintf(f, "%s\n", kv.first.c_str()); + else + fprintf(f, "%s = %s\n", kv.first.c_str(), kv.second.c_str()); + } + } + fclose(f); + return true; + } + return false; + } + + + /* + */ + bool load_file(const char_type* filename) + { + return read_file(filename); + } + + bool load_file(const StringType& filename) + { + return load_file(filename.c_str()); + } + + bool write_file(const StringType& filename) + { + return write_file(filename.c_str()); + } +#endif + + + + }; + + + /* Use default basic_ini + * + * Limitations: + * * Not unicode aware + * * Case sensitive + * * Sections must have unique keys + */ + typedef basic_ini<> ini; +} + +#endif + diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 5c0dd86e..63bf0b06 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -997,7 +997,7 @@ void CHud::Draw() } else { BigMessageAlpha[0] = 0.0f; - BigMessageX[0] = SCALE_AND_CENTER_X(-60.0f); + BigMessageX[0] = SCREEN_SCALE_FROM_RIGHT(DEFAULT_SCREEN_WIDTH + 60.0f); BigMessageInUse[0] = 1.0f; } } @@ -1008,7 +1008,7 @@ void CHud::Draw() // WastedBustedText if (m_BigMessage[2][0]) { if (BigMessageInUse[2] != 0.0f) { - BigMessageAlpha[2] += (CTimer::GetTimeStepInSeconds() * 255.0f); + BigMessageAlpha[2] += (CTimer::GetTimeStepInMilliseconds() * 0.4f); if (BigMessageAlpha[2] > 255.0f) BigMessageAlpha[2] = 255.0f; @@ -1261,7 +1261,7 @@ void CHud::DrawAfterFade() } break; case 2: - OddJob2Timer += (20.0f * CTimer::GetTimeStep()); + OddJob2Timer += CTimer::GetTimeStepInMilliseconds(); if (OddJob2Timer > 1500) { OddJob2On = 3; } @@ -1355,7 +1355,7 @@ void CHud::DrawAfterFade() } else { BigMessageAlpha[1] = 0.0f; - BigMessageX[1] = SCALE_AND_CENTER_X(-60.0f); + BigMessageX[1] = SCREEN_SCALE_FROM_RIGHT(DEFAULT_SCREEN_WIDTH + 60.0f); BigMessageInUse[1] = 1.0f; } } diff --git a/src/skel/crossplatform.cpp b/src/skel/crossplatform.cpp index 6188992d..452ad9fa 100644 --- a/src/skel/crossplatform.cpp +++ b/src/skel/crossplatform.cpp @@ -84,6 +84,16 @@ void FileTimeToSystemTime(time_t* writeTime, SYSTEMTIME* out) { } #endif +// Because wchar length differs between platforms. +wchar* +AllocUnicode(const char* src) +{ + wchar *dst = (wchar*)malloc(strlen(src)*2 + 2); + wchar *i = dst; + while((*i++ = (unsigned char)*src++) != '\0'); + return dst; +} + // Funcs/features from Windows that we need on other platforms #ifndef _WIN32 char *strupr(char *s) { diff --git a/src/skel/crossplatform.h b/src/skel/crossplatform.h index 69600385..1635781b 100644 --- a/src/skel/crossplatform.h +++ b/src/skel/crossplatform.h @@ -67,6 +67,10 @@ void CapturePad(RwInt32 padID); void joysChangeCB(int jid, int event); #endif +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS +extern char gSelectedJoystickName[128]; +#endif + enum eGameState { GS_START_UP = 0, diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 48701921..4dd9570e 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -41,7 +41,6 @@ #include "AnimViewer.h" #include "Font.h" - #define MAX_SUBSYSTEMS (16) @@ -92,6 +91,11 @@ long _dwOperatingSystemVersion; #include <signal.h> #include <errno.h> #endif + +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS +char gSelectedJoystickName[128] = ""; +#endif + /* ***************************************************************************** */ @@ -425,6 +429,10 @@ psInitialize(void) _dwOperatingSystemVersion = OS_WIN95; } } +#else + _dwOperatingSystemVersion = OS_WINXP; // To fool other classes +#endif + #ifndef PS2_MENU @@ -434,6 +442,8 @@ psInitialize(void) #endif + +#ifdef _WIN32 MEMORYSTATUS memstats; GlobalMemoryStatus(&memstats); @@ -441,22 +451,7 @@ psInitialize(void) debug("Physical memory size %u\n", memstats.dwTotalPhys); debug("Available physical memory %u\n", memstats.dwAvailPhys); -#else - -#ifndef PS2_MENU - -#ifdef GTA3_1_1_PATCH - FrontEndMenuManager.LoadSettings(); -#endif - -#endif -#ifndef __APPLE__ - struct sysinfo systemInfo; - sysinfo(&systemInfo); - _dwMemAvailPhys = systemInfo.freeram; - debug("Physical memory size %u\n", systemInfo.totalram); - debug("Available physical memory %u\n", systemInfo.freeram); -#else +#elif defined (__APPLE__) uint64_t size = 0; uint64_t page_size = 0; size_t uint64_len = sizeof(uint64_t); @@ -469,10 +464,15 @@ psInitialize(void) _dwMemAvailPhys = (uint64_t)(vm_stat.free_count * page_size); debug("Physical memory size %llu\n", _dwMemAvailPhys); debug("Available physical memory %llu\n", size); +#else + struct sysinfo systemInfo; + sysinfo(&systemInfo); + _dwMemAvailPhys = systemInfo.freeram; + debug("Physical memory size %u\n", systemInfo.totalram); + debug("Available physical memory %u\n", systemInfo.freeram); #endif - _dwOperatingSystemVersion = OS_WINXP; // To fool other classes -#endif - TheText.Unload(); + + TheText.Unload(); return TRUE; } @@ -839,35 +839,26 @@ void joysChangeCB(int jid, int event); bool IsThisJoystickBlacklisted(int i) { +#ifndef DONT_TRUST_RECOGNIZED_JOYSTICKS + return false; +#else if (glfwJoystickIsGamepad(i)) return false; const char* joyname = glfwGetJoystickName(i); - // this is just a keyboard and mouse - // Microsoft Microsoft® 2.4GHz Transceiver v8.0 Consumer Control - // Microsoft Microsoft® 2.4GHz Transceiver v8.0 System Control - if (strstr(joyname, "2.4GHz Transceiver")) - return true; - // COMPANY USB Device System Control - // COMPANY USB Device Consumer Control - if (strstr(joyname, "COMPANY USB")) - return true; - // i.e. Synaptics TM2438-005 - if (strstr(joyname, "Synaptics ")) - return true; - // i.e. ELAN Touchscreen - if (strstr(joyname, "ELAN ")) - return true; - // i.e. Primax Electronics, Ltd HP Wireless Keyboard Mouse Kit Consumer Control - if (strstr(joyname, "Keyboard")) - return true; + if (strncmp(joyname, gSelectedJoystickName, strlen(gSelectedJoystickName)) == 0) + return false; - return false; + return true; +#endif } void _InputInitialiseJoys() { + PSGLOBAL(joy1id) = -1; + PSGLOBAL(joy2id) = -1; + for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) { if (glfwJoystickPresent(i) && !IsThisJoystickBlacklisted(i)) { if (PSGLOBAL(joy1id) == -1) @@ -882,6 +873,9 @@ void _InputInitialiseJoys() if (PSGLOBAL(joy1id) != -1) { int count; glfwGetJoystickButtons(PSGLOBAL(joy1id), &count); +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS + strcpy(gSelectedJoystickName, glfwGetJoystickName(PSGLOBAL(joy1id))); +#endif ControlsManager.InitDefaultControlConfigJoyPad(count); } } @@ -2087,18 +2081,19 @@ void CapturePad(RwInt32 padID) void joysChangeCB(int jid, int event) { - if (event == GLFW_CONNECTED && !IsThisJoystickBlacklisted(jid)) - { - if (PSGLOBAL(joy1id) == -1) + if (event == GLFW_CONNECTED && !IsThisJoystickBlacklisted(jid)) { + if (PSGLOBAL(joy1id) == -1) { PSGLOBAL(joy1id) = jid; - else if (PSGLOBAL(joy2id) == -1) +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS + strcpy(gSelectedJoystickName, glfwGetJoystickName(jid)); +#endif + } else if (PSGLOBAL(joy2id) == -1) PSGLOBAL(joy2id) = jid; - } - else if (event == GLFW_DISCONNECTED) - { - if (PSGLOBAL(joy1id) == jid) + + } else if (event == GLFW_DISCONNECTED) { + if (PSGLOBAL(joy1id) == jid) { PSGLOBAL(joy1id) = -1; - else if (PSGLOBAL(joy2id) == jid) + } else if (PSGLOBAL(joy2id) == jid) PSGLOBAL(joy2id) = -1; } } diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index 119e666e..ac46d23a 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -3378,4 +3378,4 @@ int strcasecmp(const char *str1, const char *str2) return _strcmpi(str1, str2); } #endif -#endif
\ No newline at end of file +#endif diff --git a/src/text/Text.cpp b/src/text/Text.cpp index 1f6cda89..a4f2af7f 100644 --- a/src/text/Text.cpp +++ b/src/text/Text.cpp @@ -354,4 +354,4 @@ void TextCopy(wchar *dst, const wchar *src) { while((*dst++ = *src++) != '\0'); -}
\ No newline at end of file +} diff --git a/src/vehicles/CarGen.cpp b/src/vehicles/CarGen.cpp index 5de478b7..338eaba4 100644 --- a/src/vehicles/CarGen.cpp +++ b/src/vehicles/CarGen.cpp @@ -74,11 +74,12 @@ void CCarGenerator::DoInternalProcessing() } m_nVehicleHandle = CPools::GetVehiclePool()->GetIndex(pBoat); }else{ - bool groundFound = false; + bool groundFound; CVector pos = m_vecPos; if (pos.z > -100.0f){ pos.z = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, &groundFound); }else{ + groundFound = false; CColPoint cp; CEntity* pEntity; groundFound = CWorld::ProcessVerticalLine(CVector(pos.x, pos.y, 1000.0f), -1000.0f, @@ -89,7 +90,12 @@ void CCarGenerator::DoInternalProcessing() if (!groundFound) { debug("CCarGenerator::DoInternalProcessing - can't find ground z for new car x = %f y = %f \n", m_vecPos.x, m_vecPos.y); }else{ - CAutomobile* pCar = new CAutomobile(m_nModelIndex, PARKED_VEHICLE); + CAutomobile* pCar; + + // So game crashes if it's bike :D + if (((CVehicleModelInfo*)CModelInfo::GetModelInfo(m_nModelIndex))->m_vehicleType != VEHICLE_TYPE_BIKE) + pCar = new CAutomobile(m_nModelIndex, PARKED_VEHICLE); + pCar->bIsStatic = false; pCar->bEngineOn = false; pos.z += pCar->GetDistanceFromCentreOfMassToBaseOfModel(); |