From 224e805fe4e7a4d5366b228072834674f77fa0ba Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Tue, 29 Dec 2020 20:24:16 +0300 Subject: [PATCH 001/152] Sprite Scaling option --- gamefiles/TEXT/american.gxt | Bin 220080 -> 220172 bytes src/core/Frontend.cpp | 17 +++++++++++++++-- src/core/Frontend.h | 3 +++ src/core/MenuScreensCustom.cpp | 17 +++++++++++++++++ src/core/Radar.cpp | 12 +++++++++--- src/core/common.h | 13 ++++++++----- src/render/Draw.cpp | 19 +++++++++++++------ src/render/Draw.h | 16 ++++++++++++++++ src/render/Hud.cpp | 7 ++++++- src/render/Sprite.cpp | 9 +++++++++ utils/gxt/american.txt | 10 ++++++++++ 11 files changed, 106 insertions(+), 17 deletions(-) diff --git a/gamefiles/TEXT/american.gxt b/gamefiles/TEXT/american.gxt index 1054ca126d8d797e0405afb6ecd0cb36126fdbbe..4d0009e1f9d99e551c6a0c78e66fbb143da00650 100644 GIT binary patch delta 167 zcmdn6owsKPFI$MWYotWoMz%N&#tEBKHHuld_uOS-aC3Ez4|ew1d|ii^jk^sj;2ZB4 z8nXGZ(M(3}GN?d+GsEU;6GcYGn$2@flRX%pG&9zuUrv1TX|Kcmf4n859_Tfl3`2e1LpE26rIe7pTPrD8s-2 E0E;*(ng9R* delta 74 zcmV-Q0JZ;&xDBwk4F*(8MOpNHu?Ai!0f4h*D02j} 0) { m_PrefsUseWideScreen++; - if (m_PrefsUseWideScreen > 2) + if (m_PrefsUseWideScreen > AR_MAX-1) m_PrefsUseWideScreen = 0; } else { m_PrefsUseWideScreen--; if (m_PrefsUseWideScreen < 0) - m_PrefsUseWideScreen = 2; + m_PrefsUseWideScreen = AR_MAX-1; } DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0); SaveSettings(); diff --git a/src/core/Frontend.h b/src/core/Frontend.h index 8cf3dd28..68f249ee 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -636,6 +636,9 @@ public: static int8 m_nDisplayMSAALevel; #endif +#ifdef ASPECT_RATIO_SCALE + static int32 m_PrefsSpriteScalingMode; +#endif enum LANGUAGE { LANGUAGE_AMERICAN, diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp index d9fc5065..a81a76c3 100644 --- a/src/core/MenuScreensCustom.cpp +++ b/src/core/MenuScreensCustom.cpp @@ -83,6 +83,12 @@ #define INVERT_PAD_SELECTOR #endif +#ifdef ASPECT_RATIO_SCALE + #define HUD_ASPECT_RATIO_SELECTOR MENUACTION_CFO_SELECT, "FEC_SCL", { new CCFOSelect((int8*)&CMenuManager::m_PrefsSpriteScalingMode, "HudAspectRatio", SpriteScalingModes, ARRAY_SIZE(SpriteScalingModes), false, nil) }, +#else + #define HUD_ASPECT_RATIO_SELECTOR +#endif + const char *filterNames[] = { "FEM_NON", "FEM_SIM", "FEM_NRM", "FEM_MOB" }; const char *vehPipelineNames[] = { "FED_MFX", "FED_NEO" }; const char *off_on[] = { "FEM_OFF", "FEM_ON" }; @@ -342,6 +348,15 @@ wchar* DetectJoystickDraw(bool* disabled, bool userHovering) { } #endif +#ifdef ASPECT_RATIO_SCALE +const char* SpriteScalingModes[] = +{ + "FEM_PC", + "FEM_PS2", + "FEM_AUT" +}; +#endif + CMenuScreenCustom aScreens[MENUPAGES] = { // MENUPAGE_NONE = 0 { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, }, @@ -396,6 +411,7 @@ CMenuScreenCustom aScreens[MENUPAGES] = { #endif MENUACTION_SUBTITLES, "FED_SUB", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, MENUACTION_WIDESCREEN, "FED_WIS", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, + HUD_ASPECT_RATIO_SELECTOR MENUACTION_SCREENRES, "FED_RES", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, VIDEOMODE_SELECTOR MULTISAMPLING_SELECTOR @@ -827,6 +843,7 @@ CMenuScreenCustom aScreens[MENUPAGES] = { MENUACTION_SCREENRES, "FED_RES", { nil, SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS }, MENUACTION_WIDESCREEN, "FED_WIS", { nil, SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS }, + HUD_ASPECT_RATIO_SELECTOR VIDEOMODE_SELECTOR MENUACTION_FRAMESYNC, "FEM_VSC", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, MENUACTION_FRAMELIMIT, "FEM_FRM", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp index 816da6b9..2b72e0fb 100644 --- a/src/core/Radar.cpp +++ b/src/core/Radar.cpp @@ -1297,10 +1297,16 @@ void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &i } else #endif { -#ifdef FIX_BUGS - out.x = (in.x + 1.0f) * 0.5f * SCREEN_SCALE_X(RADAR_WIDTH) + SCREEN_SCALE_X(RADAR_LEFT); +#ifdef ASPECT_RATIO_SCALE +#define _RADAR_WIDTH ((CMenuManager::m_PrefsSpriteScalingMode==SCL_AUTO) ? (RADAR_HEIGHT) : (RADAR_WIDTH)) #else - out.x = (in.x + 1.0f) * 0.5f * SCREEN_SCALE_X(RADAR_WIDTH) + RADAR_LEFT; +#define _RADAR_WIDTH RADAR_WIDTH +#endif + +#ifdef FIX_BUGS + out.x = (in.x + 1.0f) * 0.5f * SCREEN_SCALE_X(_RADAR_WIDTH) + SCREEN_SCALE_X(RADAR_LEFT); +#else + out.x = (in.x + 1.0f) * 0.5f * SCREEN_SCALE_X(_RADAR_WIDTH) + RADAR_LEFT; #endif out.y = (1.0f - in.y) * 0.5f * SCREEN_SCALE_Y(RADAR_HEIGHT) + SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT); } diff --git a/src/core/common.h b/src/core/common.h index ffae30bf..ebde3a65 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -116,7 +116,7 @@ inline uint32 ldb(uint32 p, uint32 s, uint32 w) #include "skeleton.h" #include "Draw.h" -#if defined(USE_PROPER_SCALING) +#if defined(ASPECT_RATIO_SCALE) #ifdef FORCE_PC_SCALING #define DEFAULT_SCREEN_WIDTH (640) #define DEFAULT_SCREEN_HEIGHT (448) @@ -150,8 +150,8 @@ inline uint32 ldb(uint32 p, uint32 s, uint32 w) #define SCREEN_HEIGHT ((float)RsGlobal.height) #endif -#define SCREEN_HEIGHT_PAL (512) -#define SCREEN_HEIGHT_NTSC (448) +#define SCREEN_HEIGHT_PAL ((float)512) +#define SCREEN_HEIGHT_NTSC ((float)448) #define SCREEN_ASPECT_RATIO (CDraw::GetAspectRatio()) #define SCREEN_VIEWWINDOW (Tan(DEGTORAD(CDraw::GetScaledFOV() * 0.5f))) @@ -170,8 +170,11 @@ inline uint32 ldb(uint32 p, uint32 s, uint32 w) #ifdef ASPECT_RATIO_SCALE #define SCREEN_SCALE_AR(a) ((a) * DEFAULT_ASPECT_RATIO / SCREEN_ASPECT_RATIO) -extern float ScaleAndCenterX(float x); -#define SCALE_AND_CENTER_X(x) ScaleAndCenterX(x) +#define SCALE_AND_CENTER_X(x) ((SCREEN_WIDTH == DEFAULT_SCREEN_WIDTH) ? (x) : (SCREEN_WIDTH - SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)) / 2 + SCREEN_SCALE_X((x))) + #ifndef FORCE_PC_SCALING + #undef SCREEN_SCALE_Y + #define SCREEN_SCALE_Y(a) CDraw::ScaleY(SCREEN_STRETCH_Y(a)) + #endif #else #define SCREEN_SCALE_AR(a) (a) #define SCALE_AND_CENTER_X(x) SCREEN_STRETCH_X(x) diff --git a/src/render/Draw.cpp b/src/render/Draw.cpp index 4e323ec2..2a4739c9 100644 --- a/src/render/Draw.cpp +++ b/src/render/Draw.cpp @@ -35,8 +35,14 @@ CDraw::FindAspectRatio(void) default: case AR_4_3: return 4.0f / 3.0f; + case AR_5_4: + return 5.0f / 4.0f; + case AR_16_10: + return 16.0f / 10.0f; case AR_16_9: return 16.0f / 9.0f; + case AR_21_9: + return 21.0f / 9.0f; }; #endif } @@ -72,12 +78,13 @@ CDraw::SetFOV(float fov) } #ifdef ASPECT_RATIO_SCALE -float -ScaleAndCenterX(float x) +float CDraw::ScaleY(float y) { - if (SCREEN_WIDTH == DEFAULT_SCREEN_WIDTH) - return x; - else - return (SCREEN_WIDTH - SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)) / 2 + SCREEN_SCALE_X(x); + switch ( CMenuManager::m_PrefsSpriteScalingMode ) + { + case SCL_PC: return y * ((float)DEFAULT_SCREEN_HEIGHT/SCREEN_HEIGHT_NTSC); + default: + return y; + } } #endif \ No newline at end of file diff --git a/src/render/Draw.h b/src/render/Draw.h index 5c4f95b1..9b98ca17 100644 --- a/src/render/Draw.h +++ b/src/render/Draw.h @@ -5,9 +5,21 @@ enum eAspectRatio // Make sure these work the same as FrontEndMenuManager.m_PrefsUseWideScreen // without widescreen support AR_4_3, + AR_5_4, + AR_16_10, AR_16_9, + AR_21_9, AR_AUTO, + + AR_MAX, +}; + +enum eSpriteScalingMode +{ + SCL_PC, + SCL_PS2, + SCL_AUTO, }; class CDraw @@ -52,4 +64,8 @@ public: #else static float GetAspectRatio(void) { return FindAspectRatio(); } #endif + +#ifdef ASPECT_RATIO_SCALE + static float ScaleY(float y); +#endif }; diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index dcc703e9..9a2f718f 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -1186,9 +1186,14 @@ void CHud::Draw() /* DrawRadar */ +#ifdef ASPECT_RATIO_SCALE +#define _RADAR_WIDTH ((CMenuManager::m_PrefsSpriteScalingMode==SCL_AUTO) ? (RADAR_HEIGHT) : (RADAR_WIDTH)) +#else +#define _RADAR_WIDTH RADAR_WIDTH +#endif if (m_ItemToFlash == ITEM_RADAR && CTimer::GetFrameCounter() & 8 || m_ItemToFlash != ITEM_RADAR) { CRadar::DrawMap(); - CRect rect(0.0f, 0.0f, SCREEN_SCALE_X(RADAR_WIDTH), SCREEN_SCALE_Y(RADAR_HEIGHT)); + CRect rect(0.0f, 0.0f, SCREEN_SCALE_X(_RADAR_WIDTH), SCREEN_SCALE_Y(RADAR_HEIGHT)); #ifdef FIX_BUGS rect.Translate(SCREEN_SCALE_X(RADAR_LEFT), SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT)); #else diff --git a/src/render/Sprite.cpp b/src/render/Sprite.cpp index 9ec7b002..4be64ef2 100644 --- a/src/render/Sprite.cpp +++ b/src/render/Sprite.cpp @@ -5,6 +5,10 @@ #include "Camera.h" #include "Sprite.h" +#ifdef ASPECT_RATIO_SCALE +#include "Frontend.h" +#endif + float CSprite::m_f2DNearScreenZ; float CSprite::m_f2DFarScreenZ; float CSprite::m_fRecipNearClipPlane; @@ -35,6 +39,11 @@ CSprite::CalcScreenCoors(const RwV3d &in, RwV3d *out, float *outw, float *outh, *outw = fovScale * SCREEN_SCALE_AR(recip) * SCREEN_WIDTH; *outh = fovScale * recip * SCREEN_HEIGHT; + +#ifdef ASPECT_RATIO_SCALE + if ( CMenuManager::m_PrefsSpriteScalingMode==SCL_AUTO ) + *outw = fovScale * recip * SCREEN_HEIGHT; +#endif return true; } diff --git a/utils/gxt/american.txt b/utils/gxt/american.txt index cdee16f9..c680a734 100644 --- a/utils/gxt/american.txt +++ b/utils/gxt/american.txt @@ -8058,12 +8058,22 @@ NEO [FEM_PS2] PS2 +[FEM_PC] +PC + [FEM_XBX] XBOX +[FEM_AUT] +AUTO + [FEC_IVP] INVERT PAD VERTICALLY +[FEC_SCL] +SPRITE SCALING MODE + + { end of file } [DUMMY] From 97f83c9fb2b69358fec88e52e046e16cb9afc49b Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Tue, 29 Dec 2020 20:34:00 +0300 Subject: [PATCH 002/152] fix gxt --- gamefiles/TEXT/american.gxt | Bin 220172 -> 220216 bytes utils/gxt/american.txt | 4 +++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gamefiles/TEXT/american.gxt b/gamefiles/TEXT/american.gxt index 4d0009e1f9d99e551c6a0c78e66fbb143da00650..b8a677e9f30c6469b00ba10b162bfded8167970c 100644 GIT binary patch delta 91 zcmeC#!MkGzFKdXmYoy9X*2_AKcQ)VDxy`}7=Pnb2o2zepNO-{J&8CGOOf2`B)#}>S t>KM1H)iLe6D;vU)&yWs;ISi=`3Jl>4i42tt1wgS(hCGIn=?|lswE^Hq9k>7h delta 49 zcmV-10M7roxDAZB4Fyz7MOhfJ1=B16ytCOX+X%D3HE>7*0gs H5L^Q&`$!Y^ diff --git a/utils/gxt/american.txt b/utils/gxt/american.txt index c680a734..3d5d25c5 100644 --- a/utils/gxt/american.txt +++ b/utils/gxt/american.txt @@ -8070,10 +8070,12 @@ AUTO [FEC_IVP] INVERT PAD VERTICALLY +[FEM_TWP] +Toggle Waypoint + [FEC_SCL] SPRITE SCALING MODE - { end of file } [DUMMY] From 737d41e18444469b75a3d4092c174a3d9e8227aa Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Tue, 29 Dec 2020 20:35:03 +0300 Subject: [PATCH 003/152] Revert "fix gxt" This reverts commit 97f83c9fb2b69358fec88e52e046e16cb9afc49b. --- gamefiles/TEXT/american.gxt | Bin 220216 -> 220172 bytes utils/gxt/american.txt | 4 +--- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/gamefiles/TEXT/american.gxt b/gamefiles/TEXT/american.gxt index b8a677e9f30c6469b00ba10b162bfded8167970c..4d0009e1f9d99e551c6a0c78e66fbb143da00650 100644 GIT binary patch delta 49 zcmV-10M7roxDAZB4Fyz7MOhfJ1=B16ytCOX+X%D3HE>7*0gs H5L^Q&`$!Y^ delta 91 zcmeC#!MkGzFKdXmYoy9X*2_AKcQ)VDxy`}7=Pnb2o2zepNO-{J&8CGOOf2`B)#}>S t>KM1H)iLe6D;vU)&yWs;ISi=`3Jl>4i42tt1wgS(hCGIn=?|lswE^Hq9k>7h diff --git a/utils/gxt/american.txt b/utils/gxt/american.txt index 3d5d25c5..c680a734 100644 --- a/utils/gxt/american.txt +++ b/utils/gxt/american.txt @@ -8070,12 +8070,10 @@ AUTO [FEC_IVP] INVERT PAD VERTICALLY -[FEM_TWP] -Toggle Waypoint - [FEC_SCL] SPRITE SCALING MODE + { end of file } [DUMMY] From 7b9e58f7c68e6ebcf304f07bb2999dcbd34e2488 Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Tue, 29 Dec 2020 20:50:29 +0300 Subject: [PATCH 004/152] master gxt --- gamefiles/TEXT/american.gxt | Bin 220172 -> 220124 bytes utils/gxt/american.txt | 11 ++--------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/gamefiles/TEXT/american.gxt b/gamefiles/TEXT/american.gxt index 4d0009e1f9d99e551c6a0c78e66fbb143da00650..aba89f11b98c317a3648916fcd1d237a76807b23 100644 GIT binary patch delta 130 zcmeC#!Fy*rFKdXmYb3)))_4uZhRvxO#Vnhj=1cbOR6Tz%t1 z!UGt%&Oz8=!Oje2n-7{MdoZ49R;_DStz+D-TE|p*mpy{PiNT*CV*1u-W_^VahJ1!} dAk1M%Wl&%UXGmnIWGDcNWisS3lrS(b008Q+CLaI* delta 178 zcmcb!owsKPFKdXmYox?R)_4uZ37b_b096g@nONv3^kiqnkIWNK56EyYv-+F+|FCaRC!lC zfWeu8fgysyiNPO8GB7wYgffIM_)qVRX4cmTW(Z&iV( Date: Tue, 29 Dec 2020 20:58:15 +0300 Subject: [PATCH 005/152] gxt changes --- gamefiles/TEXT/american.gxt | Bin 220124 -> 220216 bytes utils/gxt/american.txt | 9 +++++++++ 2 files changed, 9 insertions(+) diff --git a/gamefiles/TEXT/american.gxt b/gamefiles/TEXT/american.gxt index aba89f11b98c317a3648916fcd1d237a76807b23..b8a677e9f30c6469b00ba10b162bfded8167970c 100644 GIT binary patch delta 173 zcmcb!op;9$Ue*wA*GQF(tnnI*6E>%66ti&Oxy!`h=IR_D?Ci7ox(+WJcNE)RDml$oFG#2l9P^ KT3moK3=9ArNi7`! delta 98 zcmdn7gZIvMUe*wA*GPtqtnnI*4VzOnidi;4(cxj+{KsepB8-x2?lLjBx%$S3 zga Date: Tue, 29 Dec 2020 21:01:36 +0300 Subject: [PATCH 006/152] fix ini key --- src/core/MenuScreensCustom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp index 9f090e39..42ddd908 100644 --- a/src/core/MenuScreensCustom.cpp +++ b/src/core/MenuScreensCustom.cpp @@ -74,7 +74,7 @@ #endif #ifdef ASPECT_RATIO_SCALE - #define HUD_ASPECT_RATIO_SELECTOR MENUACTION_CFO_SELECT, "FEC_SCL", { new CCFOSelect((int8*)&CMenuManager::m_PrefsSpriteScalingMode, "HudAspectRatio", SpriteScalingModes, ARRAY_SIZE(SpriteScalingModes), false, nil) }, + #define HUD_ASPECT_RATIO_SELECTOR MENUACTION_CFO_SELECT, "FEC_SCL", { new CCFOSelect((int8*)&CMenuManager::m_PrefsSpriteScalingMode, "SpriteScaling", SpriteScalingModes, ARRAY_SIZE(SpriteScalingModes), false, nil) }, #else #define HUD_ASPECT_RATIO_SELECTOR #endif From 8fadca196bf0e3aefe2c6ebd1130d954ab08270b Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Tue, 29 Dec 2020 22:16:52 +0300 Subject: [PATCH 007/152] gxt key, default value --- src/core/Frontend.cpp | 17 ++++++++++++----- src/render/Draw.h | 3 +-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index a6edd444..93322fd9 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -142,7 +142,7 @@ int8 CMenuManager::m_nDisplayMSAALevel = 0; #endif #ifdef ASPECT_RATIO_SCALE -int32 CMenuManager::m_PrefsSpriteScalingMode = 0; +int32 CMenuManager::m_PrefsSpriteScalingMode = SCL_AUTO; #endif #ifdef NO_ISLAND_LOADING @@ -1463,27 +1463,34 @@ CMenuManager::Draw() #else switch (m_PrefsUseWideScreen) { case AR_AUTO: - sprintf(asciiTemp, "AUTO"); + rightText = TheText.Get("FEM_AUT"); break; case AR_4_3: sprintf(asciiTemp, "4:3"); + AsciiToUnicode(asciiTemp, unicodeTemp); + rightText = unicodeTemp; break; case AR_5_4: sprintf(asciiTemp, "5:4"); + AsciiToUnicode(asciiTemp, unicodeTemp); + rightText = unicodeTemp; break; case AR_16_10: sprintf(asciiTemp, "16:10"); + AsciiToUnicode(asciiTemp, unicodeTemp); + rightText = unicodeTemp; break; case AR_16_9: sprintf(asciiTemp, "16:9"); + AsciiToUnicode(asciiTemp, unicodeTemp); + rightText = unicodeTemp; break; case AR_21_9: sprintf(asciiTemp, "21:9"); + AsciiToUnicode(asciiTemp, unicodeTemp); + rightText = unicodeTemp; break; } - - AsciiToUnicode(asciiTemp, unicodeTemp); - rightText = unicodeTemp; #endif break; case MENUACTION_RADIO: diff --git a/src/render/Draw.h b/src/render/Draw.h index 9b98ca17..bacbe18f 100644 --- a/src/render/Draw.h +++ b/src/render/Draw.h @@ -4,13 +4,12 @@ enum eAspectRatio { // Make sure these work the same as FrontEndMenuManager.m_PrefsUseWideScreen // without widescreen support + AR_AUTO, AR_4_3, AR_5_4, AR_16_10, AR_16_9, AR_21_9, - - AR_AUTO, AR_MAX, }; From 7a360b1181590df6c37e104a2f63e9da5609bd38 Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Thu, 31 Dec 2020 07:56:50 +0300 Subject: [PATCH 008/152] hud cleanup --- src/render/Hud.cpp | 527 +++++++++++---------------------------------- 1 file changed, 126 insertions(+), 401 deletions(-) diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 9a2f718f..37a69cb5 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -21,6 +21,60 @@ #include "User.h" #include "World.h" +#ifdef PS2_HUD +#define MONEY_X 100.0f +#define WEAPON_X 91.0f +#define AMMO_X 59.0f +#define HEALTH_X 100.0f +#define STARS_X 49.0f +#define ZONE_Y 61.0f +#define VEHICLE_Y 81.0f +#define CLOCK_X 101.0f +#define SUBS_Y 83.0f +#define WASTEDBUSTED_Y 122.0f +#define BIGMESSAGE_Y 80.0f +#else +#define MONEY_X 110.0f +#define WEAPON_X 99.0f +#define AMMO_X 66.0f +#define HEALTH_X 110.0f +#define STARS_X 60.0f +#define ZONE_Y 30.0f +#define VEHICLE_Y 55.0f +#define CLOCK_X 111.0f +#define SUBS_Y 68.0f +#define WASTEDBUSTED_Y 82.0f +#define BIGMESSAGE_Y 84.0f +#endif + +#ifdef FIX_BUGS +#define TIMER_RIGHT_OFFSET 34.0f // Taken from VC frenzy timer +#define BIGMESSAGE_Y_OFFSET 18.0f +#else +#define TIMER_RIGHT_OFFSET 27.0f +#define BIGMESSAGE_Y_OFFSET 20.0f +#endif + +#if defined(PS2_HUD) && !defined(FIX_BUGS) + #define SCREEN_SCALE_X_PC(a) (a) + #define SCREEN_SCALE_Y_PC(a) (a) + #define SCALE_AND_CENTER_X_PC(a) (a) +#else + #define SCREEN_SCALE_X_PC(a) SCREEN_SCALE_X(a) + #define SCREEN_SCALE_Y_PC(a) SCREEN_SCALE_Y(a) + #define SCALE_AND_CENTER_X_PC(a) SCALE_AND_CENTER_X(a) +#endif + +#if defined(FIX_BUGS) + #define SCREEN_SCALE_X_FIX(a) SCREEN_SCALE_X(a) + #define SCREEN_SCALE_Y_FIX(a) SCREEN_SCALE_Y(a) + #define SCALE_AND_CENTER_X_FIX(a) SCALE_AND_CENTER_X(a) +#else + #define SCREEN_SCALE_X_FIX(a) (a) + #define SCREEN_SCALE_Y_FIX(a) (a) + #define SCALE_AND_CENTER_X_FIX(a) (a) +#endif + // Game has colors inlined in code. // For easier modification we collect them here: CRGBA MONEY_COLOR(89, 115, 150, 255); @@ -387,11 +441,7 @@ void CHud::Draw() RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRocketSightTex)); -#if defined(PS2_HUD) && !defined(FIX_BUGS) - CSprite::RenderOneXLUSprite(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 1.0f, 40.0f, 40.0f, (100.0f * fMultBright), (200.0f * fMultBright), (100.0f * fMultBright), 255, 1.0f, 255); -#else - CSprite::RenderOneXLUSprite(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 1.0f, SCREEN_SCALE_X(40.0f), SCREEN_SCALE_Y(40.0f), (100.0f * fMultBright), (200.0f * fMultBright), (100.0f * fMultBright), 255, 1.0f, 255); -#endif + CSprite::RenderOneXLUSprite(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 1.0f, SCREEN_SCALE_X_PC(40.0f), SCREEN_SCALE_Y_PC(40.0f), (100.0f * fMultBright), (200.0f * fMultBright), (100.0f * fMultBright), 255, 1.0f, 255); } else { // Sniper @@ -452,24 +502,10 @@ void CHud::Draw() CFont::SetFontStyle(FONT_HEADING); CFont::SetPropOff(); CFont::SetColor(CRGBA(0, 0, 0, 255)); - -#ifdef PS2_HUD -#define MONEY_X 100.0f -#else -#define MONEY_X 110.0f -#endif - -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MONEY_X) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(43.0f) + SCREEN_SCALE_Y(2.0f), sPrint); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MONEY_X) + 2.0f, SCREEN_SCALE_Y(43.0f) + 2.0f, sPrint); -#endif - + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MONEY_X) + SCREEN_SCALE_X_FIX(2.0f), SCREEN_SCALE_Y(43.0f) + SCREEN_SCALE_Y_FIX(2.0f), sPrint); CFont::SetColor(MONEY_COLOR); CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MONEY_X), SCREEN_SCALE_Y(43.0f), sPrint); -#undef MONEY_X - /* DrawAmmo */ @@ -506,14 +542,6 @@ void CHud::Draw() /* DrawWeaponIcon */ -#ifdef PS2_HUD -#define WEAPON_X 91.0f -#define AMMO_X 59.0f -#else -#define WEAPON_X 99.0f -#define AMMO_X 66.0f -#endif - Sprites[WeaponType].Draw( CRect( SCREEN_SCALE_FROM_RIGHT(WEAPON_X), @@ -543,19 +571,9 @@ void CHud::Draw() CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(AMMO_X), SCREEN_SCALE_Y(73.0f), sPrint); } -#undef WEAPON_X -#undef AMMO_X - /* DrawHealth */ - -#ifdef PS2_HUD -#define HEALTH_X 100.0f -#else -#define HEALTH_X 110.0f -#endif - CFont::SetBackgroundOff(); CFont::SetScale(SCREEN_SCALE_X(0.8f), SCREEN_SCALE_Y(1.35f)); CFont::SetJustifyOff(); @@ -579,35 +597,20 @@ void CHud::Draw() sprintf(sTemp, "%03d", (int32)FindPlayerPed()->m_fHealth); #endif AsciiToUnicode(sTemp, sPrint); - CFont::SetColor(CRGBA(0, 0, 0, 255)); -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(HEALTH_X) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(65.0f) + SCREEN_SCALE_Y(2.0f), sPrint); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(HEALTH_X) + 2.0f, SCREEN_SCALE_Y(65.0f) + 2.0f, sPrint); -#endif + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(HEALTH_X) + SCREEN_SCALE_X_FIX(2.0f), SCREEN_SCALE_Y(65.0f) + SCREEN_SCALE_Y_FIX(2.0f), sPrint); - if (!CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss || CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss + 2000 || CTimer::GetFrameCounter() & 4) { -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(HEALTH_X) + SCREEN_SCALE_X(2.0f) - SCREEN_SCALE_X(56.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(65.0f) + SCREEN_SCALE_Y(2.0f), sPrintIcon); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(HEALTH_X) + 2.0f - SCREEN_SCALE_X(56.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(65.0f) + 2.0f, sPrintIcon); -#endif - } + if (!CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss || CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss + 2000 || CTimer::GetFrameCounter() & 4) + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(HEALTH_X) + SCREEN_SCALE_X_FIX(2.0f) - SCREEN_SCALE_X(56.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(65.0f) + SCREEN_SCALE_Y_FIX(2.0f), sPrintIcon); + CFont::SetColor(HEALTH_COLOR); CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(HEALTH_X), SCREEN_SCALE_Y(65.0f), sPrint); - if (!CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss || CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss + 2000 || CTimer::GetFrameCounter() & 4) { -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(HEALTH_X) + SCREEN_SCALE_X(2.0f) - SCREEN_SCALE_X(56.0f), SCREEN_SCALE_Y(65.0f), sPrintIcon); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(HEALTH_X) + 2.0f - SCREEN_SCALE_X(56.0f), SCREEN_SCALE_Y(65.0f), sPrintIcon); -#endif - } + if (!CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss || CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss + 2000 || CTimer::GetFrameCounter() & 4) + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(HEALTH_X) + SCREEN_SCALE_X_FIX(2.0f) - SCREEN_SCALE_X(56.0f), SCREEN_SCALE_Y(65.0f), sPrintIcon); } } -#undef HEALTH_X /* DrawArmour @@ -624,19 +627,10 @@ void CHud::Draw() AsciiToUnicode(sTemp, sPrint); CFont::SetColor(CRGBA(0, 0, 0, 255)); -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(182.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(65.0f) + SCREEN_SCALE_Y(2.0f), sPrint); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(182.0f) + 2.0f, SCREEN_SCALE_Y(65.0f) + 2.0f, sPrint); -#endif + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(182.0f) + SCREEN_SCALE_X_FIX(2.0f), SCREEN_SCALE_Y(65.0f) + SCREEN_SCALE_Y_FIX(2.0f), sPrint); - if (!CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss || CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss + 2000 || CTimer::GetFrameCounter() & 4) { -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(182.0f) + SCREEN_SCALE_X(2.0f) - SCREEN_SCALE_X(54.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(65.0f) + SCREEN_SCALE_Y(2.0f), sPrintIcon); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(182.0f) + 2.0f - SCREEN_SCALE_X(54.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(65.0f) + 2.0f, sPrintIcon); -#endif - } + if (!CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss || CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss + 2000 || CTimer::GetFrameCounter() & 4) + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(182.0f) + SCREEN_SCALE_X_FIX(2.0f) - SCREEN_SCALE_X(54.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(65.0f) + SCREEN_SCALE_Y_FIX(2.0f), sPrintIcon); CFont::SetColor(ARMOUR_COLOR); @@ -651,13 +645,6 @@ void CHud::Draw() /* DrawWantedLevel */ - -#ifdef PS2_HUD -#define STARS_X 49.0f -#else -#define STARS_X 60.0f -#endif - CFont::SetBackgroundOff(); CFont::SetScale(SCREEN_SCALE_X(0.8f), SCREEN_SCALE_Y(1.35f)); CFont::SetJustifyOff(); @@ -672,11 +659,8 @@ void CHud::Draw() for (int i = 0; i < 6; i++) { CFont::SetColor(CRGBA(0, 0, 0, 255)); -#ifdef FIX_BUGS - CFont::PrintString(fStarsX + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(87.0f) + SCREEN_SCALE_Y(2.0f), sPrintIcon); -#else - CFont::PrintString(fStarsX + 2.0f, SCREEN_SCALE_Y(87.0f) + 2.0f, sPrintIcon); -#endif + CFont::PrintString(fStarsX + SCREEN_SCALE_X_FIX(2.0f), SCREEN_SCALE_Y(87.0f) + SCREEN_SCALE_Y_FIX(2.0f), sPrintIcon); + if (FindPlayerPed()->m_pWanted->m_nWantedLevel > i && (CTimer::GetTimeInMilliseconds() > FindPlayerPed()->m_pWanted->m_nLastWantedLevelChange + 2000 || CTimer::GetFrameCounter() & 4)) { @@ -687,17 +671,10 @@ void CHud::Draw() fStarsX -= SCREEN_SCALE_X(23.0f); } - -#undef STARS_X /* DrawZoneName */ -#ifdef PS2_HUD -#define ZONE_Y 61.0f -#else -#define ZONE_Y 30.0f -#endif if (m_pZoneName) { float fZoneAlpha = 255.0f; @@ -783,29 +760,16 @@ void CHud::Draw() CFont::SetBackGroundOnlyTextOff(); CFont::SetFontStyle(FONT_BANK); CFont::SetColor(CRGBA(0, 0, 0, fZoneAlpha)); -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(32.0f) + SCREEN_SCALE_X(1.0f), SCREEN_SCALE_FROM_BOTTOM(ZONE_Y) + SCREEN_SCALE_Y(1.0f), m_ZoneToPrint); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(32.0f) + 1.0f, SCREEN_SCALE_FROM_BOTTOM(ZONE_Y) + 1.0f, m_ZoneToPrint); -#endif - + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(32.0f) + SCREEN_SCALE_X_FIX(1.0f), SCREEN_SCALE_FROM_BOTTOM(ZONE_Y) + SCREEN_SCALE_Y_FIX(1.0f), m_ZoneToPrint); CFont::SetColor(CRGBA(ZONE_COLOR.r, ZONE_COLOR.g, ZONE_COLOR.b, fZoneAlpha)); CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(32.0f), SCREEN_SCALE_FROM_BOTTOM(ZONE_Y), m_ZoneToPrint); } } } -#undef ZONE_Y /* DrawVehicleName */ - -#ifdef PS2_HUD -#define VEHICLE_Y 81.0f -#else -#define VEHICLE_Y 55.0f -#endif - if (m_pVehicleName) { float fVehicleAlpha = 0.0f; @@ -890,13 +854,7 @@ void CHud::Draw() CFont::SetBackGroundOnlyTextOff(); CFont::SetFontStyle(FONT_BANK); CFont::SetColor(CRGBA(0, 0, 0, fVehicleAlpha)); - -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(32.0f) + SCREEN_SCALE_X(1.0f), SCREEN_SCALE_FROM_BOTTOM(VEHICLE_Y) + SCREEN_SCALE_Y(1.0f), m_pVehicleNameToPrint); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(32.0f) + 1.0f, SCREEN_SCALE_FROM_BOTTOM(VEHICLE_Y) + 1.0f, m_pVehicleNameToPrint); -#endif - + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(32.0f) + SCREEN_SCALE_X_FIX(1.0f), SCREEN_SCALE_FROM_BOTTOM(VEHICLE_Y) + SCREEN_SCALE_Y_FIX(1.0f), m_pVehicleNameToPrint); CFont::SetColor(CRGBA(VEHICLE_COLOR.r, VEHICLE_COLOR.g, VEHICLE_COLOR.b, fVehicleAlpha)); CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(32.0f), SCREEN_SCALE_FROM_BOTTOM(VEHICLE_Y), m_pVehicleNameToPrint); } @@ -908,16 +866,10 @@ void CHud::Draw() m_VehicleFadeTimer = 0; m_VehicleNameTimer = 0; } -#undef VEHICLE_Y /* DrawClock */ -#ifdef PS2_HUD -#define CLOCK_X 101.0f -#else -#define CLOCK_X 111.0f -#endif CFont::SetJustifyOff(); CFont::SetCentreOff(); CFont::SetBackgroundOff(); @@ -932,22 +884,13 @@ void CHud::Draw() AsciiToUnicode(sTemp, sPrint); CFont::SetColor(CRGBA(0, 0, 0, 255)); - -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(CLOCK_X) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(22.0f) + SCREEN_SCALE_Y(2.0f), sPrint); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(CLOCK_X) + 2.0f, SCREEN_SCALE_Y(22.0f) + 2.0f, sPrint); -#endif - + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(CLOCK_X) + SCREEN_SCALE_X_FIX(2.0f), SCREEN_SCALE_Y(22.0f) + SCREEN_SCALE_Y_FIX(2.0f), sPrint); CFont::SetColor(CLOCK_COLOR); CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(CLOCK_X), SCREEN_SCALE_Y(22.0f), sPrint); -#undef CLOCK_X - /* DrawOnScreenTimer */ - wchar sTimer[16]; if (!CUserDisplay::OnscnTimer.m_sEntries[0].m_bTimerProcessed) @@ -955,11 +898,6 @@ void CHud::Draw() if (!CUserDisplay::OnscnTimer.m_sEntries[0].m_bCounterProcessed) CounterOnLastFrame = false; -#ifdef FIX_BUGS -#define TIMER_RIGHT_OFFSET 34.0f // Taken from VC frenzy timer -#else -#define TIMER_RIGHT_OFFSET 27.0f -#endif if (CUserDisplay::OnscnTimer.m_bProcessed) { if (CUserDisplay::OnscnTimer.m_sEntries[0].m_bTimerProcessed) { if (!TimerOnLastFrame) @@ -983,11 +921,7 @@ void CHud::Draw() CFont::SetPropOff(); CFont::SetBackGroundOnlyTextOn(); CFont::SetColor(CRGBA(0, 0, 0, 255)); -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(110.0f) + SCREEN_SCALE_Y(2.0f), sTimer); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) + 2.0f, SCREEN_SCALE_Y(110.0f) + 2.0f, sTimer); -#endif + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) + SCREEN_SCALE_X_FIX(2.0f), SCREEN_SCALE_Y(110.0f) + SCREEN_SCALE_Y_FIX(2.0f), sTimer); CFont::SetScale(SCREEN_SCALE_X(0.8f), SCREEN_SCALE_Y(1.35f)); CFont::SetColor(TIMER_COLOR); CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET), SCREEN_SCALE_Y(110.0f), sTimer); @@ -996,12 +930,7 @@ void CHud::Draw() CFont::SetPropOn(); CFont::SetColor(CRGBA(0, 0, 0, 255)); CFont::SetScale(SCREEN_SCALE_X(0.8f * 0.8f), SCREEN_SCALE_Y(1.35f)); -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(80.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(110.0f) + SCREEN_SCALE_Y(2.0f), TheText.Get(CUserDisplay::OnscnTimer.m_sEntries[0].m_aTimerText)); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(80.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(110.0f) + 2.0f, TheText.Get(CUserDisplay::OnscnTimer.m_sEntries[0].m_aTimerText)); -#endif - + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(80.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(110.0f) + SCREEN_SCALE_Y_FIX(2.0f), TheText.Get(CUserDisplay::OnscnTimer.m_sEntries[0].m_aTimerText)); CFont::SetColor(TIMER_COLOR); CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(80.0f), SCREEN_SCALE_Y(110.0f), TheText.Get(CUserDisplay::OnscnTimer.m_sEntries[0].m_aTimerText)); } @@ -1032,14 +961,8 @@ void CHud::Draw() CFont::SetWrapx(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH)); CFont::SetPropOff(); CFont::SetBackGroundOnlyTextOn(); - CFont::SetColor(CRGBA(0, 0, 0, 255)); -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y(2.0f), sTimer); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) + 2.0f, SCREEN_SCALE_Y(132.0f) + 2.0f, sTimer); -#endif - + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) + SCREEN_SCALE_X_FIX(2.0f), SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y_FIX(2.0f), sTimer); CFont::SetColor(COUNTER_COLOR); CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET), SCREEN_SCALE_Y(132.0f), sTimer); } else { @@ -1051,23 +974,10 @@ void CHud::Draw() ( CRect ( -#ifdef FIX_BUGS - SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(100.0f) / 2 + SCREEN_SCALE_X(4.0f), -#else - SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(100.0f) / 2 + 4.0f, -#endif + SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(100.0f) / 2 + SCREEN_SCALE_X_FIX(4.0f), SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y(8.0f), -#ifdef FIX_BUGS - SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) + SCREEN_SCALE_X(4.0f), -#else - SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) + 4.0f, -#endif - -#if !defined(PS2_HUD) || defined(FIX_BUGS) - SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y(11.0f) + SCREEN_SCALE_Y(8.0f) -#else - SCREEN_SCALE_Y(132.0f) + 11.0f + SCREEN_SCALE_Y(8.0f) -#endif + SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) + SCREEN_SCALE_X_FIX(4.0f), + SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y_PC(11.0f) + SCREEN_SCALE_Y(8.0f) ), CRGBA(0, 106, 164, 80) ); @@ -1076,30 +986,10 @@ void CHud::Draw() ( CRect ( -#ifdef FIX_BUGS - SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(100.0f) / 2 + SCREEN_SCALE_X(4.0f), -#else - SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(100.0f) / 2 + 4.0f, -#endif + SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(100.0f) / 2 + SCREEN_SCALE_X_FIX(4.0f), SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y(8.0f), - -#if !defined(PS2_HUD) || defined(FIX_BUGS) - SCREEN_SCALE_X(counter) / 2.0f + -#else - (float)(counter) / 2.0f + -#endif - -#ifdef FIX_BUGS - SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(100.0f) / 2.0f + SCREEN_SCALE_X(4.0f), -#else - SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(100.0f) / 2.0f + 4.0f, -#endif - -#if !defined(PS2_HUD) || defined(FIX_BUGS) - SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y(11.0f) + SCREEN_SCALE_Y(8.0f) -#else - SCREEN_SCALE_Y(132.0f) + 11.0f + SCREEN_SCALE_Y(8.0f) -#endif + SCREEN_SCALE_X_PC((float)counter) / 2.0f + SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(100.0f) / 2.0f + SCREEN_SCALE_X_FIX(4.0f), + SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y_PC(11.0f) + SCREEN_SCALE_Y(8.0f) ), CRGBA(0, 106, 164, 255) ); @@ -1109,19 +999,13 @@ void CHud::Draw() CFont::SetPropOn(); CFont::SetScale(SCREEN_SCALE_X(0.8f), SCREEN_SCALE_Y(1.35f)); CFont::SetColor(CRGBA(0, 0, 0, 255)); -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(61.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y(2.0f), TheText.Get(CUserDisplay::OnscnTimer.m_sEntries[0].m_aCounterText)); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(61.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(132.0f) + 2.0f, TheText.Get(CUserDisplay::OnscnTimer.m_sEntries[0].m_aCounterText)); -#endif - + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(61.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y_FIX(2.0f), TheText.Get(CUserDisplay::OnscnTimer.m_sEntries[0].m_aCounterText)); CFont::SetColor(COUNTER_COLOR); CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(61.0f), SCREEN_SCALE_Y(132.0f), TheText.Get(CUserDisplay::OnscnTimer.m_sEntries[0].m_aCounterText)); } } } } -#undef TIMER_RIGHT_OFFSET ///////////////////////////////// /* @@ -1158,13 +1042,7 @@ void CHud::Draw() PagerOn = 0; } } - -#ifdef FIX_BUGS - Sprites[HUD_PAGER].Draw(CRect(SCREEN_SCALE_X(26.0f) - SCREEN_SCALE_X(PagerXOffset), SCREEN_SCALE_Y(27.0f), SCREEN_SCALE_X(160.0f) + SCREEN_SCALE_X(26.0f) - SCREEN_SCALE_X(PagerXOffset), SCREEN_SCALE_Y(80.0f) + SCREEN_SCALE_Y(27.0f)), CRGBA(255, 255, 255, 255)); -#else - Sprites[HUD_PAGER].Draw(CRect(SCREEN_SCALE_X(26.0f) - PagerXOffset, SCREEN_SCALE_Y(27.0f), SCREEN_SCALE_X(160.0f) + SCREEN_SCALE_X(26.0f) - PagerXOffset, SCREEN_SCALE_Y(80.0f) + SCREEN_SCALE_Y(27.0f)), CRGBA(255, 255, 255, 255)); -#endif - + Sprites[HUD_PAGER].Draw(CRect(SCREEN_SCALE_X(26.0f) - SCREEN_SCALE_X_FIX(PagerXOffset), SCREEN_SCALE_Y(27.0f), SCREEN_SCALE_X(160.0f) + SCREEN_SCALE_X(26.0f) - SCREEN_SCALE_X_FIX(PagerXOffset), SCREEN_SCALE_Y(80.0f) + SCREEN_SCALE_Y(27.0f)), CRGBA(255, 255, 255, 255)); CFont::SetBackgroundOff(); CFont::SetScale(SCREEN_SCALE_X(0.84f), SCREEN_SCALE_Y(1.0f)); CFont::SetColor(PAGER_COLOR); @@ -1175,12 +1053,7 @@ void CHud::Draw() CFont::SetJustifyOff(); CFont::SetPropOff(); CFont::SetFontStyle(FONT_PAGER); - -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_X(52.0f) - SCREEN_SCALE_X(PagerXOffset), SCREEN_SCALE_Y(54.0f), m_PagerMessage); -#else - CFont::PrintString(SCREEN_SCALE_X(52.0f) - PagerXOffset, SCREEN_SCALE_Y(54.0f), m_PagerMessage); -#endif + CFont::PrintString(SCREEN_SCALE_X(52.0f) - SCREEN_SCALE_X_FIX(PagerXOffset), SCREEN_SCALE_Y(54.0f), m_PagerMessage); } /* @@ -1194,11 +1067,7 @@ void CHud::Draw() if (m_ItemToFlash == ITEM_RADAR && CTimer::GetFrameCounter() & 8 || m_ItemToFlash != ITEM_RADAR) { CRadar::DrawMap(); CRect rect(0.0f, 0.0f, SCREEN_SCALE_X(_RADAR_WIDTH), SCREEN_SCALE_Y(RADAR_HEIGHT)); -#ifdef FIX_BUGS - rect.Translate(SCREEN_SCALE_X(RADAR_LEFT), SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT)); -#else - rect.Translate(RADAR_LEFT, SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT)); -#endif + rect.Translate(SCREEN_SCALE_X_FIX(RADAR_LEFT), SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT)); #ifdef PS2_HUD #ifdef FIX_BUGS @@ -1231,11 +1100,12 @@ void CHud::Draw() if (!CTimer::GetIsUserPaused()) { for (int i = 0; i < ARRAY_SIZE(CTheScripts::IntroTextLines); i++) { if (CTheScripts::IntroTextLines[i].m_Text[0] && CTheScripts::IntroTextLines[i].m_bTextBeforeFade) { -#if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::SetScale(CTheScripts::IntroTextLines[i].m_fScaleX, CTheScripts::IntroTextLines[i].m_fScaleY); -#else - CFont::SetScale(SCREEN_SCALE_X(CTheScripts::IntroTextLines[i].m_fScaleX), SCREEN_SCALE_Y(CTheScripts::IntroTextLines[i].m_fScaleY * 0.5f)); + CFont::SetScale(SCREEN_SCALE_X_PC(CTheScripts::IntroTextLines[i].m_fScaleX), SCREEN_SCALE_Y_PC(CTheScripts::IntroTextLines[i].m_fScaleY +#if !defined(PS2_HUD) || defined(FIX_BUGS) + * 0.5f #endif + )); + CFont::SetColor(CTheScripts::IntroTextLines[i].m_sColor); if (CTheScripts::IntroTextLines[i].m_bJustify) @@ -1253,18 +1123,10 @@ void CHud::Draw() else CFont::SetCentreOff(); -#if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::SetWrapx(CTheScripts::IntroTextLines[i].m_fWrapX); -#else - CFont::SetWrapx(SCALE_AND_CENTER_X(CTheScripts::IntroTextLines[i].m_fWrapX)); -#endif - -#if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::SetCentreSize(CTheScripts::IntroTextLines[i].m_fCenterSize); -#else - CFont::SetCentreSize(SCREEN_SCALE_X(CTheScripts::IntroTextLines[i].m_fCenterSize)); -#endif - + CFont::SetWrapx(SCALE_AND_CENTER_X_PC(CTheScripts::IntroTextLines[i].m_fWrapX)); + + CFont::SetCentreSize(SCREEN_SCALE_X_PC(CTheScripts::IntroTextLines[i].m_fCenterSize)); + if (CTheScripts::IntroTextLines[i].m_bBackground) CFont::SetBackgroundOn(); else @@ -1320,20 +1182,11 @@ void CHud::Draw() /* DrawSubtitles */ -#ifdef PS2_HUD -#define SUBS_Y 83.0f -#else -#define SUBS_Y 68.0f -#endif if (m_Message[0] && !m_BigMessage[2][0] && (FrontEndMenuManager.m_PrefsShowSubtitles == 1 || !TheCamera.m_WideScreenOn)) { CFont::SetJustifyOff(); CFont::SetBackgroundOff(); CFont::SetBackgroundColor(CRGBA(0, 0, 0, 128)); -#if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::SetScale(0.48f, 1.12f); -#else - CFont::SetScale(SCREEN_SCALE_X(0.48f), SCREEN_SCALE_Y(1.12f)); -#endif + CFont::SetScale(SCREEN_SCALE_X_PC(0.48f), SCREEN_SCALE_Y_PC(1.12f)); CFont::SetCentreOn(); CFont::SetPropOn(); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); @@ -1358,17 +1211,10 @@ void CHud::Draw() CFont::SetColor(CRGBA(235, 235, 235, 255)); // I'm not sure shadow substaction was intentional here, might be a leftover if CFont::PrintString was used for a shadow draw call - #if defined(FIX_BUGS) - CFont::PrintString(rectWidth / 2.0f + radarBulge - SCREEN_SCALE_X(shadow), SCREEN_SCALE_Y(4.0f) + SCREEN_SCALE_FROM_BOTTOM(SUBS_Y) - SCREEN_SCALE_Y(shadow), m_Message); - #elif defined(PS2_HUD) - CFont::PrintString(rectWidth / 2.0f + radarBulge - shadow, 4.0f + SCREEN_SCALE_FROM_BOTTOM(SUBS_Y) - shadow, m_Message); - #else - CFont::PrintString(rectWidth / 2.0f + radarBulge - shadow, SCREEN_SCALE_Y(4.0f) + SCREEN_SCALE_FROM_BOTTOM(SUBS_Y) - shadow, m_Message); - #endif + CFont::PrintString(rectWidth / 2.0f + radarBulge - SCREEN_SCALE_X_FIX(shadow), SCREEN_SCALE_Y_PC(4.0f) + SCREEN_SCALE_FROM_BOTTOM(SUBS_Y) - SCREEN_SCALE_Y_FIX(shadow), m_Message); CFont::SetDropShadowPosition(0); #endif // #ifdef XBOX_SUBTITLES } -#undef SUBS_Y /* DrawBigMessage @@ -1381,17 +1227,9 @@ void CHud::Draw() CFont::SetBackGroundOnlyTextOff(); if (CGame::frenchGame || CGame::germanGame) -#if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::SetScale(1.8f, 1.8f); -#else - CFont::SetScale(SCREEN_SCALE_X(1.8f), SCREEN_SCALE_Y(1.8f)); -#endif + CFont::SetScale(SCREEN_SCALE_X_PC(1.8f), SCREEN_SCALE_Y_PC(1.8f)); else -#if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::SetScale(1.8f, 1.8f); -#else - CFont::SetScale(SCREEN_SCALE_X(1.8f), SCREEN_SCALE_Y(1.8f)); -#endif + CFont::SetScale(SCREEN_SCALE_X_PC(1.8f), SCREEN_SCALE_Y_PC(1.8f)); CFont::SetPropOn(); CFont::SetCentreOn(); @@ -1419,30 +1257,18 @@ void CHud::Draw() } } else { -#ifdef FIX_BUGS - BigMessageX[0] += SCREEN_SCALE_X((CTimer::GetTimeStepInMilliseconds() * 0.3f)); -#else - BigMessageX[0] += (CTimer::GetTimeStepInMilliseconds() * 0.3f); -#endif + BigMessageX[0] += SCREEN_SCALE_X_FIX(CTimer::GetTimeStepInMilliseconds() * 0.3f); BigMessageAlpha[0] += (CTimer::GetTimeStepInMilliseconds() * 0.3f); if (BigMessageAlpha[0] > 255.0f) BigMessageAlpha[0] = 255.0f; } - CFont::SetColor(CRGBA(0, 0, 0, BigMessageAlpha[0])); -#ifdef FIX_BUGS -#define Y_OFFSET 18.0f -#else -#define Y_OFFSET 20.0f -#endif -#if defined(FIX_BUGS) - CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(Y_OFFSET) + SCREEN_SCALE_Y(2.0f), m_BigMessage[0]); -#elif defined(PS2_HUD) // yeah, that's right. ps2 uses y=ScaleX(a) - CFont::PrintString(SCREEN_WIDTH / 2 + 2.0f, (SCREEN_WIDTH / 2) - SCREEN_SCALE_X(120.0f) + 2.0f, m_BigMessage[0]); +#if defined(PS2_HUD) && !defined(FIX_BUGS) // yeah, that's right. ps2 uses y=ScaleX(a) + CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X_FIX(2.0f), (SCREEN_WIDTH / 2) - SCREEN_SCALE_X(120.0f) + SCREEN_SCALE_Y_FIX(2.0f), m_BigMessage[0]); #else - CFont::PrintString(SCREEN_WIDTH / 2 + 2.0f, (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(Y_OFFSET) + 2.0f, m_BigMessage[0]); + CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X_FIX(2.0f), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(BIGMESSAGE_Y_OFFSET) + SCREEN_SCALE_Y_FIX(2.0f), m_BigMessage[0]); #endif CFont::SetColor(CRGBA(BIGMESSAGE_COLOR.r, BIGMESSAGE_COLOR.g, BIGMESSAGE_COLOR.b, BigMessageAlpha[0])); #if defined(PS2_HUD) && !defined(FIX_BUGS) // same @@ -1450,16 +1276,10 @@ void CHud::Draw() #else CFont::PrintString(SCREEN_WIDTH / 2, (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(18.0f), m_BigMessage[0]); #endif - -#undef Y_OFFSET } else { BigMessageAlpha[0] = 0.0f; -#ifdef FIX_BUGS - BigMessageX[0] = SCALE_AND_CENTER_X(-60.0f); -#else - BigMessageX[0] = -60.0f; -#endif + BigMessageX[0] = SCALE_AND_CENTER_X_FIX(-60.0f); BigMessageInUse[0] = 1.0f; } } @@ -1468,11 +1288,6 @@ void CHud::Draw() } // WastedBustedText -#ifdef PS2_HUD -#define WASTEDBUSTED_Y 122.0f -#else -#define WASTEDBUSTED_Y 82.0f -#endif if (m_BigMessage[2][0]) { if (BigMessageInUse[2] != 0.0f) { BigMessageAlpha[2] += (CTimer::GetTimeStepInMilliseconds() * 0.4f); @@ -1482,29 +1297,17 @@ void CHud::Draw() CFont::SetBackgroundOff(); -#if defined(PS2_HUD) && !defined(FIX_BUGS) if (CGame::frenchGame || CGame::germanGame) - CFont::SetScale(1.4f, 1.4f); + CFont::SetScale(SCREEN_SCALE_X_PC(1.4f), SCREEN_SCALE_Y_PC(1.4f)); else - CFont::SetScale(2.0f, 2.0f); -#else - if (CGame::frenchGame || CGame::germanGame) - CFont::SetScale(SCREEN_SCALE_X(1.4f), SCREEN_SCALE_Y(1.4f)); - else - CFont::SetScale(SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(2.0f)); -#endif + CFont::SetScale(SCREEN_SCALE_X_PC(2.0f), SCREEN_SCALE_Y_PC(2.0f)); CFont::SetPropOn(); CFont::SetRightJustifyOn(); CFont::SetFontStyle(FONT_HEADING); CFont::SetColor(CRGBA(0, 0, 0, BigMessageAlpha[2]*0.75f)); -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f) + SCREEN_SCALE_X(4.0f), SCREEN_SCALE_FROM_BOTTOM(WASTEDBUSTED_Y) + SCREEN_SCALE_Y(4.0f), m_BigMessage[2]); -#else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f) + 4.0f, SCREEN_SCALE_FROM_BOTTOM(WASTEDBUSTED_Y) + SCREEN_SCALE_Y(4.0f), m_BigMessage[2]); -#endif - + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f) + SCREEN_SCALE_X_FIX(4.0f), SCREEN_SCALE_FROM_BOTTOM(WASTEDBUSTED_Y) + SCREEN_SCALE_Y(4.0f), m_BigMessage[2]); CFont::SetColor(CRGBA(WASTEDBUSTED_COLOR.r, WASTEDBUSTED_COLOR.g, WASTEDBUSTED_COLOR.b, BigMessageAlpha[2])); CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(WASTEDBUSTED_Y), m_BigMessage[2]); } @@ -1516,7 +1319,6 @@ void CHud::Draw() else { BigMessageInUse[2] = 0.0f; } -#undef WASTEDBUSTED_Y } } @@ -1611,28 +1413,16 @@ void CHud::DrawAfterFade() CFont::SetJustifyOff(); #ifdef MORE_LANGUAGES if (CFont::IsJapanese()) - #ifdef FIX_BUGS - CFont::SetWrapx(SCREEN_SCALE_X(229.0f) + SCREEN_SCALE_X(26.0f) - SCREEN_SCALE_X(4.0f)); - #else - CFont::SetWrapx(SCREEN_SCALE_X(229.0f) + SCREEN_SCALE_X(26.0f) - 4.0f); - #endif + CFont::SetWrapx(SCREEN_SCALE_X(229.0f) + SCREEN_SCALE_X(26.0f) - SCREEN_SCALE_X_FIX(4.0f)); else #endif - #ifdef FIX_BUGS - CFont::SetWrapx(SCREEN_SCALE_X(200.0f) + SCREEN_SCALE_X(26.0f) - SCREEN_SCALE_X(4.0f)); - #else - CFont::SetWrapx(SCREEN_SCALE_X(200.0f) + SCREEN_SCALE_X(26.0f) - 4.0f); - #endif + CFont::SetWrapx(SCREEN_SCALE_X(200.0f) + SCREEN_SCALE_X(26.0f) - SCREEN_SCALE_X_FIX(4.0f)); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); CFont::SetBackgroundOn(); CFont::SetBackGroundOnlyTextOff(); CFont::SetBackgroundColor(CRGBA(0, 0, 0, fAlpha * 0.9f)); CFont::SetColor(CRGBA(175, 175, 175, 255)); -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_X(26.0f), SCREEN_SCALE_Y(28.0f + (150.0f - PagerXOffset) * 0.6f), m_HelpMessageToPrint); -#else - CFont::PrintString(SCREEN_SCALE_X(26.0f), SCREEN_SCALE_Y(28.0f) + (150.0f - PagerXOffset) * 0.6f, m_HelpMessageToPrint); -#endif + CFont::PrintString(SCREEN_SCALE_X(26.0f), SCREEN_SCALE_Y(28.0f) + SCREEN_SCALE_Y_FIX((150.0f - PagerXOffset) * 0.6f), m_HelpMessageToPrint); CFont::SetAlphaFade(255.0f); } } @@ -1640,11 +1430,12 @@ void CHud::DrawAfterFade() for (int i = 0; i < ARRAY_SIZE(CTheScripts::IntroTextLines); i++) { intro_text_line &line = CTheScripts::IntroTextLines[i]; if (line.m_Text[0] != '\0' && !line.m_bTextBeforeFade) { -#if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::SetScale(line.m_fScaleX, line.m_fScaleY); -#else - CFont::SetScale(SCREEN_SCALE_X(line.m_fScaleX), SCREEN_SCALE_Y(line.m_fScaleY) / 2); + + CFont::SetScale(SCREEN_SCALE_X_PC(line.m_fScaleX), SCREEN_SCALE_Y_PC(line.m_fScaleY) +#if !defined(PS2_HUD) || defined(FIX_BUGS) + / 2 #endif + ); CFont::SetColor(line.m_sColor); if (line.m_bJustify) CFont::SetJustifyOn(); @@ -1661,13 +1452,8 @@ void CHud::DrawAfterFade() else CFont::SetCentreOff(); -#if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::SetWrapx(line.m_fWrapX); - CFont::SetCentreSize(line.m_fCenterSize); -#else - CFont::SetWrapx(SCALE_AND_CENTER_X(line.m_fWrapX)); - CFont::SetCentreSize(SCREEN_SCALE_X(line.m_fCenterSize)); -#endif + CFont::SetWrapx(SCALE_AND_CENTER_X_PC(line.m_fWrapX)); + CFont::SetCentreSize(SCREEN_SCALE_X_PC(line.m_fCenterSize)); if (line.m_bBackground) CFont::SetBackgroundOn(); @@ -1711,61 +1497,34 @@ void CHud::DrawAfterFade() /* DrawBigMessage2 */ -#ifdef PS2_HUD - #define BIGMESSAGE_Y 80.0f -#else - #define BIGMESSAGE_Y 84.0f -#endif - // Oddjob if (m_BigMessage[3][0]) { CFont::SetJustifyOff(); CFont::SetBackgroundOff(); -#if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::SetScale(1.2f, 1.5f); -#else - CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.5f)); -#endif + CFont::SetScale(SCREEN_SCALE_X_PC(1.2f), SCREEN_SCALE_Y_PC(1.5f)); CFont::SetCentreOn(); CFont::SetPropOn(); CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH - 40)); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); CFont::SetColor(CRGBA(0, 0, 0, 255)); - -#ifdef FIX_BUGS - CFont::PrintString((SCREEN_WIDTH / 2) + SCREEN_SCALE_X(2.0f), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(BIGMESSAGE_Y) + SCREEN_SCALE_Y(2.0f), m_BigMessage[3]); -#else - CFont::PrintString((SCREEN_WIDTH / 2) + 2.0f, (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(BIGMESSAGE_Y) + 2.0f, m_BigMessage[3]); -#endif - + CFont::PrintString((SCREEN_WIDTH / 2) + SCREEN_SCALE_X_FIX(2.0f), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(BIGMESSAGE_Y) + SCREEN_SCALE_Y_FIX(2.0f), m_BigMessage[3]); CFont::SetColor(ODDJOB_COLOR); - CFont::PrintString((SCREEN_WIDTH / 2), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(BIGMESSAGE_Y), m_BigMessage[3]); } if (!m_BigMessage[1][0] && m_BigMessage[4][0]) { CFont::SetJustifyOff(); CFont::SetBackgroundOff(); -#if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::SetScale(1.2f, 1.5f); -#else - CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.5f)); -#endif + CFont::SetScale(SCREEN_SCALE_X_PC(1.2f), SCREEN_SCALE_Y_PC(1.5f)); CFont::SetCentreOn(); CFont::SetPropOn(); CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH - 20)); CFont::SetColor(CRGBA(0, 0, 0, 255)); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); - -#ifdef FIX_BUGS - CFont::PrintString((SCREEN_WIDTH / 2) - SCREEN_SCALE_X(2.0f), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(BIGMESSAGE_Y) - SCREEN_SCALE_Y(2.0f), m_BigMessage[4]); -#else - CFont::PrintString((SCREEN_WIDTH / 2) - 2.0f, (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(BIGMESSAGE_Y) - 2.0f, m_BigMessage[4]); -#endif + CFont::PrintString((SCREEN_WIDTH / 2) - SCREEN_SCALE_X_FIX(2.0f), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(BIGMESSAGE_Y) - SCREEN_SCALE_Y_FIX(2.0f), m_BigMessage[4]); CFont::SetColor(ODDJOB_COLOR); CFont::PrintString((SCREEN_WIDTH / 2), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(BIGMESSAGE_Y), m_BigMessage[4]); } -#undef BIGMESSAGE_Y // Oddjob result if (OddJob2OffTimer > 0) @@ -1824,19 +1583,11 @@ void CHud::DrawAfterFade() CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); #ifdef BETA_SLIDING_TEXT - #if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::PrintString(SCREEN_WIDTH / 2 + 2.0f - SCREEN_SCALE_X(OddJob2XOffset), SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(20.0f) + 2.0f, m_BigMessage[5]); - #else - CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f) - SCREEN_SCALE_X(OddJob2XOffset), SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(20.0f) + SCREEN_SCALE_Y(2.0f), m_BigMessage[5]); - #endif + CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X_PC(2.0f) - SCREEN_SCALE_X(OddJob2XOffset), SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(20.0f) + SCREEN_SCALE_Y_PC(2.0f), m_BigMessage[5]); CFont::SetColor(ODDJOB2_COLOR); CFont::PrintString(SCREEN_WIDTH / 2 - SCREEN_SCALE_X(OddJob2XOffset), SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(20.0f), m_BigMessage[5]); #else - #if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::PrintString(SCREEN_WIDTH / 2 + 2.0f, SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(20.0f) + 2.0f, m_BigMessage[5]); - #else - CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f), SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(20.0f) + SCREEN_SCALE_Y(2.0f), m_BigMessage[5]); - #endif + CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X_PC(2.0f), SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(20.0f) + SCREEN_SCALE_Y_PC(2.0f), m_BigMessage[5]); CFont::SetColor(ODDJOB2_COLOR); CFont::PrintString(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(20.0f), m_BigMessage[5]); #endif @@ -1852,17 +1603,9 @@ void CHud::DrawAfterFade() CFont::SetBackgroundOff(); if (CGame::frenchGame || FrontEndMenuManager.m_PrefsLanguage == CMenuManager::LANGUAGE_SPANISH) -#if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::SetScale(0.884f, 1.36f); -#else - CFont::SetScale(SCREEN_SCALE_X(0.884f), SCREEN_SCALE_Y(1.36f)); -#endif + CFont::SetScale(SCREEN_SCALE_X_PC(0.884f), SCREEN_SCALE_Y_PC(1.36f)); else -#if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::SetScale(1.04f, 1.6f); -#else - CFont::SetScale(SCREEN_SCALE_X(1.04f), SCREEN_SCALE_Y(1.6f)); -#endif + CFont::SetScale(SCREEN_SCALE_X_PC(1.04f), SCREEN_SCALE_Y_PC(1.6f)); CFont::SetPropOn(); #ifdef FIX_BUGS @@ -1873,11 +1616,7 @@ void CHud::DrawAfterFade() CFont::SetRightJustifyOn(); CFont::SetFontStyle(FONT_HEADING); -#ifdef FIX_BUGS - if (BigMessageX[1] >= SCREEN_WIDTH - SCREEN_SCALE_X(20.0f)) -#else - if (BigMessageX[1] >= SCREEN_WIDTH - 20.0f) -#endif + if (BigMessageX[1] >= SCREEN_WIDTH - SCREEN_SCALE_X_FIX(20.0f)) { BigMessageInUse[1] += CTimer::GetTimeStep(); @@ -1890,11 +1629,7 @@ void CHud::DrawAfterFade() BigMessageAlpha[1] = 0.0f; } } else { -#ifdef FIX_BUGS - BigMessageX[1] += SCREEN_SCALE_X((CTimer::GetTimeStepInMilliseconds() * 0.3f)); -#else - BigMessageX[1] += (CTimer::GetTimeStepInMilliseconds() * 0.3f); -#endif + BigMessageX[1] += SCREEN_SCALE_X_FIX(CTimer::GetTimeStepInMilliseconds() * 0.3f); BigMessageAlpha[1] += (CTimer::GetTimeStepInMilliseconds() * 0.3f); if (BigMessageAlpha[1] > 255.0f) @@ -1903,21 +1638,11 @@ void CHud::DrawAfterFade() CFont::SetColor(CRGBA(40, 40, 40, BigMessageAlpha[1])); #ifdef BETA_SLIDING_TEXT - #if defined(PS2_HUD) && !defined(FIX_BUGS) - CFont::PrintString(SCREEN_SCALE_X(2.0f) + BigMessageX[1], SCREEN_SCALE_FROM_BOTTOM(120.0f) + 2.0f, m_BigMessage[1]); - #else - CFont::PrintString(SCREEN_SCALE_X(2.0f) + BigMessageX[1], SCREEN_SCALE_FROM_BOTTOM(120.0f) + SCREEN_SCALE_Y(2.0f), m_BigMessage[1]); - #endif + CFont::PrintString(SCREEN_SCALE_X(2.0f) + BigMessageX[1], SCREEN_SCALE_FROM_BOTTOM(120.0f) + SCREEN_SCALE_Y_PC(2.0f), m_BigMessage[1]); CFont::SetColor(CRGBA(MISSIONTITLE_COLOR.r, MISSIONTITLE_COLOR.g, MISSIONTITLE_COLOR.b, BigMessageAlpha[1])); CFont::PrintString(BigMessageX[1], SCREEN_SCALE_FROM_BOTTOM(120.0f), m_BigMessage[1]); #else - #ifdef FIX_BUGS - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_FROM_BOTTOM(120.0f) + SCREEN_SCALE_Y(2.0f), m_BigMessage[1]); - #elif defined(PS2_HUD) - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f) + 2.0f, SCREEN_SCALE_FROM_BOTTOM(120.0f) + 2.0f, m_BigMessage[1]); - #else - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f) + 2.0f, SCREEN_SCALE_FROM_BOTTOM(120.0f) + SCREEN_SCALE_Y(2.0f), m_BigMessage[1]); - #endif + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f) + SCREEN_SCALE_X_FIX(2.0f), SCREEN_SCALE_FROM_BOTTOM(120.0f) + SCREEN_SCALE_Y_PC(2.0f), m_BigMessage[1]); CFont::SetColor(CRGBA(MISSIONTITLE_COLOR.r, MISSIONTITLE_COLOR.g, MISSIONTITLE_COLOR.b, BigMessageAlpha[1])); CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(120.0f), m_BigMessage[1]); #endif From bc7161754f9be556e11d1049c9666770eaad94fa Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Thu, 31 Dec 2020 18:10:08 +0300 Subject: [PATCH 009/152] fix compiling --- src/render/Hud.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 37a69cb5..2adcbb81 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -1100,11 +1100,11 @@ void CHud::Draw() if (!CTimer::GetIsUserPaused()) { for (int i = 0; i < ARRAY_SIZE(CTheScripts::IntroTextLines); i++) { if (CTheScripts::IntroTextLines[i].m_Text[0] && CTheScripts::IntroTextLines[i].m_bTextBeforeFade) { - CFont::SetScale(SCREEN_SCALE_X_PC(CTheScripts::IntroTextLines[i].m_fScaleX), SCREEN_SCALE_Y_PC(CTheScripts::IntroTextLines[i].m_fScaleY + CFont::SetScale(SCREEN_SCALE_X_PC(CTheScripts::IntroTextLines[i].m_fScaleX), SCREEN_SCALE_Y_PC(CTheScripts::IntroTextLines[i].m_fScaleY) #if !defined(PS2_HUD) || defined(FIX_BUGS) * 0.5f #endif - )); + ); CFont::SetColor(CTheScripts::IntroTextLines[i].m_sColor); From 2f05c64470a2b04439a07646662ac6afb57901f5 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Fri, 1 Jan 2021 13:35:23 +0300 Subject: [PATCH 010/152] actual struct name --- src/control/Script.cpp | 4 ++-- src/control/Script.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 6aa48d81..9856a8aa 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -1340,7 +1340,7 @@ void CMissionCleanup::Init() } } -CMissionCleanupEntity* CMissionCleanup::FindFree() +cleanup_entity_struct* CMissionCleanup::FindFree() { for (int i = 0; i < MAX_CLEANUP; i++){ if (m_sEntities[i].type == CLEANUP_UNUSED) @@ -1352,7 +1352,7 @@ CMissionCleanupEntity* CMissionCleanup::FindFree() void CMissionCleanup::AddEntityToList(int32 id, uint8 type) { - CMissionCleanupEntity* pNew = FindFree(); + cleanup_entity_struct* pNew = FindFree(); if (!pNew) return; pNew->id = id; diff --git a/src/control/Script.h b/src/control/Script.h index 1c4663ce..588c1f41 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -134,7 +134,7 @@ enum { CLEANUP_OBJECT }; -struct CMissionCleanupEntity +struct cleanup_entity_struct { uint8 type; int32 id; @@ -148,14 +148,14 @@ enum { class CMissionCleanup { - CMissionCleanupEntity m_sEntities[MAX_CLEANUP]; + cleanup_entity_struct m_sEntities[MAX_CLEANUP]; uint8 m_nCount; public: CMissionCleanup(); void Init(); - CMissionCleanupEntity* FindFree(); + cleanup_entity_struct* FindFree(); void AddEntityToList(int32, uint8); void RemoveEntityFromList(int32, uint8); void Process(); From c9a7fd94357f66ff87ab90eb9988f6701fc67de4 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Fri, 1 Jan 2021 12:47:11 +0200 Subject: [PATCH 011/152] small CWorld fixes --- src/core/World.cpp | 68 +++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/core/World.cpp b/src/core/World.cpp index d7694fc4..67992035 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -785,10 +785,10 @@ CWorld::FindObjectsOfTypeInRange(uint32 modelId, const CVector &position, float *nEntitiesFound = 0; const CVector2D vecSectorStartPos(position.x - radius, position.y - radius); const CVector2D vecSectorEndPos(position.x + radius, position.y + radius); - const int32 nStartX = Max(CWorld::GetSectorIndexX(vecSectorStartPos.x), 0); - const int32 nStartY = Max(CWorld::GetSectorIndexY(vecSectorStartPos.y), 0); - const int32 nEndX = Min(CWorld::GetSectorIndexX(vecSectorEndPos.x), NUMSECTORS_X - 1); - const int32 nEndY = Min(CWorld::GetSectorIndexY(vecSectorEndPos.y), NUMSECTORS_Y - 1); + const int32 nStartX = Max(GetSectorIndexX(vecSectorStartPos.x), 0); + const int32 nStartY = Max(GetSectorIndexY(vecSectorStartPos.y), 0); + const int32 nEndX = Min(GetSectorIndexX(vecSectorEndPos.x), NUMSECTORS_X - 1); + const int32 nEndY = Min(GetSectorIndexY(vecSectorEndPos.y), NUMSECTORS_Y - 1); for(int32 y = nStartY; y <= nEndY; y++) { for(int32 x = nStartX; x <= nEndX; x++) { CSector *pSector = GetSector(x, y); @@ -1056,10 +1056,10 @@ CWorld::FindObjectsKindaColliding(const CVector &position, float radius, bool bC *nCollidingEntities = 0; const CVector2D vecSectorStartPos(position.x - radius, position.y - radius); const CVector2D vecSectorEndPos(position.x + radius, position.y + radius); - const int32 nStartX = Max(CWorld::GetSectorIndexX(vecSectorStartPos.x), 0); - const int32 nStartY = Max(CWorld::GetSectorIndexY(vecSectorStartPos.y), 0); - const int32 nEndX = Min(CWorld::GetSectorIndexX(vecSectorEndPos.x), NUMSECTORS_X - 1); - const int32 nEndY = Min(CWorld::GetSectorIndexY(vecSectorEndPos.y), NUMSECTORS_Y - 1); + const int32 nStartX = Max(GetSectorIndexX(vecSectorStartPos.x), 0); + const int32 nStartY = Max(GetSectorIndexY(vecSectorStartPos.y), 0); + const int32 nEndX = Min(GetSectorIndexX(vecSectorEndPos.x), NUMSECTORS_X - 1); + const int32 nEndY = Min(GetSectorIndexY(vecSectorEndPos.y), NUMSECTORS_Y - 1); for(int32 y = nStartY; y <= nEndY; y++) { for(int32 x = nStartX; x <= nEndX; x++) { CSector *pSector = GetSector(x, y); @@ -1135,10 +1135,10 @@ CWorld::FindObjectsIntersectingCube(const CVector &vecStartPos, const CVector &v { AdvanceCurrentScanCode(); *nIntersecting = 0; - const int32 nStartX = Max(CWorld::GetSectorIndexX(vecStartPos.x), 0); - const int32 nStartY = Max(CWorld::GetSectorIndexY(vecStartPos.y), 0); - const int32 nEndX = Min(CWorld::GetSectorIndexX(vecEndPos.x), NUMSECTORS_X - 1); - const int32 nEndY = Min(CWorld::GetSectorIndexY(vecEndPos.y), NUMSECTORS_Y - 1); + const int32 nStartX = Max(GetSectorIndexX(vecStartPos.x), 0); + const int32 nStartY = Max(GetSectorIndexY(vecStartPos.y), 0); + const int32 nEndX = Min(GetSectorIndexX(vecEndPos.x), NUMSECTORS_X - 1); + const int32 nEndY = Min(GetSectorIndexY(vecEndPos.y), NUMSECTORS_Y - 1); for(int32 y = nStartY; y <= nEndY; y++) { for(int32 x = nStartX; x <= nEndX; x++) { CSector *pSector = GetSector(x, y); @@ -1216,10 +1216,10 @@ CWorld::FindObjectsIntersectingAngledCollisionBox(const CColBox &boundingBox, co { AdvanceCurrentScanCode(); *nEntitiesFound = 0; - const int32 nStartX = Max(CWorld::GetSectorIndexX(fStartX), 0); - const int32 nStartY = Max(CWorld::GetSectorIndexY(fStartY), 0); - const int32 nEndX = Min(CWorld::GetSectorIndexX(fEndX), NUMSECTORS_X - 1); - const int32 nEndY = Min(CWorld::GetSectorIndexY(fEndY), NUMSECTORS_Y - 1); + const int32 nStartX = Max(GetSectorIndexX(fStartX), 0); + const int32 nStartY = Max(GetSectorIndexY(fStartY), 0); + const int32 nEndX = Min(GetSectorIndexX(fEndX), NUMSECTORS_X - 1); + const int32 nEndY = Min(GetSectorIndexY(fEndY), NUMSECTORS_Y - 1); for(int32 y = nStartY; y <= nEndY; y++) { for(int32 x = nStartX; x <= nEndX; x++) { CSector *pSector = GetSector(x, y); @@ -1296,10 +1296,10 @@ CWorld::FindMissionEntitiesIntersectingCube(const CVector &vecStartPos, const CV { AdvanceCurrentScanCode(); *nIntersecting = 0; - const int32 nStartX = Max(CWorld::GetSectorIndexX(vecStartPos.x), 0); - const int32 nStartY = Max(CWorld::GetSectorIndexY(vecStartPos.y), 0); - const int32 nEndX = Min(CWorld::GetSectorIndexX(vecEndPos.x), NUMSECTORS_X - 1); - const int32 nEndY = Min(CWorld::GetSectorIndexY(vecEndPos.y), NUMSECTORS_Y - 1); + const int32 nStartX = Max(GetSectorIndexX(vecStartPos.x), 0); + const int32 nStartY = Max(GetSectorIndexY(vecStartPos.y), 0); + const int32 nEndX = Min(GetSectorIndexX(vecEndPos.x), NUMSECTORS_X - 1); + const int32 nEndY = Min(GetSectorIndexY(vecEndPos.y), NUMSECTORS_Y - 1); for(int32 y = nStartY; y <= nEndY; y++) { for(int32 x = nStartX; x <= nEndX; x++) { CSector *pSector = GetSector(x, y); @@ -1414,10 +1414,10 @@ CWorld::CallOffChaseForArea(float x1, float y1, float x2, float y2) float fStartY = y1 - 10.0f; float fEndX = x2 + 10.0f; float fEndY = y2 + 10.0f; - const int32 nStartX = Max(CWorld::GetSectorIndexX(fStartX), 0); - const int32 nStartY = Max(CWorld::GetSectorIndexY(fStartY), 0); - const int32 nEndX = Min(CWorld::GetSectorIndexX(fEndX), NUMSECTORS_X - 1); - const int32 nEndY = Min(CWorld::GetSectorIndexY(fEndY), NUMSECTORS_Y - 1); + const int32 nStartX = Max(GetSectorIndexX(fStartX), 0); + const int32 nStartY = Max(GetSectorIndexY(fStartY), 0); + const int32 nEndX = Min(GetSectorIndexX(fEndX), NUMSECTORS_X - 1); + const int32 nEndY = Min(GetSectorIndexY(fEndY), NUMSECTORS_Y - 1); for(int32 y = nStartY; y <= nEndY; y++) { for(int32 x = nStartX; x <= nEndX; x++) { CSector *pSector = GetSector(x, y); @@ -1854,9 +1854,9 @@ CWorld::Process(void) if(csObj->m_rwObject && RwObjectGetType(csObj->m_rwObject) == rpCLUMP && RpAnimBlendClumpGetFirstAssociation(csObj->GetClump())) { RpAnimBlendClumpUpdateAnimations(csObj->GetClump(), - 0.02f * (csObj->IsObject() - ? CTimer::GetTimeStepNonClipped() - : CTimer::GetTimeStep())); + csObj->IsObject() + ? CTimer::GetTimeStepNonClippedInSeconds() + : CTimer::GetTimeStepInSeconds()); } csObj->ProcessControl(); csObj->ProcessCollision(); @@ -1876,9 +1876,9 @@ CWorld::Process(void) #endif RpAnimBlendClumpGetFirstAssociation(movingEnt->GetClump())) { RpAnimBlendClumpUpdateAnimations(movingEnt->GetClump(), - 0.02f * (movingEnt->IsObject() - ? CTimer::GetTimeStepNonClipped() - : CTimer::GetTimeStep())); + movingEnt->IsObject() + ? CTimer::GetTimeStepNonClippedInSeconds() + : CTimer::GetTimeStepInSeconds()); } } for(CPtrNode *node = ms_listMovingEntityPtrs.first; node; node = node->next) { @@ -2020,10 +2020,10 @@ CWorld::TriggerExplosion(const CVector &position, float fRadius, float fPower, C { CVector2D vecStartPos(position.x - fRadius, position.y - fRadius); CVector2D vecEndPos(position.x + fRadius, position.y + fRadius); - const int32 nStartX = Max(CWorld::GetSectorIndexX(vecStartPos.x), 0); - const int32 nStartY = Max(CWorld::GetSectorIndexY(vecStartPos.y), 0); - const int32 nEndX = Min(CWorld::GetSectorIndexX(vecEndPos.x), NUMSECTORS_X - 1); - const int32 nEndY = Min(CWorld::GetSectorIndexY(vecEndPos.y), NUMSECTORS_Y - 1); + const int32 nStartX = Max(GetSectorIndexX(vecStartPos.x), 0); + const int32 nStartY = Max(GetSectorIndexY(vecStartPos.y), 0); + const int32 nEndX = Min(GetSectorIndexX(vecEndPos.x), NUMSECTORS_X - 1); + const int32 nEndY = Min(GetSectorIndexY(vecEndPos.y), NUMSECTORS_Y - 1); for(int32 y = nStartY; y <= nEndY; y++) { for(int32 x = nStartX; x <= nEndX; x++) { CSector *pSector = GetSector(x, y); From b3581bc0b4eb40cefe9261dae7a7ae70c16322d5 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Fri, 1 Jan 2021 16:43:26 +0100 Subject: [PATCH 012/152] Overhaul and enable cache for openal build --- src/audio/sampman_oal.cpp | 30 +++++++++++++++++------------- src/core/config.h | 4 +--- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/audio/sampman_oal.cpp b/src/audio/sampman_oal.cpp index eec5ca5f..7d6f429d 100644 --- a/src/audio/sampman_oal.cpp +++ b/src/audio/sampman_oal.cpp @@ -956,33 +956,37 @@ cSampleManager::Initialise(void) #ifdef AUDIO_CACHE FILE *cacheFile = fcaseopen("audio\\sound.cache", "rb"); if (cacheFile) { + debug("Loadind audio cache (If game crashes around here, then your cache is corrupted, remove audio/sound.cache)\n"); fread(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile); fclose(cacheFile); } else -#endif { - - for ( int32 i = 0; i < TOTAL_STREAMED_SOUNDS; i++ ) - { + debug("Cannot load audio cache\n"); +#endif + + for(int32 i = 0; i < TOTAL_STREAMED_SOUNDS; i++) { aStream[0] = new CStream(StreamedNameTable[i], ALStreamSources[0], ALStreamBuffers[0]); - - if ( aStream[0] && aStream[0]->IsOpened() ) - { + + if(aStream[0] && aStream[0]->IsOpened()) { uint32 tatalms = aStream[0]->GetLengthMS(); delete aStream[0]; aStream[0] = NULL; - + nStreamLength[i] = tatalms; - } - else + } else USERERROR("Can't open '%s'\n", StreamedNameTable[i]); } #ifdef AUDIO_CACHE cacheFile = fcaseopen("audio\\sound.cache", "wb"); - fwrite(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile); - fclose(cacheFile); -#endif + if(cacheFile) { + debug("Saving audio cache\n"); + fwrite(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile); + fclose(cacheFile); + } else { + debug("Cannot save audio cache\n"); + } } +#endif { if ( !InitialiseSampleBanks() ) diff --git a/src/core/config.h b/src/core/config.h index a9bb1a17..9f4ccd1f 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -349,9 +349,7 @@ enum Config { // Audio #define RADIO_SCROLL_TO_PREV_STATION -#ifndef AUDIO_OAL // is not working yet for openal -#define AUDIO_CACHE // cache sound lengths to speed up the cold boot -#endif +#define AUDIO_CACHE //#define PS2_AUDIO // changes audio paths for cutscenes and radio to PS2 paths, needs vbdec to support VB with MSS // IMG From d3b11c2b8cc6668d1e92f4575318e91e6c49302c Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Fri, 1 Jan 2021 20:53:25 +0100 Subject: [PATCH 013/152] Encode files to UTF-8 --- src/extras/ini_parser.hpp | 2 +- src/render/WaterLevel.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/extras/ini_parser.hpp b/src/extras/ini_parser.hpp index 99acf1ee..8e88bc29 100644 --- a/src/extras/ini_parser.hpp +++ b/src/extras/ini_parser.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015 Denilson das Mercês Amorim + * Copyright (c) 2013-2015 Denilson das Mercês Amorim * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/render/WaterLevel.cpp b/src/render/WaterLevel.cpp index a0c7ae31..7aa01f5a 100644 --- a/src/render/WaterLevel.cpp +++ b/src/render/WaterLevel.cpp @@ -37,7 +37,7 @@ bool CWaterLevel::WavesCalculatedThisFrame; RpAtomic *CWaterLevel::ms_pWavyAtomic; RpGeometry *CWaterLevel::apGeomArray[8]; int16 CWaterLevel::nGeomUsed; -//"Custom" Don´t Render Water Toggle +//"Custom" Don't Render Water Toggle bool gbDontRenderWater; //RwTexture *gpWaterTex; @@ -638,7 +638,7 @@ SectorRadius(float fSize) void CWaterLevel::RenderWater() { -//"Custom" Don´t Render Water Toggle +//"Custom" Don't Render Water Toggle #ifndef MASTER if (gbDontRenderWater) return; From 716e322246f8e75b08d1bf50943d84079b6deb8d Mon Sep 17 00:00:00 2001 From: aap Date: Fri, 1 Jan 2021 23:33:25 +0100 Subject: [PATCH 014/152] increase screen droplet splash dist --- src/extras/screendroplets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extras/screendroplets.cpp b/src/extras/screendroplets.cpp index 6ea72f09..ac3a17b2 100644 --- a/src/extras/screendroplets.cpp +++ b/src/extras/screendroplets.cpp @@ -391,7 +391,7 @@ void ScreenDroplets::RegisterSplash(CParticleObject *pobj) { CVector dist = pobj->GetPosition() - ms_prevCamPos; - if(dist.MagnitudeSqr() < 20.0f){ + if(dist.MagnitudeSqr() < 50.0f){ // 20 originally ms_splashDuration = 14; ms_splashObject = pobj; } From c587203ebe3db110b8bf00531794cd195010d93d Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 2 Jan 2021 13:28:10 +0200 Subject: [PATCH 015/152] Pad2 fix --- src/core/Pad.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index 7dc9aba0..ac195fc9 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -1109,14 +1109,11 @@ void CPad::UpdatePads(void) bUpdate = false; if ( bUpdate ) - { GetPad(0)->Update(0); -#ifndef SQUEEZE_PERFORMANCE - GetPad(1)->Update(0); -#endif - } -#if defined(MASTER) && !defined(XINPUT) +#ifndef MASTER + GetPad(1)->Update(0); +#else GetPad(1)->NewState.Clear(); GetPad(1)->OldState.Clear(); #endif From 38bca2332d6e4fc2a5d73f7c5909ab0b2ddc4985 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 2 Jan 2021 13:42:27 +0200 Subject: [PATCH 016/152] Fix arg --- src/core/Pad.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index ac195fc9..fd48ba97 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -1112,7 +1112,7 @@ void CPad::UpdatePads(void) GetPad(0)->Update(0); #ifndef MASTER - GetPad(1)->Update(0); + GetPad(1)->Update(1); #else GetPad(1)->NewState.Clear(); GetPad(1)->OldState.Clear(); From 482ff4562f2ed4806c0e51f96b656a7ad80445c7 Mon Sep 17 00:00:00 2001 From: erorcun Date: Sat, 2 Jan 2021 18:27:11 +0300 Subject: [PATCH 017/152] Vehicle: Automobile: fixes and style things --- src/vehicles/Automobile.cpp | 4 ++++ src/vehicles/HandlingMgr.cpp | 2 +- src/vehicles/Transmission.cpp | 2 +- src/vehicles/Vehicle.cpp | 4 ++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 79d3f6af..e66865da 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -216,6 +216,8 @@ CAutomobile::SetModelIndex(uint32 id) CVector vecDAMAGE_ENGINE_POS_SMALL(-0.1f, -0.1f, 0.0f); CVector vecDAMAGE_ENGINE_POS_BIG(-0.5f, -0.3f, 0.0f); +#pragma optimize("", off) // that's what R* did + void CAutomobile::ProcessControl(void) { @@ -1214,6 +1216,8 @@ CAutomobile::ProcessControl(void) } } +#pragma optimize("", on) + void CAutomobile::Teleport(CVector pos) { diff --git a/src/vehicles/HandlingMgr.cpp b/src/vehicles/HandlingMgr.cpp index 3ac6f057..be8150fb 100644 --- a/src/vehicles/HandlingMgr.cpp +++ b/src/vehicles/HandlingMgr.cpp @@ -143,7 +143,7 @@ cHandlingDataMgr::LoadHandlingData(void) case 11: handling->fTractionBias = strtod(word, nil); break; case 12: handling->Transmission.nNumberOfGears = atoi(word); break; case 13: handling->Transmission.fMaxVelocity = strtod(word, nil); break; - case 14: handling->Transmission.fEngineAcceleration = strtod(word, nil) * 0.4f; break; + case 14: handling->Transmission.fEngineAcceleration = strtod(word, nil) * 0.4; break; case 15: handling->Transmission.nDriveType = word[0]; break; case 16: handling->Transmission.nEngineType = word[0]; break; case 17: handling->fBrakeDeceleration = strtod(word, nil); break; diff --git a/src/vehicles/Transmission.cpp b/src/vehicles/Transmission.cpp index 5287055d..109847a5 100644 --- a/src/vehicles/Transmission.cpp +++ b/src/vehicles/Transmission.cpp @@ -128,7 +128,7 @@ cTransmission::CalculateDriveAcceleration(const float &gasPedal, uint8 &gear, fl else fCheat = 1.0f; float targetVelocity = Gears[gear].fMaxVelocity*speedMul*fCheat; - float accel = fEngineAcceleration*accelMul * (targetVelocity - fVelocity)/Abs(targetVelocity); + float accel = (targetVelocity - fVelocity) * (fEngineAcceleration*accelMul) / Abs(targetVelocity); if(Abs(fVelocity) < Abs(Gears[gear].fMaxVelocity*fCheat)) fAcceleration = gasPedal * accel * CTimer::GetTimeStep(); else diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index ba9348f0..eba9c596 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -531,9 +531,9 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon if(!bBraking){ if(m_fGasPedal < 0.01f){ if(GetModelIndex() == MI_RCBANDIT) - brake = 0.2f * mod_HandlingManager.fWheelFriction / m_fMass; + brake = 0.2f * mod_HandlingManager.fWheelFriction / pHandling->m_fMass; else - brake = mod_HandlingManager.fWheelFriction / m_fMass; + brake = mod_HandlingManager.fWheelFriction / pHandling->m_fMass; #ifdef FIX_BUGS brake *= CTimer::GetTimeStepFix(); #endif From cdb65e9ced68f344df6b586012042550eda5bb39 Mon Sep 17 00:00:00 2001 From: erorcun Date: Sat, 2 Jan 2021 18:30:00 +0300 Subject: [PATCH 018/152] fix fix --- src/vehicles/Vehicle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index eba9c596..b02d1152 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -531,9 +531,9 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon if(!bBraking){ if(m_fGasPedal < 0.01f){ if(GetModelIndex() == MI_RCBANDIT) - brake = 0.2f * mod_HandlingManager.fWheelFriction / pHandling->m_fMass; + brake = 0.2f * mod_HandlingManager.fWheelFriction / pHandling->fMass; else - brake = mod_HandlingManager.fWheelFriction / pHandling->m_fMass; + brake = mod_HandlingManager.fWheelFriction / pHandling->fMass; #ifdef FIX_BUGS brake *= CTimer::GetTimeStepFix(); #endif From 78fed0dfe73fa3abf2e9feebfda35256fe38d930 Mon Sep 17 00:00:00 2001 From: aap Date: Sat, 2 Jan 2021 20:15:01 +0100 Subject: [PATCH 019/152] "clarification" of handling code --- src/vehicles/HandlingMgr.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/vehicles/HandlingMgr.cpp b/src/vehicles/HandlingMgr.cpp index be8150fb..7b60acf2 100644 --- a/src/vehicles/HandlingMgr.cpp +++ b/src/vehicles/HandlingMgr.cpp @@ -202,15 +202,21 @@ cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling) handling->fInvMass = 1.0f/handling->fMass; handling->fBuoyancy = 100.0f/handling->nPercentSubmerged * GRAVITY*handling->fMass; - // What the hell is going on here? - specificVolume = handling->Dimension.x*handling->Dimension.z*0.5f / handling->fMass; // ? + // Don't quite understand this. What seems to be going on is that + // we calculate a drag (air resistance) deceleration for a given velocity and + // find the intersection between that and the max engine acceleration. + // at that point the car cannot accelerate any further and we've found the max velocity. a = 0.0f; b = 100.0f; velocity = handling->Transmission.fMaxVelocity; while(a < b && velocity > 0.0f){ velocity -= 0.01f; + // what's the 1/6? a = handling->Transmission.fEngineAcceleration/6.0f; - b = -velocity * (1.0f/(specificVolume * sq(velocity) + 1.0f) - 1.0f); + // no density or drag coefficient here... + float a_drag = 0.5f*SQR(velocity) * handling->Dimension.x*handling->Dimension.z / handling->fMass; + // can't make sense of this... maybe v - v/(drag + 1) ? but that doesn't make so much sense either + b = -velocity * (1.0f/(a_drag + 1.0f) - 1.0f); } if(handling->nIdentifier == HANDLING_RCBANDIT){ From 0d05be4e31a40d7ed84f5f0d59b7aee7cd40dfaf Mon Sep 17 00:00:00 2001 From: aap Date: Sat, 2 Jan 2021 20:30:12 +0100 Subject: [PATCH 020/152] slightly better variable name --- src/control/Script.cpp | 4 ++-- src/peds/PedAI.cpp | 6 +++--- src/vehicles/HandlingMgr.cpp | 4 ++-- src/vehicles/Transmission.h | 2 +- src/vehicles/Vehicle.cpp | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 9856a8aa..63f1f2e1 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -3582,9 +3582,9 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) car->AutoPilot.m_nCruiseSpeed = *(float*)&ScriptParams[1]; if (missionRetryScriptIndex == 40 && car->GetModelIndex() == MI_CHEETAH) // Turismo car->AutoPilot.m_nCruiseSpeed = 8 * car->AutoPilot.m_nCruiseSpeed / 10; - car->AutoPilot.m_nCruiseSpeed = Min(car->AutoPilot.m_nCruiseSpeed, 60.0f * car->pHandling->Transmission.fUnkMaxVelocity); + car->AutoPilot.m_nCruiseSpeed = Min(car->AutoPilot.m_nCruiseSpeed, 60.0f * car->pHandling->Transmission.fMaxCruiseVelocity); #else - car->AutoPilot.m_nCruiseSpeed = Min(*(float*)&ScriptParams[1], 60.0f * car->pHandling->Transmission.fUnkMaxVelocity); + car->AutoPilot.m_nCruiseSpeed = Min(*(float*)&ScriptParams[1], 60.0f * car->pHandling->Transmission.fMaxCruiseVelocity); #endif return 0; } diff --git a/src/peds/PedAI.cpp b/src/peds/PedAI.cpp index a747c684..cc27992c 100644 --- a/src/peds/PedAI.cpp +++ b/src/peds/PedAI.cpp @@ -832,10 +832,10 @@ CPed::ProcessObjective(void) m_pMyVehicle->SetStatus(STATUS_PHYSICS); m_pMyVehicle->AutoPilot.m_nPrevRouteNode = 0; if (m_nPedType == PEDTYPE_COP) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = (FindPlayerPed()->m_pWanted->m_nWantedLevel * 0.1f + 0.6f) * (GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity); + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = (FindPlayerPed()->m_pWanted->m_nWantedLevel * 0.1f + 0.6f) * (GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fMaxCruiseVelocity); m_pMyVehicle->AutoPilot.m_nCarMission = CCarAI::FindPoliceCarMissionForWantedLevel(); } else { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity * 0.8f; + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fMaxCruiseVelocity * 0.8f; m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; } m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; @@ -4775,7 +4775,7 @@ CPed::RegisterThreatWithGangPeds(CEntity *attacker) if (nearVehDriver && nearVehDriver != this && nearVehDriver->m_nPedType == m_nPedType) { if (nearVeh->IsVehicleNormal() && nearVeh->IsCar()) { - nearVeh->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * nearVeh->pHandling->Transmission.fUnkMaxVelocity * 0.8f; + nearVeh->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * nearVeh->pHandling->Transmission.fMaxCruiseVelocity * 0.8f; nearVeh->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; nearVeh->SetStatus(STATUS_PHYSICS); nearVeh->AutoPilot.m_nTempAction = TEMPACT_NONE; diff --git a/src/vehicles/HandlingMgr.cpp b/src/vehicles/HandlingMgr.cpp index 7b60acf2..fde280e8 100644 --- a/src/vehicles/HandlingMgr.cpp +++ b/src/vehicles/HandlingMgr.cpp @@ -220,9 +220,9 @@ cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling) } if(handling->nIdentifier == HANDLING_RCBANDIT){ - handling->Transmission.fUnkMaxVelocity = handling->Transmission.fMaxVelocity; + handling->Transmission.fMaxCruiseVelocity = handling->Transmission.fMaxVelocity; }else{ - handling->Transmission.fUnkMaxVelocity = velocity; + handling->Transmission.fMaxCruiseVelocity = velocity; handling->Transmission.fMaxVelocity = velocity * 1.2f; } handling->Transmission.fMaxReverseVelocity = -0.2f; diff --git a/src/vehicles/Transmission.h b/src/vehicles/Transmission.h index 8eeef1e8..a3d15513 100644 --- a/src/vehicles/Transmission.h +++ b/src/vehicles/Transmission.h @@ -18,7 +18,7 @@ public: uint8 Flags; float fEngineAcceleration; float fMaxVelocity; - float fUnkMaxVelocity; + float fMaxCruiseVelocity; float fMaxReverseVelocity; float fCurVelocity; diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index b02d1152..465d9a9e 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -659,7 +659,7 @@ CVehicle::InflictDamage(CEntity* damagedBy, eWeaponType weaponType, float damage if (m_randomSeed < DAMAGE_FLEE_IN_CAR_PROBABILITY_VALUE) { CCarCtrl::SwitchVehicleToRealPhysics(this); AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; - AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * pHandling->Transmission.fUnkMaxVelocity; + AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * pHandling->Transmission.fMaxCruiseVelocity; SetStatus(STATUS_PHYSICS); } } From 941e70a70111beeb108fadb2af48db19c41e24eb Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 3 Jan 2021 16:44:21 +0200 Subject: [PATCH 021/152] Sync miami things --- src/audio/AudioManager.cpp | 9 ++++++--- src/audio/AudioManager.h | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index 868f1b65..e1b5be1d 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -17,12 +17,15 @@ const int channels = ARRAY_SIZE(cAudioManager::m_asActiveSamples); const int policeChannel = channels + 1; const int allChannels = channels + 2; +#define SPEED_OF_SOUND 343.f +#define TIME_SPENT 50 + cAudioManager::cAudioManager() { m_bIsInitialised = false; - field_1 = 1; - m_fSpeedOfSound = 6.86f; - m_nTimeSpent = 50; + m_bReverb = true; + m_fSpeedOfSound = SPEED_OF_SOUND / TIME_SPENT; + m_nTimeSpent = TIME_SPENT; m_nActiveSamples = NUM_SOUNDS_SAMPLES_SLOTS; m_nActiveSampleQueue = 1; ClearRequestedQueue(); diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h index 9fe2f4ef..2f86ee98 100644 --- a/src/audio/AudioManager.h +++ b/src/audio/AudioManager.h @@ -185,7 +185,7 @@ class cAudioManager { public: bool m_bIsInitialised; - uint8 field_1; // unused + bool m_bReverb; // unused bool m_bFifthFrameFlag; uint8 m_nActiveSamples; uint8 field_4; // unused From 28ec412369b3f27c4e11d4ddc33c38c862686259 Mon Sep 17 00:00:00 2001 From: erorcun Date: Sun, 3 Jan 2021 18:29:09 +0300 Subject: [PATCH 022/152] Ped: PlayerPed: sync with master --- src/peds/PedAI.cpp | 3 ++- src/peds/PedFight.cpp | 32 ++++++++++++++------------------ src/peds/PlayerPed.cpp | 19 ++++++++++--------- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/peds/PedAI.cpp b/src/peds/PedAI.cpp index cc27992c..43592d80 100644 --- a/src/peds/PedAI.cpp +++ b/src/peds/PedAI.cpp @@ -2037,7 +2037,8 @@ CPed::SelectGunIfArmed(void) for (int i = 0; i < m_maxWeaponTypeAllowed; i++) { if (GetWeapon(i).m_nAmmoTotal > 0) { eWeaponType weaponType = GetWeapon(i).m_eWeaponType; - if (weaponType >= WEAPONTYPE_COLT45 && weaponType != WEAPONTYPE_M16 && weaponType <= WEAPONTYPE_FLAMETHROWER) { + if (weaponType == WEAPONTYPE_BASEBALLBAT || weaponType == WEAPONTYPE_COLT45 || weaponType == WEAPONTYPE_UZI || weaponType == WEAPONTYPE_SHOTGUN || + weaponType == WEAPONTYPE_M16 || weaponType == WEAPONTYPE_SNIPERRIFLE || weaponType == WEAPONTYPE_ROCKETLAUNCHER) { SetCurrentWeapon(i); return true; } diff --git a/src/peds/PedFight.cpp b/src/peds/PedFight.cpp index ca720479..b57f1943 100644 --- a/src/peds/PedFight.cpp +++ b/src/peds/PedFight.cpp @@ -522,9 +522,7 @@ CPed::Attack(void) CAnimBlendAssociation *weaponAnimAssoc; int32 weaponAnim; float animStart; - eWeaponType ourWeaponType; float weaponAnimTime; - eWeaponFire ourWeaponFire; float animLoopEnd; CWeaponInfo *ourWeapon; bool attackShouldContinue; @@ -533,9 +531,7 @@ CPed::Attack(void) float delayBetweenAnimAndFire; CVector firePos; - ourWeaponType = GetWeapon()->m_eWeaponType; - ourWeapon = CWeaponInfo::GetWeaponInfo(ourWeaponType); - ourWeaponFire = ourWeapon->m_eWeaponFire; + ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_AnimToPlay); attackShouldContinue = bIsAttacking; reloadAnimAssoc = nil; @@ -576,8 +572,8 @@ CPed::Attack(void) if (!weaponAnimAssoc) { if (attackShouldContinue) { - if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !IsPlayer() || ((CPlayerPed*)this)->m_bHaveTargetSelected) { - if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) { + if (ourWeapon->m_eWeaponFire != WEAPON_FIRE_PROJECTILE || !IsPlayer() || ((CPlayerPed*)this)->m_bHaveTargetSelected) { + if (!CGame::nastyGame || ourWeapon->m_eWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) { weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); } else { @@ -617,12 +613,12 @@ CPed::Attack(void) } else { firePos = ourWeapon->m_vecFireOffset; - if (ourWeaponType == WEAPONTYPE_BASEBALLBAT) { + if (GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT) { if (weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) firePos.z = 0.7f * ourWeapon->m_fRadius - 1.0f; firePos = GetMatrix() * firePos; - } else if (ourWeaponType != WEAPONTYPE_UNARMED) { + } else if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) { TransformToNode(firePos, weaponAnimAssoc->animId == ANIM_KICK_FLOOR ? PED_FOOTR : PED_HANDR); } else { firePos = GetMatrix() * firePos; @@ -630,10 +626,10 @@ CPed::Attack(void) GetWeapon()->Fire(this, &firePos); - if (ourWeaponType == WEAPONTYPE_MOLOTOV || ourWeaponType == WEAPONTYPE_GRENADE) { + if (GetWeapon()->m_eWeaponType == WEAPONTYPE_MOLOTOV || GetWeapon()->m_eWeaponType == WEAPONTYPE_GRENADE) { RemoveWeaponModel(ourWeapon->m_nModelId); } - if (!GetWeapon()->m_nAmmoTotal && ourWeaponFire != WEAPON_FIRE_MELEE && FindPlayerPed() != this) { + if (!GetWeapon()->m_nAmmoTotal && ourWeapon->m_eWeaponFire != WEAPON_FIRE_MELEE && FindPlayerPed() != this) { SelectGunIfArmed(); } @@ -666,7 +662,7 @@ CPed::Attack(void) attackShouldContinue = false; } - if (ourWeaponType == WEAPONTYPE_SHOTGUN) { + if (GetWeapon()->m_eWeaponType == WEAPONTYPE_SHOTGUN) { weaponAnimTime = weaponAnimAssoc->currentTime; firePos = ourWeapon->m_vecFireOffset; @@ -692,7 +688,7 @@ CPed::Attack(void) if (IsPlayer()) { if (CPad::GetPad(0)->GetSprint()) { // animBreakout is a member of WeaponInfo in VC, so it's me that added the below line. - float animBreakOut = ((ourWeaponType == WEAPONTYPE_FLAMETHROWER || ourWeaponType == WEAPONTYPE_UZI || ourWeaponType == WEAPONTYPE_SHOTGUN) ? 25 / 30.0f : 99 / 30.0f); + float animBreakOut = ((GetWeapon()->m_eWeaponType == WEAPONTYPE_FLAMETHROWER || GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI || GetWeapon()->m_eWeaponType == WEAPONTYPE_SHOTGUN) ? 25 / 30.0f : 99 / 30.0f); if (!attackShouldContinue && weaponAnimAssoc->currentTime > animBreakOut) { weaponAnimAssoc->blendDelta = -4.0f; FinishedAttackCB(nil, this); @@ -702,20 +698,20 @@ CPed::Attack(void) } #endif animLoopEnd = ourWeapon->m_fAnimLoopEnd; - if (ourWeaponFire == WEAPON_FIRE_MELEE && weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) + if (ourWeapon->m_eWeaponFire == WEAPON_FIRE_MELEE && weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) animLoopEnd = 3.4f/6.0f; weaponAnimTime = weaponAnimAssoc->currentTime; // Anim loop end, either start the loop again or finish the attack - if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) { + if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeapon->m_eWeaponFire != WEAPON_FIRE_PROJECTILE) { if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd && (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_shootTimer) && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { weaponAnim = weaponAnimAssoc->animId; - if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) { + if (ourWeapon->m_eWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) { if (weaponAnim != ourWeapon->m_Anim2ToPlay || weaponAnim == ANIM_RBLOCK_CSHOOT) { weaponAnimAssoc->Start(ourWeapon->m_fAnimLoopStart); } else { @@ -738,7 +734,7 @@ CPed::Attack(void) // Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading) if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) { - switch (ourWeaponType) { + switch (GetWeapon()->m_eWeaponType) { case WEAPONTYPE_UZI: DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f); break; @@ -754,7 +750,7 @@ CPed::Attack(void) } // Fun fact: removing this part leds to reloading flamethrower - if (ourWeaponType == WEAPONTYPE_FLAMETHROWER && weaponAnimAssoc->IsRunning()) { + if (GetWeapon()->m_eWeaponType == WEAPONTYPE_FLAMETHROWER && weaponAnimAssoc->IsRunning()) { weaponAnimAssoc->flags |= ASSOC_DELETEFADEDOUT; weaponAnimAssoc->flags &= ~ASSOC_RUNNING; weaponAnimAssoc->blendDelta = -4.0f; diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp index 1b5e007a..b104f14c 100644 --- a/src/peds/PlayerPed.cpp +++ b/src/peds/PlayerPed.cpp @@ -628,20 +628,21 @@ CPlayerPed::ProcessWeaponSwitch(CPad *padUsed) } } } + // Out of ammo, switch to another weapon } else if (CWeaponInfo::GetWeaponInfo((eWeaponType)m_currentWeapon)->m_eWeaponFire != WEAPON_FIRE_MELEE) { if (GetWeapon(m_currentWeapon).m_nAmmoTotal <= 0) { - if (TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON - && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER - && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER) { + if (TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON + || TheCamera.PlayerWeaponMode.Mode == CCam::MODE_SNIPER + || TheCamera.PlayerWeaponMode.Mode == CCam::MODE_ROCKETLAUNCHER) + return; - for (m_nSelectedWepSlot = m_currentWeapon - 1; m_nSelectedWepSlot >= 0; --m_nSelectedWepSlot) { - if (m_nSelectedWepSlot == WEAPONTYPE_BASEBALLBAT && HasWeapon(WEAPONTYPE_BASEBALLBAT) - || GetWeapon(m_nSelectedWepSlot).m_nAmmoTotal > 0 && m_nSelectedWepSlot != WEAPONTYPE_MOLOTOV && m_nSelectedWepSlot != WEAPONTYPE_GRENADE) { - goto switchDetectDone; - } + for (m_nSelectedWepSlot = m_currentWeapon - 1; m_nSelectedWepSlot >= 0; --m_nSelectedWepSlot) { + if (m_nSelectedWepSlot == WEAPONTYPE_BASEBALLBAT && HasWeapon(WEAPONTYPE_BASEBALLBAT) + || GetWeapon(m_nSelectedWepSlot).m_nAmmoTotal > 0 && m_nSelectedWepSlot != WEAPONTYPE_MOLOTOV && m_nSelectedWepSlot != WEAPONTYPE_GRENADE) { + goto switchDetectDone; } - m_nSelectedWepSlot = WEAPONTYPE_UNARMED; } + m_nSelectedWepSlot = WEAPONTYPE_UNARMED; } } From ee05c7fe427f473e1f5cf5e6a728bbaf4fc9218a Mon Sep 17 00:00:00 2001 From: erorcun Date: Sun, 3 Jan 2021 18:30:50 +0300 Subject: [PATCH 023/152] Frontend: disable windowed mode selector in game --- src/core/Frontend.cpp | 7 +++++++ src/core/Frontend.h | 4 +++- src/core/MenuScreensCustom.cpp | 14 +++++++------- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 4c963a13..2a87c7ad 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -1564,6 +1564,7 @@ CMenuManager::Draw() CMenuScreenCustom::CMenuEntry &option = aScreens[m_nCurrScreen].m_aEntries[i]; if (option.m_Action == MENUACTION_CFO_SELECT) { + isOptionDisabled = option.m_CFOSelect->disableIfGameLoaded && !m_bGameNotLoaded; if (option.m_CFOSelect->onlyApplyOnEnter){ if (m_nCurrOption != i) { if (option.m_CFOSelect->displayedValue != option.m_CFOSelect->lastSavedValue) @@ -5081,6 +5082,9 @@ CMenuManager::ProcessButtonPresses(void) case MENUACTION_CFO_DYNAMIC: CMenuScreenCustom::CMenuEntry &option = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption]; if (option.m_Action == MENUACTION_CFO_SELECT) { + if (option.m_CFOSelect->disableIfGameLoaded && !m_bGameNotLoaded) + break; + if (!option.m_CFOSelect->onlyApplyOnEnter) { option.m_CFOSelect->displayedValue++; if (option.m_CFOSelect->displayedValue >= option.m_CFOSelect->numRightTexts || option.m_CFOSelect->displayedValue < 0) @@ -5307,6 +5311,9 @@ CMenuManager::ProcessButtonPresses(void) case MENUACTION_CFO_DYNAMIC: CMenuScreenCustom::CMenuEntry &option = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption]; if (option.m_Action == MENUACTION_CFO_SELECT) { + if (option.m_CFOSelect->disableIfGameLoaded && !m_bGameNotLoaded) + break; + if (changeValueBy > 0) { option.m_CFOSelect->displayedValue++; if (option.m_CFOSelect->displayedValue >= option.m_CFOSelect->numRightTexts) diff --git a/src/core/Frontend.h b/src/core/Frontend.h index 8cf3dd28..36647899 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -505,9 +505,10 @@ struct CCFOSelect : CCFO int8 displayedValue; // only if onlyApplyOnEnter enabled for now int8 lastSavedValue; // only if onlyApplyOnEnter enabled ChangeFunc changeFunc; + bool disableIfGameLoaded; CCFOSelect() {}; - CCFOSelect(int8* value, const char* save, const char** rightTexts, int8 numRightTexts, bool onlyApplyOnEnter, ChangeFunc changeFunc){ + CCFOSelect(int8* value, const char* save, const char** rightTexts, int8 numRightTexts, bool onlyApplyOnEnter, ChangeFunc changeFunc = nil, bool disableIfGameLoaded = false){ this->value = value; if (value) this->lastSavedValue = this->displayedValue = *value; @@ -517,6 +518,7 @@ struct CCFOSelect : CCFO this->numRightTexts = numRightTexts; this->onlyApplyOnEnter = onlyApplyOnEnter; this->changeFunc = changeFunc; + this->disableIfGameLoaded = disableIfGameLoaded; } }; diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp index 9a763f8c..4303e4b6 100644 --- a/src/core/MenuScreensCustom.cpp +++ b/src/core/MenuScreensCustom.cpp @@ -24,7 +24,7 @@ #ifdef CUSTOM_FRONTEND_OPTIONS #ifdef IMPROVED_VIDEOMODE - #define VIDEOMODE_SELECTOR MENUACTION_CFO_SELECT, "FEM_SCF", { new CCFOSelect((int8*)&FrontEndMenuManager.m_nPrefsWindowed, nil, screenModes, 2, true, ScreenModeAfterChange) }, + #define VIDEOMODE_SELECTOR MENUACTION_CFO_SELECT, "FEM_SCF", { new CCFOSelect((int8*)&FrontEndMenuManager.m_nPrefsWindowed, nil, screenModes, 2, true, ScreenModeAfterChange, true) }, #else #define VIDEOMODE_SELECTOR #endif @@ -36,19 +36,19 @@ #endif #ifdef CUTSCENE_BORDERS_SWITCH - #define CUTSCENE_BORDERS_TOGGLE MENUACTION_CFO_SELECT, "FEM_CSB", { new CCFOSelect((int8 *)&CMenuManager::m_PrefsCutsceneBorders, "CutsceneBorders", off_on, 2, false, nil) }, + #define CUTSCENE_BORDERS_TOGGLE MENUACTION_CFO_SELECT, "FEM_CSB", { new CCFOSelect((int8 *)&CMenuManager::m_PrefsCutsceneBorders, "CutsceneBorders", off_on, 2, false) }, #else #define CUTSCENE_BORDERS_TOGGLE #endif #ifdef FREE_CAM - #define FREE_CAM_TOGGLE MENUACTION_CFO_SELECT, "FEC_FRC", { new CCFOSelect((int8*)&TheCamera.bFreeCam, "FreeCam", off_on, 2, false, nil) }, + #define FREE_CAM_TOGGLE MENUACTION_CFO_SELECT, "FEC_FRC", { new CCFOSelect((int8*)&TheCamera.bFreeCam, "FreeCam", off_on, 2, false) }, #else #define FREE_CAM_TOGGLE #endif #ifdef PS2_ALPHA_TEST - #define DUALPASS_SELECTOR MENUACTION_CFO_SELECT, "FEM_2PR", { new CCFOSelect((int8*)&gPS2alphaTest, "PS2AlphaTest", off_on, 2, false, nil) }, + #define DUALPASS_SELECTOR MENUACTION_CFO_SELECT, "FEM_2PR", { new CCFOSelect((int8*)&gPS2alphaTest, "PS2AlphaTest", off_on, 2, false) }, #else #define DUALPASS_SELECTOR #endif @@ -61,14 +61,14 @@ #ifdef EXTENDED_COLOURFILTER #define POSTFX_SELECTORS \ - MENUACTION_CFO_SELECT, "FED_CLF", { new CCFOSelect((int8*)&CPostFX::EffectSwitch, "ColourFilter", filterNames, ARRAY_SIZE(filterNames), false, nil) }, \ - MENUACTION_CFO_SELECT, "FED_MBL", { new CCFOSelect((int8*)&CPostFX::MotionBlurOn, "MotionBlur", off_on, 2, false, nil) }, + MENUACTION_CFO_SELECT, "FED_CLF", { new CCFOSelect((int8*)&CPostFX::EffectSwitch, "ColourFilter", filterNames, ARRAY_SIZE(filterNames), false) }, \ + MENUACTION_CFO_SELECT, "FED_MBL", { new CCFOSelect((int8*)&CPostFX::MotionBlurOn, "MotionBlur", off_on, 2, false) }, #else #define POSTFX_SELECTORS #endif #ifdef INVERT_LOOK_FOR_PAD - #define INVERT_PAD_SELECTOR MENUACTION_CFO_SELECT, "FEC_IVP", { new CCFOSelect((int8*)&CPad::bInvertLook4Pad, "InvertPad", off_on, 2, false, nil) }, + #define INVERT_PAD_SELECTOR MENUACTION_CFO_SELECT, "FEC_IVP", { new CCFOSelect((int8*)&CPad::bInvertLook4Pad, "InvertPad", off_on, 2, false) }, #else #define INVERT_PAD_SELECTOR #endif From 213a8eb905166ceb1bed067ac4deddd1f31fd3b4 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sun, 3 Jan 2021 18:59:03 +0300 Subject: [PATCH 024/152] fixed intro text line defaults --- src/control/Script.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/control/Script.h b/src/control/Script.h index 588c1f41..8cf6bb42 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -1,5 +1,6 @@ #pragma once #include "common.h" +#include "Font.h" #include "Ped.h" #include "PedType.h" #include "Text.h" @@ -99,7 +100,7 @@ struct intro_text_line m_sBackgroundColor = CRGBA(128, 128, 128, 128); m_bTextProportional = true; m_bTextBeforeFade = false; - m_nFont = 2; /* enum? */ + m_nFont = FONT_HEADING; m_fAtX = 0.0f; m_fAtY = 0.0f; memset(&m_Text, 0, sizeof(m_Text)); From bbbfe658704c5245df6daa1b7418003dc9169916 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Sun, 3 Jan 2021 00:12:01 +0100 Subject: [PATCH 025/152] Port nerf of rain particles from miami --- src/core/config.h | 1 + src/render/Weather.cpp | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/core/config.h b/src/core/config.h index 9f4ccd1f..8b18ffef 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -361,6 +361,7 @@ 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 + #define VC_RAIN_NERF // Reduces number of rain particles #endif #ifdef LIBRW diff --git a/src/render/Weather.cpp b/src/render/Weather.cpp index bf3e51b4..771f85de 100644 --- a/src/render/Weather.cpp +++ b/src/render/Weather.cpp @@ -202,6 +202,7 @@ void CWeather::Update(void) } // Rain +#ifndef VC_RAIN_NERF float fNewRain; if (NewWeatherType == WEATHER_RAINY) { // if raining for >1 hour, values: 0, 0.33, 0.66, 0.99, switching every ~16.5s @@ -223,6 +224,25 @@ void CWeather::Update(void) else Rain = Max(fNewRain, Rain - RAIN_CHANGE_SPEED * CTimer::GetTimeStep()); } +#else + float fNewRain; + if (NewWeatherType == WEATHER_RAINY) { + // if raining for >1 hour, values: 0, 0.33, switching every ~16.5s + fNewRain = (((uint16)CTimer::GetTimeInMilliseconds() >> 14) & 1) * 0.33f; + if (OldWeatherType != WEATHER_RAINY) { + if (InterpolationValue < 0.4f) + // if rain has just started (<24 minutes), always 0.5 + fNewRain = 0.5f; + else + // if rain is ongoing for >24 minutes, values: 0.25, 0.5, switching every ~16.5s + fNewRain = 0.25f + (((uint16)CTimer::GetTimeInMilliseconds() >> 14) & 1) * 0.25f; + } + fNewRain = Max(fNewRain, 0.5f); + } + else + fNewRain = 0.0f; + Rain = fNewRain; +#endif // Clouds if (OldWeatherType != WEATHER_SUNNY) From 2860f6e4a91804862890200560deb50e6bff6e06 Mon Sep 17 00:00:00 2001 From: erorcun Date: Mon, 4 Jan 2021 16:03:54 +0300 Subject: [PATCH 026/152] cfo fix --- src/core/re3.cpp | 1 - src/extras/frontendoption.cpp | 3 ++- src/extras/frontendoption.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 87244e2a..97c6c181 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -219,7 +219,6 @@ void LoadINISettings() void SaveINISettings() { bool changed = false; - char temp[4]; #ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS if (strncmp(cfg.get("DetectJoystick", "JoystickName", "").c_str(), gSelectedJoystickName, strlen(gSelectedJoystickName)) != 0) { diff --git a/src/extras/frontendoption.cpp b/src/extras/frontendoption.cpp index a3c4b9e3..a966de97 100644 --- a/src/extras/frontendoption.cpp +++ b/src/extras/frontendoption.cpp @@ -123,7 +123,7 @@ void FrontendOptionAddBuiltinAction(const char* gxtKey, int action, int targetMe option.m_TargetMenu = targetMenu; } -void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveName) +void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveName, bool disableIfGameLoaded) { int8 screenOptionOrder = RegisterNewOption(); @@ -142,6 +142,7 @@ void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 n option.m_CFOSelect->save = saveName; option.m_CFOSelect->onlyApplyOnEnter = onlyApplyOnEnter; option.m_CFOSelect->changeFunc = changeFunc; + option.m_CFOSelect->disableIfGameLoaded = disableIfGameLoaded; } void FrontendOptionAddDynamic(const char* gxtKey, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, const char* saveName) diff --git a/src/extras/frontendoption.h b/src/extras/frontendoption.h index 19340b20..dbd1a300 100644 --- a/src/extras/frontendoption.h +++ b/src/extras/frontendoption.h @@ -84,7 +84,7 @@ void FrontendOptionSetCursor(int screen, int8 option, bool overwrite = false); // 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 char* gxtKey, int action, int targetMenu = MENUPAGE_NONE, int saveSlot = SAVESLOT_NONE); -void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveName = nil); +void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveName = nil, bool disableIfGameLoaded = false); void FrontendOptionAddDynamic(const char* gxtKey, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, const char* saveName = nil); 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); From 3b1400eaed86f2a89f85f6d9802505a0e2e88985 Mon Sep 17 00:00:00 2001 From: erorcun Date: Mon, 4 Jan 2021 16:28:30 +0300 Subject: [PATCH 027/152] Fixes from miami Entity/Physical proof-read 1 --- src/entities/Entity.cpp | 8 ++------ src/entities/Physical.cpp | 24 +++++++++++++++--------- src/fakerw/fake.cpp | 2 +- src/fakerw/rwplcore.h | 4 ++-- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index db004af3..4ef9e8e6 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -228,12 +228,8 @@ CEntity::GetBoundRadius(void) void CEntity::UpdateRwFrame(void) { - if(m_rwObject){ - if(RwObjectGetType(m_rwObject) == rpATOMIC) - RwFrameUpdateObjects(RpAtomicGetFrame((RpAtomic*)m_rwObject)); - else if(RwObjectGetType(m_rwObject) == rpCLUMP) - RwFrameUpdateObjects(RpClumpGetFrame((RpClump*)m_rwObject)); - } + if(m_rwObject) + RwFrameUpdateObjects(rwObjectGetParent(m_rwObject)); } #ifdef PED_SKIN diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index 4fc53039..0bd87dbc 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -303,14 +303,15 @@ CPhysical::GetHasCollidedWith(CEntity *ent) void CPhysical::RemoveRefsToEntity(CEntity *ent) { - int i, j; + int i = 0, j; - for(i = 0; i < m_nCollisionRecords; i++){ + while(i < m_nCollisionRecords) { if(m_aCollisionRecords[i] == ent){ for(j = i; j < m_nCollisionRecords-1; j++) m_aCollisionRecords[j] = m_aCollisionRecords[j+1]; m_nCollisionRecords--; - } + } else + i++; } } @@ -518,13 +519,12 @@ CPhysical::ApplyAirResistance(void) m_vecMoveSpeed *= f; m_vecTurnSpeed *= f; }else{ - float f = Pow(1.0f/(m_fAirResistance*0.5f*m_vecMoveSpeed.MagnitudeSqr() + 1.0f), CTimer::GetTimeStep()); + float f = Pow(1.0f/Abs(m_fAirResistance*0.5f*m_vecMoveSpeed.MagnitudeSqr() + 1.0f), CTimer::GetTimeStep()); m_vecMoveSpeed *= f; m_vecTurnSpeed *= 0.99f; } } - bool CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, float &impulseB) { @@ -888,7 +888,11 @@ CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint) impulseB = (speedSum - fOtherSpeedB) * B->m_fMass; impulseLimit = adhesiveLimit*CTimer::GetTimeStep(); if(impulseA < -impulseLimit) impulseA = -impulseLimit; - if(impulseB > impulseLimit) impulseB = impulseLimit; // BUG: game has A's clamp again here, but this can't be right +#ifdef FIX_BUGS + if(impulseB > impulseLimit) impulseB = impulseLimit; +#else + if(impulseA < -impulseLimit) impulseA = -impulseLimit; // duplicate +#endif A->ApplyFrictionMoveForce(frictionDir*impulseA); B->ApplyFrictionMoveForce(frictionDir*impulseB); return true; @@ -1020,7 +1024,7 @@ CPhysical::ApplyFriction(float adhesiveLimit, CColPoint &colpoint) if(fOtherSpeed > 0.0f){ frictionDir = vOtherSpeed * (1.0f/fOtherSpeed); fImpulse = -fOtherSpeed * m_fMass; - impulseLimit = adhesiveLimit*CTimer::GetTimeStep() * 1.5f; + impulseLimit = adhesiveLimit*CTimer::GetTimeStep() * 1.5; if(fImpulse < -impulseLimit) fImpulse = -impulseLimit; ApplyFrictionMoveForce(frictionDir*fImpulse); ApplyFrictionTurnForce(frictionDir*fImpulse, pointpos); @@ -1111,7 +1115,8 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists) skipShift = true; Aobj->m_pCollidingEntity = B; } - } + } else + skipShift = true; }else if(B->IsObject() && A->IsVehicle()){ CObject *Bobj = (CObject*)B; if(Bobj->ObjectCreatedBy != TEMP_OBJECT && @@ -1126,7 +1131,8 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists) if(size.z < A->GetPosition().z || (Invert(A->GetMatrix(), inv) * size).z < 0.0f) skipShift = true; - } + } else + skipShift = true; }else if(IsBodyPart(A->GetModelIndex()) && B->IsPed()) skipShift = true; else if(A->IsPed() && IsBodyPart(B->GetModelIndex())) diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp index a3b9258b..6585032b 100644 --- a/src/fakerw/fake.cpp +++ b/src/fakerw/fake.cpp @@ -14,7 +14,7 @@ using namespace rw; RwUInt8 RwObjectGetType(const RwObject *obj) { return obj->type; } - +RwFrame* rwObjectGetParent(const RwObject *obj) { return (RwFrame*)obj->parent; } void *RwMalloc(size_t size) { return engine->memfuncs.rwmalloc(size, 0); } void *RwCalloc(size_t numObj, size_t sizeObj) { diff --git a/src/fakerw/rwplcore.h b/src/fakerw/rwplcore.h index 511f7678..69c921cc 100644 --- a/src/fakerw/rwplcore.h +++ b/src/fakerw/rwplcore.h @@ -108,12 +108,12 @@ enum RwCorePluginID //struct RwObject; typedef rw::Object RwObject; +typedef rw::Frame RwFrame; typedef RwObject *(*RwObjectCallBack)(RwObject *object, void *data); RwUInt8 RwObjectGetType(const RwObject *obj); - - +RwFrame* rwObjectGetParent(const RwObject *obj); #define rwsprintf sprintf #define rwvsprintf vsprintf From c2ff1713648384867944e476e97c5be72da71f69 Mon Sep 17 00:00:00 2001 From: Samilop Iter <37327589+Cimmerian-Iter@users.noreply.github.com> Date: Mon, 4 Jan 2021 18:04:50 +0100 Subject: [PATCH 028/152] Update FileLoader.cpp --- src/core/FileLoader.cpp | 93 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index 926512b9..48afa1d9 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -557,7 +557,6 @@ char *DoubleSidedNames[] = { "overpass_comse", "newdockbuilding", "newdockbuilding2", - "newdockbuilding", "policeballhall", "fuzballdoor", "ind_land106", @@ -581,7 +580,97 @@ char *DoubleSidedNames[] = { "railtrax_2b", "railtrax_straightss", "railtrax_bentr", - "" + "ind_land125", + "salvstrans", + "bridge_liftsec", + "subsign1", + "carparkfence", + "newairportwall4", + "apair_terminal", + "Helipad", + "bar_barrier10", + "damissionfence", + "sub_floodlite", + "suburbbridge1", + "damfencing", + "demfence08", + "damfence07", + "damfence06", + "damfence05", + "damfence04", + "damfence03", + "damfence02", + "damfence01", + "Dam_pod2", + "Dam_pod1", + "columansion_wall", + "wrckdhse020", + "wrckdhse01", + "arc_bridge", + "gRD_overpass19kbc", + "gRD_overpass19bkb", + "gRD_overpass19kb", + "gRD_overpass18kb", + "road_under", + "com_roadkb23", + "com_roadkb22", + "nbbridgerda", + "nbbridgerdb", + "policetenkb1", + "block3_scraper2", + "Clnm_cthdrlfcde", + "broadwaybuild", + "combillboard03", + "com_park3b", + "com_docksaa", + "newdockbuilding2", + "com_roadkb22", + "sidebarrier_gaz2", + "tunnelsupport1", + "skyscrpunbuilt2", + "cons_buid02", + "rail_platformw", + "railtrax_bent1", + "nrailstepswest", + "building_fucked", + "franksclb02", + "salvsdetail", + "crgoshp01", + "shp_wlkway", + "bar_barriergate1", + "plnt_pylon01", + "fishfctory", + "doc_crane_cab", + "nrailsteps", + "iten_club01", + "mak_Watertank", + "basketballcourt" + "carlift01", + "carlift02", + "iten_chinatown4", + "iten_details7", + "ind_customroad002" + "ind_brgrd1way", + "ind_customroad060", + "ind_customroad002", + "ind_land108", + "ind_customroad004", + "ind_customroad003", + "nbbridgcabls01", + "sbwy_tunl_bit", + "sbwy_tunl_bend", + "sbwy_tunl_cstm11", + "sbwy_tunl_cstm10", + "sbwy_tunl_cstm9", + "sbwy_tunl_cstm8", + "sbwy_tunl_cstm7", + "sbwy_tunl_cstm6", + "sbwy_tunl_cstm5", + "sbwy_tunl_cstm4", + "sbwy_tunl_cstm3", + "sbwy_tunl_cstm2", + "sbwy_tunl_cstm1", + }; char *TreeNames[] = { "coast_treepatch", From 8d782a1027073890c28d0f25fc3edb023adc93bc Mon Sep 17 00:00:00 2001 From: Samilop Iter <37327589+Cimmerian-Iter@users.noreply.github.com> Date: Mon, 4 Jan 2021 18:07:39 +0100 Subject: [PATCH 029/152] Update FileLoader.cpp --- src/core/FileLoader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index 48afa1d9..d847f473 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -670,6 +670,7 @@ char *DoubleSidedNames[] = { "sbwy_tunl_cstm3", "sbwy_tunl_cstm2", "sbwy_tunl_cstm1", + "" }; char *TreeNames[] = { From 047f9c49ece49897d43c4bd71f73a8f13080786b Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 4 Jan 2021 22:27:51 +0200 Subject: [PATCH 030/152] Fix CEntity::UpdateRwFrame --- src/entities/Entity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index 4ef9e8e6..91b417d0 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -229,7 +229,7 @@ void CEntity::UpdateRwFrame(void) { if(m_rwObject) - RwFrameUpdateObjects(rwObjectGetParent(m_rwObject)); + RwFrameUpdateObjects((RwFrame*)rwObjectGetParent(m_rwObject)); } #ifdef PED_SKIN From 150f5302b735331780815194fb7d397a477fcb19 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 4 Jan 2021 22:46:50 +0200 Subject: [PATCH 031/152] Handle stereo panning in OAL manually for streams --- src/audio/oal/stream.cpp | 223 +++++++++++++++++++++++++++++--------- src/audio/oal/stream.h | 10 +- src/audio/sampman_oal.cpp | 21 +++- 3 files changed, 189 insertions(+), 65 deletions(-) diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index 90e90dd8..f36985e5 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -19,6 +19,64 @@ #include "crossplatform.h" #endif +/* +As we ran onto an issue of having different volume levels for mono streams +and stereo streams we are now handling all the stereo panning ourselves. +Each stream now has two sources - one panned to the left and one to the right, +and uses two separate buffers to store data for each individual channel. +For that we also have to reshuffle all decoded PCM stereo data from LRLRLRLR to +LLLLRRRR (handled by CSortStereoBuffer). +*/ + +class CSortStereoBuffer +{ + uint16* PcmBuf; + size_t BufSize; +public: + CSortStereoBuffer() : PcmBuf(nil), BufSize(0) {} + ~CSortStereoBuffer() + { + if (PcmBuf) + free(PcmBuf); + } + + uint16* GetBuffer(size_t size) + { + if (size == 0) return nil; + if (!PcmBuf) + { + BufSize = size; + PcmBuf = (uint16*)malloc(BufSize); + } + else if (BufSize < size) + { + BufSize = size; + PcmBuf = (uint16*)realloc(PcmBuf, size); + } + return PcmBuf; + } + + void SortStereo(void* buf, size_t size) + { + uint16* InBuf = (uint16*)buf; + uint16* OutBuf = GetBuffer(size); + + if (!OutBuf) return; + + size_t rightStart = size / 4; + for (size_t i = 0; i < size / 4; i++) + { + OutBuf[i] = InBuf[i*2]; + OutBuf[i+rightStart] = InBuf[i*2+1]; + } + + memcpy(InBuf, OutBuf, size); + } + +}; + +CSortStereoBuffer SortStereoBuffer; + #ifndef AUDIO_OPUS class CSndFile : public IDecoder { @@ -81,7 +139,11 @@ public: uint32 Decode(void *buffer) { if ( !IsOpened() ) return 0; - return sf_read_short(m_pfSound, (short *)buffer, GetBufferSamples()) * GetSampleSize(); + + size_t size = sf_read_short(m_pfSound, (short*)buffer, GetBufferSamples()) * GetSampleSize(); + if (GetChannels()==2) + SortStereoBuffer.SortStereo(buffer, size); + return size; } }; @@ -101,6 +163,8 @@ public: m_pMH = mpg123_new(nil, nil); if ( m_pMH ) { + mpg123_param(m_pMH, MPG123_FLAGS, MPG123_FUZZY | MPG123_SEEKBUFFER | MPG123_GAPLESS, 0.0); + long rate = 0; int channels = 0; int encoding = 0; @@ -176,6 +240,8 @@ public: assert("We can't handle audio files more then 2 GB yet :shrug:" && (size < UINT32_MAX)); #endif if (err != MPG123_OK && err != MPG123_DONE) return 0; + if (GetChannels() == 2) + SortStereoBuffer.SortStereo(buffer, size); return (uint32)size; } }; @@ -267,6 +333,9 @@ public: if (size < 0) return 0; + if (GetChannels() == 2) + SortStereoBuffer.SortStereo(buffer, size * m_nChannels * GetSampleSize()); + return size * m_nChannels * GetSampleSize(); } }; @@ -286,8 +355,8 @@ void CStream::Terminate() #endif } -CStream::CStream(char *filename, ALuint &source, ALuint (&buffers)[NUM_STREAMBUFFERS]) : - m_alSource(source), +CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS]) : + m_pAlSources(sources), m_alBuffers(buffers), m_pBuffer(nil), m_bPaused(false), @@ -368,7 +437,7 @@ void CStream::Delete() bool CStream::HasSource() { - return m_alSource != AL_NONE; + return (m_pAlSources[0] != AL_NONE) && (m_pAlSources[1] != AL_NONE); } bool CStream::IsOpened() @@ -382,9 +451,10 @@ bool CStream::IsPlaying() if ( !m_bPaused ) { - ALint sourceState; - alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState); - if ( m_bActive || sourceState == AL_PLAYING ) + ALint sourceState[2]; + alGetSourcei(m_pAlSources[0], AL_SOURCE_STATE, &sourceState[0]); + alGetSourcei(m_pAlSources[1], AL_SOURCE_STATE, &sourceState[1]); + if ( m_bActive || sourceState[0] == AL_PLAYING || sourceState[1] == AL_PLAYING) return true; } @@ -395,9 +465,12 @@ void CStream::Pause() { if ( !HasSource() ) return; ALint sourceState = AL_PAUSED; - alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState); + alGetSourcei(m_pAlSources[0], AL_SOURCE_STATE, &sourceState); if (sourceState != AL_PAUSED ) - alSourcePause(m_alSource); + alSourcePause(m_pAlSources[0]); + alGetSourcei(m_pAlSources[1], AL_SOURCE_STATE, &sourceState); + if (sourceState != AL_PAUSED) + alSourcePause(m_pAlSources[1]); } void CStream::SetPause(bool bPause) @@ -419,19 +492,21 @@ void CStream::SetPause(bool bPause) void CStream::SetPitch(float pitch) { if ( !HasSource() ) return; - alSourcef(m_alSource, AL_PITCH, pitch); + alSourcef(m_pAlSources[0], AL_PITCH, pitch); + alSourcef(m_pAlSources[1], AL_PITCH, pitch); } void CStream::SetGain(float gain) { if ( !HasSource() ) return; - alSourcef(m_alSource, AL_GAIN, gain); + alSourcef(m_pAlSources[0], AL_GAIN, gain); + alSourcef(m_pAlSources[1], AL_GAIN, gain); } -void CStream::SetPosition(float x, float y, float z) +void CStream::SetPosition(int i, float x, float y, float z) { if ( !HasSource() ) return; - alSource3f(m_alSource, AL_POSITION, x, y, z); + alSource3f(m_pAlSources[i], AL_POSITION, x, y, z); } void CStream::SetVolume(uint32 nVol) @@ -442,8 +517,13 @@ void CStream::SetVolume(uint32 nVol) void CStream::SetPan(uint8 nPan) { + m_nPan = clamp((int8)nPan - 63, 0, 63); + SetPosition(0, (m_nPan - 63) / 64.0f, 0.0f, Sqrt(1.0f - SQR((m_nPan - 63) / 64.0f))); + + m_nPan = clamp((int8)nPan + 64, 64, 127); + SetPosition(1, (m_nPan - 63) / 64.0f, 0.0f, Sqrt(1.0f - SQR((m_nPan - 63) / 64.0f))); + m_nPan = nPan; - SetPosition((nPan - 63)/64.0f, 0.0f, Sqrt(1.0f-SQR((nPan-63)/64.0f))); } void CStream::SetPosMS(uint32 nPos) @@ -460,10 +540,10 @@ uint32 CStream::GetPosMS() ALint offset; //alGetSourcei(m_alSource, AL_SAMPLE_OFFSET, &offset); - alGetSourcei(m_alSource, AL_BYTE_OFFSET, &offset); + alGetSourcei(m_pAlSources[0], AL_BYTE_OFFSET, &offset); return m_pSoundFile->Tell() - - m_pSoundFile->samples2ms(m_pSoundFile->GetBufferSamples() * (NUM_STREAMBUFFERS-1)) / m_pSoundFile->GetChannels() + - m_pSoundFile->samples2ms(m_pSoundFile->GetBufferSamples() * (NUM_STREAMBUFFERS/2-1)) / m_pSoundFile->GetChannels() + m_pSoundFile->samples2ms(offset/m_pSoundFile->GetSampleSize()) / m_pSoundFile->GetChannels(); } @@ -473,33 +553,41 @@ uint32 CStream::GetLengthMS() return m_pSoundFile->GetLength(); } -bool CStream::FillBuffer(ALuint alBuffer) +bool CStream::FillBuffer(ALuint *alBuffer) { if ( !HasSource() ) return false; if ( !IsOpened() ) return false; - if ( !(alBuffer != AL_NONE && alIsBuffer(alBuffer)) ) + if ( !(alBuffer[0] != AL_NONE && alIsBuffer(alBuffer[0])) ) + return false; + if ( !(alBuffer[1] != AL_NONE && alIsBuffer(alBuffer[1])) ) return false; uint32 size = m_pSoundFile->Decode(m_pBuffer); if( size == 0 ) return false; + + uint32 channelSize = size / m_pSoundFile->GetChannels(); - alBufferData(alBuffer, m_pSoundFile->GetChannels() == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, - m_pBuffer, size, m_pSoundFile->GetSampleRate()); - + alBufferData(alBuffer[0], AL_FORMAT_MONO16, m_pBuffer, channelSize, m_pSoundFile->GetSampleRate()); + // TODO: use just one buffer if we play mono + if (m_pSoundFile->GetChannels() == 1) + alBufferData(alBuffer[1], AL_FORMAT_MONO16, m_pBuffer, channelSize, m_pSoundFile->GetSampleRate()); + else + alBufferData(alBuffer[1], AL_FORMAT_MONO16, (uint8*)m_pBuffer + channelSize, channelSize, m_pSoundFile->GetSampleRate()); return true; } int32 CStream::FillBuffers() { int32 i = 0; - for ( i = 0; i < NUM_STREAMBUFFERS; i++ ) + for ( i = 0; i < NUM_STREAMBUFFERS/2; i++ ) { - if ( !FillBuffer(m_alBuffers[i]) ) + if ( !FillBuffer(&m_alBuffers[i*2]) ) break; - alSourceQueueBuffers(m_alSource, 1, &m_alBuffers[i]); + alSourceQueueBuffers(m_pAlSources[0], 1, &m_alBuffers[i*2]); + alSourceQueueBuffers(m_pAlSources[1], 1, &m_alBuffers[i*2+1]); } return i; @@ -508,13 +596,16 @@ int32 CStream::FillBuffers() void CStream::ClearBuffers() { if ( !HasSource() ) return; - - ALint buffersQueued; - alGetSourcei(m_alSource, AL_BUFFERS_QUEUED, &buffersQueued); + + ALint buffersQueued[2]; + alGetSourcei(m_pAlSources[0], AL_BUFFERS_QUEUED, &buffersQueued[0]); + alGetSourcei(m_pAlSources[1], AL_BUFFERS_QUEUED, &buffersQueued[1]); ALuint value; - while (buffersQueued--) - alSourceUnqueueBuffers(m_alSource, 1, &value); + while (buffersQueued[0]--) + alSourceUnqueueBuffers(m_pAlSources[0], 1, &value); + while (buffersQueued[1]--) + alSourceUnqueueBuffers(m_pAlSources[1], 1, &value); } bool CStream::Setup() @@ -522,7 +613,6 @@ bool CStream::Setup() if ( IsOpened() ) { m_pSoundFile->Seek(0); - alSourcei(m_alSource, AL_SOURCE_RELATIVE, AL_TRUE); //SetPosition(0.0f, 0.0f, 0.0f); SetPitch(1.0f); //SetPan(m_nPan); @@ -538,17 +628,29 @@ void CStream::SetPlay(bool state) if ( state ) { ALint sourceState = AL_PLAYING; - alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState); + alGetSourcei(m_pAlSources[0], AL_SOURCE_STATE, &sourceState); if (sourceState != AL_PLAYING ) - alSourcePlay(m_alSource); + alSourcePlay(m_pAlSources[0]); + + sourceState = AL_PLAYING; + alGetSourcei(m_pAlSources[1], AL_SOURCE_STATE, &sourceState); + if (sourceState != AL_PLAYING) + alSourcePlay(m_pAlSources[1]); + m_bActive = true; } else { ALint sourceState = AL_STOPPED; - alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState); - if (sourceState != AL_STOPPED ) - alSourceStop(m_alSource); + alGetSourcei(m_pAlSources[0], AL_SOURCE_STATE, &sourceState); + if (sourceState != AL_STOPPED) + alSourceStop(m_pAlSources[0]); + + sourceState = AL_STOPPED; + alGetSourcei(m_pAlSources[1], AL_SOURCE_STATE, &sourceState); + if (sourceState != AL_STOPPED) + alSourceStop(m_pAlSources[1]); + m_bActive = false; } } @@ -579,35 +681,48 @@ void CStream::Update() if ( !m_bPaused ) { - ALint sourceState; - ALint buffersProcessed = 0; + ALint sourceState[2]; + ALint buffersProcessed[2] = { 0, 0 }; - alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState); - alGetSourcei(m_alSource, AL_BUFFERS_PROCESSED, &buffersProcessed); + // Relying a lot on left buffer states in here + + //alSourcef(m_pAlSources[0], AL_ROLLOFF_FACTOR, 0.0f); + alGetSourcei(m_pAlSources[0], AL_SOURCE_STATE, &sourceState[0]); + alGetSourcei(m_pAlSources[0], AL_BUFFERS_PROCESSED, &buffersProcessed[0]); + //alSourcef(m_pAlSources[1], AL_ROLLOFF_FACTOR, 0.0f); + alGetSourcei(m_pAlSources[1], AL_SOURCE_STATE, &sourceState[1]); + alGetSourcei(m_pAlSources[1], AL_BUFFERS_PROCESSED, &buffersProcessed[1]); ALint looping = AL_FALSE; - alGetSourcei(m_alSource, AL_LOOPING, &looping); + alGetSourcei(m_pAlSources[0], AL_LOOPING, &looping); if ( looping == AL_TRUE ) { TRACE("stream set looping"); - alSourcei(m_alSource, AL_LOOPING, AL_TRUE); + alSourcei(m_pAlSources[0], AL_LOOPING, AL_TRUE); + alSourcei(m_pAlSources[1], AL_LOOPING, AL_TRUE); + } + + assert(buffersProcessed[0] == buffersProcessed[1]); + + while( buffersProcessed[0]-- ) + { + ALuint buffer[2]; + + alSourceUnqueueBuffers(m_pAlSources[0], 1, &buffer[0]); + alSourceUnqueueBuffers(m_pAlSources[1], 1, &buffer[1]); + + if (m_bActive && FillBuffer(buffer)) + { + alSourceQueueBuffers(m_pAlSources[0], 1, &buffer[0]); + alSourceQueueBuffers(m_pAlSources[1], 1, &buffer[1]); + } } - while( buffersProcessed-- ) + if ( sourceState[0] != AL_PLAYING ) { - ALuint buffer; - - alSourceUnqueueBuffers(m_alSource, 1, &buffer); - - if ( m_bActive && FillBuffer(buffer) ) - alSourceQueueBuffers(m_alSource, 1, &buffer); - } - - if ( sourceState != AL_PLAYING ) - { - alGetSourcei(m_alSource, AL_BUFFERS_PROCESSED, &buffersProcessed); - SetPlay(buffersProcessed!=0); + alGetSourcei(m_pAlSources[0], AL_BUFFERS_PROCESSED, &buffersProcessed[0]); + SetPlay(buffersProcessed[0]!=0); } } } diff --git a/src/audio/oal/stream.h b/src/audio/oal/stream.h index 2476abcc..326ce6a1 100644 --- a/src/audio/oal/stream.h +++ b/src/audio/oal/stream.h @@ -3,7 +3,7 @@ #ifdef AUDIO_OAL #include -#define NUM_STREAMBUFFERS 4 +#define NUM_STREAMBUFFERS 8 class IDecoder { @@ -57,7 +57,7 @@ public: class CStream { char m_aFilename[128]; - ALuint &m_alSource; + ALuint *m_pAlSources; ALuint (&m_alBuffers)[NUM_STREAMBUFFERS]; bool m_bPaused; @@ -73,20 +73,20 @@ class CStream IDecoder *m_pSoundFile; bool HasSource(); - void SetPosition(float x, float y, float z); + void SetPosition(int i, float x, float y, float z); void SetPitch(float pitch); void SetGain(float gain); void Pause(); void SetPlay(bool state); - bool FillBuffer(ALuint alBuffer); + bool FillBuffer(ALuint *alBuffer); int32 FillBuffers(); void ClearBuffers(); public: static void Initialise(); static void Terminate(); - CStream(char *filename, ALuint &source, ALuint (&buffers)[NUM_STREAMBUFFERS]); + CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS]); ~CStream(); void Delete(); diff --git a/src/audio/sampman_oal.cpp b/src/audio/sampman_oal.cpp index 7d6f429d..5579644c 100644 --- a/src/audio/sampman_oal.cpp +++ b/src/audio/sampman_oal.cpp @@ -102,7 +102,7 @@ CChannel aChannel[MAXCHANNELS+MAX2DCHANNELS]; uint8 nChannelVolume[MAXCHANNELS+MAX2DCHANNELS]; uint32 nStreamLength[TOTAL_STREAMED_SOUNDS]; -ALuint ALStreamSources[MAX_STREAMS]; +ALuint ALStreamSources[MAX_STREAMS][2]; ALuint ALStreamBuffers[MAX_STREAMS][NUM_STREAMBUFFERS]; struct tMP3Entry @@ -245,9 +245,9 @@ release_existing() if (stream) stream->ProviderTerm(); - alDeleteSources(1, &ALStreamSources[i]); alDeleteBuffers(NUM_STREAMBUFFERS, ALStreamBuffers[i]); } + alDeleteSources(MAX_STREAMS*2, ALStreamSources[0]); CChannel::DestroyChannels(); @@ -287,7 +287,10 @@ set_new_provider(int index) //TODO: _maxSamples = MAXCHANNELS; - ALCint attr[] = {ALC_FREQUENCY,MAX_FREQ,0}; + ALCint attr[] = {ALC_FREQUENCY,MAX_FREQ, + ALC_MONO_SOURCES, MAX_STREAMS * 2 + MAXCHANNELS, + 0, + }; ALDevice = alcOpenDevice(providers[index].id); ASSERT(ALDevice != NULL); @@ -319,11 +322,17 @@ set_new_provider(int index) alGenAuxiliaryEffectSlots(1, &ALEffectSlot); alGenEffects(1, &ALEffect); } - + + alGenSources(MAX_STREAMS*2, ALStreamSources[0]); for ( int32 i = 0; i < MAX_STREAMS; i++ ) { - alGenSources(1, &ALStreamSources[i]); - alGenBuffers(NUM_STREAMBUFFERS, ALStreamBuffers[i]); + alGenBuffers(NUM_STREAMBUFFERS, ALStreamBuffers[i]); + alSourcei(ALStreamSources[i][0], AL_SOURCE_RELATIVE, AL_TRUE); + alSource3f(ALStreamSources[i][0], AL_POSITION, 0.0f, 0.0f, 0.0f); + alSourcef(ALStreamSources[i][0], AL_GAIN, 1.0f); + alSourcei(ALStreamSources[i][1], AL_SOURCE_RELATIVE, AL_TRUE); + alSource3f(ALStreamSources[i][1], AL_POSITION, 0.0f, 0.0f, 0.0f); + alSourcef(ALStreamSources[i][1], AL_GAIN, 1.0f); CStream *stream = aStream[i]; if (stream) From 63e9f6d826b950b959ce112fd3be7bf170b76c8c Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 5 Jan 2021 00:32:03 +0200 Subject: [PATCH 032/152] Audio fixes --- src/audio/AudioLogic.cpp | 148 +++++++++++++++++++-------------------- src/audio/oal/stream.cpp | 2 +- 2 files changed, 75 insertions(+), 75 deletions(-) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 94ca67de..6c5d2ad0 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -3038,81 +3038,81 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) switch (sound) { case SOUND_STEP_START: case SOUND_STEP_END: - if (!params.m_pPed->bIsLooking) { - emittingVol = m_anRandomTable[3] % 15 + 45; - if (FindPlayerPed() != m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_pEntity) - emittingVol /= 2; - maxDist = 400.f; - switch (params.m_pPed->m_nSurfaceTouched) { - case SURFACE_GRASS: - sampleIndex = m_anRandomTable[1] % 5 + SFX_FOOTSTEP_GRASS_1; - break; - case SURFACE_GRAVEL: - case SURFACE_MUD_DRY: - sampleIndex = m_anRandomTable[4] % 5 + SFX_FOOTSTEP_GRAVEL_1; - break; - case SURFACE_CAR: - case SURFACE_GARAGE_DOOR: - case SURFACE_CAR_PANEL: - case SURFACE_THICK_METAL_PLATE: - case SURFACE_SCAFFOLD_POLE: - case SURFACE_LAMP_POST: - case SURFACE_FIRE_HYDRANT: - case SURFACE_GIRDER: - case SURFACE_METAL_CHAIN_FENCE: - case SURFACE_CONTAINER: - case SURFACE_NEWS_VENDOR: - sampleIndex = m_anRandomTable[0] % 5 + SFX_FOOTSTEP_METAL_1; - break; - case SURFACE_SAND: - sampleIndex = (m_anRandomTable[4] & 3) + SFX_FOOTSTEP_SAND_1; - break; - case SURFACE_WATER: - sampleIndex = (m_anRandomTable[3] & 3) + SFX_FOOTSTEP_WATER_1; - break; - case SURFACE_WOOD_CRATES: - case SURFACE_WOOD_BENCH: - case SURFACE_WOOD_SOLID: - sampleIndex = m_anRandomTable[2] % 5 + SFX_FOOTSTEP_WOOD_1; - break; - case SURFACE_HEDGE: - sampleIndex = m_anRandomTable[2] % 5 + SFX_COL_VEG_1; - break; - default: - sampleIndex = m_anRandomTable[2] % 5 + SFX_FOOTSTEP_CONCRETE_1; - break; - } - m_sQueueSample.m_nSampleIndex = sampleIndex; - m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] - 28; - m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); - m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 17); - switch (params.m_pPed->m_nMoveState) { - case PEDMOVE_WALK: - emittingVol /= 4; - m_sQueueSample.m_nFrequency = 9 * m_sQueueSample.m_nFrequency / 10; - break; - case PEDMOVE_RUN: - emittingVol /= 2; - m_sQueueSample.m_nFrequency = 11 * m_sQueueSample.m_nFrequency / 10; - break; - case PEDMOVE_SPRINT: - m_sQueueSample.m_nFrequency = 12 * m_sQueueSample.m_nFrequency / 10; - break; - default: - break; - } - m_sQueueSample.m_nReleasingVolumeModificator = 5; - m_sQueueSample.m_fSpeedMultiplier = 0.0f; - m_sQueueSample.m_fSoundIntensity = 20.0f; - m_sQueueSample.m_nLoopCount = 1; - m_sQueueSample.m_nLoopStart = 0; - m_sQueueSample.m_nLoopEnd = -1; - m_sQueueSample.m_nEmittingVolume = emittingVol; - m_sQueueSample.m_bIs2D = false; - m_sQueueSample.m_bReleasingSoundFlag = true; - m_sQueueSample.m_bRequireReflection = true; + if (!params.m_pPed->bIsInTheAir) + continue; + emittingVol = m_anRandomTable[3] % 15 + 45; + if (FindPlayerPed() != m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_pEntity) + emittingVol /= 2; + maxDist = 400.f; + switch (params.m_pPed->m_nSurfaceTouched) { + case SURFACE_GRASS: + sampleIndex = m_anRandomTable[1] % 5 + SFX_FOOTSTEP_GRASS_1; + break; + case SURFACE_GRAVEL: + case SURFACE_MUD_DRY: + sampleIndex = m_anRandomTable[4] % 5 + SFX_FOOTSTEP_GRAVEL_1; + break; + case SURFACE_CAR: + case SURFACE_GARAGE_DOOR: + case SURFACE_CAR_PANEL: + case SURFACE_THICK_METAL_PLATE: + case SURFACE_SCAFFOLD_POLE: + case SURFACE_LAMP_POST: + case SURFACE_FIRE_HYDRANT: + case SURFACE_GIRDER: + case SURFACE_METAL_CHAIN_FENCE: + case SURFACE_CONTAINER: + case SURFACE_NEWS_VENDOR: + sampleIndex = m_anRandomTable[0] % 5 + SFX_FOOTSTEP_METAL_1; + break; + case SURFACE_SAND: + sampleIndex = (m_anRandomTable[4] & 3) + SFX_FOOTSTEP_SAND_1; + break; + case SURFACE_WATER: + sampleIndex = (m_anRandomTable[3] & 3) + SFX_FOOTSTEP_WATER_1; + break; + case SURFACE_WOOD_CRATES: + case SURFACE_WOOD_BENCH: + case SURFACE_WOOD_SOLID: + sampleIndex = m_anRandomTable[2] % 5 + SFX_FOOTSTEP_WOOD_1; + break; + case SURFACE_HEDGE: + sampleIndex = m_anRandomTable[2] % 5 + SFX_COL_VEG_1; + break; + default: + sampleIndex = m_anRandomTable[2] % 5 + SFX_FOOTSTEP_CONCRETE_1; + break; } + m_sQueueSample.m_nSampleIndex = sampleIndex; + m_sQueueSample.m_nBankIndex = SFX_BANK_0; + m_sQueueSample.m_nCounter = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] - SOUND_STEP_START + 1; + m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 17); + switch (params.m_pPed->m_nMoveState) { + case PEDMOVE_WALK: + emittingVol /= 4; + m_sQueueSample.m_nFrequency = 9 * m_sQueueSample.m_nFrequency / 10; + break; + case PEDMOVE_RUN: + emittingVol /= 2; + m_sQueueSample.m_nFrequency = 11 * m_sQueueSample.m_nFrequency / 10; + break; + case PEDMOVE_SPRINT: + m_sQueueSample.m_nFrequency = 12 * m_sQueueSample.m_nFrequency / 10; + break; + default: + break; + } + m_sQueueSample.m_nReleasingVolumeModificator = 5; + m_sQueueSample.m_fSpeedMultiplier = 0.0f; + m_sQueueSample.m_fSoundIntensity = 20.0f; + m_sQueueSample.m_nLoopCount = 1; + m_sQueueSample.m_nLoopStart = 0; + m_sQueueSample.m_nLoopEnd = -1; + m_sQueueSample.m_nEmittingVolume = emittingVol; + m_sQueueSample.m_bIs2D = false; + m_sQueueSample.m_bReleasingSoundFlag = true; + m_sQueueSample.m_bRequireReflection = true; break; case SOUND_FALL_LAND: case SOUND_FALL_COLLAPSE: diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index f36985e5..cf5fe831 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -466,7 +466,7 @@ void CStream::Pause() if ( !HasSource() ) return; ALint sourceState = AL_PAUSED; alGetSourcei(m_pAlSources[0], AL_SOURCE_STATE, &sourceState); - if (sourceState != AL_PAUSED ) + if (sourceState != AL_PAUSED) alSourcePause(m_pAlSources[0]); alGetSourcei(m_pAlSources[1], AL_SOURCE_STATE, &sourceState); if (sourceState != AL_PAUSED) From 042e21115e249f7e62c54e182c4ea59549d34127 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 5 Jan 2021 00:50:51 +0200 Subject: [PATCH 033/152] More audio fix --- src/audio/AudioLogic.cpp | 50 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 6c5d2ad0..976bbaec 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -3038,7 +3038,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) switch (sound) { case SOUND_STEP_START: case SOUND_STEP_END: - if (!params.m_pPed->bIsInTheAir) + if (params.m_pPed->bIsInTheAir) continue; emittingVol = m_anRandomTable[3] % 15 + 45; if (FindPlayerPed() != m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_pEntity) @@ -3116,31 +3116,31 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) break; case SOUND_FALL_LAND: case SOUND_FALL_COLLAPSE: - if (!ped->bIsLooking) { - maxDist = SQR(30); - emittingVol = m_anRandomTable[3] % 20 + 80; - if (ped->m_nSurfaceTouched == SURFACE_WATER) { - m_sQueueSample.m_nSampleIndex = (m_anRandomTable[3] & 3) + SFX_FOOTSTEP_WATER_1; - } else if (sound == SOUND_FALL_LAND) { - m_sQueueSample.m_nSampleIndex = SFX_BODY_LAND; - } else { - m_sQueueSample.m_nSampleIndex = SFX_BODY_LAND_AND_FALL; - } - m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = 1; - m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); - m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 17); - m_sQueueSample.m_nReleasingVolumeModificator = 2; - m_sQueueSample.m_fSpeedMultiplier = 0.0f; - m_sQueueSample.m_fSoundIntensity = 30.0f; - m_sQueueSample.m_nLoopCount = 1; - m_sQueueSample.m_nLoopStart = 0; - m_sQueueSample.m_nLoopEnd = -1; - m_sQueueSample.m_nEmittingVolume = emittingVol; - m_sQueueSample.m_bIs2D = false; - m_sQueueSample.m_bReleasingSoundFlag = true; - m_sQueueSample.m_bRequireReflection = true; + if (ped->bIsInTheAir) + continue; + maxDist = SQR(30); + emittingVol = m_anRandomTable[3] % 20 + 80; + if (ped->m_nSurfaceTouched == SURFACE_WATER) { + m_sQueueSample.m_nSampleIndex = (m_anRandomTable[3] & 3) + SFX_FOOTSTEP_WATER_1; + } else if (sound == SOUND_FALL_LAND) { + m_sQueueSample.m_nSampleIndex = SFX_BODY_LAND; + } else { + m_sQueueSample.m_nSampleIndex = SFX_BODY_LAND_AND_FALL; } + m_sQueueSample.m_nBankIndex = SFX_BANK_0; + m_sQueueSample.m_nCounter = 1; + m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 17); + m_sQueueSample.m_nReleasingVolumeModificator = 2; + m_sQueueSample.m_fSpeedMultiplier = 0.0f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nLoopCount = 1; + m_sQueueSample.m_nLoopStart = 0; + m_sQueueSample.m_nLoopEnd = -1; + m_sQueueSample.m_nEmittingVolume = emittingVol; + m_sQueueSample.m_bIs2D = false; + m_sQueueSample.m_bReleasingSoundFlag = true; + m_sQueueSample.m_bRequireReflection = true; break; case SOUND_FIGHT_PUNCH_33: m_sQueueSample.m_nSampleIndex = SFX_FIGHT_1; From 11de714d9dbeabb59129d29acb9e433c538ba4ba Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Tue, 5 Jan 2021 04:17:18 +0300 Subject: [PATCH 034/152] remake --- gamefiles/TEXT/american.gxt | Bin 220216 -> 220146 bytes src/core/Frontend.cpp | 4 ---- src/core/Frontend.h | 3 --- src/core/MenuScreensCustom.cpp | 17 ----------------- src/core/Radar.cpp | 7 +++++-- src/core/re3.cpp | 12 ++++++++++++ src/render/Draw.cpp | 8 +++++++- src/render/Draw.h | 6 +++++- src/render/Hud.cpp | 9 ++++++--- src/render/Sprite.cpp | 2 +- utils/gxt/american.txt | 6 ------ 11 files changed, 36 insertions(+), 38 deletions(-) diff --git a/gamefiles/TEXT/american.gxt b/gamefiles/TEXT/american.gxt index b8a677e9f30c6469b00ba10b162bfded8167970c..cf4bb1e537a7ed4f0ca43b2455bfbe51dde8435f 100644 GIT binary patch delta 92 zcmdn7gZI;RUe*wA*GQg?tnnI*U7J%iidi;4(cxiZY}owKXffmF1tubllH2YwF}S(< t#)pIlFmRoNu)~6#8Ok=FHBI(lx^}nOsIJ|pj&ZwD9aF{K=^LV%69DHKAp-ya delta 143 zcmeygop;9$Ue*wA*GQF(tnnI*6E>%66ti&Oxy!`h=IR_D?Ci7ox(+WJW83DZMvED_ z%fRBk@d3^Zo7+u985#FXo@*-3ShIPnX|e|s%e`i)x^}5L#_dvdOci&T0~nmA_eV1) qYXma{Fa$ApGK4U=GAJ+vGdMFiGWY=behltFzAuA6g9}iGfdK#^z9 Date: Tue, 5 Jan 2021 11:12:48 +0100 Subject: [PATCH 035/152] first version of new renderer --- src/core/config.h | 1 + src/core/main.cpp | 146 ++++++++- src/core/main.h | 5 + src/core/re3.cpp | 24 ++ src/render/Renderer.cpp | 609 ++++++++++++++++++++++++++++++++++- src/render/Renderer.h | 18 ++ src/render/SpecialFX.cpp | 3 + src/rw/VisibilityPlugins.cpp | 20 ++ src/rw/VisibilityPlugins.h | 3 + src/vehicles/Boat.cpp | 20 ++ src/vehicles/Boat.h | 1 + 11 files changed, 837 insertions(+), 13 deletions(-) diff --git a/src/core/config.h b/src/core/config.h index 8b18ffef..0199697b 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -252,6 +252,7 @@ enum Config { #define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur) #define EXTENDED_PIPELINES // custom render pipelines (includes Neo) #define SCREEN_DROPLETS // neo water droplets +#define NEW_RENDERER // leeds-like world rendering, needs librw #endif #ifndef EXTENDED_COLOURFILTER diff --git a/src/core/main.cpp b/src/core/main.cpp index 6e047b19..0887e129 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -121,6 +121,13 @@ bool gbPrintMemoryUsage; #define FOUND_GAME_TO_LOAD b_FoundRecentSavedGameWantToLoad #endif +#ifdef NEW_RENDERER +bool gbNewRenderer; +#define CLEARMODE (rwCAMERACLEARZ | rwCAMERACLEARSTENCIL) +#else +#define CLEARMODE (rwCAMERACLEARZ) +#endif + void ValidateVersion() { @@ -168,7 +175,7 @@ DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomR CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO); #endif CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &TopColor.rwRGBA, rwCAMERACLEARZ); + RwCameraClear(Scene.camera, &TopColor.rwRGBA, CLEARMODE); if(!RsCameraBeginUpdate(Scene.camera)) return false; @@ -190,7 +197,7 @@ DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO); #endif CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); + RwCameraClear(Scene.camera, &gColourTop, CLEARMODE); if(!RsCameraBeginUpdate(Scene.camera)) return false; @@ -1160,9 +1167,126 @@ DisplayGameDebugText() } #endif +#ifdef NEW_RENDERER +bool gbRenderRoads = true; +bool gbRenderEverythingBarRoads = true; +//bool gbRenderFadingInUnderwaterEntities = true; +bool gbRenderFadingInEntities = true; +bool gbRenderWater = true; +bool gbRenderBoats = true; +bool gbRenderVehicles = true; +bool gbRenderWorld0 = true; +bool gbRenderWorld1 = true; +bool gbRenderWorld2 = true; + +void +MattRenderScene(void) +{ + // this calls CMattRenderer::Render + /// CWorld::AdvanceCurrentScanCode(); + // CMattRenderer::ResetRenderStates + /// CRenderer::ClearForFrame(); // before ConstructRenderList + // CClock::CalcEnvMapTimeMultiplicator +if(gbRenderWater) + CRenderer::RenderWater(); // actually CMattRenderer::RenderWater + // CClock::ms_EnvMapTimeMultiplicator = 1.0f; + // cWorldStream::ClearDynamics + /// CRenderer::ConstructRenderList(); // before PreRender +if(gbRenderWorld0) + CRenderer::RenderWorld(0); // roads + // CMattRenderer::ResetRenderStates + /// CRenderer::PreRender(); // has to be called before BeginUpdate because of cutscene shadows + CCoronas::RenderReflections(); +if(gbRenderWorld1) + CRenderer::RenderWorld(1); // opaque +if(gbRenderRoads) + CRenderer::RenderRoads(); + + CRenderer::RenderPeds(); + +if(gbRenderBoats) + CRenderer::RenderBoats(); +//if(gbRenderFadingInUnderwaterEntities) +// CRenderer::RenderFadingInUnderwaterEntities(); + +if(gbRenderEverythingBarRoads) + CRenderer::RenderEverythingBarRoads(); + // get env map here? + // moved this: + // CRenderer::RenderFadingInEntities(); +} + +void +RenderScene_new(void) +{ + CClouds::Render(); + DoRWRenderHorizon(); + + MattRenderScene(); + DefinedState(); + // CMattRenderer::ResetRenderStates + // moved CRenderer::RenderBoats to before transparent water +} + +// TODO +bool FredIsInFirstPersonCam(void) { return false; } +void +RenderEffects_new(void) +{ + CShadows::RenderStaticShadows(); + // CRenderer::GenerateEnvironmentMap + CShadows::RenderStoredShadows(); + CSkidmarks::Render(); + CRubbish::Render(); + + // these aren't really effects + DefinedState(); + if(FredIsInFirstPersonCam()){ + DefinedState(); + C3dMarkers::Render(); // normally rendered in CSpecialFX::Render() +if(gbRenderWorld2) + CRenderer::RenderWorld(2); // transparent +if(gbRenderVehicles) + CRenderer::RenderVehicles(); + }else{ + // flipped these two, seems to give the best result +if(gbRenderWorld2) + CRenderer::RenderWorld(2); // transparent +if(gbRenderVehicles) + CRenderer::RenderVehicles(); + } + // better render these after transparent world +if(gbRenderFadingInEntities) + CRenderer::RenderFadingInEntities(); + + // actual effects here + CGlass::Render(); + // CMattRenderer::ResetRenderStates + DefinedState(); + CWeather::RenderRainStreaks(); + // CWeather::AddSnow + CWaterCannons::Render(); + CAntennas::Render(); + CSpecialFX::Render(); + CCoronas::Render(); + CParticle::Render(); + CPacManPickups::Render(); + CWeaponEffects::Render(); + CPointLights::RenderFogEffect(); + CMovingThings::Render(); + CRenderer::RenderFirstPersonVehicle(); +} +#endif + void RenderScene(void) { +#ifdef NEW_RENDERER + if(gbNewRenderer){ + RenderScene_new(); + return; + } +#endif CClouds::Render(); DoRWRenderHorizon(); CRenderer::RenderRoads(); @@ -1195,6 +1319,12 @@ RenderDebugShit(void) void RenderEffects(void) { +#ifdef NEW_RENDERER + if(gbNewRenderer){ + RenderEffects_new(); + return; + } +#endif CGlass::Render(); CWaterCannons::Render(); CSpecialFX::Render(); @@ -1390,6 +1520,12 @@ Idle(void *arg) PUSH_MEMID(MEMID_RENDERLIST); tbStartTimer(0, "CnstrRenderList"); +#ifdef NEW_RENDERER + if(gbNewRenderer){ + CWorld::AdvanceCurrentScanCode(); // don't think this is even necessary + CRenderer::ClearForFrame(); + } +#endif CRenderer::ConstructRenderList(); tbEndTimer("CnstrRenderList"); @@ -1457,7 +1593,7 @@ Idle(void *arg) CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, DEFAULT_ASPECT_RATIO); #endif CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); + RwCameraClear(Scene.camera, &gColourTop, CLEARMODE); if(!RsCameraBeginUpdate(Scene.camera)) goto popret; } @@ -1523,7 +1659,7 @@ FrontendIdle(void) CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, DEFAULT_ASPECT_RATIO); #endif CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); + RwCameraClear(Scene.camera, &gColourTop, CLEARMODE); if(!RsCameraBeginUpdate(Scene.camera)) return; @@ -1780,7 +1916,7 @@ void TheGame(void) CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, DEFAULT_ASPECT_RATIO); #endif CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); + RwCameraClear(Scene.camera, &gColourTop, CLEARMODE); RsCameraBeginUpdate(Scene.camera); } diff --git a/src/core/main.h b/src/core/main.h index 149c0878..37a82fb2 100644 --- a/src/core/main.h +++ b/src/core/main.h @@ -48,3 +48,8 @@ void TheModelViewer(void); void LoadINISettings(); void SaveINISettings(); #endif + +#ifdef NEW_RENDERER +extern bool gbNewRenderer; +bool FredIsInFirstPersonCam(void); +#endif diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 97c6c181..6f22e999 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -558,6 +558,30 @@ DebugMenuPopulate(void) DebugMenuAddVarBool8("Render", "Frame limiter", &FrontEndMenuManager.m_PrefsFrameLimiter, nil); DebugMenuAddVarBool8("Render", "VSynch", &FrontEndMenuManager.m_PrefsVsync, nil); DebugMenuAddVar("Render", "Max FPS", &RsGlobal.maxFPS, nil, 1, 1, 1000, nil); +#ifdef NEW_RENDERER + DebugMenuAddVarBool8("Render", "new renderer", &gbNewRenderer, nil); +extern bool gbRenderRoads; +extern bool gbRenderEverythingBarRoads; +//extern bool gbRenderFadingInUnderwaterEntities; +extern bool gbRenderFadingInEntities; +extern bool gbRenderWater; +extern bool gbRenderBoats; +extern bool gbRenderVehicles; +extern bool gbRenderWorld0; +extern bool gbRenderWorld1; +extern bool gbRenderWorld2; + DebugMenuAddVarBool8("Render", "gbRenderRoads", &gbRenderRoads, nil); + DebugMenuAddVarBool8("Render", "gbRenderEverythingBarRoads", &gbRenderEverythingBarRoads, nil); +// DebugMenuAddVarBool8("Render", "gbRenderFadingInUnderwaterEntities", &gbRenderFadingInUnderwaterEntities, nil); + DebugMenuAddVarBool8("Render", "gbRenderFadingInEntities", &gbRenderFadingInEntities, nil); + DebugMenuAddVarBool8("Render", "gbRenderWater", &gbRenderWater, nil); + DebugMenuAddVarBool8("Render", "gbRenderBoats", &gbRenderBoats, nil); + DebugMenuAddVarBool8("Render", "gbRenderVehicles", &gbRenderVehicles, nil); + DebugMenuAddVarBool8("Render", "gbRenderWorld0", &gbRenderWorld0, nil); + DebugMenuAddVarBool8("Render", "gbRenderWorld1", &gbRenderWorld1, nil); + DebugMenuAddVarBool8("Render", "gbRenderWorld2", &gbRenderWorld2, nil); +#endif + #ifdef EXTENDED_COLOURFILTER static const char *filternames[] = { "None", "Simple", "Normal", "Mobile" }; e = DebugMenuAddVar("Render", "Colourfilter", &CPostFX::EffectSwitch, nil, 1, CPostFX::POSTFX_OFF, CPostFX::POSTFX_MOBILE, filternames); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 2559b743..53971f95 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1,3 +1,4 @@ +#define WITH_D3D #include "common.h" #include "main.h" @@ -6,6 +7,7 @@ #include "Treadable.h" #include "Ped.h" #include "Vehicle.h" +#include "Boat.h" #include "Heli.h" #include "Object.h" #include "PathFind.h" @@ -68,6 +70,12 @@ int32 CRenderer::ms_nNoOfVisibleEntities; CEntity *CRenderer::ms_aVisibleEntityPtrs[NUMVISIBLEENTITIES]; CEntity *CRenderer::ms_aInVisibleEntityPtrs[NUMINVISIBLEENTITIES]; int32 CRenderer::ms_nNoOfInVisibleEntities; +#ifdef NEW_RENDERER +int32 CRenderer::ms_nNoOfVisibleVehicles; +CEntity *CRenderer::ms_aVisibleVehiclePtrs[NUMVISIBLEENTITIES]; +int32 CRenderer::ms_nNoOfVisibleBuildings; +CEntity *CRenderer::ms_aVisibleBuildingPtrs[NUMVISIBLEENTITIES]; +#endif CVector CRenderer::ms_vecCameraPosition; CVehicle *CRenderer::m_pFirstPersonVehicle; @@ -109,6 +117,20 @@ CRenderer::PreRender(void) for(i = 0; i < ms_nNoOfVisibleEntities; i++) ms_aVisibleEntityPtrs[i]->PreRender(); +#ifdef NEW_RENDERER + if(gbNewRenderer){ + for(i = 0; i < ms_nNoOfVisibleVehicles; i++) + ms_aVisibleVehiclePtrs[i]->PreRender(); + // How is this done with cWorldStream? + for(i = 0; i < ms_nNoOfVisibleBuildings; i++) + ms_aVisibleBuildingPtrs[i]->PreRender(); + for(node = CVisibilityPlugins::m_alphaBuildingList.head.next; + node != &CVisibilityPlugins::m_alphaBuildingList.tail; + node = node->next) + ((CEntity*)node->item.entity)->PreRender(); + } +#endif + for (i = 0; i < ms_nNoOfInVisibleEntities; i++) { #ifdef SQUEEZE_PERFORMANCE if (ms_aInVisibleEntityPtrs[i]->IsVehicle() && ((CVehicle*)ms_aInVisibleEntityPtrs[i])->IsHeli()) @@ -241,6 +263,8 @@ CRenderer::RenderFirstPersonVehicle(void) RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); } +inline bool IsRoad(CEntity *e) { return e->IsBuilding() && ((CBuilding*)e)->GetIsATreadable(); } + void CRenderer::RenderRoads(void) { @@ -254,7 +278,7 @@ CRenderer::RenderRoads(void) for(i = 0; i < ms_nNoOfVisibleEntities; i++){ t = (CTreadable*)ms_aVisibleEntityPtrs[i]; - if(t->IsBuilding() && t->GetIsATreadable()){ + if(IsRoad(t)){ #ifndef MASTER if(gbShowCarRoadGroups || gbShowPedRoadGroups){ int ind = 0; @@ -288,7 +312,7 @@ CRenderer::RenderEverythingBarRoads(void) for(i = 0; i < ms_nNoOfVisibleEntities; i++){ e = ms_aVisibleEntityPtrs[i]; - if(e->IsBuilding() && ((CBuilding*)e)->GetIsATreadable()) + if(IsRoad(e)) continue; #ifdef EXTENDED_PIPELINES @@ -349,6 +373,556 @@ CRenderer::RenderBoats(void) } } +#ifdef NEW_RENDERER +#ifndef LIBRW +#error "Need librw for EXTENDED_PIPELINES" +#endif +#include "WaterLevel.h" + +enum { + // blend passes + PASS_NOZ, // no z-write + PASS_ADD, // additive + PASS_BLEND // normal blend +}; + +static RwRGBAReal black; + +static void +SetStencilState(int state) +{ + switch(state){ + // disable stencil + case 0: + rw::SetRenderState(rw::STENCILENABLE, FALSE); + break; + // test against stencil + case 1: + rw::SetRenderState(rw::STENCILENABLE, TRUE); + rw::SetRenderState(rw::STENCILFUNCTION, rw::STENCILNOTEQUAL); + rw::SetRenderState(rw::STENCILPASS, rw::STENCILKEEP); + rw::SetRenderState(rw::STENCILFAIL, rw::STENCILKEEP); + rw::SetRenderState(rw::STENCILZFAIL, rw::STENCILKEEP); + rw::SetRenderState(rw::STENCILFUNCTIONMASK, 0xFF); + rw::SetRenderState(rw::STENCILFUNCTIONREF, 0xFF); + break; + // write to stencil + case 2: + rw::SetRenderState(rw::STENCILENABLE, TRUE); + rw::SetRenderState(rw::STENCILFUNCTION, rw::STENCILALWAYS); + rw::SetRenderState(rw::STENCILPASS, rw::STENCILREPLACE); + rw::SetRenderState(rw::STENCILFUNCTIONREF, 0xFF); + break; + } +} + +#ifdef RW_D3D9 +struct BuildingInst +{ + rw::RawMatrix combinedMat; + rw::d3d9::InstanceDataHeader *instHeader; + uint8 fadeAlpha; + bool lighting; +}; +static BuildingInst blendInsts[3][2000]; +static int numBlendInsts[3]; + +static void +SetMatrix(BuildingInst *building, rw::Matrix *worldMat) +{ + using namespace rw; + RawMatrix world, worldview; + Camera *cam = engine->currentCamera; + convMatrix(&world, worldMat); + RawMatrix::mult(&worldview, &world, &cam->devView); + RawMatrix::mult(&building->combinedMat, &worldview, &cam->devProj); +} + +static bool +IsTextureTransparent(RwTexture *tex) +{ + if(tex == nil || tex->raster == nil) + return false; + return PLUGINOFFSET(rw::d3d::D3dRaster, tex->raster, rw::d3d::nativeRasterOffset)->hasAlpha; +} + +// Render all opaque meshes and put atomics that needs blending +// into the deferred list. +static void +AtomicFirstPass(RpAtomic *atomic, int pass) +{ + using namespace rw; + using namespace rw::d3d; + using namespace rw::d3d9; + + BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; + + atomic->getPipeline()->instance(atomic); + building->instHeader = (d3d9::InstanceDataHeader*)atomic->geometry->instData; + assert(building->instHeader != nil); + assert(building->instHeader->platform == PLATFORM_D3D9); + building->fadeAlpha = 255; + building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); + + bool setupDone = false; + bool defer = false; + SetMatrix(building, atomic->getFrame()->getLTM()); + + InstanceData *inst = building->instHeader->inst; + for(rw::uint32 i = 0; i < building->instHeader->numMeshes; i++, inst++){ + Material *m = inst->material; + + if(inst->vertexAlpha || m->color.alpha != 255 || + IsTextureTransparent(m->texture)){ + defer = true; + continue; + } + + // alright we're rendering this atomic + if(!setupDone){ + setStreamSource(0, building->instHeader->vertexStream[0].vertexBuffer, 0, building->instHeader->vertexStream[0].stride); + setIndices(building->instHeader->indexBuffer); + setVertexDeclaration(building->instHeader->vertexDeclaration); + setVertexShader(default_amb_VS); + d3ddevice->SetVertexShaderConstantF(VSLOC_combined, (float*)&building->combinedMat, 4); + if(building->lighting) + setAmbient(pAmbient->color); + else + setAmbient(black); + setupDone = true; + } + + setMaterial(m->color, m->surfaceProps); + + if(m->texture){ + d3d::setTexture(0, m->texture); + setPixelShader(default_tex_PS); + }else + setPixelShader(default_PS); + + drawInst(building->instHeader, inst); + } + if(defer) + numBlendInsts[pass]++; +} + +static void +AtomicFullyTransparent(RpAtomic *atomic, int pass, int fadeAlpha) +{ + using namespace rw; + using namespace rw::d3d; + using namespace rw::d3d9; + + BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; + + atomic->getPipeline()->instance(atomic); + building->instHeader = (d3d9::InstanceDataHeader*)atomic->geometry->instData; + assert(building->instHeader != nil); + assert(building->instHeader->platform == PLATFORM_D3D9); + building->fadeAlpha = fadeAlpha; + building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); + SetMatrix(building, atomic->getFrame()->getLTM()); + numBlendInsts[pass]++; +} + +static void +RenderBlendPass(int pass) +{ + using namespace rw; + using namespace rw::d3d; + using namespace rw::d3d9; + + setVertexShader(default_amb_VS); + + int i; + for(i = 0; i < numBlendInsts[pass]; i++){ + BuildingInst *building = &blendInsts[pass][i]; + + setStreamSource(0, building->instHeader->vertexStream[0].vertexBuffer, 0, building->instHeader->vertexStream[0].stride); + setIndices(building->instHeader->indexBuffer); + setVertexDeclaration(building->instHeader->vertexDeclaration); + d3ddevice->SetVertexShaderConstantF(VSLOC_combined, (float*)&building->combinedMat, 4); + if(building->lighting) + setAmbient(pAmbient->color); + else + setAmbient(black); + + InstanceData *inst = building->instHeader->inst; + for(rw::uint32 j = 0; j < building->instHeader->numMeshes; j++, inst++){ + Material *m = inst->material; + if(!inst->vertexAlpha && m->color.alpha == 255 && !IsTextureTransparent(m->texture) && building->fadeAlpha == 255) + continue; // already done this one + + rw::RGBA color = m->color; + color.alpha = (color.alpha * building->fadeAlpha)/255; + setMaterial(color, m->surfaceProps); + + if(m->texture){ + d3d::setTexture(0, m->texture); + setPixelShader(default_tex_PS); + }else + setPixelShader(default_PS); + + drawInst(building->instHeader, inst); + } + } +} +#endif +#ifdef RW_GL3 +struct BuildingInst +{ + rw::Matrix matrix; + rw::gl3::InstanceDataHeader *instHeader; + uint8 fadeAlpha; + bool lighting; +}; +static BuildingInst blendInsts[3][2000]; +static int numBlendInsts[3]; + +static bool +IsTextureTransparent(RwTexture *tex) +{ + if(tex == nil || tex->raster == nil) + return false; + return PLUGINOFFSET(rw::gl3::Gl3Raster, tex->raster, rw::gl3::nativeRasterOffset)->hasAlpha; +} + +// Render all opaque meshes and put atomics that needs blending +// into the deferred list. +static void +AtomicFirstPass(RpAtomic *atomic, int pass) +{ + using namespace rw; + using namespace rw::gl3; + + BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; + + atomic->getPipeline()->instance(atomic); + building->instHeader = (gl3::InstanceDataHeader*)atomic->geometry->instData; + assert(building->instHeader != nil); + assert(building->instHeader->platform == PLATFORM_GL3); + building->fadeAlpha = 255; + building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); + + WorldLights lights; + lights.numAmbients = 1; + lights.numDirectionals = 0; + lights.numLocals = 0; + if(building->lighting) + lights.ambient = pAmbient->color; + else + lights.ambient = black; + + bool setupDone = false; + bool defer = false; + building->matrix = *atomic->getFrame()->getLTM(); + + InstanceData *inst = building->instHeader->inst; + for(rw::uint32 i = 0; i < building->instHeader->numMeshes; i++, inst++){ + Material *m = inst->material; + + if(inst->vertexAlpha || m->color.alpha != 255 || + IsTextureTransparent(m->texture)){ + defer = true; + continue; + } + + // alright we're rendering this atomic + if(!setupDone){ + defaultShader->use(); + setWorldMatrix(&building->matrix); +#ifdef RW_GL_USE_VAOS + glBindVertexArray(building->instHeader->vao); +#else + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, building->instHeader->ibo); + glBindBuffer(GL_ARRAY_BUFFER, building->instHeader->vbo); + setAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); +#endif + setLights(&lights); + setupDone = true; + } + + setMaterial(m->color, m->surfaceProps); + + setTexture(0, m->texture); + + drawInst(building->instHeader, inst); + } +#ifndef RW_GL_USE_VAOS + disableAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); +#endif + if(defer) + numBlendInsts[pass]++; +} + +static void +AtomicFullyTransparent(RpAtomic *atomic, int pass, int fadeAlpha) +{ + using namespace rw; + using namespace rw::gl3; + + BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; + + atomic->getPipeline()->instance(atomic); + building->instHeader = (gl3::InstanceDataHeader*)atomic->geometry->instData; + assert(building->instHeader != nil); + assert(building->instHeader->platform == PLATFORM_GL3); + building->fadeAlpha = fadeAlpha; + building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); + building->matrix = *atomic->getFrame()->getLTM(); + numBlendInsts[pass]++; +} + +static void +RenderBlendPass(int pass) +{ + using namespace rw; + using namespace rw::gl3; + + defaultShader->use(); + WorldLights lights; + lights.numAmbients = 1; + lights.numDirectionals = 0; + lights.numLocals = 0; + + int i; + for(i = 0; i < numBlendInsts[pass]; i++){ + BuildingInst *building = &blendInsts[pass][i]; + +#ifdef RW_GL_USE_VAOS + glBindVertexArray(building->instHeader->vao); +#else + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, building->instHeader->ibo); + glBindBuffer(GL_ARRAY_BUFFER, building->instHeader->vbo); + setAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); +#endif + setWorldMatrix(&building->matrix); + if(building->lighting) + lights.ambient = pAmbient->color; + else + lights.ambient = black; + setLights(&lights); + + InstanceData *inst = building->instHeader->inst; + for(rw::uint32 j = 0; j < building->instHeader->numMeshes; j++, inst++){ + Material *m = inst->material; + if(!inst->vertexAlpha && m->color.alpha == 255 && !IsTextureTransparent(m->texture) && building->fadeAlpha == 255) + continue; // already done this one + + rw::RGBA color = m->color; + color.alpha = (color.alpha * building->fadeAlpha)/255; + setMaterial(color, m->surfaceProps); + + setTexture(0, m->texture); + + drawInst(building->instHeader, inst); + } +#ifndef RW_GL_USE_VAOS + disableAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); +#endif + } +} +#endif + +void +CRenderer::RenderOneBuilding(CEntity *ent, float camdist) +{ + if(ent->m_rwObject == nil) + return; + + ent->bImBeingRendered = true; // TODO: this seems wrong, but do we even need it? + + assert(RwObjectGetType(ent->m_rwObject) == rpATOMIC); + RpAtomic *atomic = (RpAtomic*)ent->m_rwObject; + CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(ent->GetModelIndex()); + + int pass = PASS_BLEND; + if(mi->m_additive) // very questionable + pass = PASS_ADD; + if(mi->m_noZwrite) + pass = PASS_NOZ; + + if(ent->bDistanceFade){ + RpAtomic *lodatm; + float fadefactor; + uint32 alpha; + + lodatm = mi->GetAtomicFromDistance(camdist - FADE_DISTANCE); + fadefactor = (mi->GetLargestLodDistance() - (camdist - FADE_DISTANCE))/FADE_DISTANCE; + if(fadefactor > 1.0f) + fadefactor = 1.0f; + alpha = mi->m_alpha * fadefactor; + + if(alpha == 255) + AtomicFirstPass(atomic, pass); + else{ + // not quite sure what this is about, do we have to do that? + RpGeometry *geo = RpAtomicGetGeometry(lodatm); + if(geo != RpAtomicGetGeometry(atomic)) + RpAtomicSetGeometry(atomic, geo, rpATOMICSAMEBOUNDINGSPHERE); + AtomicFullyTransparent(atomic, pass, alpha); + } + }else + AtomicFirstPass(atomic, pass); + + ent->bImBeingRendered = false; // TODO: this seems wrong, but do we even need it? +} + +void +CRenderer::RenderWorld(int pass) +{ + int i; + CEntity *e; + CLink *node; + + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE); + DeActivateDirectional(); + SetAmbientColours(); + + // Temporary...have to figure out sorting better + switch(pass){ + case 0: + // Roads + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + for(i = 0; i < ms_nNoOfVisibleBuildings; i++){ + e = ms_aVisibleBuildingPtrs[i]; + if(e->bIsBIGBuilding || IsRoad(e)) + RenderOneBuilding(e); + } + for(node = CVisibilityPlugins::m_alphaBuildingList.tail.prev; + node != &CVisibilityPlugins::m_alphaBuildingList.head; + node = node->prev){ + e = node->item.entity; + if(e->bIsBIGBuilding || IsRoad(e)) + RenderOneBuilding(e, node->item.sort); + } + + // KLUDGE for road puddles which have to be rendered at road-time + // only very temporary, there are more rendering issues + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RenderBlendPass(PASS_BLEND); + numBlendInsts[PASS_BLEND] = 0; + break; + case 1: + // Opaque + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + for(i = 0; i < ms_nNoOfVisibleBuildings; i++){ + e = ms_aVisibleBuildingPtrs[i]; + if(!(e->bIsBIGBuilding || IsRoad(e))) + RenderOneBuilding(e); + } + for(node = CVisibilityPlugins::m_alphaBuildingList.tail.prev; + node != &CVisibilityPlugins::m_alphaBuildingList.head; + node = node->prev){ + e = node->item.entity; + if(!(e->bIsBIGBuilding || IsRoad(e))) + RenderOneBuilding(e, node->item.sort); + } + // Now we have iterated through all visible buildings (unsorted and sorted) + // and the transparency list is done. + + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE); + RenderBlendPass(PASS_NOZ); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + break; + case 2: + // Transparent + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + RenderBlendPass(PASS_ADD); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RenderBlendPass(PASS_BLEND); + break; + } +} + +void +CRenderer::RenderPeds(void) +{ + int i; + CEntity *e; + + for(i = 0; i < ms_nNoOfVisibleVehicles; i++){ + e = ms_aVisibleVehiclePtrs[i]; + if(e->IsPed()) + RenderOneNonRoad(e); + } +} + +void +CRenderer::RenderVehicles(void) +{ + int i; + CEntity *e; + EntityInfo ei; + CLink *node; + + // not the real thing + for(i = 0; i < ms_nNoOfVisibleVehicles; i++){ + e = ms_aVisibleVehiclePtrs[i]; + if(!e->IsVehicle()) + continue; +// if(PutIntoSortedVehicleList((CVehicle*)e)) +// continue; // boats handled elsewhere + ei.ent = e; + ei.sort = (ms_vecCameraPosition - e->GetPosition()).MagnitudeSqr(); + gSortedVehiclesAndPeds.InsertSorted(ei); + } + + for(node = gSortedVehiclesAndPeds.tail.prev; + node != &gSortedVehiclesAndPeds.head; + node = node->prev) + RenderOneNonRoad(node->item.ent); +} + +void +CRenderer::RenderWater(void) +{ + int i; + CEntity *e; + + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDZERO); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + SetStencilState(2); + + for(i = 0; i < ms_nNoOfVisibleVehicles; i++){ + e = ms_aVisibleVehiclePtrs[i]; + if(e->IsVehicle() && ((CVehicle*)e)->IsBoat()) + ((CBoat*)e)->RenderWaterOutPolys(); + } + + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + SetStencilState(1); + + CWaterLevel::RenderWater(); + + SetStencilState(0); +} + +void +CRenderer::ClearForFrame(void) +{ + ms_nNoOfVisibleEntities = 0; + ms_nNoOfVisibleVehicles = 0; + ms_nNoOfVisibleBuildings = 0; + ms_nNoOfInVisibleEntities = 0; + gSortedVehiclesAndPeds.Clear(); + + numBlendInsts[PASS_NOZ] = 0; + numBlendInsts[PASS_ADD] = 0; + numBlendInsts[PASS_BLEND] = 0; +} +#endif + void CRenderer::RenderFadingInEntities(void) { @@ -634,9 +1208,14 @@ CRenderer::SetupBigBuildingVisibility(CEntity *ent) void CRenderer::ConstructRenderList(void) +{ +#ifdef NEW_RENDERER + if(!gbNewRenderer) +#endif { ms_nNoOfVisibleEntities = 0; ms_nNoOfInVisibleEntities = 0; +} ms_vecCameraPosition = TheCamera.GetPosition(); // unused @@ -1122,6 +1701,20 @@ CRenderer::ScanSectorPoly(RwV2d *poly, int32 numVertices, void (*scanfunc)(CPtrL } } +void +CRenderer::InsertEntityIntoList(CEntity *ent) +{ +#ifdef NEW_RENDERER + // TODO: there are more flags being checked here + if(gbNewRenderer && (ent->IsVehicle() || ent->IsPed())) + ms_aVisibleVehiclePtrs[ms_nNoOfVisibleVehicles++] = ent; + else if(gbNewRenderer && ent->IsBuilding()) + ms_aVisibleBuildingPtrs[ms_nNoOfVisibleBuildings++] = ent; + else +#endif + ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; +} + void CRenderer::ScanBigBuildingList(CPtrList &list) { @@ -1136,7 +1729,7 @@ CRenderer::ScanBigBuildingList(CPtrList &list) #endif if(!ent->bZoneCulled){ if(SetupBigBuildingVisibility(ent) == VIS_VISIBLE) - ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; + InsertEntityIntoList(ent); #ifndef MASTER EntitiesRendered++; RenderedBigBuildings++; @@ -1167,7 +1760,7 @@ CRenderer::ScanSectorList(CPtrList *lists) if(IsEntityCullZoneVisible(ent)){ switch(SetupEntityVisibility(ent)){ case VIS_VISIBLE: - ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; + InsertEntityIntoList(ent); break; case VIS_INVISIBLE: if(!IsGlass(ent->GetModelIndex())) @@ -1210,7 +1803,7 @@ CRenderer::ScanSectorList(CPtrList *lists) break; } #endif - }else if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable() && !CStreaming::ms_disableStreaming){ + }else if(IsRoad(ent) && !CStreaming::ms_disableStreaming){ if(SetupEntityVisibility(ent) == VIS_STREAMME) if(!m_loadingPriority || CStreaming::ms_numModelsRequested < 10) CStreaming::RequestModel(ent->GetModelIndex(), 0); @@ -1243,7 +1836,7 @@ CRenderer::ScanSectorList_Priority(CPtrList *lists) if(IsEntityCullZoneVisible(ent)){ switch(SetupEntityVisibility(ent)){ case VIS_VISIBLE: - ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; + InsertEntityIntoList(ent); break; case VIS_INVISIBLE: if(!IsGlass(ent->GetModelIndex())) @@ -1289,7 +1882,7 @@ CRenderer::ScanSectorList_Priority(CPtrList *lists) break; } #endif - }else if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable() && !CStreaming::ms_disableStreaming){ + }else if(IsRoad(ent) && !CStreaming::ms_disableStreaming){ if(SetupEntityVisibility(ent) == VIS_STREAMME) CStreaming::RequestModel(ent->GetModelIndex(), 0); }else{ @@ -1320,7 +1913,7 @@ CRenderer::ScanSectorList_Subway(CPtrList *lists) ent->m_scanCode = CWorld::GetCurrentScanCode(); switch(SetupEntityVisibility(ent)){ case VIS_VISIBLE: - ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; + InsertEntityIntoList(ent); break; case VIS_OFFSCREEN: dx = ms_vecCameraPosition.x - ent->GetPosition().x; diff --git a/src/render/Renderer.h b/src/render/Renderer.h index e14f73b1..35b43a0b 100644 --- a/src/render/Renderer.h +++ b/src/render/Renderer.h @@ -40,6 +40,13 @@ class CRenderer static CEntity *ms_aVisibleEntityPtrs[NUMVISIBLEENTITIES]; static int32 ms_nNoOfInVisibleEntities; static CEntity *ms_aInVisibleEntityPtrs[NUMINVISIBLEENTITIES]; +#ifdef NEW_RENDERER + static int32 ms_nNoOfVisibleVehicles; + static CEntity *ms_aVisibleVehiclePtrs[NUMVISIBLEENTITIES]; + // for cWorldStream emulation + static int32 ms_nNoOfVisibleBuildings; + static CEntity *ms_aVisibleBuildingPtrs[NUMVISIBLEENTITIES]; +#endif static CVector ms_vecCameraPosition; static CVehicle *m_pFirstPersonVehicle; @@ -90,4 +97,15 @@ public: static bool IsVehicleCullZoneVisible(CEntity *ent); static void RemoveVehiclePedLights(CEntity *ent, bool reset); + + +#ifdef NEW_RENDERER + static void ClearForFrame(void); + static void RenderPeds(void); + static void RenderVehicles(void); // also renders peds in LCS + static void RenderOneBuilding(CEntity *ent, float camdist = 0.0f); + static void RenderWorld(int pass); // like cWorldStream::Render(int) + static void RenderWater(void); // keep-out polys and water +#endif + static void InsertEntityIntoList(CEntity *ent); }; diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp index 5c970855..4ad06543 100644 --- a/src/render/SpecialFX.cpp +++ b/src/render/SpecialFX.cpp @@ -141,6 +141,9 @@ CSpecialFX::Render(void) CBrightLights::Render(); CShinyTexts::Render(); CMoneyMessages::Render(); +#ifdef NEW_RENDERER + if(!(gbNewRenderer && FredIsInFirstPersonCam())) +#endif C3dMarkers::Render(); } diff --git a/src/rw/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp index 916696de..32461d1c 100644 --- a/src/rw/VisibilityPlugins.cpp +++ b/src/rw/VisibilityPlugins.cpp @@ -2,6 +2,7 @@ #include "RwHelper.h" #include "templates.h" +#include "main.h" #include "Entity.h" #include "ModelInfo.h" #include "Lights.h" @@ -14,6 +15,9 @@ CLinkList CVisibilityPlugins::m_alphaList; CLinkList CVisibilityPlugins::m_alphaEntityList; +#ifdef NEW_RENDERER +CLinkList CVisibilityPlugins::m_alphaBuildingList; +#endif int32 CVisibilityPlugins::ms_atomicPluginOffset = -1; int32 CVisibilityPlugins::ms_framePluginOffset = -1; @@ -158,6 +162,12 @@ CVisibilityPlugins::Initialise(void) #endif // ASPECT_RATIO_SCALE m_alphaEntityList.head.item.sort = 0.0f; m_alphaEntityList.tail.item.sort = 100000000.0f; + +#ifdef NEW_RENDERER + m_alphaBuildingList.Init(NUMALPHAENTITYLIST); + m_alphaBuildingList.head.item.sort = 0.0f; + m_alphaBuildingList.tail.item.sort = 100000000.0f; +#endif } void @@ -165,12 +175,18 @@ CVisibilityPlugins::Shutdown(void) { m_alphaList.Shutdown(); m_alphaEntityList.Shutdown(); +#ifdef NEW_RENDERER + m_alphaBuildingList.Shutdown(); +#endif } void CVisibilityPlugins::InitAlphaEntityList(void) { m_alphaEntityList.Clear(); +#ifdef NEW_RENDERER + m_alphaBuildingList.Clear(); +#endif } bool @@ -179,6 +195,10 @@ CVisibilityPlugins::InsertEntityIntoSortedList(CEntity *e, float dist) AlphaObjectInfo item; item.entity = e; item.sort = dist; +#ifdef NEW_RENDERER + if(gbNewRenderer && e->IsBuilding()) + return !!m_alphaBuildingList.InsertSorted(item); +#endif bool ret = !!m_alphaEntityList.InsertSorted(item); // if(!ret) // printf("list full %d\n", m_alphaEntityList.Count()); diff --git a/src/rw/VisibilityPlugins.h b/src/rw/VisibilityPlugins.h index 0721dfcc..f092de5a 100644 --- a/src/rw/VisibilityPlugins.h +++ b/src/rw/VisibilityPlugins.h @@ -22,6 +22,9 @@ public: static CLinkList m_alphaList; static CLinkList m_alphaEntityList; +#ifdef NEW_RENDERER + static CLinkList m_alphaBuildingList; +#endif static RwCamera *ms_pCamera; static RwV3d *ms_pCameraPosn; static float ms_cullCompsDist; diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index aba48bad..f2f80569 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -1,5 +1,6 @@ #include "common.h" +#include "main.h" #include "General.h" #include "Timecycle.h" #include "HandlingMgr.h" @@ -719,6 +720,15 @@ CBoat::Render() ((CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()))->SetVehicleColour(m_currentColour1, m_currentColour2); if (!CVehicle::bWheelsOnlyCheat) CEntity::Render(); +#ifdef NEW_RENDERER + if(!gbNewRenderer) +#endif + RenderWaterOutPolys(); // not separate function in III +} + +void +CBoat::RenderWaterOutPolys(void) +{ KeepWaterOutIndices[0] = 0; KeepWaterOutIndices[1] = 2; KeepWaterOutIndices[2] = 1; @@ -758,19 +768,29 @@ CBoat::Render() KeepWaterOutVertices[2].v = 1.0f; KeepWaterOutVertices[3].u = 1.0f; KeepWaterOutVertices[3].v = 1.0f; +#ifdef NEW_RENDERER + if(!gbNewRenderer) +#endif +{ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpWaterRaster); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDZERO); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); +} if (!CVehicle::bWheelsOnlyCheat && RwIm3DTransform(KeepWaterOutVertices, 4, GetMatrix().m_attachment, rwIM3D_VERTEXUV)) { RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, KeepWaterOutIndices, 6); RwIm3DEnd(); } +#ifdef NEW_RENDERER + if(!gbNewRenderer) +#endif +{ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); } +} void CBoat::Teleport(CVector v) diff --git a/src/vehicles/Boat.h b/src/vehicles/Boat.h index 56aff264..157b4852 100644 --- a/src/vehicles/Boat.h +++ b/src/vehicles/Boat.h @@ -54,6 +54,7 @@ public: virtual bool IsComponentPresent(int32 component) { return true; } virtual void BlowUpCar(CEntity *ent); + void RenderWaterOutPolys(void); void ApplyWaterResistance(void); void SetupModelNodes(); void PruneWakeTrail(void); From 2e734a47504c13b1d5e5b7382d7c23e74c6ad4b8 Mon Sep 17 00:00:00 2001 From: erorcun Date: Tue, 5 Jan 2021 13:45:20 +0300 Subject: [PATCH 036/152] Automobile: more pointless fixes --- src/vehicles/Automobile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index e66865da..753b853d 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -224,6 +224,7 @@ CAutomobile::ProcessControl(void) int i; float wheelRot; CColModel *colModel; + float brake = 0.0f; if(bUsingSpecialColModel) colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel; @@ -539,7 +540,6 @@ CAutomobile::ProcessControl(void) break; } - float brake; if(skipPhysics){ bHasContacted = false; bIsInSafePosition = false; @@ -725,7 +725,7 @@ CAutomobile::ProcessControl(void) traction *= 4.0f; if(FindPlayerVehicle() && FindPlayerVehicle() == this){ - if(CPad::GetPad(0)->WeaponJustDown()){ + if(CPad::GetPad(0)->CarGunJustDown()){ if(m_bombType == CARBOMB_TIMED){ m_bombType = CARBOMB_TIMEDACTIVE; m_nBombTimer = 7000; From fd4c2172f5469161106edbb196b79b8896300402 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 5 Jan 2021 21:06:17 +0200 Subject: [PATCH 037/152] Add support of PS2 audio streams to OpenAL --- src/audio/oal/stream.cpp | 242 +++++++++++++++++++++++++++++++++++++- src/audio/oal/stream.h | 2 +- src/audio/sampman_oal.cpp | 22 ++-- 3 files changed, 255 insertions(+), 11 deletions(-) diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index cf5fe831..1f8f4c1a 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -147,6 +147,12 @@ public: } }; +#ifdef _WIN32 +// fuzzy seek eliminates stutter when playing ADF but spams errors a lot (nothing breaks though) +#define MP3_USE_FUZZY_SEEK +#endif // _WIN32 + + class CMP3File : public IDecoder { mpg123_handle *m_pMH; @@ -163,8 +169,9 @@ public: m_pMH = mpg123_new(nil, nil); if ( m_pMH ) { +#ifdef MP3_USE_FUZZY_SEEK mpg123_param(m_pMH, MPG123_FLAGS, MPG123_FUZZY | MPG123_SEEKBUFFER | MPG123_GAPLESS, 0.0); - +#endif long rate = 0; int channels = 0; int encoding = 0; @@ -245,6 +252,233 @@ public: return (uint32)size; } }; + +#define VAG_LINE_SIZE (0x10) +#define VAG_SAMPLES_IN_LINE (28) + +class CVagDecoder +{ + const double f[5][2] = { { 0.0, 0.0 }, + { 60.0 / 64.0, 0.0 }, + { 115.0 / 64.0, -52.0 / 64.0 }, + { 98.0 / 64.0, -55.0 / 64.0 }, + { 122.0 / 64.0, -60.0 / 64.0 } }; + + double s_1; + double s_2; +public: + CVagDecoder() + { + ResetState(); + } + + void ResetState() + { + s_1 = s_2 = 0.0; + } + + static short quantize(double sample) + { + int a = int(sample + 0.5); + return short(clamp(int(sample + 0.5), -32768, 32767)); + } + + void Decode(void* _inbuf, int16* _outbuf, size_t size) + { + uint8* inbuf = (uint8*)_inbuf; + int16* outbuf = _outbuf; + size &= ~(VAG_LINE_SIZE - 1); + + while (size > 0) { + double samples[VAG_SAMPLES_IN_LINE]; + + int predict_nr, shift_factor, flags; + predict_nr = *(inbuf++); + shift_factor = predict_nr & 0xf; + predict_nr >>= 4; + flags = *(inbuf++); + if (flags == 7) // TODO: ignore? + break; + for (int i = 0; i < VAG_SAMPLES_IN_LINE; i += 2) { + int d = *(inbuf++); + int16 s = int16((d & 0xf) << 12); + samples[i] = (double)(s >> shift_factor); + s = int16((d & 0xf0) << 8); + samples[i + 1] = (double)(s >> shift_factor); + } + + for (int i = 0; i < VAG_SAMPLES_IN_LINE; i++) { + samples[i] = samples[i] + s_1 * f[predict_nr][0] + s_2 * f[predict_nr][1]; + s_2 = s_1; + s_1 = samples[i]; + *(outbuf++) = quantize(samples[i] + 0.5); + } + size -= VAG_LINE_SIZE; + } + } +}; + +#define VB_BLOCK_SIZE (0x2000) +#define NUM_VAG_LINES_IN_BLOCK (VB_BLOCK_SIZE / VAG_LINE_SIZE) +#define NUM_VAG_SAMPLES_IN_BLOCK (NUM_VAG_LINES_IN_BLOCK * VAG_SAMPLES_IN_LINE) + +class CVbFile : public IDecoder +{ + FILE* pFile; + size_t m_FileSize; + size_t m_nNumberOfBlocks; + CVagDecoder* decoders; + + uint32 m_nSampleRate; + uint8 m_nChannels; + bool m_bBlockRead; + uint16 m_LineInBlock; + size_t m_CurrentBlock; + + uint8** ppTempBuffers; + + void ReadBlock(int32 block = -1) + { + // just read next block if -1 + if (block != -1) + fseek(pFile, block * m_nChannels * VB_BLOCK_SIZE, SEEK_SET); + + for (int i = 0; i < m_nChannels; i++) + fread(ppTempBuffers[i], VB_BLOCK_SIZE, 1, pFile); + m_bBlockRead = true; + } + +public: + CVbFile(const char* path, uint32 nSampleRate = 32000, uint8 nChannels = 2) : m_nSampleRate(nSampleRate), m_nChannels(nChannels) + { + pFile = fopen(path, "rb"); + if (pFile) { + fseek(pFile, 0, SEEK_END); + m_FileSize = ftell(pFile); + fseek(pFile, 0, SEEK_SET); + m_nNumberOfBlocks = m_FileSize / (nChannels * VB_BLOCK_SIZE); + decoders = new CVagDecoder[nChannels]; + m_CurrentBlock = 0; + m_LineInBlock = 0; + m_bBlockRead = false; + ppTempBuffers = new uint8 * [nChannels]; + for (uint8 i = 0; i < nChannels; i++) + ppTempBuffers[i] = new uint8[VB_BLOCK_SIZE]; + } + } + + ~CVbFile() + { + if (pFile) + { + fclose(pFile); + delete decoders; + for (int i = 0; i < m_nChannels; i++) + delete ppTempBuffers[i]; + delete ppTempBuffers; + } + } + + bool IsOpened() + { + return pFile != nil; + } + + uint32 GetSampleSize() + { + return sizeof(uint16); + } + + uint32 GetSampleCount() + { + if (!IsOpened()) return 0; + return m_nNumberOfBlocks * NUM_VAG_LINES_IN_BLOCK * VAG_SAMPLES_IN_LINE; + } + + uint32 GetSampleRate() + { + return m_nSampleRate; + } + + uint32 GetChannels() + { + return m_nChannels; + } + + void Seek(uint32 milliseconds) + { + if (!IsOpened()) return; + uint32 samples = ms2samples(milliseconds); + int32 block = samples / NUM_VAG_SAMPLES_IN_BLOCK; + if (block > m_nNumberOfBlocks) + { + samples = 0; + block = 0; + } + if (block != m_CurrentBlock) + ReadBlock(block); + + uint32 remainingSamples = samples - block * NUM_VAG_SAMPLES_IN_BLOCK; + uint32 newLine = remainingSamples / VAG_SAMPLES_IN_LINE / VAG_LINE_SIZE; + + if (m_CurrentBlock != block || m_LineInBlock != newLine) + { + m_CurrentBlock = block; + m_LineInBlock = newLine; + for (int i = 0; i < GetChannels(); i++) + decoders[i].ResetState(); + } + + } + + uint32 Tell() + { + if (!IsOpened()) return 0; + uint32 pos = (m_CurrentBlock * NUM_VAG_LINES_IN_BLOCK + m_LineInBlock) * VAG_SAMPLES_IN_LINE; + return samples2ms(pos); + } + + uint32 Decode(void* buffer) + { + if (!IsOpened()) return 0; + + if (!m_bBlockRead) + ReadBlock(m_CurrentBlock); + + if (m_CurrentBlock == m_nNumberOfBlocks) return 0; + int size = 0; + + int numberOfRequiredLines = GetBufferSamples() / GetChannels() / VAG_SAMPLES_IN_LINE; + int numberOfRemainingLines = (m_nNumberOfBlocks - m_CurrentBlock) * NUM_VAG_LINES_IN_BLOCK - m_LineInBlock; + int bufSizePerChannel = Min(numberOfRequiredLines, numberOfRemainingLines) * VAG_SAMPLES_IN_LINE * GetSampleSize(); + + if (numberOfRequiredLines > numberOfRemainingLines) + numberOfRemainingLines = numberOfRemainingLines; + + int16* buffers[2] = { (int16*)buffer, &((int16*)buffer)[bufSizePerChannel / GetSampleSize()] }; + + while (size < bufSizePerChannel) + { + for (int i = 0; i < GetChannels(); i++) + { + decoders[i].Decode(ppTempBuffers[i] + m_LineInBlock * VAG_LINE_SIZE, buffers[i], VAG_LINE_SIZE); + buffers[i] += VAG_SAMPLES_IN_LINE; + } + size += VAG_SAMPLES_IN_LINE * GetSampleSize(); + m_LineInBlock++; + if (m_LineInBlock >= NUM_VAG_LINES_IN_BLOCK) + { + m_CurrentBlock++; + if (m_CurrentBlock >= m_nNumberOfBlocks) + break; + m_LineInBlock = 0; + ReadBlock(); + } + } + + return bufSizePerChannel * GetChannels(); + } +}; #else class COpusFile : public IDecoder { @@ -341,6 +575,8 @@ public: }; #endif +#ifdef MP3_USE_FUZZY_SEEK +#endif void CStream::Initialise() { #ifndef AUDIO_OPUS @@ -355,7 +591,7 @@ void CStream::Terminate() #endif } -CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS]) : +CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate) : m_pAlSources(sources), m_alBuffers(buffers), m_pBuffer(nil), @@ -388,6 +624,8 @@ CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBU m_pSoundFile = new CMP3File(m_aFilename); else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".wav")], ".wav")) m_pSoundFile = new CSndFile(m_aFilename); + else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".vb")], ".VB")) + m_pSoundFile = new CVbFile(m_aFilename, overrideSampleRate); #else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".opus")], ".opus")) m_pSoundFile = new COpusFile(m_aFilename); diff --git a/src/audio/oal/stream.h b/src/audio/oal/stream.h index 326ce6a1..bcbc5e54 100644 --- a/src/audio/oal/stream.h +++ b/src/audio/oal/stream.h @@ -86,7 +86,7 @@ public: static void Initialise(); static void Terminate(); - CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS]); + CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate = 32000); ~CStream(); void Delete(); diff --git a/src/audio/sampman_oal.cpp b/src/audio/sampman_oal.cpp index 5579644c..07d943e3 100644 --- a/src/audio/sampman_oal.cpp +++ b/src/audio/sampman_oal.cpp @@ -393,6 +393,12 @@ set_new_provider(int index) return false; } +static bool +IsThisTrackAt16KHz(uint32 track) +{ + return track == STREAMED_SOUND_RADIO_CHAT; +} + cSampleManager::cSampleManager(void) { ; @@ -974,7 +980,7 @@ cSampleManager::Initialise(void) #endif for(int32 i = 0; i < TOTAL_STREAMED_SOUNDS; i++) { - aStream[0] = new CStream(StreamedNameTable[i], ALStreamSources[0], ALStreamBuffers[0]); + aStream[0] = new CStream(StreamedNameTable[i], ALStreamSources[0], ALStreamBuffers[0], IsThisTrackAt16KHz(i) ? 16000 : 32000); if(aStream[0] && aStream[0]->IsOpened()) { uint32 tatalms = aStream[0]->GetLengthMS(); @@ -1661,7 +1667,7 @@ cSampleManager::PreloadStreamedFile(uint8 nFile, uint8 nStream) strcpy(filename, StreamedNameTable[nFile]); - CStream *stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream]); + CStream *stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000); ASSERT(stream != NULL); aStream[nStream] = stream; @@ -1736,7 +1742,7 @@ cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream) nFile = 0; strcat(filename, StreamedNameTable[nFile]); - CStream* stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream]); + CStream* stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000); ASSERT(stream != NULL); aStream[nStream] = stream; @@ -1760,12 +1766,12 @@ cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream) } if (mp3->pLinkPath != NULL) - aStream[nStream] = new CStream(mp3->pLinkPath, ALStreamSources[nStream], ALStreamBuffers[nStream]); + aStream[nStream] = new CStream(mp3->pLinkPath, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000); else { strcpy(filename, _mp3DirectoryPath); strcat(filename, mp3->aFilename); - aStream[nStream] = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream]); + aStream[nStream] = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000); } if (aStream[nStream]->IsOpened()) { @@ -1792,7 +1798,7 @@ cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream) { nFile = 0; strcat(filename, StreamedNameTable[nFile]); - CStream* stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream]); + CStream* stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000); ASSERT(stream != NULL); aStream[nStream] = stream; @@ -1816,7 +1822,7 @@ cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream) } if (e->pLinkPath != NULL) - aStream[nStream] = new CStream(e->pLinkPath, ALStreamSources[nStream], ALStreamBuffers[nStream]); + aStream[nStream] = new CStream(e->pLinkPath, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000); else { strcpy(filename, _mp3DirectoryPath); strcat(filename, e->aFilename); @@ -1849,7 +1855,7 @@ cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream) strcpy(filename, StreamedNameTable[nFile]); - CStream *stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream]); + CStream *stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000); ASSERT(stream != NULL); aStream[nStream] = stream; From d94e8e8fafadf3a41b8d9c531f01383ecdb5f65f Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 5 Jan 2021 21:31:49 +0200 Subject: [PATCH 038/152] duh --- src/audio/oal/stream.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index 1f8f4c1a..9beb27a0 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -575,8 +575,6 @@ public: }; #endif -#ifdef MP3_USE_FUZZY_SEEK -#endif void CStream::Initialise() { #ifndef AUDIO_OPUS From a6409fb44550870637ece43b0b5fe201ef5d7f1d Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 5 Jan 2021 20:58:39 +0100 Subject: [PATCH 039/152] fix --- src/peds/PedAI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/peds/PedAI.cpp b/src/peds/PedAI.cpp index 43592d80..3dc64e2e 100644 --- a/src/peds/PedAI.cpp +++ b/src/peds/PedAI.cpp @@ -2152,7 +2152,7 @@ CPed::ReactToAttack(CEntity *attacker) CCarCtrl::SwitchVehicleToRealPhysics(m_pMyVehicle); m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity; + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fMaxCruiseVelocity; m_pMyVehicle->SetStatus(STATUS_PHYSICS); } } else From 493f6cb57851c147c340ceab9937df43582e53c3 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Wed, 6 Jan 2021 15:46:59 +0200 Subject: [PATCH 040/152] Implementing our own WAV decoder to replace SndFile --- src/audio/oal/stream.cpp | 357 ++++++++++++++++++++++++++++++++++++--- src/core/config.h | 1 + 2 files changed, 330 insertions(+), 28 deletions(-) diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index 9beb27a0..0a5be049 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -8,10 +8,14 @@ #include #else #ifdef _WIN32 +#ifdef AUDIO_OAL_USE_SNDFILE #pragma comment( lib, "libsndfile-1.lib" ) +#endif #pragma comment( lib, "libmpg123-0.lib" ) #endif +#ifdef AUDIO_OAL_USE_SNDFILE #include +#endif #include #endif @@ -78,6 +82,290 @@ public: CSortStereoBuffer SortStereoBuffer; #ifndef AUDIO_OPUS +class CImaADPCMDecoder +{ + const uint16 StepTable[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, + 16, 17, 19, 21, 23, 25, 28, 31, + 34, 37, 41, 45, 50, 55, 60, 66, + 73, 80, 88, 97, 107, 118, 130, 143, + 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1411, + 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, + 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, + 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, + 32767 + }; + + int16 Sample, StepIndex; + +public: + CImaADPCMDecoder() + { + Init(0, 0); + } + + void Init(int16 _Sample, int16 _StepIndex) + { + Sample = _Sample; + StepIndex = _StepIndex; + } + + void Decode(uint8 *inbuf, int16 *_outbuf, size_t size) + { + int16* outbuf = _outbuf; + for (size_t i = 0; i < size; i++) + { + *(outbuf++) = DecodeSample(inbuf[i] & 0xF); + *(outbuf++) = DecodeSample(inbuf[i] >> 4); + } + } + + int16 DecodeSample(uint8 adpcm) + { + uint16 step = StepTable[StepIndex]; + + if (adpcm & 4) + StepIndex += ((adpcm & 3) + 1) * 2; + else + StepIndex--; + + StepIndex = clamp(StepIndex, 0, 88); + + int delta = step >> 3; + if (adpcm & 1) delta += step >> 2; + if (adpcm & 2) delta += step >> 1; + if (adpcm & 4) delta += step; + if (adpcm & 8) delta = -delta; + + int newSample = Sample + delta; + Sample = clamp(newSample, -32768, 32767); + return Sample; + } +}; + +class CWavFile : public IDecoder +{ + enum + { + WAVEFMT_PCM = 1, + WAVEFMT_IMA_ADPCM = 0x11, + WAVEFMT_XBOX_ADPCM = 0x69, + }; + + struct tDataHeader + { + uint32 ID; + uint32 Size; + }; + + struct tFormatHeader + { + uint16 AudioFormat; + uint16 NumChannels; + uint32 SampleRate; + uint32 ByteRate; + uint16 BlockAlign; + uint16 BitsPerSample; + uint16 extra[2]; // adpcm only + + tFormatHeader() { memset(this, 0, sizeof(*this)); } + }; + + FILE* pFile; + bool bIsOpen; + tFormatHeader FormatHeader; + + uint32 DataStartOffset; + uint32 SampleCount; + uint32 SamplesPerBlock; + + // ADPCM things + uint8 *AdpcmBlock; + int16 **buffers; + CImaADPCMDecoder* decoders; + + void Close() + { + if (pFile) { + fclose(pFile); + pFile = nil; + } + if (AdpcmBlock) delete AdpcmBlock; + if (buffers) delete buffers; + if (decoders) delete decoders; + } + +public: + CWavFile(const char* path) : bIsOpen(false), DataStartOffset(0), SampleCount(0), SamplesPerBlock(0), AdpcmBlock(nil), buffers(nil), decoders(nil) + { + pFile = fopen(path, "rb"); + if (!pFile) return; + +#define CLOSE_ON_ERROR(op)\ + if (op) { \ + Close(); \ + return; \ + } + + tDataHeader DataHeader; + + CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, pFile) == 0); + CLOSE_ON_ERROR(DataHeader.ID != 'FFIR'); + + int WAVE; + CLOSE_ON_ERROR(fread(&WAVE, 4, 1, pFile) == 0); + CLOSE_ON_ERROR(WAVE != 'EVAW') + CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, pFile) == 0); + CLOSE_ON_ERROR(DataHeader.ID != ' tmf'); + + CLOSE_ON_ERROR(fread(&FormatHeader, Min(DataHeader.Size, sizeof(tFormatHeader)), 1, pFile) == 0); + CLOSE_ON_ERROR(DataHeader.Size > sizeof(tFormatHeader)); + + switch (FormatHeader.AudioFormat) + { + case WAVEFMT_XBOX_ADPCM: + FormatHeader.AudioFormat = WAVEFMT_IMA_ADPCM; + case WAVEFMT_IMA_ADPCM: + SamplesPerBlock = (FormatHeader.BlockAlign / FormatHeader.NumChannels - 4) * 2 + 1; + AdpcmBlock = new uint8[FormatHeader.BlockAlign]; + buffers = new int16*[FormatHeader.NumChannels]; + decoders = new CImaADPCMDecoder[FormatHeader.NumChannels]; + break; + case WAVEFMT_PCM: + SamplesPerBlock = 1; + if (FormatHeader.BitsPerSample != 16) + { + debug("Unsupported PCM (%d bits), only signed 16-bit is supported (%s)\n", FormatHeader.BitsPerSample, path); + return; + } + break; + default: + debug("Unsupported wav format 0x%x (%s)\n", FormatHeader.AudioFormat, path); + return; + } + + while (true) { + CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, pFile) == 0); + if (DataHeader.ID == 'atad') + break; + fseek(pFile, DataHeader.Size, SEEK_CUR); + } + + DataStartOffset = ftell(pFile); + SampleCount = DataHeader.Size / FormatHeader.BlockAlign * SamplesPerBlock; + + bIsOpen = true; +#undef CLOSE_ON_ERROR + } + + ~CWavFile() + { + Close(); + } + + bool IsOpened() + { + return bIsOpen; + } + + uint32 GetSampleSize() + { + return sizeof(uint16); + } + + uint32 GetSampleCount() + { + return SampleCount; + } + + uint32 GetSampleRate() + { + return FormatHeader.SampleRate; + } + + uint32 GetChannels() + { + return FormatHeader.NumChannels; + } + + void Seek(uint32 milliseconds) + { + if (!IsOpened()) return; + fseek(pFile, DataStartOffset + ms2samples(milliseconds) / SamplesPerBlock * FormatHeader.BlockAlign, SEEK_SET); + } + + uint32 Tell() + { + if (!IsOpened()) return 0; + return samples2ms((ftell(pFile) - DataStartOffset) / FormatHeader.BlockAlign * SamplesPerBlock); + } + +#define SAMPLES_IN_LINE (8) + + uint32 Decode(void* buffer) + { + if (!IsOpened()) return 0; + + if (FormatHeader.AudioFormat == WAVEFMT_PCM) + { + uint32 size = fread(buffer, 1, GetBufferSize(), pFile); + if (FormatHeader.NumChannels == 2) + SortStereoBuffer.SortStereo(buffer, size); + return size; + } + else if (FormatHeader.AudioFormat == WAVEFMT_IMA_ADPCM) + { + uint32 MaxSamples = GetBufferSamples() / FormatHeader.NumChannels; + uint32 CurSample = (ftell(pFile) - DataStartOffset) / FormatHeader.BlockAlign * SamplesPerBlock; + + MaxSamples = Min(MaxSamples, SampleCount - CurSample); + MaxSamples = MaxSamples / SamplesPerBlock * SamplesPerBlock; + uint32 OutBufSizePerChannel = MaxSamples * GetSampleSize(); + uint32 OutBufSize = OutBufSizePerChannel * FormatHeader.NumChannels; + int16** buffers = new int16*[FormatHeader.NumChannels]; + CImaADPCMDecoder* decoders = new CImaADPCMDecoder[FormatHeader.NumChannels]; + for (uint32 i = 0; i < FormatHeader.NumChannels; i++) + buffers[i] = (int16*)((int8*)buffer + OutBufSizePerChannel * i); + + uint32 samplesRead = 0; + while (samplesRead < MaxSamples) + { + uint8* AdpcmBuf = AdpcmBlock; + if (fread(AdpcmBlock, 1, FormatHeader.BlockAlign, pFile) == 0) + return 0; + + for (uint32 i = 0; i < FormatHeader.NumChannels; i++) + { + int16 Sample = *(int16*)AdpcmBuf; + AdpcmBuf += sizeof(int16); + int16 Step = *(int16*)AdpcmBuf; + AdpcmBuf += sizeof(int16); + decoders[i].Init(Sample, Step); + *(buffers[i]) = Sample; + buffers[i]++; + } + samplesRead++; + for (uint32 s = 1; s < SamplesPerBlock; s += SAMPLES_IN_LINE) + { + for (uint32 i = 0; i < FormatHeader.NumChannels; i++) + { + decoders[i].Decode(AdpcmBuf, buffers[i], SAMPLES_IN_LINE / 2); + AdpcmBuf += SAMPLES_IN_LINE / 2; + buffers[i] += SAMPLES_IN_LINE; + } + samplesRead += SAMPLES_IN_LINE; + } + } + return OutBufSize; + } + return 0; + } +}; + +#ifdef AUDIO_OAL_USE_SNDFILE class CSndFile : public IDecoder { SNDFILE *m_pfSound; @@ -146,6 +434,7 @@ public: return size; } }; +#endif #ifdef _WIN32 // fuzzy seek eliminates stutter when playing ADF but spams errors a lot (nothing breaks though) @@ -280,7 +569,7 @@ public: static short quantize(double sample) { int a = int(sample + 0.5); - return short(clamp(int(sample + 0.5), -32768, 32767)); + return short(clamp(a, -32768, 32767)); } void Decode(void* _inbuf, int16* _outbuf, size_t size) @@ -336,6 +625,7 @@ class CVbFile : public IDecoder size_t m_CurrentBlock; uint8** ppTempBuffers; + int16** buffers; void ReadBlock(int32 block = -1) { @@ -349,22 +639,24 @@ class CVbFile : public IDecoder } public: - CVbFile(const char* path, uint32 nSampleRate = 32000, uint8 nChannels = 2) : m_nSampleRate(nSampleRate), m_nChannels(nChannels) + CVbFile(const char* path, uint32 nSampleRate = 32000, uint8 nChannels = 2) : m_nSampleRate(nSampleRate), m_nChannels(nChannels), decoders(nil), ppTempBuffers(nil), buffers(nil), + m_FileSize(0), m_nNumberOfBlocks(0), m_bBlockRead(false), m_LineInBlock(0), m_CurrentBlock(0) { pFile = fopen(path, "rb"); - if (pFile) { - fseek(pFile, 0, SEEK_END); - m_FileSize = ftell(pFile); - fseek(pFile, 0, SEEK_SET); - m_nNumberOfBlocks = m_FileSize / (nChannels * VB_BLOCK_SIZE); - decoders = new CVagDecoder[nChannels]; - m_CurrentBlock = 0; - m_LineInBlock = 0; - m_bBlockRead = false; - ppTempBuffers = new uint8 * [nChannels]; - for (uint8 i = 0; i < nChannels; i++) - ppTempBuffers[i] = new uint8[VB_BLOCK_SIZE]; - } + if (!pFile) return; + + fseek(pFile, 0, SEEK_END); + m_FileSize = ftell(pFile); + fseek(pFile, 0, SEEK_SET); + m_nNumberOfBlocks = m_FileSize / (nChannels * VB_BLOCK_SIZE); + decoders = new CVagDecoder[nChannels]; + m_CurrentBlock = 0; + m_LineInBlock = 0; + m_bBlockRead = false; + ppTempBuffers = new uint8*[nChannels]; + buffers = new int16*[nChannels]; + for (uint8 i = 0; i < nChannels; i++) + ppTempBuffers[i] = new uint8[VB_BLOCK_SIZE]; } ~CVbFile() @@ -376,6 +668,7 @@ public: for (int i = 0; i < m_nChannels; i++) delete ppTempBuffers[i]; delete ppTempBuffers; + delete buffers; } } @@ -409,14 +702,14 @@ public: { if (!IsOpened()) return; uint32 samples = ms2samples(milliseconds); - int32 block = samples / NUM_VAG_SAMPLES_IN_BLOCK; + uint32 block = samples / NUM_VAG_SAMPLES_IN_BLOCK; if (block > m_nNumberOfBlocks) { samples = 0; block = 0; } if (block != m_CurrentBlock) - ReadBlock(block); + m_bBlockRead = false; uint32 remainingSamples = samples - block * NUM_VAG_SAMPLES_IN_BLOCK; uint32 newLine = remainingSamples / VAG_SAMPLES_IN_LINE / VAG_LINE_SIZE; @@ -425,7 +718,7 @@ public: { m_CurrentBlock = block; m_LineInBlock = newLine; - for (int i = 0; i < GetChannels(); i++) + for (uint32 i = 0; i < GetChannels(); i++) decoders[i].ResetState(); } @@ -448,18 +741,19 @@ public: if (m_CurrentBlock == m_nNumberOfBlocks) return 0; int size = 0; - int numberOfRequiredLines = GetBufferSamples() / GetChannels() / VAG_SAMPLES_IN_LINE; + int numberOfRequiredLines = GetBufferSamples() / m_nChannels / VAG_SAMPLES_IN_LINE; int numberOfRemainingLines = (m_nNumberOfBlocks - m_CurrentBlock) * NUM_VAG_LINES_IN_BLOCK - m_LineInBlock; int bufSizePerChannel = Min(numberOfRequiredLines, numberOfRemainingLines) * VAG_SAMPLES_IN_LINE * GetSampleSize(); if (numberOfRequiredLines > numberOfRemainingLines) numberOfRemainingLines = numberOfRemainingLines; - int16* buffers[2] = { (int16*)buffer, &((int16*)buffer)[bufSizePerChannel / GetSampleSize()] }; + for (uint32 i = 0; i < m_nChannels; i++) + buffers[i] = (int16*)((int8*)buffer + bufSizePerChannel * i); while (size < bufSizePerChannel) { - for (int i = 0; i < GetChannels(); i++) + for (uint32 i = 0; i < m_nChannels; i++) { decoders[i].Decode(ppTempBuffers[i] + m_LineInBlock * VAG_LINE_SIZE, buffers[i], VAG_LINE_SIZE); buffers[i] += VAG_SAMPLES_IN_LINE; @@ -476,7 +770,7 @@ public: } } - return bufSizePerChannel * GetChannels(); + return bufSizePerChannel * m_nChannels; } }; #else @@ -621,7 +915,11 @@ CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBU if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".mp3")], ".mp3")) m_pSoundFile = new CMP3File(m_aFilename); else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".wav")], ".wav")) +#ifdef AUDIO_OAL_USE_SNDFILE m_pSoundFile = new CSndFile(m_aFilename); +#else + m_pSoundFile = new CWavFile(m_aFilename); +#endif else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".vb")], ".VB")) m_pSoundFile = new CVbFile(m_aFilename, overrideSampleRate); #else @@ -922,12 +1220,15 @@ void CStream::Update() // Relying a lot on left buffer states in here - //alSourcef(m_pAlSources[0], AL_ROLLOFF_FACTOR, 0.0f); - alGetSourcei(m_pAlSources[0], AL_SOURCE_STATE, &sourceState[0]); - alGetSourcei(m_pAlSources[0], AL_BUFFERS_PROCESSED, &buffersProcessed[0]); - //alSourcef(m_pAlSources[1], AL_ROLLOFF_FACTOR, 0.0f); - alGetSourcei(m_pAlSources[1], AL_SOURCE_STATE, &sourceState[1]); - alGetSourcei(m_pAlSources[1], AL_BUFFERS_PROCESSED, &buffersProcessed[1]); + do + { + //alSourcef(m_pAlSources[0], AL_ROLLOFF_FACTOR, 0.0f); + alGetSourcei(m_pAlSources[0], AL_SOURCE_STATE, &sourceState[0]); + alGetSourcei(m_pAlSources[0], AL_BUFFERS_PROCESSED, &buffersProcessed[0]); + //alSourcef(m_pAlSources[1], AL_ROLLOFF_FACTOR, 0.0f); + alGetSourcei(m_pAlSources[1], AL_SOURCE_STATE, &sourceState[1]); + alGetSourcei(m_pAlSources[1], AL_BUFFERS_PROCESSED, &buffersProcessed[1]); + } while (buffersProcessed[0] != buffersProcessed[1]); ALint looping = AL_FALSE; alGetSourcei(m_pAlSources[0], AL_LOOPING, &looping); diff --git a/src/core/config.h b/src/core/config.h index 0199697b..764198b9 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -352,6 +352,7 @@ enum Config { #define RADIO_SCROLL_TO_PREV_STATION #define AUDIO_CACHE //#define PS2_AUDIO // changes audio paths for cutscenes and radio to PS2 paths, needs vbdec to support VB with MSS +//#define AUDIO_OAL_USE_SNDFILE // use libsndfile to decode WAVs instead of our internal decoder // IMG #define BIG_IMG // allows to read larger img files From 148383ff53845fdec41c65aeb0770df46864bd0e Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Wed, 6 Jan 2021 18:56:13 +0300 Subject: [PATCH 041/152] upd --- src/core/Radar.cpp | 2 +- src/render/Hud.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp index 7af51929..f8227bf7 100644 --- a/src/core/Radar.cpp +++ b/src/core/Radar.cpp @@ -1298,7 +1298,7 @@ void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &i #endif { #ifdef ASPECT_RATIO_SCALE -// The values are from from an early screenshot taken before R* broke radar +// The values are from an early screenshot taken before R* broke radar #define _RADAR_WIDTH ((CDraw::ms_bFixRadar) ? (82.0f) : (RADAR_WIDTH)) #define _RADAR_HEIGHT ((CDraw::ms_bFixRadar) ? (82.0f) : (RADAR_HEIGHT)) #else diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index b6f173c7..84146fba 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -1060,7 +1060,7 @@ void CHud::Draw() DrawRadar */ #ifdef ASPECT_RATIO_SCALE -// The values are from from an early screenshot taken before R* broke radar +// The values are from an early screenshot taken before R* broke radar #define _RADAR_WIDTH ((CDraw::ms_bFixRadar) ? (82.0f) : (RADAR_WIDTH)) #define _RADAR_HEIGHT ((CDraw::ms_bFixRadar) ? (82.0f) : (RADAR_HEIGHT)) #else From 4cb00d3801aebaed3d1f24e31fd7518323c89729 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Wed, 6 Jan 2021 17:22:05 +0100 Subject: [PATCH 042/152] Remove fastmath from premake's config --- premake5.lua | 4 ---- 1 file changed, 4 deletions(-) diff --git a/premake5.lua b/premake5.lua index c5812f24..e6f34c9f 100644 --- a/premake5.lua +++ b/premake5.lua @@ -125,11 +125,9 @@ workspace "re3" filter { "platforms:*x86*" } architecture "x86" - floatingpoint "Fast" filter { "platforms:*amd64*" } architecture "amd64" - floatingpoint "Fast" filter { "platforms:*arm*" } architecture "ARM" @@ -191,11 +189,9 @@ project "librw" filter { "platforms:*x86*" } architecture "x86" - floatingpoint "Fast" filter { "platforms:*amd64*" } architecture "amd64" - floatingpoint "Fast" filter "platforms:win*" staticruntime "on" From 145bd243e8fc0a25e18288cb9d012320aef8b43e Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Wed, 6 Jan 2021 17:56:23 +0100 Subject: [PATCH 043/152] Small fixes for new wav decoder --- src/audio/oal/stream.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index 0a5be049..2b1d37c2 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -193,9 +193,9 @@ class CWavFile : public IDecoder fclose(pFile); pFile = nil; } - if (AdpcmBlock) delete AdpcmBlock; - if (buffers) delete buffers; - if (decoders) delete decoders; + if (AdpcmBlock) delete[] AdpcmBlock; + if (buffers) delete[] buffers; + if (decoders) delete[] decoders; } public: From 36996af82b9f4b8d9d20335f8141347a51304e02 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Wed, 6 Jan 2021 18:14:44 +0100 Subject: [PATCH 044/152] Fixes for CVbFile --- src/audio/oal/stream.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index 2b1d37c2..c084f2a9 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -664,11 +664,11 @@ public: if (pFile) { fclose(pFile); - delete decoders; + delete[] decoders; for (int i = 0; i < m_nChannels; i++) - delete ppTempBuffers[i]; - delete ppTempBuffers; - delete buffers; + delete[] ppTempBuffers[i]; + delete[] ppTempBuffers; + delete[] buffers; } } From 02a28996f4028b49d70dfa573f9faf0578ed7244 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Wed, 6 Jan 2021 20:22:09 +0200 Subject: [PATCH 045/152] Cleanup and fixes for new decoders --- src/audio/oal/stream.cpp | 265 ++++++++++++++++++++++----------------- 1 file changed, 148 insertions(+), 117 deletions(-) diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index c084f2a9..f9c02821 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -174,35 +174,45 @@ class CWavFile : public IDecoder tFormatHeader() { memset(this, 0, sizeof(*this)); } }; - FILE* pFile; - bool bIsOpen; - tFormatHeader FormatHeader; + FILE *m_pFile; + bool m_bIsOpen; - uint32 DataStartOffset; - uint32 SampleCount; - uint32 SamplesPerBlock; + tFormatHeader m_FormatHeader; + + uint32 m_DataStartOffset; // TODO: 64 bit? + uint32 m_nSampleCount; + uint32 m_nSamplesPerBlock; // ADPCM things - uint8 *AdpcmBlock; - int16 **buffers; - CImaADPCMDecoder* decoders; + uint8 *m_pAdpcmBuffer; + int16 **m_ppPcmBuffers; + CImaADPCMDecoder *m_pAdpcmDecoders; void Close() { - if (pFile) { - fclose(pFile); - pFile = nil; + if (m_pFile) { + fclose(m_pFile); + m_pFile = nil; } - if (AdpcmBlock) delete[] AdpcmBlock; - if (buffers) delete[] buffers; - if (decoders) delete[] decoders; + delete[] m_pAdpcmBuffer; + delete[] m_ppPcmBuffers; + delete[] m_pAdpcmDecoders; + } + + uint32 GetCurrentSample() const + { + // TODO: 64 bit? + uint32 FilePos = ftell(m_pFile); + if (FilePos <= m_DataStartOffset) + return 0; + return (FilePos - m_DataStartOffset) / m_FormatHeader.BlockAlign * m_nSamplesPerBlock; } public: - CWavFile(const char* path) : bIsOpen(false), DataStartOffset(0), SampleCount(0), SamplesPerBlock(0), AdpcmBlock(nil), buffers(nil), decoders(nil) + CWavFile(const char* path) : m_bIsOpen(false), m_DataStartOffset(0), m_nSampleCount(0), m_nSamplesPerBlock(0), m_pAdpcmBuffer(nil), m_ppPcmBuffers(nil), m_pAdpcmDecoders(nil) { - pFile = fopen(path, "rb"); - if (!pFile) return; + m_pFile = fopen(path, "rb"); + if (!m_pFile) return; #define CLOSE_ON_ERROR(op)\ if (op) { \ @@ -212,52 +222,58 @@ public: tDataHeader DataHeader; - CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, pFile) == 0); + CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, m_pFile) == 0); CLOSE_ON_ERROR(DataHeader.ID != 'FFIR'); + // TODO? validate filesizes + int WAVE; - CLOSE_ON_ERROR(fread(&WAVE, 4, 1, pFile) == 0); + CLOSE_ON_ERROR(fread(&WAVE, 4, 1, m_pFile) == 0); CLOSE_ON_ERROR(WAVE != 'EVAW') - CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, pFile) == 0); + CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, m_pFile) == 0); CLOSE_ON_ERROR(DataHeader.ID != ' tmf'); - CLOSE_ON_ERROR(fread(&FormatHeader, Min(DataHeader.Size, sizeof(tFormatHeader)), 1, pFile) == 0); + CLOSE_ON_ERROR(fread(&m_FormatHeader, Min(DataHeader.Size, sizeof(tFormatHeader)), 1, m_pFile) == 0); CLOSE_ON_ERROR(DataHeader.Size > sizeof(tFormatHeader)); - switch (FormatHeader.AudioFormat) + switch (m_FormatHeader.AudioFormat) { case WAVEFMT_XBOX_ADPCM: - FormatHeader.AudioFormat = WAVEFMT_IMA_ADPCM; + m_FormatHeader.AudioFormat = WAVEFMT_IMA_ADPCM; case WAVEFMT_IMA_ADPCM: - SamplesPerBlock = (FormatHeader.BlockAlign / FormatHeader.NumChannels - 4) * 2 + 1; - AdpcmBlock = new uint8[FormatHeader.BlockAlign]; - buffers = new int16*[FormatHeader.NumChannels]; - decoders = new CImaADPCMDecoder[FormatHeader.NumChannels]; + m_nSamplesPerBlock = (m_FormatHeader.BlockAlign / m_FormatHeader.NumChannels - 4) * 2 + 1; + m_pAdpcmBuffer = new uint8[m_FormatHeader.BlockAlign]; + m_ppPcmBuffers = new int16*[m_FormatHeader.NumChannels]; + m_pAdpcmDecoders = new CImaADPCMDecoder[m_FormatHeader.NumChannels]; break; case WAVEFMT_PCM: - SamplesPerBlock = 1; - if (FormatHeader.BitsPerSample != 16) + m_nSamplesPerBlock = 1; + if (m_FormatHeader.BitsPerSample != 16) { - debug("Unsupported PCM (%d bits), only signed 16-bit is supported (%s)\n", FormatHeader.BitsPerSample, path); + debug("Unsupported PCM (%d bits), only signed 16-bit is supported (%s)\n", m_FormatHeader.BitsPerSample, path); + Close(); return; } break; default: - debug("Unsupported wav format 0x%x (%s)\n", FormatHeader.AudioFormat, path); + debug("Unsupported wav format 0x%x (%s)\n", m_FormatHeader.AudioFormat, path); + Close(); return; } while (true) { - CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, pFile) == 0); + CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, m_pFile) == 0); if (DataHeader.ID == 'atad') break; - fseek(pFile, DataHeader.Size, SEEK_CUR); + fseek(m_pFile, DataHeader.Size, SEEK_CUR); + // TODO? validate data size + // maybe check if there no extreme custom headers that might break this } - DataStartOffset = ftell(pFile); - SampleCount = DataHeader.Size / FormatHeader.BlockAlign * SamplesPerBlock; + m_DataStartOffset = ftell(m_pFile); + m_nSampleCount = DataHeader.Size / m_FormatHeader.BlockAlign * m_nSamplesPerBlock; - bIsOpen = true; + m_bIsOpen = true; #undef CLOSE_ON_ERROR } @@ -268,7 +284,7 @@ public: bool IsOpened() { - return bIsOpen; + return m_bIsOpen; } uint32 GetSampleSize() @@ -278,29 +294,29 @@ public: uint32 GetSampleCount() { - return SampleCount; + return m_nSampleCount; } uint32 GetSampleRate() { - return FormatHeader.SampleRate; + return m_FormatHeader.SampleRate; } uint32 GetChannels() { - return FormatHeader.NumChannels; + return m_FormatHeader.NumChannels; } void Seek(uint32 milliseconds) { if (!IsOpened()) return; - fseek(pFile, DataStartOffset + ms2samples(milliseconds) / SamplesPerBlock * FormatHeader.BlockAlign, SEEK_SET); + fseek(m_pFile, m_DataStartOffset + ms2samples(milliseconds) / m_nSamplesPerBlock * m_FormatHeader.BlockAlign, SEEK_SET); } uint32 Tell() { if (!IsOpened()) return 0; - return samples2ms((ftell(pFile) - DataStartOffset) / FormatHeader.BlockAlign * SamplesPerBlock); + return samples2ms(GetCurrentSample()); } #define SAMPLES_IN_LINE (8) @@ -309,52 +325,61 @@ public: { if (!IsOpened()) return 0; - if (FormatHeader.AudioFormat == WAVEFMT_PCM) + if (m_FormatHeader.AudioFormat == WAVEFMT_PCM) { - uint32 size = fread(buffer, 1, GetBufferSize(), pFile); - if (FormatHeader.NumChannels == 2) + // just read the file and sort the samples + uint32 size = fread(buffer, 1, GetBufferSize(), m_pFile); + if (m_FormatHeader.NumChannels == 2) SortStereoBuffer.SortStereo(buffer, size); return size; } - else if (FormatHeader.AudioFormat == WAVEFMT_IMA_ADPCM) + else if (m_FormatHeader.AudioFormat == WAVEFMT_IMA_ADPCM) { - uint32 MaxSamples = GetBufferSamples() / FormatHeader.NumChannels; - uint32 CurSample = (ftell(pFile) - DataStartOffset) / FormatHeader.BlockAlign * SamplesPerBlock; + // trim the buffer size if we're at the end of our file + uint32 nMaxSamples = GetBufferSamples() / m_FormatHeader.NumChannels; + uint32 nSamplesLeft = m_nSampleCount - GetCurrentSample(); + nMaxSamples = Min(nMaxSamples, nSamplesLeft); - MaxSamples = Min(MaxSamples, SampleCount - CurSample); - MaxSamples = MaxSamples / SamplesPerBlock * SamplesPerBlock; - uint32 OutBufSizePerChannel = MaxSamples * GetSampleSize(); - uint32 OutBufSize = OutBufSizePerChannel * FormatHeader.NumChannels; - int16** buffers = new int16*[FormatHeader.NumChannels]; - CImaADPCMDecoder* decoders = new CImaADPCMDecoder[FormatHeader.NumChannels]; - for (uint32 i = 0; i < FormatHeader.NumChannels; i++) - buffers[i] = (int16*)((int8*)buffer + OutBufSizePerChannel * i); + // align sample count to our block + nMaxSamples = nMaxSamples / m_nSamplesPerBlock * m_nSamplesPerBlock; + + // count the size of output buffer + uint32 OutBufSizePerChannel = nMaxSamples * GetSampleSize(); + uint32 OutBufSize = OutBufSizePerChannel * m_FormatHeader.NumChannels; + + // calculate the pointers to individual channel buffers + for (uint32 i = 0; i < m_FormatHeader.NumChannels; i++) + m_ppPcmBuffers[i] = (int16*)((int8*)buffer + OutBufSizePerChannel * i); uint32 samplesRead = 0; - while (samplesRead < MaxSamples) + while (samplesRead < nMaxSamples) { - uint8* AdpcmBuf = AdpcmBlock; - if (fread(AdpcmBlock, 1, FormatHeader.BlockAlign, pFile) == 0) + // read the file + uint8 *pAdpcmBuf = m_pAdpcmBuffer; + if (fread(m_pAdpcmBuffer, 1, m_FormatHeader.BlockAlign, m_pFile) == 0) return 0; - for (uint32 i = 0; i < FormatHeader.NumChannels; i++) + // get the first sample in adpcm block and initialise the decoder(s) + for (uint32 i = 0; i < m_FormatHeader.NumChannels; i++) { - int16 Sample = *(int16*)AdpcmBuf; - AdpcmBuf += sizeof(int16); - int16 Step = *(int16*)AdpcmBuf; - AdpcmBuf += sizeof(int16); - decoders[i].Init(Sample, Step); - *(buffers[i]) = Sample; - buffers[i]++; + int16 Sample = *(int16*)pAdpcmBuf; + pAdpcmBuf += sizeof(int16); + int16 Step = *(int16*)pAdpcmBuf; + pAdpcmBuf += sizeof(int16); + m_pAdpcmDecoders[i].Init(Sample, Step); + *(m_ppPcmBuffers[i]) = Sample; + m_ppPcmBuffers[i]++; } samplesRead++; - for (uint32 s = 1; s < SamplesPerBlock; s += SAMPLES_IN_LINE) + + // decode the rest of the block + for (uint32 s = 1; s < m_nSamplesPerBlock; s += SAMPLES_IN_LINE) { - for (uint32 i = 0; i < FormatHeader.NumChannels; i++) + for (uint32 i = 0; i < m_FormatHeader.NumChannels; i++) { - decoders[i].Decode(AdpcmBuf, buffers[i], SAMPLES_IN_LINE / 2); - AdpcmBuf += SAMPLES_IN_LINE / 2; - buffers[i] += SAMPLES_IN_LINE; + m_pAdpcmDecoders[i].Decode(pAdpcmBuf, m_ppPcmBuffers[i], SAMPLES_IN_LINE / 2); + pAdpcmBuf += SAMPLES_IN_LINE / 2; + m_ppPcmBuffers[i] += SAMPLES_IN_LINE; } samplesRead += SAMPLES_IN_LINE; } @@ -613,68 +638,68 @@ public: class CVbFile : public IDecoder { - FILE* pFile; - size_t m_FileSize; - size_t m_nNumberOfBlocks; - CVagDecoder* decoders; + FILE *m_pFile; + CVagDecoder *m_pVagDecoders; - uint32 m_nSampleRate; - uint8 m_nChannels; - bool m_bBlockRead; - uint16 m_LineInBlock; - size_t m_CurrentBlock; + size_t m_FileSize; + size_t m_nNumberOfBlocks; - uint8** ppTempBuffers; - int16** buffers; + uint32 m_nSampleRate; + uint8 m_nChannels; + bool m_bBlockRead; + uint16 m_LineInBlock; + size_t m_CurrentBlock; + + uint8 **m_ppVagBuffers; // buffers that cache actual ADPCM file data + int16 **m_ppPcmBuffers; void ReadBlock(int32 block = -1) { // just read next block if -1 if (block != -1) - fseek(pFile, block * m_nChannels * VB_BLOCK_SIZE, SEEK_SET); + fseek(m_pFile, block * m_nChannels * VB_BLOCK_SIZE, SEEK_SET); for (int i = 0; i < m_nChannels; i++) - fread(ppTempBuffers[i], VB_BLOCK_SIZE, 1, pFile); + fread(m_ppVagBuffers[i], VB_BLOCK_SIZE, 1, m_pFile); m_bBlockRead = true; } public: - CVbFile(const char* path, uint32 nSampleRate = 32000, uint8 nChannels = 2) : m_nSampleRate(nSampleRate), m_nChannels(nChannels), decoders(nil), ppTempBuffers(nil), buffers(nil), + CVbFile(const char* path, uint32 nSampleRate = 32000, uint8 nChannels = 2) : m_nSampleRate(nSampleRate), m_nChannels(nChannels), m_pVagDecoders(nil), m_ppVagBuffers(nil), m_ppPcmBuffers(nil), m_FileSize(0), m_nNumberOfBlocks(0), m_bBlockRead(false), m_LineInBlock(0), m_CurrentBlock(0) { - pFile = fopen(path, "rb"); - if (!pFile) return; + m_pFile = fopen(path, "rb"); + if (!m_pFile) return; + + fseek(m_pFile, 0, SEEK_END); + m_FileSize = ftell(m_pFile); + fseek(m_pFile, 0, SEEK_SET); - fseek(pFile, 0, SEEK_END); - m_FileSize = ftell(pFile); - fseek(pFile, 0, SEEK_SET); m_nNumberOfBlocks = m_FileSize / (nChannels * VB_BLOCK_SIZE); - decoders = new CVagDecoder[nChannels]; - m_CurrentBlock = 0; - m_LineInBlock = 0; - m_bBlockRead = false; - ppTempBuffers = new uint8*[nChannels]; - buffers = new int16*[nChannels]; + m_pVagDecoders = new CVagDecoder[nChannels]; + m_ppVagBuffers = new uint8*[nChannels]; + m_ppPcmBuffers = new int16*[nChannels]; for (uint8 i = 0; i < nChannels; i++) - ppTempBuffers[i] = new uint8[VB_BLOCK_SIZE]; + m_ppVagBuffers[i] = new uint8[VB_BLOCK_SIZE]; } ~CVbFile() { - if (pFile) + if (m_pFile) { - fclose(pFile); - delete[] decoders; + fclose(m_pFile); + + delete[] m_pVagDecoders; for (int i = 0; i < m_nChannels; i++) - delete[] ppTempBuffers[i]; - delete[] ppTempBuffers; - delete[] buffers; + delete[] m_ppVagBuffers[i]; + delete[] m_ppVagBuffers; + delete[] m_ppPcmBuffers; } } bool IsOpened() { - return pFile != nil; + return m_pFile != nil; } uint32 GetSampleSize() @@ -702,6 +727,8 @@ public: { if (!IsOpened()) return; uint32 samples = ms2samples(milliseconds); + + // find the block of our sample uint32 block = samples / NUM_VAG_SAMPLES_IN_BLOCK; if (block > m_nNumberOfBlocks) { @@ -711,6 +738,7 @@ public: if (block != m_CurrentBlock) m_bBlockRead = false; + // find a line of our sample within our block uint32 remainingSamples = samples - block * NUM_VAG_SAMPLES_IN_BLOCK; uint32 newLine = remainingSamples / VAG_SAMPLES_IN_LINE / VAG_LINE_SIZE; @@ -719,7 +747,7 @@ public: m_CurrentBlock = block; m_LineInBlock = newLine; for (uint32 i = 0; i < GetChannels(); i++) - decoders[i].ResetState(); + m_pVagDecoders[i].ResetState(); } } @@ -735,35 +763,38 @@ public: { if (!IsOpened()) return 0; + if (m_CurrentBlock >= m_nNumberOfBlocks) return 0; + + // cache current ADPCM block if (!m_bBlockRead) ReadBlock(m_CurrentBlock); - if (m_CurrentBlock == m_nNumberOfBlocks) return 0; - int size = 0; - + // trim the buffer size if we're at the end of our file int numberOfRequiredLines = GetBufferSamples() / m_nChannels / VAG_SAMPLES_IN_LINE; int numberOfRemainingLines = (m_nNumberOfBlocks - m_CurrentBlock) * NUM_VAG_LINES_IN_BLOCK - m_LineInBlock; int bufSizePerChannel = Min(numberOfRequiredLines, numberOfRemainingLines) * VAG_SAMPLES_IN_LINE * GetSampleSize(); - if (numberOfRequiredLines > numberOfRemainingLines) - numberOfRemainingLines = numberOfRemainingLines; - + // calculate the pointers to individual channel buffers for (uint32 i = 0; i < m_nChannels; i++) - buffers[i] = (int16*)((int8*)buffer + bufSizePerChannel * i); + m_ppPcmBuffers[i] = (int16*)((int8*)buffer + bufSizePerChannel * i); + int size = 0; while (size < bufSizePerChannel) { + // decode the VAG lines for (uint32 i = 0; i < m_nChannels; i++) { - decoders[i].Decode(ppTempBuffers[i] + m_LineInBlock * VAG_LINE_SIZE, buffers[i], VAG_LINE_SIZE); - buffers[i] += VAG_SAMPLES_IN_LINE; + m_pVagDecoders[i].Decode(m_ppVagBuffers[i] + m_LineInBlock * VAG_LINE_SIZE, m_ppPcmBuffers[i], VAG_LINE_SIZE); + m_ppPcmBuffers[i] += VAG_SAMPLES_IN_LINE; } size += VAG_SAMPLES_IN_LINE * GetSampleSize(); m_LineInBlock++; + + // block is over, read the next block if (m_LineInBlock >= NUM_VAG_LINES_IN_BLOCK) { m_CurrentBlock++; - if (m_CurrentBlock >= m_nNumberOfBlocks) + if (m_CurrentBlock >= m_nNumberOfBlocks) // end of file break; m_LineInBlock = 0; ReadBlock(); From 416a898943e5853c650799826b0e29117919bded Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Thu, 7 Jan 2021 16:33:42 +0300 Subject: [PATCH 046/152] minor refactoring --- src/control/Garages.h | 12 +--- src/control/Script.cpp | 104 +++++++---------------------------- src/control/Script.h | 67 +++++++++++----------- src/control/Script3.cpp | 4 +- src/control/Script5.cpp | 74 +++++++++++++++++++++++++ src/control/Script6.cpp | 10 ++-- src/control/ScriptCommands.h | 2 +- src/core/config.h | 5 ++ 8 files changed, 143 insertions(+), 135 deletions(-) diff --git a/src/control/Garages.h b/src/control/Garages.h index 34b74fb6..ee5ac4d3 100644 --- a/src/control/Garages.h +++ b/src/control/Garages.h @@ -81,6 +81,7 @@ VALIDATE_SIZE(CStoredCar, 0x28); class CGarage { +public: uint8 m_eGarageType; uint8 m_eGarageState; bool field_2; // unused @@ -167,9 +168,6 @@ class CGarage void FindDoorsEntitiesSectorList(CPtrList&, bool); void PlayerArrestedOrDied(); - friend class CGarages; - friend class cAudioManager; - friend class CCamera; }; VALIDATE_SIZE(CGarage, 140); @@ -179,6 +177,7 @@ class CGarages enum { MESSAGE_LENGTH = 8 }; +public: static int32 BankVansCollected; static bool BombsAreFree; static bool RespraysAreFree; @@ -200,7 +199,6 @@ class CGarages static CStoredCar aCarsInSafeHouse3[NUM_GARAGE_STORED_CARS]; static bool bCamShouldBeOutisde; -public: static void Init(void); #ifndef PS2 static void Shutdown(void); @@ -240,7 +238,6 @@ public: static void SetFreeBombs(bool bValue) { BombsAreFree = bValue; } static void SetFreeResprays(bool bValue) { RespraysAreFree = bValue; } -private: static bool IsCarSprayable(CVehicle*); static float FindDoorHeightForMI(int32); static void CloseHideOutGaragesBeforeSave(void); @@ -249,9 +246,4 @@ private: static int32 GetBombTypeForGarageType(uint8 type) { return type - GARAGE_BOMBSHOP1 + 1; } static int32 GetCarsCollectedIndexForGarageType(uint8 type) { return type - GARAGE_COLLECTCARS_1; } - friend class cAudioManager; - friend class CGarage; -#ifdef FIX_BUGS - friend class CReplay; -#endif }; diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 63f1f2e1..136244fa 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -1225,7 +1225,7 @@ const tScriptCommandData commands[] = { REGISTER_COMMAND(COMMAND_SET_JAMES_CAR_ON_PATH_TO_PLAYER, INPUT_ARGUMENTS(ARGTYPE_INT,), OUTPUT_ARGUMENTS(), false, -1, ""), REGISTER_COMMAND(COMMAND_LOAD_END_OF_GAME_TUNE, INPUT_ARGUMENTS(), OUTPUT_ARGUMENTS(), false, -1, ""), REGISTER_COMMAND(COMMAND_ENABLE_PLAYER_CONTROL_CAMERA, INPUT_ARGUMENTS(), OUTPUT_ARGUMENTS(), false, -1, ""), -#ifndef GTA_PS2 +#if GTA_VERSION > GTA3_PS2_160 REGISTER_COMMAND(COMMAND_SET_OBJECT_ROTATION, INPUT_ARGUMENTS(ARGTYPE_INT, ARGTYPE_FLOAT, ARGTYPE_FLOAT, ARGTYPE_FLOAT,), OUTPUT_ARGUMENTS(), false, -1, ""), REGISTER_COMMAND(COMMAND_GET_DEBUG_CAMERA_COORDINATES, INPUT_ARGUMENTS(), OUTPUT_ARGUMENTS(ARGTYPE_FLOAT, ARGTYPE_FLOAT, ARGTYPE_FLOAT,), false, -1, ""), REGISTER_COMMAND(COMMAND_GET_DEBUG_CAMERA_FRONT_VECTOR, INPUT_ARGUMENTS(), OUTPUT_ARGUMENTS(ARGTYPE_FLOAT, ARGTYPE_FLOAT, ARGTYPE_FLOAT,), false, -1, ""), @@ -1444,10 +1444,16 @@ void CUpsideDownCarCheck::Init() bool CUpsideDownCarCheck::IsCarUpsideDown(int32 id) { - CVehicle* v = CPools::GetVehiclePool()->GetAt(id); - return v->GetUp().z <= -0.97f && - v->GetMoveSpeed().Magnitude() < 0.01f && - v->GetTurnSpeed().Magnitude() < 0.02f; + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(id); + return IsCarUpsideDown(pVehicle); +} + +bool CUpsideDownCarCheck::IsCarUpsideDown(CVehicle* pVehicle) +{ + assert(pVehicle); + return pVehicle->GetUp().z <= UPSIDEDOWN_UP_THRESHOLD && + pVehicle->GetMoveSpeed().Magnitude() < UPSIDEDOWN_MOVE_SPEED_THRESHOLD && + pVehicle->GetTurnSpeed().Magnitude() < UPSIDEDOWN_TURN_SPEED_THRESHOLD; } void CUpsideDownCarCheck::UpdateTimers() @@ -1470,7 +1476,7 @@ void CUpsideDownCarCheck::UpdateTimers() bool CUpsideDownCarCheck::AreAnyCarsUpsideDown() { for (int i = 0; i < MAX_UPSIDEDOWN_CAR_CHECKS; i++){ - if (m_sCars[i].m_nVehicleIndex >= 0 && m_sCars[i].m_nUpsideDownTimer > 1000) + if (m_sCars[i].m_nVehicleIndex >= 0 && m_sCars[i].m_nUpsideDownTimer > UPSIDEDOWN_TIMER_THRESHOLD) return true; } return false; @@ -1481,8 +1487,10 @@ void CUpsideDownCarCheck::AddCarToCheck(int32 id) uint16 index = 0; while (index < MAX_UPSIDEDOWN_CAR_CHECKS && m_sCars[index].m_nVehicleIndex >= 0) index++; +#ifdef FIX_BUGS if (index >= MAX_UPSIDEDOWN_CAR_CHECKS) return; +#endif m_sCars[index].m_nVehicleIndex = id; m_sCars[index].m_nUpsideDownTimer = 0; } @@ -1501,7 +1509,7 @@ bool CUpsideDownCarCheck::HasCarBeenUpsideDownForAWhile(int32 id) { for (int i = 0; i < MAX_UPSIDEDOWN_CAR_CHECKS; i++){ if (m_sCars[i].m_nVehicleIndex == id) - return m_sCars[i].m_nUpsideDownTimer > 1000; + return m_sCars[i].m_nUpsideDownTimer > UPSIDEDOWN_TIMER_THRESHOLD; } return false; } @@ -1551,7 +1559,10 @@ void CStuckCarCheck::AddCarToCheck(int32 id, float radius, uint32 time) int index = 0; while (index < MAX_STUCK_CAR_CHECKS && m_sCars[index].m_nVehicleIndex >= 0) index++; - /* Would be nice to return if index >= MAX_STUCK_CAR_CHECKS... */ +#ifdef FIX_BUGS + if (index >= MAX_STUCK_CAR_CHECKS) + return; +#endif m_sCars[index].m_nVehicleIndex = id; m_sCars[index].m_vecPos = pv->GetPosition(); m_sCars[index].m_nLastCheck = CTimer::GetTimeInMilliseconds(); @@ -2098,7 +2109,7 @@ int8 CRunningScript::ProcessOneCommand() retval = ProcessCommands800To899(command); else if (command < 1000) retval = ProcessCommands900To999(command); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 else if (command < 1200) retval = ProcessCommands1000To1099(command); #else @@ -4314,81 +4325,6 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) return -1; } - -void CRunningScript::Save(uint8*& buf) -{ -#ifdef COMPATIBLE_SAVES - SkipSaveBuf(buf, 8); - for (int i = 0; i < 8; i++) - WriteSaveBuf(buf, m_abScriptName[i]); - WriteSaveBuf(buf, m_nIp); -#ifdef CHECK_STRUCT_SIZES - static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6"); -#endif - for (int i = 0; i < MAX_STACK_DEPTH; i++) - WriteSaveBuf(buf, m_anStack[i]); - WriteSaveBuf(buf, m_nStackPointer); - SkipSaveBuf(buf, 2); -#ifdef CHECK_STRUCT_SIZES - static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18"); -#endif - for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++) - WriteSaveBuf(buf, m_anLocalVariables[i]); - WriteSaveBuf(buf, m_bCondResult); - WriteSaveBuf(buf, m_bIsMissionScript); - WriteSaveBuf(buf, m_bSkipWakeTime); - SkipSaveBuf(buf, 1); - WriteSaveBuf(buf, m_nWakeTime); - WriteSaveBuf(buf, m_nAndOrState); - WriteSaveBuf(buf, m_bNotFlag); - WriteSaveBuf(buf, m_bDeatharrestEnabled); - WriteSaveBuf(buf, m_bDeatharrestExecuted); - WriteSaveBuf(buf, m_bMissionFlag); - SkipSaveBuf(buf, 2); -#else - WriteSaveBuf(buf, *this); -#endif -} - -void CRunningScript::Load(uint8*& buf) -{ -#ifdef COMPATIBLE_SAVES - SkipSaveBuf(buf, 8); - for (int i = 0; i < 8; i++) - m_abScriptName[i] = ReadSaveBuf(buf); - m_nIp = ReadSaveBuf(buf); -#ifdef CHECK_STRUCT_SIZES - static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6"); -#endif - for (int i = 0; i < MAX_STACK_DEPTH; i++) - m_anStack[i] = ReadSaveBuf(buf); - m_nStackPointer = ReadSaveBuf(buf); - SkipSaveBuf(buf, 2); -#ifdef CHECK_STRUCT_SIZES - static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18"); -#endif - for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++) - m_anLocalVariables[i] = ReadSaveBuf(buf); - m_bCondResult = ReadSaveBuf(buf); - m_bIsMissionScript = ReadSaveBuf(buf); - m_bSkipWakeTime = ReadSaveBuf(buf); - SkipSaveBuf(buf, 1); - m_nWakeTime = ReadSaveBuf(buf); - m_nAndOrState = ReadSaveBuf(buf); - m_bNotFlag = ReadSaveBuf(buf); - m_bDeatharrestEnabled = ReadSaveBuf(buf); - m_bDeatharrestExecuted = ReadSaveBuf(buf); - m_bMissionFlag = ReadSaveBuf(buf); - SkipSaveBuf(buf, 2); -#else - CRunningScript* n = next; - CRunningScript* p = prev; - *this = ReadSaveBuf(buf); - next = n; - prev = p; -#endif -} - #ifdef MISSION_REPLAY bool CRunningScript::CanAllowMissionReplay() diff --git a/src/control/Script.h b/src/control/Script.h index 8cf6bb42..b18206e4 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -20,27 +20,32 @@ extern int32 ScriptParams[32]; void FlushLog(); #define script_assert(_Expression) FlushLog(); assert(_Expression); -#define PICKUP_PLACEMENT_OFFSET 0.5f -#define PED_FIND_Z_OFFSET 5.0f +#define PICKUP_PLACEMENT_OFFSET (0.5f) +#define PED_FIND_Z_OFFSET (5.0f) -#define SPHERE_MARKER_R 0 -#define SPHERE_MARKER_G 128 -#define SPHERE_MARKER_B 255 -#define SPHERE_MARKER_A 128 -#define SPHERE_MARKER_PULSE_PERIOD 2048 -#define SPHERE_MARKER_PULSE_FRACTION 0.1f +#define UPSIDEDOWN_UP_THRESHOLD (-0.97f) +#define UPSIDEDOWN_MOVE_SPEED_THRESHOLD (0.01f) +#define UPSIDEDOWN_TURN_SPEED_THRESHOLD (0.02f) +#define UPSIDEDOWN_TIMER_THRESHOLD (1000) + +#define SPHERE_MARKER_R (0) +#define SPHERE_MARKER_G (128) +#define SPHERE_MARKER_B (255) +#define SPHERE_MARKER_A (128) +#define SPHERE_MARKER_PULSE_PERIOD (2048) +#define SPHERE_MARKER_PULSE_FRACTION (0.1f) #ifdef USE_PRECISE_MEASUREMENT_CONVERTION -#define METERS_IN_FOOT 0.3048f -#define FEET_IN_METER 3.28084f +#define METERS_IN_FOOT (0.3048f) +#define FEET_IN_METER (3.28084f) #else -#define METERS_IN_FOOT 0.3f -#define FEET_IN_METER 3.33f +#define METERS_IN_FOOT (0.3f) +#define FEET_IN_METER (3.33f) #endif -#define KEY_LENGTH_IN_SCRIPT 8 +#define KEY_LENGTH_IN_SCRIPT (8) -#if GTA_VERSION <= GTA_PS2_160 +#if GTA_VERSION <= GTA3_PS2_160 #define GTA_SCRIPT_COLLECTIVE #endif @@ -95,8 +100,8 @@ struct intro_text_line m_bCentered = false; m_bBackground = false; m_bBackgroundOnly = false; - m_fWrapX = 182.0f; /* TODO: scaling as bugfix */ - m_fCenterSize = 640.0f; /* --||-- */ + m_fWrapX = 182.0f; + m_fCenterSize = DEFAULT_SCREEN_WIDTH; m_sBackgroundColor = CRGBA(128, 128, 128, 128); m_bTextProportional = true; m_bTextBeforeFade = false; @@ -162,7 +167,7 @@ public: void Process(); }; -struct CUpsideDownCarCheckEntry +struct upsidedown_car_data { int32 m_nVehicleIndex; uint32 m_nUpsideDownTimer; @@ -170,11 +175,12 @@ struct CUpsideDownCarCheckEntry class CUpsideDownCarCheck { - CUpsideDownCarCheckEntry m_sCars[MAX_UPSIDEDOWN_CAR_CHECKS]; + upsidedown_car_data m_sCars[MAX_UPSIDEDOWN_CAR_CHECKS]; public: void Init(); bool IsCarUpsideDown(int32); + bool IsCarUpsideDown(CVehicle*); void UpdateTimers(); bool AreAnyCarsUpsideDown(); void AddCarToCheck(int32); @@ -192,7 +198,7 @@ struct stuck_car_data bool m_bStuck; stuck_car_data() { } - inline void Reset(); + void Reset(); }; class CStuckCarCheck @@ -269,6 +275,7 @@ enum { class CTheScripts { +public: static uint8 ScriptSpace[SIZE_SCRIPT_SPACE]; static CRunningScript ScriptsArray[MAX_NUM_SCRIPTS]; static int32 BaseBriefIdForContact[MAX_NUM_CONTACTS]; @@ -310,7 +317,6 @@ class CTheScripts static uint16 CommandsExecuted; static uint16 ScriptsUpdated; -public: static void Init(); static void Process(); @@ -367,8 +373,6 @@ public: return Read4BytesFromScript(&tmp); } -private: - static CRunningScript* StartNewScript(uint32); static void CleanUpThisVehicle(CVehicle*); @@ -418,13 +422,6 @@ private: static void SetObjectiveForAllPedsInCollective(int, eObjective); #endif - friend class CRunningScript; - friend class CHud; - friend void CMissionCleanup::Process(); -#ifdef MISSION_REPLAY - friend void RetryMission(int, int); -#endif - #ifdef MISSION_SWITCHER public: static void SwitchToMission(int32 mission); @@ -433,7 +430,11 @@ public: enum { - MAX_STACK_DEPTH = 6, // 4 PS2 +#if GTA_VERSION > GTA3_PS2_160 + MAX_STACK_DEPTH = 6, +#else + MAX_STACK_DEPTH = 4, +#endif NUM_LOCAL_VARS = 16, NUM_TIMERS = 2 }; @@ -460,6 +461,7 @@ class CRunningScript ORS_8 }; +public: CRunningScript* next; CRunningScript* prev; char m_abScriptName[8]; @@ -497,7 +499,6 @@ public: static const uint32 nSaveStructSize; -private: void CollectParameters(uint32*, int16); int32 CollectNextParameterWithoutIncreasingPC(uint32); int32* GetPointerToScriptVariable(uint32*, int16); @@ -519,7 +520,7 @@ private: int8 ProcessCommands800To899(int32); int8 ProcessCommands900To999(int32); int8 ProcessCommands1000To1099(int32); -#ifndef GTA_PS2 +#if GTA_VERSION > GTA3_PS2_160 int8 ProcessCommands1100To1199(int32); #endif void LocatePlayerCommand(int32, uint32*); @@ -575,8 +576,6 @@ private: return false; } } - - friend class CTheScripts; }; #ifdef MISSION_REPLAY diff --git a/src/control/Script3.cpp b/src/control/Script3.cpp index 9a37cb6c..add1c249 100644 --- a/src/control/Script3.cpp +++ b/src/control/Script3.cpp @@ -342,7 +342,7 @@ int8 CRunningScript::ProcessCommands500To599(int32 command) CollectParameters(&m_nIp, 1); CGarages::SetFreeBombs(ScriptParams[0] != 0); return 0; -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 case COMMAND_SET_POWERPOINT: { CollectParameters(&m_nIp, 7); @@ -376,7 +376,7 @@ int8 CRunningScript::ProcessCommands500To599(int32 command) return 0; } -#endif // GTA_PS2 +#endif // GTA_VERSION <= GTA3_PS2_160 case COMMAND_SET_ALL_TAXI_LIGHTS: CollectParameters(&m_nIp, 1); CAutomobile::SetAllTaxiLights(ScriptParams[0] != 0); diff --git a/src/control/Script5.cpp b/src/control/Script5.cpp index c7e190ac..7521fede 100644 --- a/src/control/Script5.cpp +++ b/src/control/Script5.cpp @@ -2075,6 +2075,80 @@ VALIDATESAVEBUF(size) #undef SCRIPT_DATA_SIZE +void CRunningScript::Save(uint8*& buf) +{ +#ifdef COMPATIBLE_SAVES + SkipSaveBuf(buf, 8); + for (int i = 0; i < 8; i++) + WriteSaveBuf(buf, m_abScriptName[i]); + WriteSaveBuf(buf, m_nIp); +#ifdef CHECK_STRUCT_SIZES + static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6"); +#endif + for (int i = 0; i < MAX_STACK_DEPTH; i++) + WriteSaveBuf(buf, m_anStack[i]); + WriteSaveBuf(buf, m_nStackPointer); + SkipSaveBuf(buf, 2); +#ifdef CHECK_STRUCT_SIZES + static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18"); +#endif + for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++) + WriteSaveBuf(buf, m_anLocalVariables[i]); + WriteSaveBuf(buf, m_bCondResult); + WriteSaveBuf(buf, m_bIsMissionScript); + WriteSaveBuf(buf, m_bSkipWakeTime); + SkipSaveBuf(buf, 1); + WriteSaveBuf(buf, m_nWakeTime); + WriteSaveBuf(buf, m_nAndOrState); + WriteSaveBuf(buf, m_bNotFlag); + WriteSaveBuf(buf, m_bDeatharrestEnabled); + WriteSaveBuf(buf, m_bDeatharrestExecuted); + WriteSaveBuf(buf, m_bMissionFlag); + SkipSaveBuf(buf, 2); +#else + WriteSaveBuf(buf, *this); +#endif +} + +void CRunningScript::Load(uint8*& buf) +{ +#ifdef COMPATIBLE_SAVES + SkipSaveBuf(buf, 8); + for (int i = 0; i < 8; i++) + m_abScriptName[i] = ReadSaveBuf(buf); + m_nIp = ReadSaveBuf(buf); +#ifdef CHECK_STRUCT_SIZES + static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6"); +#endif + for (int i = 0; i < MAX_STACK_DEPTH; i++) + m_anStack[i] = ReadSaveBuf(buf); + m_nStackPointer = ReadSaveBuf(buf); + SkipSaveBuf(buf, 2); +#ifdef CHECK_STRUCT_SIZES + static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18"); +#endif + for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++) + m_anLocalVariables[i] = ReadSaveBuf(buf); + m_bCondResult = ReadSaveBuf(buf); + m_bIsMissionScript = ReadSaveBuf(buf); + m_bSkipWakeTime = ReadSaveBuf(buf); + SkipSaveBuf(buf, 1); + m_nWakeTime = ReadSaveBuf(buf); + m_nAndOrState = ReadSaveBuf(buf); + m_bNotFlag = ReadSaveBuf(buf); + m_bDeatharrestEnabled = ReadSaveBuf(buf); + m_bDeatharrestExecuted = ReadSaveBuf(buf); + m_bMissionFlag = ReadSaveBuf(buf); + SkipSaveBuf(buf, 2); +#else + CRunningScript* n = next; + CRunningScript* p = prev; + *this = ReadSaveBuf(buf); + next = n; + prev = p; +#endif +} + void CTheScripts::ClearSpaceForMissionEntity(const CVector& pos, CEntity* pEntity) { static CColPoint aTempColPoints[MAX_COLLISION_POINTS]; diff --git a/src/control/Script6.cpp b/src/control/Script6.cpp index 77dae53a..0dbac139 100644 --- a/src/control/Script6.cpp +++ b/src/control/Script6.cpp @@ -33,9 +33,12 @@ #include "Zones.h" #include "main.h" +// NB: on PS2 this file did not exist; ProcessCommands1000To1099 was in Script5.cpp and ProcessCommands1100To1199 was only added on PC +// however to avoid redundant copies of code, Script6.cpp is used with PS2 defines + int8 CRunningScript::ProcessCommands1000To1099(int32 command) { -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 char tmp[48]; #endif switch (command) { @@ -746,7 +749,7 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command) pPed->m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER); return 0; } -#ifndef GTA_PS2 +#if GTA_VERSION > GTA3_PS2_160 default: script_assert(0); } @@ -838,8 +841,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) case COMMAND_ENABLE_PLAYER_CONTROL_CAMERA: CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_CAMERA); return 0; -#ifndef GTA_PS2 - // To be precise, on PS2 previous handlers were in 1000-1099 function +#if GTA_VERSION > GTA3_PS2_160 // These are "beta" VC commands (with bugs) case COMMAND_SET_OBJECT_ROTATION: { diff --git a/src/control/ScriptCommands.h b/src/control/ScriptCommands.h index b9067bea..a33275f7 100644 --- a/src/control/ScriptCommands.h +++ b/src/control/ScriptCommands.h @@ -1108,7 +1108,7 @@ enum { COMMAND_SET_JAMES_CAR_ON_PATH_TO_PLAYER, COMMAND_LOAD_END_OF_GAME_TUNE, COMMAND_ENABLE_PLAYER_CONTROL_CAMERA, -#ifndef GTA_PS2 +#if GTA_VERSION > GTA3_PS2_160 COMMAND_SET_OBJECT_ROTATION, COMMAND_GET_DEBUG_CAMERA_COORDINATES, COMMAND_GET_DEBUG_CAMERA_FRONT_VECTOR, diff --git a/src/core/config.h b/src/core/config.h index 764198b9..9e52311c 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -323,6 +323,11 @@ enum Config { #define USE_BASIC_SCRIPT_DEBUG_OUTPUT #endif +#ifdef MASTER +#undef USE_ADVANCED_SCRIPT_DEBUG_OUTPUT +#undef USE_BASIC_SCRIPT_DEBUG_OUTPUT +#endif + // Replay //#define DONT_FIX_REPLAY_BUGS // keeps various bugs in CReplay, some of which are fairly cool! //#define USE_BETA_REPLAY_MODE // adds another replay mode, a few seconds slomo (caution: buggy!) From 2173ceae95c49bafded7b014017c8b70ad04d935 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Thu, 7 Jan 2021 18:36:02 +0300 Subject: [PATCH 047/152] missing changes --- src/control/Script.cpp | 34 +++++++++++++++++----------------- src/control/Script.h | 4 ++-- src/control/Script2.cpp | 14 +++++++------- src/control/Script3.cpp | 6 +++--- src/control/Script4.cpp | 8 ++++---- src/control/Script6.cpp | 6 +++--- 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 136244fa..3563a2b4 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -73,7 +73,7 @@ uint16 CTheScripts::NumScriptDebugLines; uint16 CTheScripts::NumberOfIntroRectanglesThisFrame; uint16 CTheScripts::NumberOfIntroTextLinesThisFrame; uint8 CTheScripts::UseTextCommands; -CMissionCleanup CTheScripts::MissionCleanup; +CMissionCleanup CTheScripts::MissionCleanUp; CUpsideDownCarCheck CTheScripts::UpsideDownCars; CStuckCarCheck CTheScripts::StuckCars; uint16 CTheScripts::CommandsExecuted; @@ -1801,7 +1801,7 @@ void CTheScripts::Init() ScriptsArray[i].Init(); ScriptsArray[i].AddScriptToList(&pIdleScripts); } - MissionCleanup.Init(); + MissionCleanUp.Init(); UpsideDownCars.Init(); StuckCars.Init(); CFileMgr::SetDir("data"); @@ -3217,7 +3217,7 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) ScriptParams[0] = CPools::GetPedPool()->GetIndex(ped); StoreParameters(&m_nIp, 1); if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); + CTheScripts::MissionCleanUp.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); return 0; } case COMMAND_DELETE_CHAR: @@ -3243,7 +3243,7 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) --CPopulation::ms_nTotalMissionPeds; } if (m_bIsMissionScript) - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); + CTheScripts::MissionCleanUp.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); return 0; } case COMMAND_CHAR_WANDER_DIR: @@ -3462,7 +3462,7 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) ScriptParams[0] = handle; StoreParameters(&m_nIp, 1); if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(handle, CLEANUP_CAR); + CTheScripts::MissionCleanUp.AddEntityToList(handle, CLEANUP_CAR); return 0; } case COMMAND_DELETE_CAR: @@ -3475,7 +3475,7 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) delete car; } if (m_bIsMissionScript) - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CAR); + CTheScripts::MissionCleanUp.RemoveEntityFromList(ScriptParams[0], CLEANUP_CAR); return 0; } case COMMAND_CAR_GOTO_COORDINATES: @@ -3792,7 +3792,7 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) return 0; if (strcmp(m_abScriptName, "love3") == 0) /* A Drop in the Ocean */ CPickups::RemoveAllFloatingPickups(); - CTheScripts::MissionCleanup.Process(); + CTheScripts::MissionCleanUp.Process(); return 0; } case COMMAND_STORE_CAR_CHAR_IS_IN: @@ -3815,7 +3815,7 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) pOld->bIsLocked = false; CCarCtrl::NumRandomCars++; CCarCtrl::NumMissionCars--; - CTheScripts::MissionCleanup.RemoveEntityFromList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); + CTheScripts::MissionCleanUp.RemoveEntityFromList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); } } @@ -3826,14 +3826,14 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) CCarCtrl::NumMissionCars++; CCarCtrl::NumRandomCars--; CTheScripts::StoreVehicleWasRandom = true; - CTheScripts::MissionCleanup.AddEntityToList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); + CTheScripts::MissionCleanUp.AddEntityToList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); break; case PARKED_VEHICLE: pCurrent->VehicleCreatedBy = MISSION_VEHICLE; CCarCtrl::NumMissionCars++; CCarCtrl::NumParkedCars--; CTheScripts::StoreVehicleWasRandom = true; - CTheScripts::MissionCleanup.AddEntityToList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); + CTheScripts::MissionCleanUp.AddEntityToList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); break; case MISSION_VEHICLE: case PERMANENT_VEHICLE: @@ -3866,7 +3866,7 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) pOld->bIsLocked = false; CCarCtrl::NumRandomCars++; CCarCtrl::NumMissionCars--; - CTheScripts::MissionCleanup.RemoveEntityFromList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); + CTheScripts::MissionCleanUp.RemoveEntityFromList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); } } @@ -3877,14 +3877,14 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) CCarCtrl::NumMissionCars++; CCarCtrl::NumRandomCars--; CTheScripts::StoreVehicleWasRandom = true; - CTheScripts::MissionCleanup.AddEntityToList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); + CTheScripts::MissionCleanUp.AddEntityToList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); break; case PARKED_VEHICLE: pCurrent->VehicleCreatedBy = MISSION_VEHICLE; CCarCtrl::NumMissionCars++; CCarCtrl::NumParkedCars--; CTheScripts::StoreVehicleWasRandom = true; - CTheScripts::MissionCleanup.AddEntityToList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); + CTheScripts::MissionCleanUp.AddEntityToList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); break; case MISSION_VEHICLE: case PERMANENT_VEHICLE: @@ -4035,7 +4035,7 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) ScriptParams[0] = CPools::GetObjectPool()->GetIndex(pObj); StoreParameters(&m_nIp, 1); if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_OBJECT); + CTheScripts::MissionCleanUp.AddEntityToList(ScriptParams[0], CLEANUP_OBJECT); return 0; } case COMMAND_DELETE_OBJECT: @@ -4048,7 +4048,7 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) delete pObj; } if (m_bIsMissionScript) - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_OBJECT); + CTheScripts::MissionCleanUp.RemoveEntityFromList(ScriptParams[0], CLEANUP_OBJECT); return 0; } case COMMAND_ADD_SCORE: @@ -4273,7 +4273,7 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPed); StoreParameters(&m_nIp, 1); if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); + CTheScripts::MissionCleanUp.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); return 0; } case COMMAND_WARP_PLAYER_FROM_CAR_TO_COORD: @@ -4359,7 +4359,7 @@ void RetryMission(int type, int unk) else if (type == 2) { doingMissionRetry = false; AllowMissionReplay = 6; - CTheScripts::MissionCleanup.Process(); + CTheScripts::MissionCleanUp.Process(); } } diff --git a/src/control/Script.h b/src/control/Script.h index b18206e4..c0b69e0f 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -154,10 +154,10 @@ enum { class CMissionCleanup { +public: cleanup_entity_struct m_sEntities[MAX_CLEANUP]; uint8 m_nCount; -public: CMissionCleanup(); void Init(); @@ -292,7 +292,7 @@ public: static CStoredLine aStoredLines[MAX_NUM_STORED_LINES]; static bool DbgFlag; static uint32 OnAMissionFlag; - static CMissionCleanup MissionCleanup; + static CMissionCleanup MissionCleanUp; static CStuckCarCheck StuckCars; static CUpsideDownCarCheck UpsideDownCars; static int32 StoreVehicleIndex; diff --git a/src/control/Script2.cpp b/src/control/Script2.cpp index 562125c6..6cb078bb 100644 --- a/src/control/Script2.cpp +++ b/src/control/Script2.cpp @@ -1051,7 +1051,7 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); CTheScripts::CleanUpThisPed(pPed); if (m_bIsMissionScript) - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); + CTheScripts::MissionCleanUp.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); return 0; } case COMMAND_MARK_CAR_AS_NO_LONGER_NEEDED: @@ -1060,7 +1060,7 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); CTheScripts::CleanUpThisVehicle(pVehicle); if (m_bIsMissionScript) - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CAR); + CTheScripts::MissionCleanUp.RemoveEntityFromList(ScriptParams[0], CLEANUP_CAR); return 0; } case COMMAND_MARK_OBJECT_AS_NO_LONGER_NEEDED: @@ -1069,7 +1069,7 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); CTheScripts::CleanUpThisObject(pObject); if (m_bIsMissionScript) - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_OBJECT); + CTheScripts::MissionCleanUp.RemoveEntityFromList(ScriptParams[0], CLEANUP_OBJECT); return 0; } case COMMAND_DONT_REMOVE_CHAR: @@ -1077,7 +1077,7 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) CollectParameters(&m_nIp, 1); CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); script_assert(pPed); - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); + CTheScripts::MissionCleanUp.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); return 0; } case COMMAND_DONT_REMOVE_CAR: @@ -1085,7 +1085,7 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) CollectParameters(&m_nIp, 1); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); script_assert(pVehicle); - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CAR); + CTheScripts::MissionCleanUp.RemoveEntityFromList(ScriptParams[0], CLEANUP_CAR); return 0; } case COMMAND_DONT_REMOVE_OBJECT: @@ -1093,7 +1093,7 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) CollectParameters(&m_nIp, 1); CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); script_assert(pObject); - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_OBJECT); + CTheScripts::MissionCleanUp.RemoveEntityFromList(ScriptParams[0], CLEANUP_OBJECT); return 0; } case COMMAND_CREATE_CHAR_AS_PASSENGER: @@ -1165,7 +1165,7 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPed); StoreParameters(&m_nIp, 1); if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); + CTheScripts::MissionCleanUp.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); return 0; } case COMMAND_SET_CHAR_OBJ_KILL_CHAR_ON_FOOT: diff --git a/src/control/Script3.cpp b/src/control/Script3.cpp index add1c249..27277f0e 100644 --- a/src/control/Script3.cpp +++ b/src/control/Script3.cpp @@ -1263,7 +1263,7 @@ int8 CRunningScript::ProcessCommands600To699(int32 command) ScriptParams[0] = CPools::GetObjectPool()->GetIndex(pObj); StoreParameters(&m_nIp, 1); if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_OBJECT); + CTheScripts::MissionCleanUp.AddEntityToList(ScriptParams[0], CLEANUP_OBJECT); return 0; } case COMMAND_IS_BOAT: @@ -1799,7 +1799,7 @@ int8 CRunningScript::ProcessCommands700To799(int32 command) pPed->bRespondsToThreats = false; ++CPopulation::ms_nTotalMissionPeds; if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ped_handle, CLEANUP_CHAR); + CTheScripts::MissionCleanUp.AddEntityToList(ped_handle, CLEANUP_CHAR); } ScriptParams[0] = ped_handle; StoreParameters(&m_nIp, 1); @@ -1848,7 +1848,7 @@ int8 CRunningScript::ProcessCommands700To799(int32 command) pPed->bRespondsToThreats = false; ++CPopulation::ms_nTotalMissionPeds; if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ped_handle, CLEANUP_CHAR); + CTheScripts::MissionCleanUp.AddEntityToList(ped_handle, CLEANUP_CHAR); } ScriptParams[0] = ped_handle; StoreParameters(&m_nIp, 1); diff --git a/src/control/Script4.cpp b/src/control/Script4.cpp index 3c794859..d17334a9 100644 --- a/src/control/Script4.cpp +++ b/src/control/Script4.cpp @@ -148,7 +148,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) ++CCarCtrl::NumMissionCars; --CCarCtrl::NumRandomCars; if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(handle, CLEANUP_CAR); + CTheScripts::MissionCleanUp.AddEntityToList(handle, CLEANUP_CAR); } ScriptParams[0] = handle; StoreParameters(&m_nIp, 1); @@ -180,7 +180,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) ++CCarCtrl::NumMissionCars; --CCarCtrl::NumRandomCars; if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(handle, CLEANUP_CAR); + CTheScripts::MissionCleanUp.AddEntityToList(handle, CLEANUP_CAR); } ScriptParams[0] = handle; StoreParameters(&m_nIp, 1); @@ -594,7 +594,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) } } if (m_bIsMissionScript) - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); + CTheScripts::MissionCleanUp.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); return 0; } case COMMAND_SET_CHAR_STAY_IN_SAME_PLACE: @@ -1002,7 +1002,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) ScriptParams[0] = CPools::GetPedPool()->GetIndex(ped); StoreParameters(&m_nIp, 1); if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); + CTheScripts::MissionCleanUp.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); return 0; } case COMMAND_SET_CHAR_OBJ_STEAL_ANY_CAR: diff --git a/src/control/Script6.cpp b/src/control/Script6.cpp index 0dbac139..811b537f 100644 --- a/src/control/Script6.cpp +++ b/src/control/Script6.cpp @@ -607,7 +607,7 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command) ScriptParams[0] = CPools::GetVehiclePool()->GetIndex(pVehicle); StoreParameters(&m_nIp, 1); if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CAR); + CTheScripts::MissionCleanUp.AddEntityToList(ScriptParams[0], CLEANUP_CAR); return 0; } case COMMAND_START_BOAT_FOAM_ANIMATION: @@ -1121,7 +1121,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) pPed->bRespondsToThreats = false; ++CPopulation::ms_nTotalMissionPeds; if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ped_handle, CLEANUP_CHAR); + CTheScripts::MissionCleanUp.AddEntityToList(ped_handle, CLEANUP_CHAR); } ScriptParams[0] = ped_handle; StoreParameters(&m_nIp, 1); @@ -1168,7 +1168,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) pPed->bRespondsToThreats = false; ++CPopulation::ms_nTotalMissionPeds; if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ped_handle, CLEANUP_CHAR); + CTheScripts::MissionCleanUp.AddEntityToList(ped_handle, CLEANUP_CHAR); } ScriptParams[0] = ped_handle; StoreParameters(&m_nIp, 1); From 168d3d7ddbc4aebe8d673ab42b83c1ff2ee89066 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Thu, 7 Jan 2021 19:30:12 +0300 Subject: [PATCH 048/152] PS2 combinations for our cheats --- src/core/Pad.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index fd48ba97..7187efac 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -872,6 +872,30 @@ void CPad::AddToCheatString(char c) // "S1CD13TR1X" - SQUARE L1 CIRCLE DOWN L1 R1 TRIANGLE RIGHT L1 CROSS else if ( !_CHEATCMP("X1RT31DC1S") ) NastyLimbsCheat(); + +#ifdef KANGAROO_CHEAT + // "X1DUC3RLS3" - R1 SQUARE LEFT RIGHT R1 CIRCLE UP DOWN L1 CROSS + else if (!_CHEATCMP("X1DUC3RLS3")) + KangarooCheat(); +#endif + +#ifndef MASTER + // "31UD13XUD" - DOWN UP CROSS R1 L1 DOWN UP L1 R1 + else if (!_CHEATCMP("31UD13XUD")) + CPed::SwitchDebugDisplay(); +#endif + +#ifdef ALLCARSHELI_CHEAT + // "UCCL3R1TT" - TRIANGLE TRIANGLE L1 RIGHT R1 LEFT CIRCLE CIRCLE UP + else if (!_CHEATCMP("UCCL3R1TT")) + AllCarsHeliCheat(); +#endif + +#ifdef ALT_DODO_CHEAT + // "DUU31XX13" - R1 L1 CROSS CROSS L1 R1 UP UP DOWN + else if (!_CHEATCMP("DUU31XX13")) + AltDodoCheat(); +#endif #undef _CHEATCMP } #endif From ef13866af6e08797030865a33a1d5ba260a833bf Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Thu, 7 Jan 2021 22:01:44 +0200 Subject: [PATCH 049/152] Make opus available alongside other formats --- src/audio/oal/stream.cpp | 34 ++++++++++++++++++---------------- src/audio/sampman.h | 6 ++++-- src/audio/sampman_oal.cpp | 12 ++++++------ src/core/config.h | 14 +++++++++++++- 4 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index f9c02821..8c7b3232 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -4,20 +4,23 @@ #include "stream.h" #include "sampman.h" -#ifdef AUDIO_OPUS -#include -#else #ifdef _WIN32 #ifdef AUDIO_OAL_USE_SNDFILE #pragma comment( lib, "libsndfile-1.lib" ) #endif +#ifdef AUDIO_OAL_USE_MPG123 #pragma comment( lib, "libmpg123-0.lib" ) #endif +#endif #ifdef AUDIO_OAL_USE_SNDFILE #include #endif +#ifdef AUDIO_OAL_USE_MPG123 #include #endif +#ifdef AUDIO_OAL_USE_OPUS +#include +#endif #ifndef _WIN32 #include "crossplatform.h" @@ -81,7 +84,6 @@ public: CSortStereoBuffer SortStereoBuffer; -#ifndef AUDIO_OPUS class CImaADPCMDecoder { const uint16 StepTable[89] = { @@ -461,11 +463,9 @@ public: }; #endif -#ifdef _WIN32 +#ifdef AUDIO_OAL_USE_MPG123 // fuzzy seek eliminates stutter when playing ADF but spams errors a lot (nothing breaks though) #define MP3_USE_FUZZY_SEEK -#endif // _WIN32 - class CMP3File : public IDecoder { @@ -567,6 +567,7 @@ public: } }; +#endif #define VAG_LINE_SIZE (0x10) #define VAG_SAMPLES_IN_LINE (28) @@ -804,7 +805,7 @@ public: return bufSizePerChannel * m_nChannels; } }; -#else +#ifdef AUDIO_OAL_USE_OPUS class COpusFile : public IDecoder { OggOpusFile *m_FileH; @@ -902,14 +903,14 @@ public: void CStream::Initialise() { -#ifndef AUDIO_OPUS +#ifdef AUDIO_OAL_USE_MPG123 mpg123_init(); #endif } void CStream::Terminate() { -#ifndef AUDIO_OPUS +#ifdef AUDIO_OAL_USE_MPG123 mpg123_exit(); #endif } @@ -942,19 +943,20 @@ CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBU DEV("Stream %s\n", m_aFilename); -#ifndef AUDIO_OPUS - if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".mp3")], ".mp3")) - m_pSoundFile = new CMP3File(m_aFilename); - else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".wav")], ".wav")) + if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".wav")], ".wav")) #ifdef AUDIO_OAL_USE_SNDFILE m_pSoundFile = new CSndFile(m_aFilename); #else m_pSoundFile = new CWavFile(m_aFilename); +#endif +#ifdef AUDIO_OAL_USE_MPG123 + else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".mp3")], ".mp3")) + m_pSoundFile = new CMP3File(m_aFilename); #endif else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".vb")], ".VB")) m_pSoundFile = new CVbFile(m_aFilename, overrideSampleRate); -#else - if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".opus")], ".opus")) +#ifdef AUDIO_OAL_USE_OPUS + else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".opus")], ".opus")) m_pSoundFile = new COpusFile(m_aFilename); #endif else diff --git a/src/audio/sampman.h b/src/audio/sampman.h index 2284d385..72c3eb7f 100644 --- a/src/audio/sampman.h +++ b/src/audio/sampman.h @@ -218,7 +218,7 @@ extern uint32 BankStartOffset[MAX_SFX_BANKS]; extern int defaultProvider; #endif -#ifdef AUDIO_OPUS +#if defined(OPUS_AUDIO_PATHS) static char StreamedNameTable[][25] = { "AUDIO\\HEAD.OPUS", "AUDIO\\CLASS.OPUS", "AUDIO\\KJAH.OPUS", "AUDIO\\RISE.OPUS", "AUDIO\\LIPS.OPUS", "AUDIO\\GAME.OPUS", "AUDIO\\MSX.OPUS", "AUDIO\\FLASH.OPUS", "AUDIO\\CHAT.OPUS", "AUDIO\\HEAD.OPUS", "AUDIO\\POLICE.OPUS", "AUDIO\\CITY.OPUS", @@ -254,9 +254,9 @@ static char StreamedNameTable[][25] = { "AUDIO\\door_2.OPUS", "AUDIO\\door_3.OPUS", "AUDIO\\door_4.OPUS", "AUDIO\\door_5.OPUS", "AUDIO\\door_6.OPUS", "AUDIO\\t3_a.OPUS", "AUDIO\\t3_b.OPUS", "AUDIO\\t3_c.OPUS", "AUDIO\\k1_b.OPUS", "AUDIO\\cat1.OPUS"}; #else +#if defined(PS2_AUDIO_PATHS) static char StreamedNameTable[][25]= { -#ifdef PS2_AUDIO "AUDIO\\MUSIC\\HEAD.VB", "AUDIO\\MUSIC\\CLASS.VB", "AUDIO\\MUSIC\\KJAH.VB", @@ -353,6 +353,8 @@ static char StreamedNameTable[][25]= "AUDIO\\MUSIC\\MISCOM.VB", "AUDIO\\MUSIC\\END.VB", #else +static char StreamedNameTable[][25] = +{ "AUDIO\\HEAD.WAV", "AUDIO\\CLASS.WAV", "AUDIO\\KJAH.WAV", diff --git a/src/audio/sampman_oal.cpp b/src/audio/sampman_oal.cpp index 07d943e3..bb7f0aac 100644 --- a/src/audio/sampman_oal.cpp +++ b/src/audio/sampman_oal.cpp @@ -30,7 +30,7 @@ #include "MusicManager.h" #include "Frontend.h" #include "Timer.h" -#ifdef AUDIO_OPUS +#ifdef AUDIO_OAL_USE_OPUS #include #endif @@ -83,7 +83,7 @@ char SampleBankDescFilename[] = "audio/sfx.SDT"; char SampleBankDataFilename[] = "audio/sfx.RAW"; FILE *fpSampleDescHandle; -#ifdef AUDIO_OPUS +#ifdef OPUS_SFX OggOpusFile *fpSampleDataHandle; #else FILE *fpSampleDataHandle; @@ -1218,7 +1218,7 @@ cSampleManager::LoadSampleBank(uint8 nBank) return false; } -#ifdef AUDIO_OPUS +#ifdef OPUS_SFX int samplesRead = 0; int samplesSize = nSampleBankSize[nBank] / 2; op_pcm_seek(fpSampleDataHandle, 0); @@ -1331,7 +1331,7 @@ cSampleManager::LoadPedComment(uint32 nComment) } } -#ifdef AUDIO_OPUS +#ifdef OPUS_SFX int samplesRead = 0; int samplesSize = m_aSamples[nComment].nSize / 2; op_pcm_seek(fpSampleDataHandle, m_aSamples[nComment].nOffset / 2); @@ -1978,7 +1978,7 @@ cSampleManager::InitialiseSampleBanks(void) fpSampleDescHandle = fcaseopen(SampleBankDescFilename, "rb"); if ( fpSampleDescHandle == NULL ) return false; -#ifndef AUDIO_OPUS +#ifndef OPUS_SFX fpSampleDataHandle = fcaseopen(SampleBankDataFilename, "rb"); if ( fpSampleDataHandle == NULL ) { @@ -1996,7 +1996,7 @@ cSampleManager::InitialiseSampleBanks(void) fpSampleDataHandle = op_open_file(SampleBankDataFilename, &e); #endif fread(m_aSamples, sizeof(tSample), TOTAL_AUDIO_SAMPLES, fpSampleDescHandle); -#ifdef AUDIO_OPUS +#ifdef OPUS_SFX int32 _nSampleDataEndOffset = m_aSamples[TOTAL_AUDIO_SAMPLES - 1].nOffset + m_aSamples[TOTAL_AUDIO_SAMPLES - 1].nSize; #endif fclose(fpSampleDescHandle); diff --git a/src/core/config.h b/src/core/config.h index 9e52311c..295ddee0 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -356,9 +356,21 @@ enum Config { // Audio #define RADIO_SCROLL_TO_PREV_STATION #define AUDIO_CACHE -//#define PS2_AUDIO // changes audio paths for cutscenes and radio to PS2 paths, needs vbdec to support VB with MSS +//#define PS2_AUDIO_PATHS // changes audio paths for cutscenes and radio to PS2 paths (needs vbdec on MSS builds) //#define AUDIO_OAL_USE_SNDFILE // use libsndfile to decode WAVs instead of our internal decoder +#define AUDIO_OAL_USE_MPG123 // use mpg123 to support mp3 files +#ifdef AUDIO_OPUS +#define AUDIO_OAL_USE_OPUS // enable support of opus files +#define OPUS_AUDIO_PATHS // changes audio paths to opus paths (doesn't work if AUDIO_OAL_USE_OPUS isn't enabled) +#define OPUS_SFX // enable if your sfx.raw is encoded with opus (doesn't work if AUDIO_OAL_USE_OPUS isn't enabled) + +#ifndef AUDIO_OAL_USE_OPUS +#undef OPUS_AUDIO_PATHS +#undef OPUS_SFX +#endif + +#endif // IMG #define BIG_IMG // allows to read larger img files From d8a04c9e43f493362dd522f67929c850b8e45f49 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Thu, 7 Jan 2021 22:15:30 +0200 Subject: [PATCH 050/152] Add MPG123_QUIET to mp3 files --- src/audio/oal/stream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index 8c7b3232..ccb17577 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -484,7 +484,7 @@ public: if ( m_pMH ) { #ifdef MP3_USE_FUZZY_SEEK - mpg123_param(m_pMH, MPG123_FLAGS, MPG123_FUZZY | MPG123_SEEKBUFFER | MPG123_GAPLESS, 0.0); + mpg123_param(m_pMH, MPG123_FLAGS, MPG123_FUZZY | MPG123_SEEKBUFFER | MPG123_GAPLESS | MPG123_QUIET, 0.0); #endif long rate = 0; int channels = 0; From ec61964bcedfacb1c651a4d41a0dac33b3526748 Mon Sep 17 00:00:00 2001 From: aap Date: Fri, 8 Jan 2021 01:44:08 +0100 Subject: [PATCH 051/152] unused var --- src/vehicles/HandlingMgr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vehicles/HandlingMgr.cpp b/src/vehicles/HandlingMgr.cpp index fde280e8..00aaa682 100644 --- a/src/vehicles/HandlingMgr.cpp +++ b/src/vehicles/HandlingMgr.cpp @@ -191,7 +191,7 @@ void cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling) { // acceleration is in ms^-2, but we need mf^-2 where f is one frame time (50fps) - float velocity, a, b, specificVolume; + float velocity, a, b; handling->Transmission.fEngineAcceleration *= 1.0f/(50.0f*50.0f); handling->Transmission.fMaxVelocity *= 1000.0f/(60.0f*60.0f * 50.0f); From 223b49e3be40afa963a31e43f348d2e859c2e543 Mon Sep 17 00:00:00 2001 From: aap Date: Fri, 8 Jan 2021 13:51:50 +0100 Subject: [PATCH 052/152] little fixes --- src/core/FileMgr.cpp | 3 ++- src/core/FileMgr.h | 2 +- src/core/Streaming.cpp | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/core/FileMgr.cpp b/src/core/FileMgr.cpp index 99923ddf..32aa4041 100644 --- a/src/core/FileMgr.cpp +++ b/src/core/FileMgr.cpp @@ -241,7 +241,7 @@ CFileMgr::SetDirMyDocuments(void) } ssize_t -CFileMgr::LoadFile(const char *file, uint8 *buf, int unused, const char *mode) +CFileMgr::LoadFile(const char *file, uint8 *buf, int maxlen, const char *mode) { int fd; ssize_t n, len; @@ -257,6 +257,7 @@ CFileMgr::LoadFile(const char *file, uint8 *buf, int unused, const char *mode) return -1; #endif len += n; + assert(len < maxlen); }while(n == 0x4000); buf[len] = 0; myfclose(fd); diff --git a/src/core/FileMgr.h b/src/core/FileMgr.h index 98a78360..f70451b7 100644 --- a/src/core/FileMgr.h +++ b/src/core/FileMgr.h @@ -9,7 +9,7 @@ public: static void ChangeDir(const char *dir); static void SetDir(const char *dir); static void SetDirMyDocuments(void); - static ssize_t LoadFile(const char *file, uint8 *buf, int unused, const char *mode); + static ssize_t LoadFile(const char *file, uint8 *buf, int maxlen, const char *mode); static int OpenFile(const char *file, const char *mode); static int OpenFile(const char *file) { return OpenFile(file, "rb"); } static int OpenFileForWriting(const char *file); diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index 03b49fd6..dae7fadb 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -509,10 +509,18 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) mi = CModelInfo::GetModelInfo(streamId); // Txd has to be loaded +#ifdef FIX_BUGS + if(!HasTxdLoaded(mi->GetTxdSlot())){ +#else + // texDict will exist even if only first part has loaded if(CTxdStore::GetSlot(mi->GetTxdSlot())->texDict == nil){ +#endif debug("failed to load %s because TXD %s is not in memory\n", mi->GetName(), CTxdStore::GetTxdName(mi->GetTxdSlot())); RemoveModel(streamId); +#ifndef FIX_BUGS + // if we're just waiting for it to load, don't remove this RemoveTxd(mi->GetTxdSlot()); +#endif ReRequestModel(streamId); RwStreamClose(stream, &mem); return false; From 368d2f3279b474056e888dcccea234f32614b506 Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Fri, 8 Jan 2021 19:31:48 +0300 Subject: [PATCH 053/152] bb .ini hello defines --- src/core/Radar.cpp | 15 +++------------ src/core/Radar.h | 18 ++++++++++++++++++ src/core/common.h | 6 +----- src/core/config.h | 4 ++++ src/core/re3.cpp | 12 ------------ src/render/Draw.cpp | 20 +------------------- src/render/Draw.h | 15 --------------- src/render/Hud.cpp | 12 ++---------- src/render/Sprite.cpp | 9 ++++----- 9 files changed, 33 insertions(+), 78 deletions(-) diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp index f8227bf7..816da6b9 100644 --- a/src/core/Radar.cpp +++ b/src/core/Radar.cpp @@ -1297,21 +1297,12 @@ void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &i } else #endif { -#ifdef ASPECT_RATIO_SCALE -// The values are from an early screenshot taken before R* broke radar -#define _RADAR_WIDTH ((CDraw::ms_bFixRadar) ? (82.0f) : (RADAR_WIDTH)) -#define _RADAR_HEIGHT ((CDraw::ms_bFixRadar) ? (82.0f) : (RADAR_HEIGHT)) -#else -#define _RADAR_WIDTH RADAR_WIDTH -#define _RADAR_HEIGHT RADAR_HEIGHT -#endif - #ifdef FIX_BUGS - out.x = (in.x + 1.0f) * 0.5f * SCREEN_SCALE_X(_RADAR_WIDTH) + SCREEN_SCALE_X(RADAR_LEFT); + out.x = (in.x + 1.0f) * 0.5f * SCREEN_SCALE_X(RADAR_WIDTH) + SCREEN_SCALE_X(RADAR_LEFT); #else - out.x = (in.x + 1.0f) * 0.5f * SCREEN_SCALE_X(_RADAR_WIDTH) + RADAR_LEFT; + out.x = (in.x + 1.0f) * 0.5f * SCREEN_SCALE_X(RADAR_WIDTH) + RADAR_LEFT; #endif - out.y = (1.0f - in.y) * 0.5f * SCREEN_SCALE_Y(_RADAR_HEIGHT) + SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + _RADAR_HEIGHT); + out.y = (1.0f - in.y) * 0.5f * SCREEN_SCALE_Y(RADAR_HEIGHT) + SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT); } } diff --git a/src/core/Radar.h b/src/core/Radar.h index 5caf5bbb..725c8351 100644 --- a/src/core/Radar.h +++ b/src/core/Radar.h @@ -91,8 +91,26 @@ VALIDATE_SIZE(sRadarTrace, 0x30); #else #define RADAR_BOTTOM (47.0f) #endif + +#ifdef FIX_RADAR +/* + The values are from an early screenshot taken before R* broke radar +*/ +#define RADAR_WIDTH (82.0f) +#define RADAR_HEIGHT (82.0f) +#else +/* + broken since forever, someone tried to fix size for 640x512(PAL) + http://aap.rockstarvision.com/pics/gta3/ps2screens/gta3_interface.jpg + but failed: + http://aap.rockstarvision.com/pics/gta3/artwork/gta3_artwork_16.jpg + most likely the guy used something like this: + int y = 82 * (640.0/512.0)/(640.0/480.0); + int x = y * (640.0/512.0); +*/ #define RADAR_WIDTH (94.0f) #define RADAR_HEIGHT (76.0f) +#endif class CRadar { diff --git a/src/core/common.h b/src/core/common.h index 44d94370..5767b087 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -121,7 +121,7 @@ inline uint32 ldb(uint32 p, uint32 s, uint32 w) #include "skeleton.h" #include "Draw.h" -#if defined(ASPECT_RATIO_SCALE) +#if defined(PROPER_SCALING) || defined(PS2_HUD) #ifdef FORCE_PC_SCALING #define DEFAULT_SCREEN_WIDTH (640) #define DEFAULT_SCREEN_HEIGHT (448) @@ -176,10 +176,6 @@ inline uint32 ldb(uint32 p, uint32 s, uint32 w) #ifdef ASPECT_RATIO_SCALE #define SCREEN_SCALE_AR(a) ((a) * DEFAULT_ASPECT_RATIO / SCREEN_ASPECT_RATIO) #define SCALE_AND_CENTER_X(x) ((SCREEN_WIDTH == DEFAULT_SCREEN_WIDTH) ? (x) : (SCREEN_WIDTH - SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)) / 2 + SCREEN_SCALE_X((x))) - #ifndef FORCE_PC_SCALING - #undef SCREEN_SCALE_Y - #define SCREEN_SCALE_Y(a) CDraw::ScaleY(SCREEN_STRETCH_Y(a)) - #endif #else #define SCREEN_SCALE_AR(a) (a) #define SCALE_AND_CENTER_X(x) SCREEN_STRETCH_X(x) diff --git a/src/core/config.h b/src/core/config.h index a9bb1a17..3d5ef281 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -241,6 +241,7 @@ enum Config { //# define HARDCODED_MODEL_FLAGS // sets the flags enabled above from hardcoded model names. // NB: keep this enabled unless your map IDEs have these flags baked in #define ASPECT_RATIO_SCALE // Not just makes everything scale with aspect ratio, also adds support for all aspect ratios +#define PROPER_SCALING // use original DEFAULT_SCREEN_WIDTH/DEFAULT_SCREEN_HEIGHT from PS2 instead of PC(R* changed HEIGHT here to make radar look better, but broke other hud elements aspect ratio). #define DEFAULT_NATIVE_RESOLUTION // Set default video mode to your native resolution (fixes Windows 10 launch) #define USE_TXD_CDIMAGE // generate and load textures from txd.img #define PS2_ALPHA_TEST // emulate ps2 alpha test @@ -254,6 +255,8 @@ enum Config { #define SCREEN_DROPLETS // neo water droplets #endif +#define FIX_SPRITES // fix sprites aspect ratio(moon, coronas, particle etc) + #ifndef EXTENDED_COLOURFILTER #undef SCREEN_DROPLETS // we need the backbuffer for this effect #endif @@ -282,6 +285,7 @@ enum Config { #define HUD_ENHANCEMENTS // Adjusts some aspects to make the HUD look/behave a little bit better. // #define BETA_SLIDING_TEXT #define TRIANGULAR_BLIPS // height indicating triangular radar blips, as in VC +#define FIX_RADAR // use radar size from early version before R* broke it // #define XBOX_SUBTITLES // the infamous outlines #define RADIO_OFF_TEXT #define PC_MENU diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 14457db4..87244e2a 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -214,12 +214,6 @@ void LoadINISettings() CustomPipes::LightmapMult = CheckAndReadIniFloat("CustomPipesValues", "LightmapMult", CustomPipes::LightmapMult); CustomPipes::GlossMult = CheckAndReadIniFloat("CustomPipesValues", "GlossMult", CustomPipes::GlossMult); #endif - -#ifdef ASPECT_RATIO_SCALE - CDraw::ms_nScalingMode = CheckAndReadIniInt("Draw", "ScalingMode", CDraw::ms_nScalingMode); - CDraw::ms_bFixRadar = CheckAndReadIniInt("Draw", "FixRadar", CDraw::ms_bFixRadar); - CDraw::ms_bFixSprites = CheckAndReadIniInt("Draw", "FixSpritesAspectRatio", CDraw::ms_bFixSprites); -#endif } void SaveINISettings() @@ -259,12 +253,6 @@ void SaveINISettings() CheckAndSaveIniFloat("CustomPipesValues", "GlossMult", CustomPipes::GlossMult, changed); #endif -#ifdef ASPECT_RATIO_SCALE - CheckAndSaveIniInt("Draw", "ScalingMode", CDraw::ms_nScalingMode, changed); - CheckAndSaveIniInt("Draw", "FixRadar", CDraw::ms_bFixRadar, changed); - CheckAndSaveIniInt("Draw", "FixSpritesAspectRatio", CDraw::ms_bFixSprites, changed); -#endif - if (changed) cfg.write_file("re3.ini"); } diff --git a/src/render/Draw.cpp b/src/render/Draw.cpp index 42015176..fcd5d18f 100644 --- a/src/render/Draw.cpp +++ b/src/render/Draw.cpp @@ -20,12 +20,6 @@ uint8 CDraw::FadeRed; uint8 CDraw::FadeGreen; uint8 CDraw::FadeBlue; -#ifdef ASPECT_RATIO_SCALE -int32 CDraw::ms_nScalingMode = SCL_PS2; -int32 CDraw::ms_bFixRadar = true; -int32 CDraw::ms_bFixSprites = true; -#endif - float CDraw::FindAspectRatio(void) { @@ -81,16 +75,4 @@ CDraw::SetFOV(float fov) ms_fScaledFOV = fov; #endif ms_fFOV = fov; -} - -#ifdef ASPECT_RATIO_SCALE -float CDraw::ScaleY(float y) -{ - switch ( ms_nScalingMode ) - { - case SCL_PC: return y * ((float)DEFAULT_SCREEN_HEIGHT/SCREEN_HEIGHT_NTSC); - default: - return y; - } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/render/Draw.h b/src/render/Draw.h index bd97f76f..45f7906f 100644 --- a/src/render/Draw.h +++ b/src/render/Draw.h @@ -14,12 +14,6 @@ enum eAspectRatio AR_MAX, }; -enum eSpriteScalingMode -{ - SCL_PC, - SCL_PS2, -}; - class CDraw { private: @@ -40,11 +34,6 @@ public: static uint8 FadeRed; static uint8 FadeGreen; static uint8 FadeBlue; -#ifdef ASPECT_RATIO_SCALE - static int32 ms_nScalingMode; - static int32 ms_bFixRadar; - static int32 ms_bFixSprites; -#endif static void SetNearClipZ(float nearclip) { ms_fNearClipZ = nearclip; } static float GetNearClipZ(void) { return ms_fNearClipZ; } @@ -67,8 +56,4 @@ public: #else static float GetAspectRatio(void) { return FindAspectRatio(); } #endif - -#ifdef ASPECT_RATIO_SCALE - static float ScaleY(float y); -#endif }; diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 84146fba..ae7b7eb3 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -1059,18 +1059,10 @@ void CHud::Draw() /* DrawRadar */ -#ifdef ASPECT_RATIO_SCALE -// The values are from an early screenshot taken before R* broke radar -#define _RADAR_WIDTH ((CDraw::ms_bFixRadar) ? (82.0f) : (RADAR_WIDTH)) -#define _RADAR_HEIGHT ((CDraw::ms_bFixRadar) ? (82.0f) : (RADAR_HEIGHT)) -#else -#define _RADAR_WIDTH RADAR_WIDTH -#define _RADAR_HEIGHT RADAR_HEIGHT -#endif if (m_ItemToFlash == ITEM_RADAR && CTimer::GetFrameCounter() & 8 || m_ItemToFlash != ITEM_RADAR) { CRadar::DrawMap(); - CRect rect(0.0f, 0.0f, SCREEN_SCALE_X(_RADAR_WIDTH), SCREEN_SCALE_Y(_RADAR_HEIGHT)); - rect.Translate(SCREEN_SCALE_X_FIX(RADAR_LEFT), SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + _RADAR_HEIGHT)); + CRect rect(0.0f, 0.0f, SCREEN_SCALE_X(RADAR_WIDTH), SCREEN_SCALE_Y(RADAR_HEIGHT)); + rect.Translate(SCREEN_SCALE_X_FIX(RADAR_LEFT), SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT)); #ifdef PS2_HUD #ifdef FIX_BUGS diff --git a/src/render/Sprite.cpp b/src/render/Sprite.cpp index 390737f3..c31c75d2 100644 --- a/src/render/Sprite.cpp +++ b/src/render/Sprite.cpp @@ -37,13 +37,12 @@ CSprite::CalcScreenCoors(const RwV3d &in, RwV3d *out, float *outw, float *outh, // this is used to scale correctly if you zoom in with sniper rifle float fovScale = fov / CDraw::GetFOV(); +#ifdef FIX_SPRITES + *outw = fovScale * recip * SCREEN_HEIGHT; +#else *outw = fovScale * SCREEN_SCALE_AR(recip) * SCREEN_WIDTH; - *outh = fovScale * recip * SCREEN_HEIGHT; - -#ifdef ASPECT_RATIO_SCALE - if ( CDraw::ms_bFixSprites ) - *outw = fovScale * recip * SCREEN_HEIGHT; #endif + *outh = fovScale * recip * SCREEN_HEIGHT; return true; } From 8eed6ae1794989eb15fe95d867c44c196080c4dd Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Fri, 8 Jan 2021 21:50:59 +0200 Subject: [PATCH 054/152] Use original names --- src/animation/AnimBlendAssocGroup.cpp | 4 ++-- src/audio/AudioLogic.cpp | 2 +- src/control/Script5.cpp | 2 +- src/core/FileLoader.cpp | 24 ++++++++++++------------ src/core/Pools.cpp | 2 +- src/core/Streaming.cpp | 18 +++++++++--------- src/entities/Entity.cpp | 2 +- src/modelinfo/BaseModelInfo.h | 4 ++-- src/modelinfo/ClumpModelInfo.cpp | 4 ++-- src/modelinfo/ModelInfo.cpp | 2 +- src/modelinfo/PedModelInfo.cpp | 6 +++--- src/modelinfo/SimpleModelInfo.cpp | 2 +- src/modelinfo/TimeModelInfo.cpp | 4 ++-- src/peds/PedChat.cpp | 2 +- src/vehicles/Automobile.cpp | 4 ++-- 15 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/animation/AnimBlendAssocGroup.cpp b/src/animation/AnimBlendAssocGroup.cpp index fe419f2a..1d234bb8 100644 --- a/src/animation/AnimBlendAssocGroup.cpp +++ b/src/animation/AnimBlendAssocGroup.cpp @@ -111,7 +111,7 @@ GetModelFromName(const char *name) for(i = 0; i < MODELINFOSIZE; i++){ mi = CModelInfo::GetModelInfo(i); if(mi && mi->GetRwObject() && RwObjectGetType(mi->GetRwObject()) == rpCLUMP && - strcmpIgnoringDigits(mi->GetName(), name)) + strcmpIgnoringDigits(mi->GetModelName(), name)) return mi; } return nil; @@ -134,7 +134,7 @@ CAnimBlendAssocGroup::CreateAssociations(const char *name) CAnimBlendHierarchy *anim = CAnimManager::GetAnimation(animBlock->firstIndex + i); CBaseModelInfo *model = GetModelFromName(anim->name); assert(model); - printf("Associated anim %s with model %s\n", anim->name, model->GetName()); + printf("Associated anim %s with model %s\n", anim->name, model->GetModelName()); RpClump *clump = (RpClump*)model->CreateInstance(); #ifdef PED_SKIN if(IsClumpSkinned(clump)) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 976bbaec..777fdfe4 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -5788,7 +5788,7 @@ cAudioManager::GetCasualMaleOldTalkSfx(int16 sound) uint32 cAudioManager::GetSpecialCharacterTalkSfx(int32 modelIndex, int32 sound) { - char *modelName = CModelInfo::GetModelInfo(modelIndex)->GetName(); + char *modelName = CModelInfo::GetModelInfo(modelIndex)->GetModelName(); if (!CGeneral::faststricmp(modelName, "eight") || !CGeneral::faststricmp(modelName, "eight2")) { return GetEightTalkSfx(sound); } diff --git a/src/control/Script5.cpp b/src/control/Script5.cpp index 7521fede..751fefa2 100644 --- a/src/control/Script5.cpp +++ b/src/control/Script5.cpp @@ -2556,7 +2556,7 @@ void CTheScripts::UpdateObjectIndices() CBaseModelInfo* pModel = CModelInfo::GetModelInfo(j); if (!pModel) continue; - strcpy(name, pModel->GetName()); + strcpy(name, pModel->GetModelName()); #ifdef FIX_BUGS for (int k = 0; k < USED_OBJECT_NAME_LENGTH && name[k]; k++) #else diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index d847f473..22e0159c 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -445,7 +445,7 @@ bool CFileLoader::StartLoadClumpFile(RwStream *stream, uint32 id) { if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){ - printf("Start loading %s\n", CModelInfo::GetModelInfo(id)->GetName()); + printf("Start loading %s\n", CModelInfo::GetModelInfo(id)->GetModelName()); return RpClumpGtaStreamRead1(stream); }else{ printf("FAILED\n"); @@ -459,7 +459,7 @@ CFileLoader::FinishLoadClumpFile(RwStream *stream, uint32 id) RpClump *clump; CClumpModelInfo *mi; - printf("Finish loading %s\n", CModelInfo::GetModelInfo(id)->GetName()); + printf("Finish loading %s\n", CModelInfo::GetModelInfo(id)->GetModelName()); clump = RpClumpGtaStreamRead2(stream); if(clump){ @@ -1075,9 +1075,9 @@ SetModelInfoFlags(CSimpleModelInfo *mi, uint32 flags) #ifdef HARDCODED_MODEL_FLAGS // mobile sets these flags in CFileLoader::SetRelatedModelInfoCB, but that's stupid - if(MatchModelName(mi->GetName(), DoubleSidedNames)) mi->m_bIsDoubleSided = true; - if(MatchModelName(mi->GetName(), TreeNames)) mi->m_bIsTree = true; - if(MatchModelName(mi->GetName(), OptimizedNames)) mi->m_bCanBeIgnored = true; + if(MatchModelName(mi->GetModelName(), DoubleSidedNames)) mi->m_bIsDoubleSided = true; + if(MatchModelName(mi->GetModelName(), TreeNames)) mi->m_bIsTree = true; + if(MatchModelName(mi->GetModelName(), OptimizedNames)) mi->m_bCanBeIgnored = true; #endif #endif @@ -1119,7 +1119,7 @@ CFileLoader::LoadObject(const char *line) } mi = CModelInfo::AddSimpleModel(id); - mi->SetName(model); + mi->SetModelName(model); mi->SetNumAtomics(numObjs); mi->SetLodDistances(dist); SetModelInfoFlags(mi, flags); @@ -1138,7 +1138,7 @@ CFileLoader::LoadMLO(const char *line) sscanf(line, "%s %s %d %f", smth, name, &modelIndex, &someFloat); CMloModelInfo *minfo = CModelInfo::AddMloModel(modelIndex); - minfo->SetName(name); + minfo->SetModelName(name); minfo->field_34 = someFloat; int instId = CModelInfo::GetMloInstanceStore().allocPtr; minfo->firstInstance = instId; @@ -1216,7 +1216,7 @@ CFileLoader::LoadTimeObject(const char *line) } mi = CModelInfo::AddTimeModel(id); - mi->SetName(model); + mi->SetModelName(model); mi->SetNumAtomics(numObjs); mi->SetLodDistances(dist); SetModelInfoFlags(mi, flags); @@ -1238,7 +1238,7 @@ CFileLoader::LoadClumpObject(const char *line) if(sscanf(line, "%d %s %s", &id, model, txd) == 3){ mi = CModelInfo::AddClumpModel(id); - mi->SetName(model); + mi->SetModelName(model); mi->SetTexDictionary(txd); mi->SetColModel(&CTempColModels::ms_colModelBBox); } @@ -1262,7 +1262,7 @@ CFileLoader::LoadVehicleObject(const char *line) &frequency, &level, &comprules, &misc, &wheelScale); mi = CModelInfo::AddVehicleModel(id); - mi->SetName(model); + mi->SetModelName(model); mi->SetTexDictionary(txd); for(p = gamename; *p; p++) if(*p == '_') *p = ' '; @@ -1341,7 +1341,7 @@ CFileLoader::LoadPedObject(const char *line) return; mi = CModelInfo::AddPedModel(id); - mi->SetName(model); + mi->SetModelName(model); mi->SetTexDictionary(txd); mi->SetColModel(&CTempColModels::ms_colModelPed1); mi->m_pedType = CPedType::FindPedType(pedType); @@ -1815,7 +1815,7 @@ CFileLoader::ReloadObject(const char *line) #ifdef FIX_BUGS mi && #endif - mi->GetModelType() == MITYPE_SIMPLE && !strcmp(mi->GetName(), model) && mi->m_numAtomics == numObjs) { + mi->GetModelType() == MITYPE_SIMPLE && !strcmp(mi->GetModelName(), model) && mi->m_numAtomics == numObjs) { mi->SetLodDistances(dist); SetModelInfoFlags(mi, flags); } else { diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp index 79841c14..d3801a2a 100644 --- a/src/core/Pools.cpp +++ b/src/core/Pools.cpp @@ -485,7 +485,7 @@ INITSAVEBUF #endif CopyToBuf(buf, CWanted::MaximumWantedLevel); CopyToBuf(buf, CWanted::nMaximumWantedLevel); - memcpy(buf, CModelInfo::GetModelInfo(pPed->GetModelIndex())->GetName(), MAX_MODEL_NAME); + memcpy(buf, CModelInfo::GetModelInfo(pPed->GetModelIndex())->GetModelName(), MAX_MODEL_NAME); SkipSaveBuf(buf, MAX_MODEL_NAME); } } diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index dae7fadb..7b4218ba 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -515,7 +515,7 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) // texDict will exist even if only first part has loaded if(CTxdStore::GetSlot(mi->GetTxdSlot())->texDict == nil){ #endif - debug("failed to load %s because TXD %s is not in memory\n", mi->GetName(), CTxdStore::GetTxdName(mi->GetTxdSlot())); + debug("failed to load %s because TXD %s is not in memory\n", mi->GetModelName(), CTxdStore::GetTxdName(mi->GetTxdSlot())); RemoveModel(streamId); #ifndef FIX_BUGS // if we're just waiting for it to load, don't remove this @@ -557,7 +557,7 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) CTxdStore::RemoveRefWithoutDelete(mi->GetTxdSlot()); if(!success){ - debug("Failed to load %s\n", CModelInfo::GetModelInfo(streamId)->GetName()); + debug("Failed to load %s\n", CModelInfo::GetModelInfo(streamId)->GetModelName()); RemoveModel(streamId); ReRequestModel(streamId); RwStreamClose(stream, &mem); @@ -598,7 +598,7 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) if(!success){ ReRequestModel(streamId); if(streamId < STREAM_OFFSET_TXD) - debug("Failed to load %s.dff\n", mi->GetName()); + debug("Failed to load %s.dff\n", mi->GetModelName()); else debug("Failed to load %s.txd\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD)); return false; @@ -639,7 +639,7 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) timeDiff = endTime - startTime; if(timeDiff > 5){ if(streamId < STREAM_OFFSET_TXD) - debug("model %s took %d ms\n", CModelInfo::GetModelInfo(streamId)->GetName(), timeDiff); + debug("model %s took %d ms\n", CModelInfo::GetModelInfo(streamId)->GetModelName(), timeDiff); else debug("txd %s took %d ms\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD), timeDiff); } @@ -713,7 +713,7 @@ CStreaming::FinishLoadingLargeFile(int8 *buf, int32 streamId) timeDiff = endTime - startTime; if(timeDiff > 5){ if(streamId < STREAM_OFFSET_TXD) - debug("finish model %s took %d ms\n", CModelInfo::GetModelInfo(streamId)->GetName(), timeDiff); + debug("finish model %s took %d ms\n", CModelInfo::GetModelInfo(streamId)->GetModelName(), timeDiff); else debug("finish txd %s took %d ms\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD), timeDiff); } @@ -867,14 +867,14 @@ CStreaming::RequestSpecialModel(int32 modelId, const char *modelName, int32 flag uint32 pos, size; mi = CModelInfo::GetModelInfo(modelId); - if(!CGeneral::faststrcmp(mi->GetName(), modelName)){ + if(!CGeneral::faststrcmp(mi->GetModelName(), modelName)){ // Already have the correct name, just request it RequestModel(modelId, flags); return; } - strcpy(oldName, mi->GetName()); - mi->SetName(modelName); + strcpy(oldName, mi->GetModelName()); + mi->SetModelName(modelName); // What exactly is going on here? if(CModelInfo::GetModelInfo(oldName, nil)){ @@ -2775,7 +2775,7 @@ CStreaming::PrintStreamingBufferState() sprintf(str, "txd %s, refs %d, size %dK, flags 0x%x", CTxdStore::GetTxdName(modelIndex - STREAM_OFFSET_TXD), CTxdStore::GetNumRefs(modelIndex - STREAM_OFFSET_TXD), 2 * size, streamingInfo->m_flags); else - sprintf(str, "model %d,%s, refs%d, size%dK, flags%x", modelIndex, modelInfo->GetName(), modelInfo->GetNumRefs(), 2 * size, + sprintf(str, "model %d,%s, refs%d, size%dK, flags%x", modelIndex, modelInfo->GetModelName(), modelInfo->GetNumRefs(), 2 * size, streamingInfo->m_flags); AsciiToUnicode(str, wstr); CFont::PrintString(24.0f, y, wstr); diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index 91b417d0..7fcc3829 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -582,7 +582,7 @@ CEntity::SetupBigBuilding(void) if(m_level == LEVEL_GENERIC){ if(mi->GetTxdSlot() != CTxdStore::FindTxdSlot("generic")){ mi->SetTexDictionary("generic"); - printf("%d:%s txd has been set to generic\n", m_modelIndex, mi->GetName()); + printf("%d:%s txd has been set to generic\n", m_modelIndex, mi->GetModelName()); } } if(mi->m_lodDistances[0] > 2000.0f) diff --git a/src/modelinfo/BaseModelInfo.h b/src/modelinfo/BaseModelInfo.h index ae2b6668..3a94a83a 100644 --- a/src/modelinfo/BaseModelInfo.h +++ b/src/modelinfo/BaseModelInfo.h @@ -54,8 +54,8 @@ public: bool IsClump(void) { return m_type == MITYPE_CLUMP || m_type == MITYPE_PED || m_type == MITYPE_VEHICLE || m_type == MITYPE_MLO || m_type == MITYPE_XTRACOMPS; // unused but what the heck } - char *GetName(void) { return m_name; } - void SetName(const char *name) { strncpy(m_name, name, MAX_MODEL_NAME); } + char *GetModelName(void) { return m_name; } + void SetModelName(const char *name) { strncpy(m_name, name, MAX_MODEL_NAME); } void SetColModel(CColModel *col, bool owns = false){ m_colModel = col; m_bOwnsColModel = owns; } CColModel *GetColModel(void) { return m_colModel; } diff --git a/src/modelinfo/ClumpModelInfo.cpp b/src/modelinfo/ClumpModelInfo.cpp index 64bb5ed5..ec64977b 100644 --- a/src/modelinfo/ClumpModelInfo.cpp +++ b/src/modelinfo/ClumpModelInfo.cpp @@ -112,7 +112,7 @@ CClumpModelInfo::SetClump(RpClump *clump) } RpHAnimHierarchySetFlags(hier, (RpHAnimHierarchyFlag)(rpHANIMHIERARCHYUPDATEMODELLINGMATRICES|rpHANIMHIERARCHYUPDATELTMS)); } - if(strcmp(GetName(), "playerh") == 0){ + if(strcmp(GetModelName(), "playerh") == 0){ // playerh is incompatible with the xbox player skin // so check if player model is skinned and only apply skin to head if it isn't CPedModelInfo *body = (CPedModelInfo*)CModelInfo::GetModelInfo(MI_PLAYER); @@ -120,7 +120,7 @@ CClumpModelInfo::SetClump(RpClump *clump) RpClumpForAllAtomics(clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPlayerCB); } #else - if(strcmp(GetName(), "playerh") == 0){ + if(strcmp(GetModelName(), "playerh") == 0){ RpClumpForAllAtomics(clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPlayerCB); #endif } diff --git a/src/modelinfo/ModelInfo.cpp b/src/modelinfo/ModelInfo.cpp index dcde0df3..7aa5fc8b 100644 --- a/src/modelinfo/ModelInfo.cpp +++ b/src/modelinfo/ModelInfo.cpp @@ -192,7 +192,7 @@ CModelInfo::GetModelInfo(const char *name, int *id) CBaseModelInfo *modelinfo; for(int i = 0; i < MODELINFOSIZE; i++){ modelinfo = CModelInfo::ms_modelInfoPtrs[i]; - if(modelinfo && !CGeneral::faststricmp(modelinfo->GetName(), name)){ + if(modelinfo && !CGeneral::faststricmp(modelinfo->GetModelName(), name)){ if(id) *id = i; return modelinfo; diff --git a/src/modelinfo/PedModelInfo.cpp b/src/modelinfo/PedModelInfo.cpp index 38ce6d38..d0816467 100644 --- a/src/modelinfo/PedModelInfo.cpp +++ b/src/modelinfo/PedModelInfo.cpp @@ -97,7 +97,7 @@ CPedModelInfo::SetClump(RpClump *clump) #endif #ifdef PED_SKIN // CB has to be set here before atomics are detached from clump - if(strcmp(GetName(), "player") == 0) + if(strcmp(GetModelName(), "player") == 0) RpClumpForAllAtomics(clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPlayerCB); if(IsClumpSkinned(clump)){ LimbCBarg limbs = { this, clump, { 0, 0, 0 } }; @@ -108,7 +108,7 @@ CPedModelInfo::SetClump(RpClump *clump) if(m_hitColModel == nil && !IsClumpSkinned(clump)) CreateHitColModel(); // And again because CClumpModelInfo resets it - if(strcmp(GetName(), "player") == 0) + if(strcmp(GetModelName(), "player") == 0) RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPlayerCB); else if(IsClumpSkinned(clump)) // skinned peds have no low detail version, so they don't have the right render Cb @@ -118,7 +118,7 @@ CPedModelInfo::SetClump(RpClump *clump) SetFrameIds(m_pPedIds); if(m_hitColModel == nil) CreateHitColModel(); - if(strcmp(GetName(), "player") == 0) + if(strcmp(GetModelName(), "player") == 0) RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPlayerCB); #endif } diff --git a/src/modelinfo/SimpleModelInfo.cpp b/src/modelinfo/SimpleModelInfo.cpp index 416bdad5..55828b31 100644 --- a/src/modelinfo/SimpleModelInfo.cpp +++ b/src/modelinfo/SimpleModelInfo.cpp @@ -143,7 +143,7 @@ CSimpleModelInfo::FindRelatedModel(void) for(i = 0; i < MODELINFOSIZE; i++){ mi = CModelInfo::GetModelInfo(i); if(mi && mi != this && - !CGeneral::faststrcmp(GetName()+3, mi->GetName()+3)){ + !CGeneral::faststrcmp(GetModelName()+3, mi->GetModelName()+3)){ assert(mi->IsSimple()); this->SetRelatedModel((CSimpleModelInfo*)mi); return; diff --git a/src/modelinfo/TimeModelInfo.cpp b/src/modelinfo/TimeModelInfo.cpp index c1c18dac..0db5fb78 100644 --- a/src/modelinfo/TimeModelInfo.cpp +++ b/src/modelinfo/TimeModelInfo.cpp @@ -11,7 +11,7 @@ CTimeModelInfo::FindOtherTimeModel(void) char *p; int i; - strcpy(name, GetName()); + strcpy(name, GetModelName()); // change _nt to _dy if(p = strstr(name, "_nt")) strncpy(p, "_dy", 4); @@ -24,7 +24,7 @@ CTimeModelInfo::FindOtherTimeModel(void) for(i = 0; i < MODELINFOSIZE; i++){ CBaseModelInfo *mi = CModelInfo::GetModelInfo(i); if (mi && mi->GetModelType() == MITYPE_TIME && - !CGeneral::faststrncmp(name, mi->GetName(), MAX_MODEL_NAME)){ + !CGeneral::faststrncmp(name, mi->GetModelName(), MAX_MODEL_NAME)){ m_otherTimeModelID = i; return (CTimeModelInfo*)mi; } diff --git a/src/peds/PedChat.cpp b/src/peds/PedChat.cpp index 81e295c6..907f5756 100644 --- a/src/peds/PedChat.cpp +++ b/src/peds/PedChat.cpp @@ -59,7 +59,7 @@ CPed::ServiceTalking(void) if (bBodyPartJustCameOff && m_bodyPartBleeding == PED_HEAD) return; - if (!CGeneral::faststricmp(CModelInfo::GetModelInfo(GetModelIndex())->GetName(), "bomber")) + if (!CGeneral::faststricmp(CModelInfo::GetModelInfo(GetModelIndex())->GetModelName(), "bomber")) m_queuedSound = SOUND_PED_BOMBER; else if (m_nPedState == PED_ON_FIRE) m_queuedSound = SOUND_PED_BURNING; diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 753b853d..8f034126 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -4582,7 +4582,7 @@ CAutomobile::SetBumperDamage(int32 component, ePanels panel, bool noFlyingCompon int status = Damage.GetPanelStatus(panel); if(m_aCarNodes[component] == nil){ printf("Trying to damage component %d of %s\n", - component, CModelInfo::GetModelInfo(GetModelIndex())->GetName()); + component, CModelInfo::GetModelInfo(GetModelIndex())->GetModelName()); return; } if(status == PANEL_STATUS_SMASHED1){ @@ -4602,7 +4602,7 @@ CAutomobile::SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents int status = Damage.GetDoorStatus(door); if(m_aCarNodes[component] == nil){ printf("Trying to damage component %d of %s\n", - component, CModelInfo::GetModelInfo(GetModelIndex())->GetName()); + component, CModelInfo::GetModelInfo(GetModelIndex())->GetModelName()); return; } From 00d23c61d99a0a676de2219da42d576b5c5c0474 Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Fri, 8 Jan 2021 23:30:30 +0300 Subject: [PATCH 055/152] .ini for scaling, radar, sprites --- src/core/Radar.h | 7 +++++-- src/core/common.h | 6 ++++++ src/core/re3.cpp | 20 ++++++++++++++++++++ src/render/Draw.cpp | 19 ++++++++++++++++++- src/render/Draw.h | 14 ++++++++++++++ src/render/Sprite.cpp | 2 +- 6 files changed, 64 insertions(+), 4 deletions(-) diff --git a/src/core/Radar.h b/src/core/Radar.h index 725c8351..5b38d350 100644 --- a/src/core/Radar.h +++ b/src/core/Radar.h @@ -1,5 +1,6 @@ #pragma once #include "Sprite2d.h" +#include "Draw.h" enum eBlipType { @@ -95,9 +96,11 @@ VALIDATE_SIZE(sRadarTrace, 0x30); #ifdef FIX_RADAR /* The values are from an early screenshot taken before R* broke radar + #define RADAR_WIDTH (82.0f) + #define RADAR_HEIGHT (82.0f) */ -#define RADAR_WIDTH (82.0f) -#define RADAR_HEIGHT (82.0f) +#define RADAR_WIDTH ((CDraw::ms_bFixRadar) ? (82.0f) : (94.0f)) +#define RADAR_HEIGHT ((CDraw::ms_bFixRadar) ? (82.0f) : (76.0f)) #else /* broken since forever, someone tried to fix size for 640x512(PAL) diff --git a/src/core/common.h b/src/core/common.h index 5767b087..9253a465 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -176,6 +176,12 @@ inline uint32 ldb(uint32 p, uint32 s, uint32 w) #ifdef ASPECT_RATIO_SCALE #define SCREEN_SCALE_AR(a) ((a) * DEFAULT_ASPECT_RATIO / SCREEN_ASPECT_RATIO) #define SCALE_AND_CENTER_X(x) ((SCREEN_WIDTH == DEFAULT_SCREEN_WIDTH) ? (x) : (SCREEN_WIDTH - SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)) / 2 + SCREEN_SCALE_X((x))) +#ifdef PROPER_SCALING + #ifndef FORCE_PC_SCALING + #undef SCREEN_SCALE_Y + #define SCREEN_SCALE_Y(a) CDraw::ScaleY(SCREEN_STRETCH_Y(a)) + #endif +#endif #else #define SCREEN_SCALE_AR(a) (a) #define SCALE_AND_CENTER_X(x) SCREEN_STRETCH_X(x) diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 6f22e999..3cfc0ec0 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -214,6 +214,16 @@ void LoadINISettings() CustomPipes::LightmapMult = CheckAndReadIniFloat("CustomPipesValues", "LightmapMult", CustomPipes::LightmapMult); CustomPipes::GlossMult = CheckAndReadIniFloat("CustomPipesValues", "GlossMult", CustomPipes::GlossMult); #endif + +#ifdef PROPER_SCALING + CDraw::ms_bProperScaling = CheckAndReadIniInt("Draw", "ProperScaling", CDraw::ms_bProperScaling); +#endif +#ifdef FIX_SPRITES + CDraw::ms_bFixRadar = CheckAndReadIniInt("Draw", "FixRadar", CDraw::ms_bFixRadar); +#endif +#ifdef FIX_RADAR + CDraw::ms_bFixSprites = CheckAndReadIniInt("Draw", "FixSprites", CDraw::ms_bFixSprites); +#endif } void SaveINISettings() @@ -252,6 +262,16 @@ void SaveINISettings() CheckAndSaveIniFloat("CustomPipesValues", "GlossMult", CustomPipes::GlossMult, changed); #endif +#ifdef PROPER_SCALING + CheckAndSaveIniInt("Draw", "ProperScaling", CDraw::ms_bProperScaling, changed); +#endif +#ifdef FIX_SPRITES + CheckAndSaveIniInt("Draw", "FixRadar", CDraw::ms_bFixRadar, changed); +#endif +#ifdef FIX_RADAR + CheckAndSaveIniInt("Draw", "FixSprites", CDraw::ms_bFixSprites, changed); +#endif + if (changed) cfg.write_file("re3.ini"); } diff --git a/src/render/Draw.cpp b/src/render/Draw.cpp index fcd5d18f..f2fdad27 100644 --- a/src/render/Draw.cpp +++ b/src/render/Draw.cpp @@ -20,6 +20,16 @@ uint8 CDraw::FadeRed; uint8 CDraw::FadeGreen; uint8 CDraw::FadeBlue; +#ifdef PROPER_SCALING +int32 CDraw::ms_bProperScaling = true; +#endif +#ifdef FIX_SPRITES +int32 CDraw::ms_bFixRadar = true; +#endif +#ifdef FIX_RADAR +int32 CDraw::ms_bFixSprites = true; +#endif + float CDraw::FindAspectRatio(void) { @@ -75,4 +85,11 @@ CDraw::SetFOV(float fov) ms_fScaledFOV = fov; #endif ms_fFOV = fov; -} \ No newline at end of file +} + +#ifdef PROPER_SCALING +float CDraw::ScaleY(float y) +{ + return ms_bProperScaling ? y : y * ((float)DEFAULT_SCREEN_HEIGHT/SCREEN_HEIGHT_NTSC); +} +#endif \ No newline at end of file diff --git a/src/render/Draw.h b/src/render/Draw.h index 45f7906f..4f8f523d 100644 --- a/src/render/Draw.h +++ b/src/render/Draw.h @@ -34,6 +34,16 @@ public: static uint8 FadeRed; static uint8 FadeGreen; static uint8 FadeBlue; + +#ifdef PROPER_SCALING + static int32 ms_bProperScaling; +#endif +#ifdef FIX_SPRITES + static int32 ms_bFixRadar; +#endif +#ifdef FIX_RADAR + static int32 ms_bFixSprites; +#endif static void SetNearClipZ(float nearclip) { ms_fNearClipZ = nearclip; } static float GetNearClipZ(void) { return ms_fNearClipZ; } @@ -56,4 +66,8 @@ public: #else static float GetAspectRatio(void) { return FindAspectRatio(); } #endif + +#ifdef PROPER_SCALING + static float ScaleY(float y); +#endif }; diff --git a/src/render/Sprite.cpp b/src/render/Sprite.cpp index c31c75d2..a441e08b 100644 --- a/src/render/Sprite.cpp +++ b/src/render/Sprite.cpp @@ -38,7 +38,7 @@ CSprite::CalcScreenCoors(const RwV3d &in, RwV3d *out, float *outw, float *outh, float fovScale = fov / CDraw::GetFOV(); #ifdef FIX_SPRITES - *outw = fovScale * recip * SCREEN_HEIGHT; + *outw = CDraw::ms_bFixSprites ? (fovScale * recip * SCREEN_HEIGHT) : (fovScale * SCREEN_SCALE_AR(recip) * SCREEN_WIDTH); #else *outw = fovScale * SCREEN_SCALE_AR(recip) * SCREEN_WIDTH; #endif From 02f6ed7da39c06ba7c219e976150999f18a1461e Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Fri, 8 Jan 2021 23:55:13 +0300 Subject: [PATCH 056/152] fix last commit, debugmenu options --- src/core/re3.cpp | 20 ++++++++++++++++---- src/render/Draw.cpp | 10 +++++----- src/render/Draw.h | 10 +++++----- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 3cfc0ec0..6117462a 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -218,10 +218,10 @@ void LoadINISettings() #ifdef PROPER_SCALING CDraw::ms_bProperScaling = CheckAndReadIniInt("Draw", "ProperScaling", CDraw::ms_bProperScaling); #endif -#ifdef FIX_SPRITES +#ifdef FIX_RADAR CDraw::ms_bFixRadar = CheckAndReadIniInt("Draw", "FixRadar", CDraw::ms_bFixRadar); #endif -#ifdef FIX_RADAR +#ifdef FIX_SPRITES CDraw::ms_bFixSprites = CheckAndReadIniInt("Draw", "FixSprites", CDraw::ms_bFixSprites); #endif } @@ -265,10 +265,10 @@ void SaveINISettings() #ifdef PROPER_SCALING CheckAndSaveIniInt("Draw", "ProperScaling", CDraw::ms_bProperScaling, changed); #endif -#ifdef FIX_SPRITES +#ifdef FIX_RADAR CheckAndSaveIniInt("Draw", "FixRadar", CDraw::ms_bFixRadar, changed); #endif -#ifdef FIX_RADAR +#ifdef FIX_SPRITES CheckAndSaveIniInt("Draw", "FixSprites", CDraw::ms_bFixSprites, changed); #endif @@ -636,6 +636,18 @@ extern bool gbRenderWorld2; DebugMenuAddVarBool8("Render", "Don't render Vehicles", &gbDontRenderVehicles, nil); DebugMenuAddVarBool8("Render", "Don't render Objects", &gbDontRenderObjects, nil); DebugMenuAddVarBool8("Render", "Don't Render Water", &gbDontRenderWater, nil); + +#ifdef PROPER_SCALING + DebugMenuAddVarBool8("Draw", "Proper Scaling", &CDraw::ms_bProperScaling, nil); +#endif +#ifdef FIX_RADAR + DebugMenuAddVarBool8("Draw", "Fix Radar", &CDraw::ms_bFixRadar, nil); +#endif +#ifdef FIX_SPRITES + DebugMenuAddVarBool8("Draw", "Fix Sprites", &CDraw::ms_bFixSprites, nil); +#endif + + #ifndef FINAL DebugMenuAddVarBool8("Debug", "Print Memory Usage", &gbPrintMemoryUsage, nil); diff --git a/src/render/Draw.cpp b/src/render/Draw.cpp index f2fdad27..f702f188 100644 --- a/src/render/Draw.cpp +++ b/src/render/Draw.cpp @@ -21,13 +21,13 @@ uint8 CDraw::FadeGreen; uint8 CDraw::FadeBlue; #ifdef PROPER_SCALING -int32 CDraw::ms_bProperScaling = true; +bool CDraw::ms_bProperScaling = true; +#endif +#ifdef FIX_RADAR +bool CDraw::ms_bFixRadar = true; #endif #ifdef FIX_SPRITES -int32 CDraw::ms_bFixRadar = true; -#endif -#ifdef FIX_RADAR -int32 CDraw::ms_bFixSprites = true; +bool CDraw::ms_bFixSprites = true; #endif float diff --git a/src/render/Draw.h b/src/render/Draw.h index 4f8f523d..8727e0e0 100644 --- a/src/render/Draw.h +++ b/src/render/Draw.h @@ -36,13 +36,13 @@ public: static uint8 FadeBlue; #ifdef PROPER_SCALING - static int32 ms_bProperScaling; -#endif -#ifdef FIX_SPRITES - static int32 ms_bFixRadar; + static bool ms_bProperScaling; #endif #ifdef FIX_RADAR - static int32 ms_bFixSprites; + static bool ms_bFixRadar; +#endif +#ifdef FIX_SPRITES + static bool ms_bFixSprites; #endif static void SetNearClipZ(float nearclip) { ms_fNearClipZ = nearclip; } From 822f0bd40b637839c4d8832a791e3a12f102b198 Mon Sep 17 00:00:00 2001 From: aap Date: Sat, 9 Jan 2021 12:11:52 +0100 Subject: [PATCH 057/152] cam sector fix --- src/core/Cam.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp index 1d73a272..a11cd6a4 100644 --- a/src/core/Cam.cpp +++ b/src/core/Cam.cpp @@ -3829,11 +3829,11 @@ CCam::Process_Debug(const CVector&, float, float, float) } // stay inside sectors - while(CWorld::GetSectorX(Source.x) > 95.0f) + while(CWorld::GetSectorX(Source.x) > NUMSECTORS_X-5.0f) Source.x -= 1.0f; while(CWorld::GetSectorX(Source.x) < 5.0f) Source.x += 1.0f; - while(CWorld::GetSectorY(Source.y) > 95.0f) + while(CWorld::GetSectorY(Source.y) > NUMSECTORS_X-5.0f) Source.y -= 1.0f; while(CWorld::GetSectorY(Source.y) < 5.0f) Source.y += 1.0f; @@ -3900,11 +3900,11 @@ CCam::Process_Debug(const CVector&, float, float, float) } // stay inside sectors - while(CWorld::GetSectorX(Source.x) > 95.0f) + while(CWorld::GetSectorX(Source.x) > NUMSECTORS_X-5.0f) Source.x -= 1.0f; while(CWorld::GetSectorX(Source.x) < 5.0f) Source.x += 1.0f; - while(CWorld::GetSectorY(Source.y) > 95.0f) + while(CWorld::GetSectorY(Source.y) > NUMSECTORS_X-5.0f) Source.y -= 1.0f; while(CWorld::GetSectorY(Source.y) < 5.0f) Source.y += 1.0f; @@ -3981,11 +3981,11 @@ CCam::Process_Editor(const CVector&, float, float, float) } // stay inside sectors - while(CWorld::GetSectorX(Source.x) > 95.0f) + while(CWorld::GetSectorX(Source.x) > NUMSECTORS_X-5.0f) Source.x -= 1.0f; while(CWorld::GetSectorX(Source.x) < 5.0f) Source.x += 1.0f; - while(CWorld::GetSectorY(Source.y) > 95.0f) + while(CWorld::GetSectorY(Source.y) > NUMSECTORS_X-5.0f) Source.y -= 1.0f; while(CWorld::GetSectorY(Source.y) < 5.0f) Source.y += 1.0f; From 9693184cea6fa08944a7d4862852c15e9a6d29e3 Mon Sep 17 00:00:00 2001 From: aap Date: Sat, 9 Jan 2021 16:13:33 +0100 Subject: [PATCH 058/152] boat fix --- src/vehicles/Boat.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index f2f80569..4bbbadbd 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -22,15 +22,15 @@ #define INVALID_ORIENTATION (-9999.99f) -float fShapeLength = 0.4f; -float fShapeTime = 0.05f; -float fRangeMult = 0.75f; //0.6f; // 0.75f gta 3 -float fTimeMult; - float MAX_WAKE_LENGTH = 50.0f; float MIN_WAKE_INTERVAL = 1.0f; float WAKE_LIFETIME = 400.0f; +float fShapeLength = 0.4f; +float fShapeTime = 0.05f; +float fRangeMult = 0.75f; +float fTimeMult = 1.0f/WAKE_LIFETIME; + CBoat *CBoat::apFrameWakeGeneratingBoats[4]; const uint32 CBoat::nSaveStructSize = From 4bb6740bf42c951413e2ddf91ba1a012ce1356ab Mon Sep 17 00:00:00 2001 From: aap Date: Sat, 9 Jan 2021 18:22:02 +0100 Subject: [PATCH 059/152] moved new renderer, fixed a bug --- src/extras/custompipes.h | 8 + src/extras/custompipes_d3d9.cpp | 168 +++++++++++++++- src/extras/custompipes_gl.cpp | 171 ++++++++++++++++- src/render/Renderer.cpp | 330 ++------------------------------ src/render/SpecialFX.cpp | 3 + 5 files changed, 357 insertions(+), 323 deletions(-) diff --git a/src/extras/custompipes.h b/src/extras/custompipes.h index ca3f0fb4..183b85da 100644 --- a/src/extras/custompipes.h +++ b/src/extras/custompipes.h @@ -134,4 +134,12 @@ void AttachRimPipe(rw::Clump *clump); } #endif + +namespace WorldRender{ +extern int numBlendInsts[3]; +void AtomicFirstPass(RpAtomic *atomic, int pass); +void AtomicFullyTransparent(RpAtomic *atomic, int pass, int fadeAlpha); +void RenderBlendPass(int pass); +} + #endif diff --git a/src/extras/custompipes_d3d9.cpp b/src/extras/custompipes_d3d9.cpp index 63ca5f28..1f4ee07d 100644 --- a/src/extras/custompipes_d3d9.cpp +++ b/src/extras/custompipes_d3d9.cpp @@ -2,8 +2,6 @@ #include "common.h" #ifdef RW_D3D9 -#ifdef EXTENDED_PIPELINES - #include "main.h" #include "RwHelper.h" #include "Lights.h" @@ -16,6 +14,8 @@ #include "World.h" #include "custompipes.h" +#ifdef EXTENDED_PIPELINES + #ifndef LIBRW #error "Need librw for EXTENDED_PIPELINES" #endif @@ -553,4 +553,168 @@ DestroyRimLightPipes(void) } #endif + +#ifdef NEW_RENDERER +#ifndef LIBRW +#error "Need librw for NEW_PIPELINES" +#endif + +namespace WorldRender +{ + +struct BuildingInst +{ + rw::RawMatrix combinedMat; + rw::d3d9::InstanceDataHeader *instHeader; + uint8 fadeAlpha; + bool lighting; +}; +BuildingInst blendInsts[3][2000]; +int numBlendInsts[3]; + +static RwRGBAReal black; + +static void +SetMatrix(BuildingInst *building, rw::Matrix *worldMat) +{ + using namespace rw; + RawMatrix world, worldview; + Camera *cam = engine->currentCamera; + convMatrix(&world, worldMat); + RawMatrix::mult(&worldview, &world, &cam->devView); + RawMatrix::mult(&building->combinedMat, &worldview, &cam->devProj); +} + +static bool +IsTextureTransparent(RwTexture *tex) +{ + if(tex == nil || tex->raster == nil) + return false; + return PLUGINOFFSET(rw::d3d::D3dRaster, tex->raster, rw::d3d::nativeRasterOffset)->hasAlpha; +} + +// Render all opaque meshes and put atomics that needs blending +// into the deferred list. +void +AtomicFirstPass(RpAtomic *atomic, int pass) +{ + using namespace rw; + using namespace rw::d3d; + using namespace rw::d3d9; + + BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; + + atomic->getPipeline()->instance(atomic); + building->instHeader = (d3d9::InstanceDataHeader*)atomic->geometry->instData; + assert(building->instHeader != nil); + assert(building->instHeader->platform == PLATFORM_D3D9); + building->fadeAlpha = 255; + building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); + + bool setupDone = false; + bool defer = false; + SetMatrix(building, atomic->getFrame()->getLTM()); + + InstanceData *inst = building->instHeader->inst; + for(rw::uint32 i = 0; i < building->instHeader->numMeshes; i++, inst++){ + Material *m = inst->material; + + if(inst->vertexAlpha || m->color.alpha != 255 || + IsTextureTransparent(m->texture)){ + defer = true; + continue; + } + + // alright we're rendering this atomic + if(!setupDone){ + setStreamSource(0, building->instHeader->vertexStream[0].vertexBuffer, 0, building->instHeader->vertexStream[0].stride); + setIndices(building->instHeader->indexBuffer); + setVertexDeclaration(building->instHeader->vertexDeclaration); + setVertexShader(default_amb_VS); + d3ddevice->SetVertexShaderConstantF(VSLOC_combined, (float*)&building->combinedMat, 4); + if(building->lighting) + setAmbient(pAmbient->color); + else + setAmbient(black); + setupDone = true; + } + + setMaterial(m->color, m->surfaceProps); + + if(m->texture){ + d3d::setTexture(0, m->texture); + setPixelShader(default_tex_PS); + }else + setPixelShader(default_PS); + + drawInst(building->instHeader, inst); + } + if(defer) + numBlendInsts[pass]++; +} + +void +AtomicFullyTransparent(RpAtomic *atomic, int pass, int fadeAlpha) +{ + using namespace rw; + using namespace rw::d3d; + using namespace rw::d3d9; + + BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; + + atomic->getPipeline()->instance(atomic); + building->instHeader = (d3d9::InstanceDataHeader*)atomic->geometry->instData; + assert(building->instHeader != nil); + assert(building->instHeader->platform == PLATFORM_D3D9); + building->fadeAlpha = fadeAlpha; + building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); + SetMatrix(building, atomic->getFrame()->getLTM()); + numBlendInsts[pass]++; +} + +void +RenderBlendPass(int pass) +{ + using namespace rw; + using namespace rw::d3d; + using namespace rw::d3d9; + + setVertexShader(default_amb_VS); + + int i; + for(i = 0; i < numBlendInsts[pass]; i++){ + BuildingInst *building = &blendInsts[pass][i]; + + setStreamSource(0, building->instHeader->vertexStream[0].vertexBuffer, 0, building->instHeader->vertexStream[0].stride); + setIndices(building->instHeader->indexBuffer); + setVertexDeclaration(building->instHeader->vertexDeclaration); + d3ddevice->SetVertexShaderConstantF(VSLOC_combined, (float*)&building->combinedMat, 4); + if(building->lighting) + setAmbient(pAmbient->color); + else + setAmbient(black); + + InstanceData *inst = building->instHeader->inst; + for(rw::uint32 j = 0; j < building->instHeader->numMeshes; j++, inst++){ + Material *m = inst->material; + if(!inst->vertexAlpha && m->color.alpha == 255 && !IsTextureTransparent(m->texture) && building->fadeAlpha == 255) + continue; // already done this one + + rw::RGBA color = m->color; + color.alpha = (color.alpha * building->fadeAlpha)/255; + setMaterial(color, m->surfaceProps); + + if(m->texture){ + d3d::setTexture(0, m->texture); + setPixelShader(default_tex_PS); + }else + setPixelShader(default_PS); + + drawInst(building->instHeader, inst); + } + } +} +} +#endif + #endif diff --git a/src/extras/custompipes_gl.cpp b/src/extras/custompipes_gl.cpp index a7267fc6..0c092c5f 100644 --- a/src/extras/custompipes_gl.cpp +++ b/src/extras/custompipes_gl.cpp @@ -1,8 +1,6 @@ #include "common.h" #ifdef RW_OPENGL -#ifdef EXTENDED_PIPELINES - #include "main.h" #include "RwHelper.h" #include "Lights.h" @@ -15,6 +13,8 @@ #include "World.h" #include "custompipes.h" +#ifdef EXTENDED_PIPELINES + #ifndef LIBRW #error "Need librw for EXTENDED_PIPELINES" #endif @@ -614,4 +614,171 @@ CustomPipeRegisterGL(void) } #endif + +#ifdef NEW_RENDERER +#ifndef LIBRW +#error "Need librw for NEW_PIPELINES" +#endif + +namespace WorldRender +{ + +struct BuildingInst +{ + rw::Matrix matrix; + rw::gl3::InstanceDataHeader *instHeader; + uint8 fadeAlpha; + bool lighting; +}; +BuildingInst blendInsts[3][2000]; +int numBlendInsts[3]; + +static RwRGBAReal black; + +static bool +IsTextureTransparent(RwTexture *tex) +{ + if(tex == nil || tex->raster == nil) + return false; + return PLUGINOFFSET(rw::gl3::Gl3Raster, tex->raster, rw::gl3::nativeRasterOffset)->hasAlpha; +} + +// Render all opaque meshes and put atomics that needs blending +// into the deferred list. +void +AtomicFirstPass(RpAtomic *atomic, int pass) +{ + using namespace rw; + using namespace rw::gl3; + + BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; + + atomic->getPipeline()->instance(atomic); + building->instHeader = (gl3::InstanceDataHeader*)atomic->geometry->instData; + assert(building->instHeader != nil); + assert(building->instHeader->platform == PLATFORM_GL3); + building->fadeAlpha = 255; + building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); + + WorldLights lights; + lights.numAmbients = 1; + lights.numDirectionals = 0; + lights.numLocals = 0; + if(building->lighting) + lights.ambient = pAmbient->color; + else + lights.ambient = black; + + bool setupDone = false; + bool defer = false; + building->matrix = *atomic->getFrame()->getLTM(); + + InstanceData *inst = building->instHeader->inst; + for(rw::uint32 i = 0; i < building->instHeader->numMeshes; i++, inst++){ + Material *m = inst->material; + + if(inst->vertexAlpha || m->color.alpha != 255 || + IsTextureTransparent(m->texture)){ + defer = true; + continue; + } + + // alright we're rendering this atomic + if(!setupDone){ + defaultShader->use(); + setWorldMatrix(&building->matrix); +#ifdef RW_GL_USE_VAOS + glBindVertexArray(building->instHeader->vao); +#else + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, building->instHeader->ibo); + glBindBuffer(GL_ARRAY_BUFFER, building->instHeader->vbo); + setAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); +#endif + setLights(&lights); + setupDone = true; + } + + setMaterial(m->color, m->surfaceProps); + + setTexture(0, m->texture); + + drawInst(building->instHeader, inst); + } +#ifndef RW_GL_USE_VAOS + disableAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); +#endif + if(defer) + numBlendInsts[pass]++; +} + +void +AtomicFullyTransparent(RpAtomic *atomic, int pass, int fadeAlpha) +{ + using namespace rw; + using namespace rw::gl3; + + BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; + + atomic->getPipeline()->instance(atomic); + building->instHeader = (gl3::InstanceDataHeader*)atomic->geometry->instData; + assert(building->instHeader != nil); + assert(building->instHeader->platform == PLATFORM_GL3); + building->fadeAlpha = fadeAlpha; + building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); + building->matrix = *atomic->getFrame()->getLTM(); + numBlendInsts[pass]++; +} + +void +RenderBlendPass(int pass) +{ + using namespace rw; + using namespace rw::gl3; + + defaultShader->use(); + WorldLights lights; + lights.numAmbients = 1; + lights.numDirectionals = 0; + lights.numLocals = 0; + + int i; + for(i = 0; i < numBlendInsts[pass]; i++){ + BuildingInst *building = &blendInsts[pass][i]; + +#ifdef RW_GL_USE_VAOS + glBindVertexArray(building->instHeader->vao); +#else + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, building->instHeader->ibo); + glBindBuffer(GL_ARRAY_BUFFER, building->instHeader->vbo); + setAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); +#endif + setWorldMatrix(&building->matrix); + if(building->lighting) + lights.ambient = pAmbient->color; + else + lights.ambient = black; + setLights(&lights); + + InstanceData *inst = building->instHeader->inst; + for(rw::uint32 j = 0; j < building->instHeader->numMeshes; j++, inst++){ + Material *m = inst->material; + if(!inst->vertexAlpha && m->color.alpha == 255 && !IsTextureTransparent(m->texture) && building->fadeAlpha == 255) + continue; // already done this one + + rw::RGBA color = m->color; + color.alpha = (color.alpha * building->fadeAlpha)/255; + setMaterial(color, m->surfaceProps); + + setTexture(0, m->texture); + + drawInst(building->instHeader, inst); + } +#ifndef RW_GL_USE_VAOS + disableAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); +#endif + } +} +} +#endif + #endif diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 53971f95..131e77fe 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -416,314 +416,6 @@ SetStencilState(int state) } } -#ifdef RW_D3D9 -struct BuildingInst -{ - rw::RawMatrix combinedMat; - rw::d3d9::InstanceDataHeader *instHeader; - uint8 fadeAlpha; - bool lighting; -}; -static BuildingInst blendInsts[3][2000]; -static int numBlendInsts[3]; - -static void -SetMatrix(BuildingInst *building, rw::Matrix *worldMat) -{ - using namespace rw; - RawMatrix world, worldview; - Camera *cam = engine->currentCamera; - convMatrix(&world, worldMat); - RawMatrix::mult(&worldview, &world, &cam->devView); - RawMatrix::mult(&building->combinedMat, &worldview, &cam->devProj); -} - -static bool -IsTextureTransparent(RwTexture *tex) -{ - if(tex == nil || tex->raster == nil) - return false; - return PLUGINOFFSET(rw::d3d::D3dRaster, tex->raster, rw::d3d::nativeRasterOffset)->hasAlpha; -} - -// Render all opaque meshes and put atomics that needs blending -// into the deferred list. -static void -AtomicFirstPass(RpAtomic *atomic, int pass) -{ - using namespace rw; - using namespace rw::d3d; - using namespace rw::d3d9; - - BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; - - atomic->getPipeline()->instance(atomic); - building->instHeader = (d3d9::InstanceDataHeader*)atomic->geometry->instData; - assert(building->instHeader != nil); - assert(building->instHeader->platform == PLATFORM_D3D9); - building->fadeAlpha = 255; - building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); - - bool setupDone = false; - bool defer = false; - SetMatrix(building, atomic->getFrame()->getLTM()); - - InstanceData *inst = building->instHeader->inst; - for(rw::uint32 i = 0; i < building->instHeader->numMeshes; i++, inst++){ - Material *m = inst->material; - - if(inst->vertexAlpha || m->color.alpha != 255 || - IsTextureTransparent(m->texture)){ - defer = true; - continue; - } - - // alright we're rendering this atomic - if(!setupDone){ - setStreamSource(0, building->instHeader->vertexStream[0].vertexBuffer, 0, building->instHeader->vertexStream[0].stride); - setIndices(building->instHeader->indexBuffer); - setVertexDeclaration(building->instHeader->vertexDeclaration); - setVertexShader(default_amb_VS); - d3ddevice->SetVertexShaderConstantF(VSLOC_combined, (float*)&building->combinedMat, 4); - if(building->lighting) - setAmbient(pAmbient->color); - else - setAmbient(black); - setupDone = true; - } - - setMaterial(m->color, m->surfaceProps); - - if(m->texture){ - d3d::setTexture(0, m->texture); - setPixelShader(default_tex_PS); - }else - setPixelShader(default_PS); - - drawInst(building->instHeader, inst); - } - if(defer) - numBlendInsts[pass]++; -} - -static void -AtomicFullyTransparent(RpAtomic *atomic, int pass, int fadeAlpha) -{ - using namespace rw; - using namespace rw::d3d; - using namespace rw::d3d9; - - BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; - - atomic->getPipeline()->instance(atomic); - building->instHeader = (d3d9::InstanceDataHeader*)atomic->geometry->instData; - assert(building->instHeader != nil); - assert(building->instHeader->platform == PLATFORM_D3D9); - building->fadeAlpha = fadeAlpha; - building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); - SetMatrix(building, atomic->getFrame()->getLTM()); - numBlendInsts[pass]++; -} - -static void -RenderBlendPass(int pass) -{ - using namespace rw; - using namespace rw::d3d; - using namespace rw::d3d9; - - setVertexShader(default_amb_VS); - - int i; - for(i = 0; i < numBlendInsts[pass]; i++){ - BuildingInst *building = &blendInsts[pass][i]; - - setStreamSource(0, building->instHeader->vertexStream[0].vertexBuffer, 0, building->instHeader->vertexStream[0].stride); - setIndices(building->instHeader->indexBuffer); - setVertexDeclaration(building->instHeader->vertexDeclaration); - d3ddevice->SetVertexShaderConstantF(VSLOC_combined, (float*)&building->combinedMat, 4); - if(building->lighting) - setAmbient(pAmbient->color); - else - setAmbient(black); - - InstanceData *inst = building->instHeader->inst; - for(rw::uint32 j = 0; j < building->instHeader->numMeshes; j++, inst++){ - Material *m = inst->material; - if(!inst->vertexAlpha && m->color.alpha == 255 && !IsTextureTransparent(m->texture) && building->fadeAlpha == 255) - continue; // already done this one - - rw::RGBA color = m->color; - color.alpha = (color.alpha * building->fadeAlpha)/255; - setMaterial(color, m->surfaceProps); - - if(m->texture){ - d3d::setTexture(0, m->texture); - setPixelShader(default_tex_PS); - }else - setPixelShader(default_PS); - - drawInst(building->instHeader, inst); - } - } -} -#endif -#ifdef RW_GL3 -struct BuildingInst -{ - rw::Matrix matrix; - rw::gl3::InstanceDataHeader *instHeader; - uint8 fadeAlpha; - bool lighting; -}; -static BuildingInst blendInsts[3][2000]; -static int numBlendInsts[3]; - -static bool -IsTextureTransparent(RwTexture *tex) -{ - if(tex == nil || tex->raster == nil) - return false; - return PLUGINOFFSET(rw::gl3::Gl3Raster, tex->raster, rw::gl3::nativeRasterOffset)->hasAlpha; -} - -// Render all opaque meshes and put atomics that needs blending -// into the deferred list. -static void -AtomicFirstPass(RpAtomic *atomic, int pass) -{ - using namespace rw; - using namespace rw::gl3; - - BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; - - atomic->getPipeline()->instance(atomic); - building->instHeader = (gl3::InstanceDataHeader*)atomic->geometry->instData; - assert(building->instHeader != nil); - assert(building->instHeader->platform == PLATFORM_GL3); - building->fadeAlpha = 255; - building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); - - WorldLights lights; - lights.numAmbients = 1; - lights.numDirectionals = 0; - lights.numLocals = 0; - if(building->lighting) - lights.ambient = pAmbient->color; - else - lights.ambient = black; - - bool setupDone = false; - bool defer = false; - building->matrix = *atomic->getFrame()->getLTM(); - - InstanceData *inst = building->instHeader->inst; - for(rw::uint32 i = 0; i < building->instHeader->numMeshes; i++, inst++){ - Material *m = inst->material; - - if(inst->vertexAlpha || m->color.alpha != 255 || - IsTextureTransparent(m->texture)){ - defer = true; - continue; - } - - // alright we're rendering this atomic - if(!setupDone){ - defaultShader->use(); - setWorldMatrix(&building->matrix); -#ifdef RW_GL_USE_VAOS - glBindVertexArray(building->instHeader->vao); -#else - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, building->instHeader->ibo); - glBindBuffer(GL_ARRAY_BUFFER, building->instHeader->vbo); - setAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); -#endif - setLights(&lights); - setupDone = true; - } - - setMaterial(m->color, m->surfaceProps); - - setTexture(0, m->texture); - - drawInst(building->instHeader, inst); - } -#ifndef RW_GL_USE_VAOS - disableAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); -#endif - if(defer) - numBlendInsts[pass]++; -} - -static void -AtomicFullyTransparent(RpAtomic *atomic, int pass, int fadeAlpha) -{ - using namespace rw; - using namespace rw::gl3; - - BuildingInst *building = &blendInsts[pass][numBlendInsts[pass]]; - - atomic->getPipeline()->instance(atomic); - building->instHeader = (gl3::InstanceDataHeader*)atomic->geometry->instData; - assert(building->instHeader != nil); - assert(building->instHeader->platform == PLATFORM_GL3); - building->fadeAlpha = fadeAlpha; - building->lighting = !!(atomic->geometry->flags & rw::Geometry::LIGHT); - building->matrix = *atomic->getFrame()->getLTM(); - numBlendInsts[pass]++; -} - -static void -RenderBlendPass(int pass) -{ - using namespace rw; - using namespace rw::gl3; - - defaultShader->use(); - WorldLights lights; - lights.numAmbients = 1; - lights.numDirectionals = 0; - lights.numLocals = 0; - - int i; - for(i = 0; i < numBlendInsts[pass]; i++){ - BuildingInst *building = &blendInsts[pass][i]; - -#ifdef RW_GL_USE_VAOS - glBindVertexArray(building->instHeader->vao); -#else - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, building->instHeader->ibo); - glBindBuffer(GL_ARRAY_BUFFER, building->instHeader->vbo); - setAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); -#endif - setWorldMatrix(&building->matrix); - if(building->lighting) - lights.ambient = pAmbient->color; - else - lights.ambient = black; - setLights(&lights); - - InstanceData *inst = building->instHeader->inst; - for(rw::uint32 j = 0; j < building->instHeader->numMeshes; j++, inst++){ - Material *m = inst->material; - if(!inst->vertexAlpha && m->color.alpha == 255 && !IsTextureTransparent(m->texture) && building->fadeAlpha == 255) - continue; // already done this one - - rw::RGBA color = m->color; - color.alpha = (color.alpha * building->fadeAlpha)/255; - setMaterial(color, m->surfaceProps); - - setTexture(0, m->texture); - - drawInst(building->instHeader, inst); - } -#ifndef RW_GL_USE_VAOS - disableAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs); -#endif - } -} -#endif - void CRenderer::RenderOneBuilding(CEntity *ent, float camdist) { @@ -754,16 +446,16 @@ CRenderer::RenderOneBuilding(CEntity *ent, float camdist) alpha = mi->m_alpha * fadefactor; if(alpha == 255) - AtomicFirstPass(atomic, pass); + WorldRender::AtomicFirstPass(atomic, pass); else{ // not quite sure what this is about, do we have to do that? RpGeometry *geo = RpAtomicGetGeometry(lodatm); if(geo != RpAtomicGetGeometry(atomic)) RpAtomicSetGeometry(atomic, geo, rpATOMICSAMEBOUNDINGSPHERE); - AtomicFullyTransparent(atomic, pass, alpha); + WorldRender::AtomicFullyTransparent(atomic, pass, alpha); } }else - AtomicFirstPass(atomic, pass); + WorldRender::AtomicFirstPass(atomic, pass); ent->bImBeingRendered = false; // TODO: this seems wrong, but do we even need it? } @@ -801,8 +493,8 @@ CRenderer::RenderWorld(int pass) // only very temporary, there are more rendering issues RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RenderBlendPass(PASS_BLEND); - numBlendInsts[PASS_BLEND] = 0; + WorldRender::RenderBlendPass(PASS_BLEND); + WorldRender::numBlendInsts[PASS_BLEND] = 0; break; case 1: // Opaque @@ -824,16 +516,16 @@ CRenderer::RenderWorld(int pass) RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE); - RenderBlendPass(PASS_NOZ); + WorldRender::RenderBlendPass(PASS_NOZ); RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); break; case 2: // Transparent RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); - RenderBlendPass(PASS_ADD); + WorldRender::RenderBlendPass(PASS_ADD); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RenderBlendPass(PASS_BLEND); + WorldRender::RenderBlendPass(PASS_BLEND); break; } } @@ -917,9 +609,9 @@ CRenderer::ClearForFrame(void) ms_nNoOfInVisibleEntities = 0; gSortedVehiclesAndPeds.Clear(); - numBlendInsts[PASS_NOZ] = 0; - numBlendInsts[PASS_ADD] = 0; - numBlendInsts[PASS_BLEND] = 0; + WorldRender::numBlendInsts[PASS_NOZ] = 0; + WorldRender::numBlendInsts[PASS_ADD] = 0; + WorldRender::numBlendInsts[PASS_BLEND] = 0; } #endif diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp index 4ad06543..e3d2ffa6 100644 --- a/src/render/SpecialFX.cpp +++ b/src/render/SpecialFX.cpp @@ -725,6 +725,9 @@ CBrightLights::Render(void) RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + TempBufferVerticesStored = 0; + TempBufferIndicesStored = 0; + for(i = 0; i < NumBrightLights; i++){ if(TempBufferIndicesStored > TEMPBUFFERINDEXSIZE-40 || TempBufferVerticesStored > TEMPBUFFERVERTSIZE-40) RenderOutGeometryBuffer(); From cc2cebffb6ad1a810df046001179d536129666f6 Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 10 Jan 2021 18:43:11 +0100 Subject: [PATCH 060/152] update librw --- src/core/main.cpp | 2 +- vendor/librw | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/main.cpp b/src/core/main.cpp index 0887e129..d43f4a74 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -1211,7 +1211,7 @@ if(gbRenderBoats) if(gbRenderEverythingBarRoads) CRenderer::RenderEverythingBarRoads(); - // get env map here? + // seam fixer // moved this: // CRenderer::RenderFadingInEntities(); } diff --git a/vendor/librw b/vendor/librw index ed9cb45e..61b288a9 160000 --- a/vendor/librw +++ b/vendor/librw @@ -1 +1 @@ -Subproject commit ed9cb45ee9a2749a0a89231bf16f09a5c53bfc92 +Subproject commit 61b288a9fe72ae4073c0ac5fd2a5815ed510c8c8 From 59825a526851715c5593312a5432b7de007241a7 Mon Sep 17 00:00:00 2001 From: withmorten Date: Sun, 10 Jan 2021 20:31:26 +0100 Subject: [PATCH 061/152] premake: add startrpoject; add lto option; fix copying of binary to gamedir; update premake5.exe --- premake5.exe | Bin 1362432 -> 1395712 bytes premake5.lua | 13 +++++++++++-- premake5Linux | Bin 2035312 -> 2035312 bytes 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/premake5.exe b/premake5.exe index 9048d51e09da5bde02e6337dcfaa603a2cebf292..a8483721467dc3d67ca25ac14a6ff811c0bb92c7 100644 GIT binary patch delta 391910 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 z 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 OPBg~%z9?O()c*mL#PjU{ delta 366598 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 W!IeWYu`HmS0*VL&<9M>|@V^1su9s;5 diff --git a/premake5.lua b/premake5.lua index e6f34c9f..0d77ae2c 100644 --- a/premake5.lua +++ b/premake5.lua @@ -34,6 +34,11 @@ newoption { description = "Build with opus" } +newoption { + trigger = "lto", + description = "Use link time optimization" +} + if(_OPTIONS["with-librw"]) then Librw = "vendor/librw" else @@ -61,6 +66,7 @@ end workspace "re3" language "C++" configurations { "Debug", "Release" } + startproject "re3" location "build" symbols "Full" staticruntime "off" @@ -109,7 +115,10 @@ workspace "re3" filter "configurations:Release" defines { "NDEBUG" } - optimize "On" + optimize "Speed" + if(_OPTIONS["lto"]) then + flags { "LinkTimeOptimization" } + end filter { "platforms:win*" } system "windows" @@ -166,7 +175,7 @@ workspace "re3" scriptspath = scriptspath or "" if (gamepath) then postbuildcommands { - '{COPY} "%{cfg.buildtarget.abspath}" "' .. gamepath .. scriptspath .. '%{cfg.buildtarget.name}"' + '{COPYFILE} "%{cfg.buildtarget.abspath}" "' .. gamepath .. scriptspath .. '%{cfg.buildtarget.name}"' } debugdir (gamepath) if (exepath) then diff --git a/premake5Linux b/premake5Linux index 2fd412dae93e9f171478c06fd50a66ba3e09f2ee..1ca751679b30a4fcc547ae41d928965520c4223f 100755 GIT binary patch delta 226351 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

aHDdSAz!jSP=L2+SXs*{a7 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 WB(D!ahUUnJ)iSpn$jE&s>3;x8LuMNQ delta 225048 zcmZ^s2Yeev`u<0unJy;;+o8#U1QQ^ZLo*OS4$Tftrkc>?&`camF`)^a6P~S$UACpMhyT}@kar%C|E?|ni+4hgckbD@6?2y(!kYY zkGy+x?{xKF=i$JKmH*2*bq<_U&URyt+vK8SKTqz}UisdKGuMiQk4=_8zG!^-sje}D z(*tRzb)T||;CUsU`2#j4IbPn`n6YLflXAL6E%Za3NOkVMP$SM#QR9zq$h z-VyZF3i>WR-Bsu=dJ5`-ACW}_#3|@^0XOk~I5#02m_H!Be3ul677JA%yZokro%&X|nN%TFa)R)TC1*YP21B z)k?Mfc&HJl`GB%Sst@`9I@JruLNyPe&j-1x?8)2+Z3A#B?N`pEeJg6g$QpBwO$5&;5eXY@0ta#QZ^P)%VGQdY$8v5( zrrqPWE)M(9t)Bf9vx35#yTKt@vxZ0ZCx1qI9|KueFO3;5Sty6U%mq0CB2KHQg+~!w z1A~|$IbnTe`4BbENpdnvUZ0aB>MX41f^fBZ}2|!o8+Q*+`Aok?oK4@ zZg4X{p8+0mY8s@j-7$G))9XLwek9GJ=6^@0`wK@_%xqm*r&H8q34HxF{;k?q`$diY zfPs~%Api(RN3HKO;7spRxav#tYJ+D;)1Pn46~Pq^iY$}u3N+k2 zIu%A4r}Ut*hR_@g$(1bn7*5{Mj_7(B5bwyI%^162?_ZS5WuR;iMV;1zWU|E20)J$l z*&S-y=@vCJfKmO0qq>D$r>t+%St@G&0`%@A*7#`D_YE8@CI4Dn@9x_|%{Vny&0-q* z+l*-k`o7Jg=66BUC$r=&R^?0Q!DWHC^U%T74TUWFa4XuZ*aan+cMJPb>UykZV` zb`zAJLX*tf9MjxwUe7oO9$H$FdIfdS#MCy!H|4Y*Di`|eQR7jRFJ=EnobE%*8ghT2 z=ig+#+wKbAPzCs<%$De$;Q4OFZ5BYf$ z>*|;bHS9EtnmHS)pMh6%I~sO6ZOM%Y{~WerGnsp~-n`QWEh#b7VTF|1sM7fd|W(&kV6ulEm6a#-aRH+Fw`!o}cH9xbt9RX+y3BWiDi0C!7nL(3Qvv z^p!D(@(PxD53yZJ`~BG)5hrlCY(n-%Q;w$k)BY$e=G2Iq-vTr7HL8Q&$gXdioMur| zpCVd6-?nB(6`W2{V}C=vavAZCU)j&HO+CD}iI1yf#po7d02O^&2 z09rkX_S0Ec-l;sItRl2AGGRTcJ#rDV{h4(XHbwzY6@Eot7jp<^9 za&vlA*@S32RvtfFj)}lGlyasWH8mjjAxD)pMDD?0+{z+OlM3u!Jjp%xBlP})gO~gX z_A_WdHiklzPQR2E3!oVxsvB~XV0zFgeuDmTIK0wbC=F?C%nh7uVW;wFNnBpo_G4*r ziN$tG*l83sorLd!?3&ZLutuGBQFAFY{zdxEm1~>zO*_4!#(pmDn)~NMjXFbCy&0`Q zau^fb9%{iUJw`TBGZF1Sm}3(RzVFu zg#NjT(H_1Hc=RIFwHdP5>?H2C6L9(EkAs?a0!^~H89^IAq`F{ljI5c6 zt=gL8uO0xeO_gmf=eSqGZM*B6R;2EdC zNfw>M5c$jO!w*lTm$OpT+z%+z_dS&TpK&UW6qt&J{3LSPr{3sjcI4-*s?&@`RUl|iZG{~zfJvYHWiaRx;W;a3Nd`$II?ww;!^KoT~!sY0V^VnCvpTI3T@3{Q@cO*Hz zHQ`EJ;CY{5?qXe`$FTTb$Z~p5Mued&5gS)X^D~$1*j`>PIX@m(T9I8JZJ*8gvNv;B zHVwy@HN>~Wh`ho0ryRrn{2NN1Pp`{3%8{MW-Z*)T7vq@IE~O>=G3~~pP;=R7ENuni ze}fG^P13_=MeuGEGmf<%Spyz+hK`q>zX&n#p1_L35+{@; zqB~$V{govzVWtJQ#X2BMnRl#l2+Axx2EHYG_yV>o$UA>7CuXOKj8Hv2yz&h2;PGBL zQ_KRUT45&$na9xf-C4nNOu?iRI8k;1-2NWPk=*-OR^!x&8oLm|eZio=m#nfK5qFwT zl%3s8Q2hiwWq+t4J|63(*S1HHuZ6BTfswo#r@*s@ejZ~juBw1&r)Rli6 z$#faZY&;3RrcqWUIbvbWQnwO$pz*ld4SP_v{*`Y6B$c84YKcV z<`JmIOylwtycn_lO8YK$dguo9Z8iCG7ci<#&@+jBV^G_e$me*eHjwyD3-IfKiD~xFAopBqmTCSao#XEZnLaL zybYI}^NvBz_>|M%T%8E*ff6Kxy<@K_tZ`TH1>{fg`J~wnk$gqI<-V{_XOWJJ7~z*3 z05cx;Wwie?2K(qgybc{}E~dlNaR@1=eYVWbN_2!jKF>__)m~AfeCp*dDg65Lz6bN~7_Ld{t!h`ZsG*gJ z?P|7b!bHRtcREFlrI5M)M?NkGQq~wzQdceOM#-(B zX4HN1o)e&koo-w5X{gs_RL$HB#GIw4l_m1LrP`HI?axbpXdK2pO#YiR&DNN?7^SgO z%?T%in+S4Sy30G}o&lad6eH+g2QIG!4{hP~^DI+Mhv)p;>xa-0|7J(Ly)`RXg5lf> zahdNXgQq%B@qsMoS}D*58g=?lmtp43-*Z%F$?USKVcMZgW8RfHV0nz!?<;5@J04u_ zb6OVY|LRypzOow z4QY;d9CrxIU*au8vrH9*=?p8#kI7^tyrYL3PqPw>`7p=O*&GF>)km)F%y;=PcTU-u z;MUH?bEZ~A_VH>nKd{hEH>I=FKS%c4Yom8%#qf@GnFXQOQCFUQ^Dk+N9m)8g5z0E8 z6<^A%u{_Cz(O=U4Z#(i0(U<;`JM(n#{FYw5&M{|}HWaQ$3^HH5qlybcj%B{ad2r(_ z_=fmsPrBJVri-JEA>;I(Dfz-JgY=Pi>?v!qRb_`PYMA?f|Gwr$&LMfwc2-#+=WKVD z+)t^`_U>7g`>kim60{{+^b&h!EVDo!o{E~x;1cj0b7c23QM)`+x4!&b(9h-igP=y8 zz}d2O`VK{&!jhktuJ-!esS!2C4*=d`$y+lCCr> zun|0b8pikUP?I(GIGsXNyVO>@n;v*^~pD|ZS z1ZYg$a|2eQ#aS%W*vP#>SQ_j-4Wr;Aah_adYj-7YpZLLbR0nXrP7|DGNr&*SDg<=@C z6no~tdejm>1;hV7dFPSfk#4UX=k$1KMJ$P4eUC9DX4A&$j7zWX2sOkS&zs__{i3FR zL_E^f-ZB0}sA*@VRiDF@*n;Xp*?!r!7o5sg8Ic8u4Uro&em}qDMp07-<3hgyhx17( z3YpN}Dz9VkZUQ#O{LJgU`4@8F5d>{wT-2gpAd-*C7aii4Hq z)FEm7fS%%(B-zAr)GUv(mmQPAh zqcI;u;FWV~M9uJH$E{fAnp}JGPP3?m4dhggiR_@lq41SALqs+ApxH8KykmhBVq2GU z`p=V_?LRQ^x4_6;T8B=IsEvG}6X|lF^ z$1d~yGCMCQYsememDNv?_x;Op5^KX`zpj1Y6%I>(iyt2T3*&EZIc=&pl8mb%|HWeB2JyC!6>q;gX$k#KjKcSsNpZ+ z`z9yP>-F%BJKdtjZbpU-(f4C++vPotw(6SnRkGm8(N1-%0~p(_@cNqkoe+51skulJ zH-_nY0()SI%mK8hS=8{WDAT{z?Iw+~s@#WORF*Kj%8h5q}PPRr+N7t8o=fo8qL z8lAa_FxZ0$DU--M_TjZO+>4dx0`~s~(tPAnuPv=o0vmPgc@#_I?a`ss)?l_ruEA(V z$lr~_KJJvxm+jxa$fd)mzQs&PId$`^<>Rf^`EsMi=gM^)ov*e<&*b?GYz2J-?BUG$ zSi-g=cP{X2TsptJ{KMkZJ7gk6`MhO;B<2DH>rb+^nxICVng#M<=z0jYiGe)I9i=%7 zJ@q^*+>FaoYAFKQmYMT?l^;l_)D_|fzE{)hwKJj0RY24@Z@$l<`c1X3u3R9u=3EFD zGLmm+Lk;rY6$5L`Gn^dpi_oq+SlUKhw}ZT+ew+NOaVRJ9C|cz2%Ku&up1#K`*}3|X z(u#BpX;Q}J>Z2oIBloD6Nc^~oH))o<`!+1u84@-1CL-JubHPm71FAd{z0@uqsC|3- zz9Bh<=~yRfx&n>%V@}JAv8vpoiW=ko-G6s+*R!F@BP&sZ^H8DWrgy~Kpk|z6H$7tEtPu58XVK`v*>d-QQ8o_9P$5yHfx4h*XhV=&VTa^m#FkJScLu#**rWG_EBeL zLVA)9W~Q^WEp~z$aVnGYEZ{pv!roZ>WT^5Akf^z@kx?ff0_PA*4m<6lM%YGaG7fGx zWuG8wh#!={N%15u(m7{H)Yu!ytAp5|QEmYwH`?Xnfg8|Er_=WlX|f&t&{nwEzJ&&x z)8*9iSOGn@kgaGq&~HU+yNvk8=$MVDj@=HbWQ)|5&Y;XW-T)Z$yFY9A%7MRd{>Twb zU5E_13L%<1n^BtFtzITe-8xV&rFy^goQ<&H)QFnqy}K+C-cfxJ)RfaKYLGAJp)JPb z8K+!=L=D}8u~?t2_*N>iC8wQ!Tkmr|*=XQikyWS5ypwLv<>`pOF%m&@(M z8R$+vm@(fpa_Mctvm5_nb-*6*3UM344l}JS;3=p5a_Mc}oK&!`>Uya1dA`&Y?M9sb z>s}kpg&MpJ`QUG|s-+WbgxRgppZ=C-{=VRHVYx!;;)P{0>w5KIsItuzHG|tcbCusG zO;F`UQBe!GAQFH5`6nZhCl;a(sE=L_-kb3_OGP!ep~qfl$?r<=HrlWgxUyPa)vLKu zRzH4T>i792vwWLoQ48my_Ul=~?K7ZeoX#ud?Sp@zZ|75eKpJSv58Vl`{g?w+^6sF( zp=+T1D5ZK zU3LWCvCW=PWlaz@yB^kUzh~N4ZS8wS4JEMlZZGrM9#`z%S`W(S;N~}SrWbDe$L0tZCGtSN2i;Qq@!${5%nfZr7XPY z)#eWSLCQrP)eU(*)y23N^BA)|cp(aVjddMx4$FKQ5&CO;=Tva{khMeB=k-xe5942> z4r_a?3_ zp|cU~?)YQ&Iv-w<`RIW^kd$UaW^&HymeTT9lz8PF$kJYrMaI?@>_;)bGQx&B@X%b; zK8E~h)}C_$*GlI9jxmz`sdpTFIK0A6ji_;cn?vsByyG~wy5Ka6n!X#6>`3*dknh_m zYVa4tb34^e&Z)4|FKXmhv{6#UJ09A__g#6dJS}+u{n^Ot>{hd(nl|M8zHG}+XM*RM zX)m(0O6GjpX}nHmD0e&lxR)IPFUgAQ%4*^P%uxSZOFhie_&m&rM;ODUGJLk5)6So+ ztFB0|gZSTPjTf8%RcjBak5;JEKl;WW|*ZNdLnq(S!(Oz(`Z?IykmJO)RYsrL1xV(XyfTrGcshhOj+}9 zC<{cKh8wCIV!X-2m>P5YL9hwk0AGI`|9l>Jl8SY7rwj;}meY7m&J43bXzkmNu99pLT{s4RWuDOfY6&S+Z=I5vMdIzI=ox z0eHv!sZizfDy#msfk(eYN0@c?hbs31qDGVG)dT2zJ9ARzxTtZi(y%dRQ<)~VUisuf z)cl8-9lr0M+Mi>B zN$z1k!^mc-UK4~G;zJ-=e7xiG8u0vE=m&r7p5R_L>GVon`SBR{X}nb^G{7tF3`t!< zzUu5}`@*x4McMCZj!;ZA4zCQq2q4=b@7P=ZkBvO<)H(9$<4uS}E*ai&6Eil%H!fsq zc*hUyjU=xKJCX0keOj;|${t5FT{DU`-oDZC_Z%T?S7 z+$>A=`$(mInC9>8iGpRB7d3bzxYBZ3!S1!b-2O03bN1#aS#JA84J}5!{`S9* zsT6ZcZ6 zNygXtQ7yeyHUeXdlP)k3DI7Upf|p}48f>na#4o|lTecgNGHcm^x@4=X4*LtQdpZ_1J-#}s;9d$Qlu(nWGV%Wj(N z*%m;eKLzDy@Q%Fm!J^WJGnUSQiV{l~fmm5RZJ7@V2rEky5C9XlS-L4ar@9j z!sn80cIB2xwh_0>1z-?aS;?TcUv=?r6g7Dq)ElWT6EoZ05vTq3GTFc_y1lw0xE==k zC)ykvgN+RK?Q*%=jT;L#z+UKW385!3FZqJI>%AqK1bB?I{Cv)g++IkR<5*4?SCp)?^bScu^(s(C_5n8L zf)lt?F752kvGg61X<=2lN{AZa3pkfjoy8hMPV=2IQ^%vPc4KcWJs!Tnh3JjHP4&t{pqk&%>J!KhI1Icn2idqK>zc?+mfOp_<@z%jr7fZQv|NfYYIUN9`2z~? zqmd@e6;vJ=-CY(4JJ;N8KlxgGw|q_gI`r-CEazyc&XyB(0_n1b&|X*|(p1l$12wo0 z^4y*T6xD_%(SFa*)40rx9A46#h7I~Gg_xn)HL4%^s}qI9;&>+-|fx% zZs{dH&hVG5pP8Am7w9f8UyhX7nw9t0`hl0;BLl_HfnJoZu*aVJK#e$cqDF2*m-sI_ zoF#o=yFcl)iW=MvgM2+Z>`6{Oxg!uY^*U7leYKsL0`k$KsL5%Fs)?(|WJZ;B0{6zh|=S1Kj&l?_;OC~>wlJxP8Tj(Zlorr4KdSsI^*;PH=D{6$#Dq84! zLfSH^1|lAH~p%ly6D2)kZx7)8x- zqr(I;x3Ko8(P?JPGfRGZ3hK=|{i4R# zM0Pz!^`yB_B?m+eZvypxs(Wq=z?E^n!oC6=1Hy!xR-YZzwG`a91ms%f} zJq5R+k5HX+zOQzR8omqlo<()}UQpxC(#K^ByGHRS{3y$&Ejgr~`|cw1!}8n@Vj#yf z_EpI|@PbqGgybRb6lJgG9qE{_Hd}QY^z(yM>-T{w_kvHzgO1xVbI)VR@6Uv4_`Q-1 zcqJJt{bt8Hu+KRwrLYWg0;O?K#P#1mzYeId#3jgfjf``!WI8K+xHi}DLOayjsh z=Q$UGti@l=PT&PKbuVI@Py6~uaUFMjjND8ua?LubG@cnIdQKeF>>V%jq0wn56w--N8-q%!w$ z-H14qPsteZEtR)f=GnY8N;-{C$*q1XT6#Iv#f>Q0@SEga^4x-P0r}_hLjbvBwwES{g4~m>bbw?R}JDbeK=r{kD8d|qywEP~> zWG+vW!{DKdk?oxv_g@bMkMKHG&GN5c?crm+Ty=JPMpm<{;k$x1b5`x6o1c+>z4WPvwXuZp{+&!HFG{Vfc1(UX_j+u7UZt1j`p?EA+{gt)#ppM zupeR%dAaIr`>gy_&qf&Vx9OYa+L&<~pOq^nKN0o!-AlGX&!nApQG=Cedj)-`a9zqd zy`n~wG7@qeF4rx4Y|4?1Iz!Kv$>Xq}o|PNdHBo~9gDBtZi}Gb(@tj;$KSE1CZgMTX>}i@)_h(1ZC!*$Qmai+MT73?6C%C zXn`+#$#%#)(xvFzKJ}2?{y?M6+tl9Z+ui!)SN--w3|G%-51MmE_~%hZYJQ5sjc#BZ(l6y+Y@NZ5|;lA+bd(eSbj65OHSnoax6aO)x>Oy z?Ankc_zBnB*fj{GgQdO8t7pzBeO|`>daNf8Q+;hZBFQ;*q89!GwS?+}A0MR^5TO0mbq^xbSn#M7nXyfFr^ z9Pb7EYr$l$LK&z1Md`6Da(FBD|C_7UlU}Rx9f~bk*GFtc!5I=Yqt=sgEVrkbGFkt_ob;d<^}Ypf4vKF7n4<)eYextXlrB?T+0OHo@<3?T|&! zJI2Ssvuh*HJDElH!yj9w+=;v*D>k3H)zQnD;n&zGYAlEW_$Sp4wq3?u)WS;i=N(l4 z9D}c{53iKXOud5~d!6dcL!g=g?E3sKCoEzA7!E3v$lU0+>sM!NcB;H)R+p8uo{fpu z%tHTGi$cRrtEh3lL?QFpJN|SwRC(<%D@lJdma{VvwKyEAwLCBnUWIMZu7}AVtOn0I-LK02t_87O$R7SzD^yu6L=E#RRC2NP zj%_%f zn0saFTQ7NfA!=5Ah_H6KulB!IRujDnBfd9le3N4uEJd0AuN%!i%=cRN^>8`Y^zXUt_S3;sqz?xq;FN;l1JOzXCe-eAt+KpISCB_3DKGoB3#mF`>;6R2zTP z+~;|I`6a3NH#?SkQFSQpe+1+IIJ#fXU=8ehV88m2ziFM|71XB+T1khj;@PucpHqCT zX{caOadRZ>hl_Z^m~uK4iUeaK2g1SJgz4b74QI_=mL5E1sU4fI~qE-_c=2@#HzM zFL8=_{;@1=cC@$CAr z&ny1AXD{^+DFC?3lP=ul7&>D}O9ZYj3! zqkW0u*%0i@6@Q!dA)llD($_!9E=Z2BFL-Ch{F4r~iswIreZArQt@AC-=TQuIoNk8zR|A8 zx%91jBmey&NIn3EjB?nL4taiPC|$qas$|>6n~cXU8_0g z-wJs$AxF<@!8`v89WsiC{tWx9;vds~K=IgO*bgfH@7)p@v%C_Lcfp~c_^+&BMDb7; z>`N9E=fozpC_kupvIF*^gc7FFp-S=ed^pr9ehBR&il;AteN^!l+BcD}+W*InheL~U zxQq^Q#j}UQKB>4%`wqpEJHo!Jm?z95bVwHqCN>EU8O2|weV^j_O4tu5zLfSk#q-bG zhgy<tjpn?~3-jpE+?+lLjzMhSNQz_J~*Tl|AY2jipQRYeUIW}d9BM7amkiQ1`gRG!N^bbfDb5c z9t9s%yq5NP#nbo0zM%La*4}38h!P_A!J*`i;uL6R1wq9lXTv_Ec!Ks-if8A*zE-$5 zTm0qXPC7)CL%IbHQN;^Pu_nc1N5H;C@h!sO@zor&)kGj9R|{UYzQBMw6i-fveV5{I z(>|?ui1vBKPx&H&=Z(WkI5h=cQ2e0Zz|Eb-L-PpjOB8>cJgE4E+sJz*a)h+-o*Ot_ zW@YweeC!ZbeowKyTE)|^z&@h*NzWtRdc}h*KdSiP^IlvD)1-vV|Dl4I;)@wji{jCK z*vA!rnf7gpXR@$Qdi>1Qm#`Ix$aE-&Fk75bd_4cbm@dULFQJ08;&;03EdlvZtPgTl z$?v(nA}0*P%PH9(k3q!?&!M=y;sZ}%+=mqpE`fbPagN^{Ap1RA@)#G@nbqMV>%Q!AEAPj;>XdxYc#j3T67Q&>CuAl z7#(^P579oO_^Gt-Q#|_t%Fil3N9?^-bwCNxkKvG0{CHL{sCbGM?k>*Z3u#}Xc=AJ35LCRK_T{TMuPWhxz#+6suxqX{SJRRi-&>6;o}zt|;+gl*fSBSp)4oOVAng-zC3MlDP4NPg zE~)sPwC_+n$}vtUersrRuV=f!SMTale?tq>%AuPT^e7&qeMa$S+V?3QrhT@E%lJP^ zhk+tN?m*aroZ_d^eo*lY?emKJ3(>IRN!z0~{|ZXjofVjLakft<4=P?q9#Z^Z@`&QG zPtnu$!rcXP0~=H%{{<3NmMOP;u3YkBDCmD0v*anopC|89{AKdA;!DVTy45A*4GJ0M@MrQq#or>&D*jjU0ma`X&#mHK`;8f- zFt|#v{bI~N$n%O1kq;}roV=j;3i1)fzf4dt_MiEZ!%xPq$x9UfmOQBVPvqr_|3)5C z+$_Q@NK`3dAsxbsuR(`e#Y@N|if=+*uXvC=3cmUhQbD0fIZPvuDIOwkQM`&gu6PZ3 zTM?J>--AN3NHAswd57XN$y16qlBX44w3sWY;)|`l&A*Hi`dLt);%|~?70;0mDE`$?Bt3olU?l*1=<7*RaE4qv*ww>Wt}rG1Iw5tbiZ%`yM}O^5Q;f;SuT zYodaX;$~Ys7^qS_O8c(DZYffOYs5nwBr9q-UGgR!}K17jB@yxyif6EyQ@|-++8X@$r^>`S(C^RxiE_6_hBxGsixt_~xvj zT=81+km9#Lj`FL7PqHoXSHL%T?-^DOkGnMqxl|m%xFSmS>#0|K8`d9He0%bk;*ULs zxLOpCR(O-meKQd#t$3P7ZOSO?u9O%n{Ofp!lA~^AQe^+C)}`c(+bD8kJV^Wc(cI=ltPK@JM+?Hs z=+LBip&j-y#kZk-i{j=Y*vA#WTQ&#onpXxkNrV|eQd#)Vb2}8zU5FA>itoq>x)cvH z;}w;~IQze@WN#iMSgEzZ9hlssI#W(B{;AO#iw zD~l^vJn62q!GB1(O37Kb@*0spr(CP#xZ7yu0_A!oXWe!y|3#Dsp1b-&-sBhTD;fImM^G06wUA4S8Pi zUCD-z84EJj}(u$zlAMPypHxk#rGgD_xPw~=zM=~tsGwRGedEI z?;ckCclKzl;{PO%jOGW+Y_GPzV;H?Q@EsOFroFQ35CzFR2KZm?l@r%hLiWejxTfeDS!WDFgD&9%nr1<^hF~!SYM^CgU{tWHo zkE*9hSqg2+;jiRL#UresL-EgPpHlpL@~&0fYripTact771lupNUnK8Qd@^}P@qNhq z6mKNYD&7)f3kI}6hn(UUlMgC>Bl)o6@)>+et`hkiF2W^`73Xl?T{>E>QnFn6JHVQo-4DeNqkUTOS>WG6_p@?D67Jc!c}57RA@!8um%W*VzNSL-DvfbdwC1 z|Ks~zO3u5bjvdY4@w*C{|B~xOUN_5sJ8i(NkyE$L2?Q&y*&P*@JW(8Y-0ij{`W2Qd zS+Z+%h4o6#xPhDP6=*Jg`lUn3$#cO|il=CwR@^VAM{&QLjN&XOVe(2?V_&p(Sn+kp z3yQB#KBD->+t?)wRkABkQd+OH zsM{`DMJ|HhXo@L0?)F+awm;;!lH~?X>}FS6uGzh!n3OZ&AFDfp#gLCm&F}F#k&iiYrdjp;qx0R?wn&2YHv`edGg*50j4!B#J98??DTy{#4BC z$(s~^$sYp6E84 z;y&_P#q;DXikCc$fVvb9lMg7~1TL?9C?QFQs=pKm)I;8+_#ki=n|G8O@1TI~3%=gRO51$B3t;pPj7pJ1{ z6n9zDt<1;+mn7wwTPmk+Qzj6c5GG40m*1ATmt_J|$E^3M`=tF_@u|Da{+;}(JGM74 zb@!0(_qXDzg5+I_8}hVU(;Fx&%_uqVb_-rN--!lf-A*}m2YV&L6j?#J?DVNS=1GYt z@~Jyb{stm$^ON$NCwwD{NWEJeSctsKZ4|T8w372~zu*bk8{nN&@*$tP-`dKK{nVZK zlvi2fQxahEDS7r1f3LWvnAX-esN_vw^d{}^0WjJQ<{88CEA3z-y=#s|5NuJsbS1j(vi=|UspO({sy9M^D{CQ z(GjrfiuZi#F0rL8mL9Wz-;y4CR!Ysfjn7J{S-Pd&IyrSao|O@f zljR1BtN2KAPh7|RTe`&l{Y|>$Ir+QMXYLI9cj9O6x%Tg_pSkzgzcW8`-?4v>`^+8F zCx6fS%$;WcUhDq$Q zB5tGALW=_>Gt9@ueum|hD4u6C!-}`w>OQ$x!peN+F0+4cxYZr|yo48X>z)sk&5Y44 z^pE0dLgZD78}g{)FG?>-v110Lm+aqnrI%iiYI1JP3(^ZYxow(e+%>J!e?mlV%?zP-qX8$%UcgMaY ze~()3&ai)*m%HcMzh^IZ?~%XK2}@tHlgU9cwha|W7jXkG%Q)m-3Y1i&lop~-m%CDm zC`~I_p3RDDBFlwoK*^tfhedZ#@dEj<;^uqUk0`z#dC9Wk$R~g&Ot})ap+lA8Q^{); z-n0Wxx%{sau~71RK(1!^)+GwT~zsWfkVr;(m>|-L{G_<)GUsr-5>} zU;dPalyTM#^h-a3QSA0J0s}%1duT?z6aw3Y~3;Tpg zD&ce%lu|rP-lg~s;}B?%;&0NvPw^ai*5jkL+D$AdryM?@LtgPb`LNtbv=d&R5`KT_Ho@@4dRPlpYPWdYCwcnUiKgB9u zwMvjuk0}@PF_S`07XP2eY8Ca_}$6wf}?HD}Ff3X;R$3%*Beh zjK43$iv;~1QQW)W+x*M?{{-P##alUMImP`Q!l2^wX+Ny^ zLh=#eUjF+J8~i~no9Pf#{9f{q;{IN#O7X{NA6v~a{|@E!h_4px>@zRYp-plB zbL=9!LV*rh#eX0lQ2cjtv!b}?_VX7a#W&)TT%J(E))cA~ z50lp_z6W_k@x#cYiXTrNBVYBX{WJKfF@^mpznCB>DiUre8 z-lzEA$p;kwl6+9{@5%FuZ{S@!B>xIZ*uuZ4d|5n}+me?kz7Ki1;!*M{#b=R+Ew}ma zPrq|1M3lqjSa33mE*lcyB#B~L59Uie#cP= zD~D6aYZbqMJf?WWznCe0Iqlmlx+;a>g? zDB(Ri3@ScMKCJk^$qR}H%5ZfxUlkA8Sn}XkYX84Eg>vOkLmpH7uYATISNtH_w<&%+ zd2$u!{A;1mu}ZL$&zLjGyA+>Go>sh_yhrgWfBGqYO@ad^#4}q`V|9?uMN;xbiuT^{n zc|`HG%aL^Tif>FFE#fl%V=2Un1Y z*F)qbia$plRQwh4a>bXBS1JBRIrslzCA?3ETE&ORBZ_}U9#wppyh-sN$zus6d`+Q6 zaZ`b;Zc}_s@}%Nhl6NS+9(js<)&74c3TfrA8+ni7`;uoA-;2CY@domNVxBOEP{seMDdizZT=OClkO@ylqh~1dAZ{ElZO=VBd=2YPvl|CZT$X_EB*y}RPp!8lZvl;H((U^=HEhomp3&^kho0CmPooT#m^#7D?XpRNAcuV zC?}(McB{<~u=SWeB^drLaaQqr_;1V(D4udV|1J;T*W!;m3@bV9_FMU3dXFeM>aMi% zE*oR3U9z$`ALLW?59QN=>vVpH)a$}LKkPf)Dv|HgTn zlGE;xmEWd!hmz&Pl#fKVzl~v!E+vQEI+53XkKR3Qjht?mRaPHS9#A~%cH6?sdeIky zN{+irMQ$i?i#x1j^9}yZ;DX|xv9=M#lWxt&QrsF-(Uhuhi+kQILUCcm*QI@};&HcA zimTX|a=nrxZoic`r`)9ExVzHIlPI?+Ip-F7SQNx4hO zS+`f@#J-e!lpMSp9g$J|XxjHF9=sp+S;gnjen9bPw`cDj_=)_$)Z%Fzdu5byTR)K| z+{7}5l`L-^SowU)BTAOcvGM}SCEpbfbKnJ!nu!@#|?{rFh(Jmg3f3 zM7h>&lvB6spYnm@y=3*uCHN4kh${XV?VA*rFAhnW6@8Rjlq~6zmj=B|xlPIDanzPn z{7k@BFD zO)r{~SNxP}%<5sqLwCa7d|#Xb0os=+9$M_#PccCyY)FT4#U+=P1jS zJ-s`WEN|Ob`EbfzO3u6OA~zgQc|ggg5iQLtelqQc70qi){34U7RXpr=+u~Xm^5;R69Q+Q&MHPP>zw%|86i>N< z2 z0IeLSoL6$xE&W2|2<3v3We+3r8C@G<-&p=*aZDk)g%l5xS1E4D!-{AAgO@XE-A<{_ z9sEMx=g8a#R`2#(Rx&IvY^2Cql)wK;f1Bb-+RI$FWwb~c6*01uvdy@i!;-dP%4sDB z$$Jzx00_U&>@C{DD&AN;bcNw<#X`9XzRc@E7n7#WUn7 z#dBl4$>u)zrR;sOYjEZ%BiX%3j1?i+n#_O6fq#jdG5ohNlpJ+yteh-?oKtezZMJfD zJ;-?_%gv4Fy&>enf64t;j%^It1d4}RzAbEJQwlk#WVyNdx5%NjAcvGJ*AtOtzYjUA zF&36wTOcYt$P8HIKPuT|X41CJ;kc6+~(CP(QORdT@{vT}@aOvz!lv>^EzsYc;( zB?rUcZHlMJlZwaORw=F`%E3)3Iqr7b+ERO=)U=XAb>KaU=V_l&JnaTnN^Lnmm6RNI zYea4c?SfKsN)GM{KBzfs%PTHh7+YJMazV*Sx8KU4Td^3MHHvd9=B~7I;Tp(6C5PS0 zZ$-|>AcvGJKUQpI(+WAPW%Ap$|7nGcL`>h$U!CN-OB%n zY}z1)lq|m^Y2{cFa#+a)x82I=1muX4L{QY0ZBG?@>HU z`;xVaoBqrW-t(1lrd$cx9o$(z1g0jE=V04AqV&l5;AZXO0?ozXC5mU0;6cUXSAv%- zo&?|5gtTxS9K!#D*D9XB{kfSx29}Ra9P*#(rvA$8yfJ^|>Mwt-F0;OwZvL2b zy!?0Lts?UO?0JjboUX|KA;+Y{?RmhS=e+Zo_S}x+imZ1&!=BrvYDLC7-@~5Ued>y| zcRtOY+uNZPsXr1zCQY%x-tVkPdIl5i`8xJI?wwDt=XPVfBIccswdeLHy;elM^Y!ex z{pqX~5$}AAJ-0t@vLfuA|NOO_Z(z?u-ubuod_#L4OnBf+3+&ezRv7PmnLW2R87m6E z3z+nwJrCORym$VNJ-3feR^+_%x9qw7*P>Tsz4ImZ-2U^|D>B~s^Y+~Sljkea-uaXE ze7rqRq&)Dj1)Exs^v>_G=VkUh?w#Le&&%z3%saoyo>$oOsCT~5p4%K>5%JD1v*$L4 zSA@Oui|x71kQE{C{9Jp!g`6i=1U)dvf-S9q@y=)4^R4W8;Wyg@v+Q}up69*u!|i#c zJA~cRtacZ)?xv z-uVQ3US-c?-uYO2zMVafdgtre^C|W`;+>DN=iA%!uy_9RS8~3CJr8;3-`evXrG7~Q z4}59CRBK?o^JVtD+MXAF^>V{OAmP9VGDM(=SlDU9(%r*2 zi;8P;9LDhy6;~x3*C(74(o{k@&cI(cvIRCS10~~kd_@0Vea2&(&ITc58+>PUG71!suJI7m8T#Mr#94}FETvbl! z$q8vHp&ZA(IG(8D(j52Zc!-MKIOelaURM=6aNL*UXcZUXxF5$MDh7`Gb6iEmU!D;j zz;Q{A<9yz5!az>2QyHFeJcwhRiXU)1nB)9Usts^FgyVZEzQFNNj?bz11joZT&Q|du zj)!x+Ma6qLj^%g>;kW{yZJaQI6Vgpgh z@idOdavY-K$sGU9aTOJh<#-&&B|lOA1wO+#VLT_;sSN!%p1`qA#oaho9aa8E)do18 z$kXqsxCO_PI6kN1NRB6SoUP*e9LICKMa8u^PT+XSN6Npzrz$5TazdKQP>$m%98Xkn zX^xXP9-?A5j;C_mRmBb*CvzOF;vyVR<2Xdcz;O!4RaE@tDdFiHmyA;hZ#W^96YNy{ zl;as3>s0)J#xZg{M8)$tp38Ap70=>$9>>utp2qQfjzd&Dnd1cJr%d$cqzx{R2<3iGLExV zT%Y6R9B)x^Esj^H^Zyc+P?Zx_a)vY&m*aR9#}idtn&Z_R4^goj$7?w5s$vI@*K!=K z;vyWc<2Xdc!0~#HtEl)(9^nn@{9jTfyy1k6oWV}TPdVPiu};MgINr>0{yWtMINrkX zJr!Tzcq_-}RD6QtZ5(H-_z=h2Io|Rsy;oZI0w2!UE3LqX7l1!`$$O=>G$(&Gr_?hi zpEoDJF{hfEWVq-8vMq^E1f4mhc9uwrEW1qv;-6cYQ%2dDQ;iLX#d3to_Dhxv24=9Y zMmQyahaEd!9Q*~3Dju#nbMj@&tjCHP`j;eGZ%#`!89mV83dOYpzvN=BZ<0Jajn#&Y3rvw)vy_U-~(OAq>?4$A+cGC^|C~)s33oi|Qt%TBS zb2&I82t9E^1;`N=V^~FKAauZ~6(Is9wZe-Pp=wUVsTebWQ(SVxyh{%06BE#jxV=@IdM>~P8Xi|!jQO=iV~h!U`R|LdkateU`TvReCFh*S@u73x11j=>nsCElp0;8 zOaijA%2NnM)wk@TBy&8?EU|S1E@bh#VzdeLaf>;fltlbeGMy_4)Rge}J*%yzf@(aJ zl8%P^QLU$YyGS}+4|BC*K7ORjoP5oY*jc6@laBaNLWfSF9YZ^Xb`I@wI4vysC9lZN z6FOb|C)tn~sMRbg)#UlymPX0#n=}r~P`?!m8eFEwbu6rg(`SUg`+0N(3o*}{@P@XGW&R#=(OSSknx3DYnw z2wdn(=e0plMhIi4gWw;4A1APDZ7>PBm{A*=2vhJ;Z3v-@BYf&Wq)-Ki)B(4OR!?kI z+c$(AGN+j49H$YRoJ(WUGUhyWV@mL3qFBCP;=hekkkx?=CBh!t>MT31>U7kR+;({P zK0eKBZFI!AU+8k!4Oy}_K}uFib+1k)ju}#%#w30PtK}Yyvn64`dw7B zc$>=_*9A!sVlcWMcnVE$a6Ry~^?gXjoI1|ij(TnGWn5kl)(E38Dg-tt!A~Yrd-i+s#S-mvar2_)y6w-K%jAo!J~WQJcb6LIrNKt!wtU{p z``MPYG{%Sfv3~@ZOZb!Kyg@V<@lCIZw5w@I_&`1P#$YF}!m|-jD&YA}$}Gj^vHA#Z z$~!C7`03iOtebRy6q(ZTvCa~ILd~`UmWqTD&EF7*At8c~^^{;Bsloz;2NYNuXq?aY zQDGb9aw(f3n)>TRBK76|sF}0IOhy?AU24};8G=hvOYN;j1y!|L=BYe3rL{!A6aUlU z<1_^_`Zb2W!bzOf7<#~p)A*?|cteMH^o)Xl>IVj>v#BLVb2qW}WV2RRxv}#3=dMHH z! ziqblp^YLb0gQuH7DR{XR^P50)%Y|F11%40Z?@Vow)t7#?x24umwVfYQily#h_4iec zYpeDDbhW+4xEE(Pg_god_Fq#dD%5?txsHw-SD~+H%uOrR`2NE045m^vMV%HvDVFKn z8dHLOG_C>#t3-p7V1?n)P`Zg~6RMt6LaI&o|-AXfV~?LzF+t>!vC)9y$NJynksLbUeEb*=l*; z?NDoVMvpPg!3nPJz){Vis#iRb4;0~U?7k*5j0lz&2UIuaW5i?4p%FP^yB5$>=#3*= zK&##^=l<|m;o01rZGLR{pCWbHu4ZOUoIgj|Lao-}lww&zQwKF+O^wS@cBQ%X*Ki!J zF_yr9me5gng)>^hIUyLkw1QQ_Ow_jqlYN+4g1eT8Ol@4Y!>HEqS!jk0+dz_VhMj2x z)dXQSLR*LzoY|DN5Fvp10G@9L7d+RlSIc(e6tBg>pT&E)M=jEHJlGxv+l@QH6JJ># z?cs)P8i64lz+GsL9XpWE)8pn2Fi9AP0Ug0j=!;Pup_5P)*L8%Z&TUk|r!*)+laE-Q zJXFWUcC_sTXQ9?UyxR$ClZSKf3`a{mJIeFmtQOq^osMETzr^ElK|EaBhTl6wEnzMO zb%7_u@6{Dt;n^0f)s=Dz!ns|ct?TXkF4SrdxcKY4yboe2Y)uW0PQ)#P!HAwQP(*l$ z{xQ^j<8f#Vl{5;c$I$qm;)B~_;0KIg+**+s`_Wo2b^=5F2GqykJNWX;vl;MN#Mljq0pCz(e6Y-cFxs7vou`!D}L!JLibi zlC(a!#S@qGs`NA1qV%$u&J29f7~XRvl8&%oQthm=y4s^G1`;N|yYmx?a$wAE?ZguE&!$m8oX zgBP*c+|klcVwoY}123IfW64McEGZMVX>HIyC9KcYF8UJCXjq4`b>bX zLLi$m0h~mLTZ#8ZfE(_b1PASwt5ik{`eRD zlAwcK&;sftGHoG+RHOv2!`VqtpH|6Nk|+c>F=;C71)(V(m_}Wr#~vxLr$}iMq4jR6 z?1^QkL#>d!`CLWeGIbN}w&iu9KK`}npv=}5W^(WX89@EQF`Ae?!imyiJaFlB2qpV| zI30XSgsaN#?p6b1g)7@lOTk`g#F>QNsnA_Gj#E=%x>bXDs&$=UC1!vf?}&;ssd<7~ z!c3S0kUxjH&4T^{%$dy_*clhihN||FbX%BZH*H9oQ|fqA3!lV$v!OJd+7suHui1^| z=D;DkXz9fqSR_=%lypcH>Y!@|mCk@2GN@&X;iL?x53gsioD9C35P);$(u8pxOU#1{ zLM41P4+c42o6g(g6>SJudW=zB;!!qaKDY|-H5F49z+_TtyAa9=<+0{M=uJwOE`)_e zUePO+SO=cl-*S7DFpx8}?lc?S&rf$YKZ< zg!%|eV3x2G)0a?XX5juMw3zFM_m-(-|;BI2^U7hm{X!@ z;xM^PCc*fFj+&od(~qz4=(oDavs~{+s*>+g6sB$;SgyC^_$9Zzx)iw4Gx?}RqTO`< z>R9dk4xJAF^rQhFCVr8KCB%?^)N;3fA(J&X5tR$?u7NsM-v)F0uISFntc7DB%){sF zX=L_9mkqROGl&^B!W}_i_;M2r6eeNE%`jbX!o1DYR_oGWX zEA5e8#}!*)iqH*cE(B6vQwn3OM07JLKe5>}uNpEU! zCO+Iw2K*muwgb`yn#v#VBy)_z;k(FylJLVW2=+CnmqCc zkt<0x9gd;MD79iK){#MyNY3NYURo$Yr_uO*ADn@xj_mY)cp(U#abFf~LeyZ_v*4^C z48gV8WbGmBY&P5%Xk%dOA%a2d>LIu*2;Gn!A-@!e*N#9Fs6H6W=1|E7H80jap8l`WN!< z``%g2ZikD?{IsQ}c%{bNS)<-Aq|Vf+RvPtGA$5#Ky--}$5YHe7`R3*iVYbwD9(qosPa(PaP9Qo9tU25G6Gg{d{Q)K-P5Zd&S% zXjL}O;;tn(C`|sQ?cLTRXvwEj5oC9<4XB;XG=TGi)IwD+WIfMWsRtr*cte>g6q5HA zk{^^LW6kbxm}Ux1XMPLPxlq$NVgpSuBU;$vtLsqC^{}(5xCJq2#`K0>Pm{_+SoH?f zrAT_{4RCZHOUV?`9^j6FX2rfiv<69jMVonfP4V9wu%3*o@lA4dA9msWn_#Bty4)=o zDcr)Pw`fZB!{FQCYj3?nwKzka`C>#W$xdjZbj7Fye_ye!|&ns_Z7`!jy6v98_p?>uIZ*F?8qjx z<3L$>;MMz3&G>+}HmO+Z{;{RCo0@bFy&iy(W@pm_a)cRp@&RnLd$+N+u60Z98N#WL zer&|451}0F-H1CLLIvY=N~JVI!ffh;h~#&~^3O&bf0Y6)!y|BXj^yd7tp?Jc64aYF zDeg}-g<;SmXp2i8L2;AMblQGCPO}wlQgZ*#o64SO=EN7V)v5b=lUCrKw}PL#(M{gT zQVO3xf*|`()aU^p`1=5wujU-JOhwaUsNh&Wg~-2@k!DLW#y+O))$X|NF|-%`B5j%S z1QctUW(}{vC|ZTuV%b+PM{E^hi&?KI7XN{j^PybK!xCx$9onjO!10!Riv6mt87%!L z@-kD&erIF(i)c*}AH~+EGE<&pwX|_Mj1&Z-C{+yRozv!Ekoi>8g1%`v&4`DpM)+DC0AbUpuHdYH4==+Nsb2f z3H4z*sXlBj(IeSoGBL-0HJFoId0UYOKTE{7h6!N==xqp5g>{amoYj8BQRg*MLvBY2OJ-CV?^keWF z@DwZ4k2LyWrh+OF0Qs!tS3)N&o=DJPL>bY(I(+u^7NL|)RL+P%%$zYzu!U${Xdju8G?)6 zLhT~n)PodBrpOKO!CMH3^XCdSBBE3_hUbx6* zsecL^{9iRm)3T5F)do+ZAAawt!AH`M2>M~$^A}r+&2c;2|AuBjH*@!!=HxTxlySH0 zEYn>05`r4{=cG}JB-D=3M!{1rN-zC0UG0h}ttro zJn5xVWzxX6JgQ*DkF??Q0w;b1C%@4~?krxbsb>F!=Hz2$;hI^<;f`cKrO`8j#%FWf z|B)8JL-E!}=;xrP3e%{qe>9J-`#I~QHhHwUFexjE)mvPM}7+ljhRaAE~Xu#Y( znjl5%sQ{LVR9S8l&1uDDPEp5!=~N)^x9dOW$V`m>44!sp_-IZw6|cY(?^?RxgwM3P z{*GHdgHvQ5s-@=hMx5hCJ?2nQFmarBBQdr%^$EQ|^d_6Lv>+9E8N8_ra|)%Lk`IO_ z-}{-D&J}IHfP0)H=ltsr&TTbpH5WpY_ED$~UD^70x zkHto>w6}+U?||@~WS0Gf#yd2fhF0I;6^xjVpT9vS?3#zWzr!Y1{k-BdTm}mUdw5Gr z6$)VzFOc28nu~EipfsGEi_3oiEvDyUg#uUw^ARr<(Au#Lrn`t!;Z#QYGBH6|g=GaX z5NtEBt02~ZE9p2_5Jy7ibhHD}7iy$q5Qr!BediR{Jv)k}>_unv5=8|X&Otv>oB~<1 zaf>L@ed4st6~zf)I~%)7T+u9?D~U6p;Vkr%MIZ2*h0SEKKWzJl?U%(O0<22IV|vj9 zgVV4;FAj$+zwZEM19QqiS|xE|I{$DAT!DVQ=H zEk(qWuqOp~78P4Vw-hW^Ok4zqr{VfyVgr~k4fBf;|M_HGWJB^9$#~61JPhZj;v!qo zA68ApW44t3ISEG?!~i&&gli1qYzRogU^`0JCt)8uF&$>cVu77l0-8@j4|~eD(i9A_ z7hj8Sez>se4&q)BCQQP7qu3cdC$VT}(NO^FiP*C^skjrz(u#}j0vw!x8(qY9&}#x( zxr*^{e>|qTip^ohc)aH-PKF}mv4@-30(OnV-ENc~Fb;#=#WAq!Z?@ZA>@Gm_vFPDJ zh4dVY(HLxwdtPEo0cz4FR4FQh?MT+O6esM7 z#hs5+DkF{s&*2#DEiQwx!|;98A1Pg2=#dq26&4e zaApWD@fEi~i6PjctoRK)2V=CKm;qA;p~a7??mLK?{l&ThJQ={ImJ>Y%INBfAlouC6 zetTxFAc6pQ+OnvM;tc^B_CdeOB=e*o=gtpR~p+RX`$pdWi=a(oor z@b~P8Cf?8`(2z8`HNkr|#Rxl_Lb3QGE+kiS1J-tsU_Be^6RluZE=__TUT6{7t9@3s(gDqZmKOVhYOdmWgXGqdv7FZNpYb4<59!?kP@#?9sAL6tX>#$(v94Vd^ zz^*R)ud&!%D1WO?aheD3Q|*fcbM99bpv`{u%n=7B%2rJ_Zm7e$HzDhXHnmu8GqJS* z1wqWSIq856foy0Cv9ti!8?f}2VrK!y)MxKoiJ}B$0@#rr;$aEw+hgl4 z;(q85$Q-+hTSRE<%W}GlLuh1pv%sF>S;?t$GhPyP>nY`qI_(K1(XAi3I!`ZF&`-Q7 zIn9Xp#j@|3$`as)PX~+BVYw@g9wH7X+0d0Z4&IZ@{)f%UUF@Ev@vWhhE_UYbhp4h+ zT~QiJr7*eRp`ql3R~Bb2hKUOW*yW7*!^LW_)tULkiX#PR@5C035O)DAvuCYGi@{(s z$c{9}=Lk`$!OV{RJ67Cp1x>85Q#`pF*$TJDi}RtIf=v>{AJA8iO%lbP0D86~QJgHo z6ktKgVn1^40$VXnoGOcJzB#kXY2r3T{QJE#dxYZSq9y)%=B!Hz{S<%C5dTRUL5IGY z=bPgXk;$6O&+zebu^}|iV-;73Jp>qKVY63?3jlgOVO7?MfmS8<-1+|#UU!GZZxQW5 zXp8CF#N!~|!miuJi7@3R{ck5?vpThJI%_ZUc!<$?*AI2;pr$!~w3RNFFHg_6=dFI% zQmr#h_7qa+I?%KlLUwHW`z8+DA(n+}H!x!d&1UQdX6_J+!`vI}$`0`rz_F{C%fwdJ zBddU2x?SJL`=k~Sk zD(>7Zj)3}Cu)-eE3uYu^lRadtov+|l{@i^TjeBW!@V$)Yz2vQjT*lse#UN;T8JF%Q z2bysSuk95RV0;pG-bdB=?;WEi}-P$7-ik`qFU;v7cpwTSRL9;q5npM*bZO7 z_4`FrSO_IsM$zXPeBU7;ltM3|e3R5zZ-|xoL!c_G20qR{TI^{c)00P$Pn!KGh^Uzx zOMC1_xQO1FwlFs9QnPOFVcOKod#J14wJdVf`y-Hm>_q)9) zw6e1#ZTQ({L8NZaIoz2=LB>jQ+6+63J+n#Ae`hc$nP%f$|f^tbOy^F6g{nb->gNwZ+v_Pn;sPXpwd|!eNb!+ z4regupx6b>r_uKib>Ezc*yxa0+PT~5KZ;R5Nzh91dd68M3}7+30_khFRI}xc)4)`uGF*`m7iMcG+0xoLDZ- zwzZAUGAV~TF!}D@qBN`mK3KLjR=rx$)3vlsdP__urKg&1WT{PSX)#Y_&*CAs#aLOb z*Y*Qynzn!cx|yn=+^L@mN^%7hcmLoLv&)lTPx0w!qHPv@d`>jL=q&tjPOM&csg{A- z`<4-^661vCHhlbPqA^6H^H?{klPJ;b_&VlA7d10_z18QuSkd`YrdAMcL6#z#j_fR4 ze_nL+OCmYTWQ~6T=gSS@C-1l}zUMM`F0ZCBF$-Uu7wP!X0jz$3EUVlB*5iU$LI9^M zoP3d@He)7kyeLkCo|#zl5;1n%j}tG6?oe+(F1jRoLco5^yd-8&_}=QW_%FQ}dv{sv z>Ckwev#yuH@7!339p1}O$=F~Y>wiV0lLMALxa+ET#q~Y#a74Nxbm79 zS^vduO`dcdBY6uQW%1dn(pnuhB+aC15cQrRDM$Ndvxw5(80=|bH_U+_dr7DN()&6s z3LZ1ubDbQ?X2xD!7pn@eZx@!iDQ<=O7x2nWacHIVomxgbgBa~MW!UN>sedr4JpHw4 zNz`GsTxs*2IN}zKrh*;#?=2dX-*?c>T4JwCJ9qrnF-iOVe{>8ds-|P;4s3m!ba?H+ zxZ4y;*zdrNx5Xejjq&8RSh`VI_D?IivH3><&ve^%t)ceP3w`RZTia-uam%7^w2Y(| zh@2;*kS9aq*|!aw-JxMOe;bbA&$w-D!5z_8@GeinVaW%hl26d`GOIV=ISA4HkH7KX zhL7)x_uU6>rEIPi`X%cc1qF2CQ$4k0+D3OOiAP}W7F>N_94f3~t`Ee@0@!ZG$cJPu z$2a4Mhhi`2upDnc6w_cpXB_;99O8*HPV5jYIfD3sah{QLWb2ADt~?jHg`RhW0)Kj%V@h zCw{PpFMdO&syqo*Fx?`)gg0w2F;A>wof|@9E7hh$Wz5PGy{wO#X^KrXR;!Fp@+jCC zxdwfnirwMX8l3i2tZBV%HP70#bv2%PO4hz@HRe4f|2<>Qp9xmEyH!B;oQiNdTrEPa3V8Q9 z6=D2J^n4-y1+P}(s25~juoCCJ5ZhZ%UZEH!X3VmKa!=s8m168>( zy1M4&RIgPTC%hK*<@)@|=dST(Ezt_5@+phdUTw4#H@y}E=t$wxQvy0BUTZ> zeL1##E6#=MOYp^8>WQsOSj0Q=nE-Q_VvP@CY1@tqxQFO`gT{+-^aAYlf%X~-=HtH~ z#HzLr=l@P4+T9Q0C~(fkwjafyVz*RZ|J^+4`6nH29cg96tsli~DEcoO{ztaiLb$aF7x=#WA&ykEcA!iTM#zj+5%c!j$!z|KSo zk?7q>8;R7?r7?Yk6b~60JHJRJp=67H)oDCzm(~#4{(FvPK_9g(b|9-IO7#Fz((!Lu zDh-3v@n2c;2k$v}LY6u~!7TLGOP=7Gf)V_Acoz2M&qZ}GSud4=_*u9~FZn{uEWE;T z=q&uopQUDDNk#I5Z~tJVB2|QyMjWF^v!U)k%+^Y(A;7sbY-mjxd``oa*3w)kn}+p@ zNb{iS47^c9Y6lgkpsA?T6jrBVVo|9DGzrA(MWvc09RiE%42k>>3##kN89y7KOiQ&s z1=F!=F)65I&U9zu;@9R7SCd~{Cn=)iHaQ)qajxMiSAxd%KJ}-r;Tl(u>G+_SG|zf{ z3MHhPPNrajjZ_)7PRE@#(q-!<(^T^HX*kS#HfC*tG*C7+E?d8+7$gO-H)g9k6*R)Z^>##Req&g@$|T$pA4oi zoIx$ZD~ek4Mp455IOrR{($Dhr0$#p9&spvLmA;v$C;gvv<0!2FvwyKoCAR9ksuHnM z4O1tnB^>^Xp${?e^fZ1rfgGl$U`R54Gf4h)M$OkwDorOQBJ8BHuwfbwvm=8^o`y^9 zBzG8{f?1RdZKmM^J83N(NXArqsTmAP#yj@X6nHX~^>UED2!ak{oTOfKQsJ1BbQ}&( z!P!PKuYQU6#z^Wy6Im%|$tZ&NWDIhZ?n9$V=Rq2ibo-x?GmgMAP6;r5`uh`wLsCxT%bEfqMeIoOUz8gw4 zm55=}YDv{(_^T5hs3)aCw+`4mL@He>vV*fujX62<^E`nI@!i;={J1=QQPhFW36cJm z;ZsLdb_=#nYMNFP>V7-3Wtr8hC+BLe9WJglGt{< zv>n1rqRj+yY(XW_G(lPqo4nYA2~tM^KKNkBM5zPp@xetC$uSM}!q*d}IG}H|hE0;X zLS6}WX_B-8pjc@fn;>biFmB3=tq)qU~9rsU@ zI>Rh?ERjObs_r;0MOp>ZoSFA@Zkl!NSzM~LR)R}TSZ)@z|8yrdf0pDSz#>Q7Gh0f8 z^F=UZj#L9i7QxYTq!Q4#2xiQYvS6GIwn>)`K}BnH%aAf4$_}?>NOkBd2F%Z(sl~|- z9gyT6D;SAn^Hml6j#S@RTkJNMrjTWNmO59W9pnHRm(7y~!lGhmKVRw(Rf^$+`O+BJ zSrk9dmqtL{qHM?li6ZOy3a(fv#X5%pnH`_0_*mrdtyt?t(sB_b zJ$_k22KPv2^_NOV1z0Fyk>ygL=>E;f!j?;Y1o#AO(+aNmosK6n>r9R@70wdeHnvVC0U%nf0=Nf6W7)L*!jYIA5r4g zNk_!wFGkjIy|fd=c3+J6W1}<&F7Z|x!S_#dbv)5ZCPr=>e zy^)`!sIlRDf%@rwnmOffzE5=fospH>E>#rZzdY7%2eCq@H#laeWQP84@bFG)JUG3< z`n%}(;AsmxwM)tc$b5w9d!%X5<1s6>SMn9$;{%M?C(VG0&)M~TlC1#Y&oFPlR2Pch zNB>OeC1mEIYnBuP+w$1BEXe`D`Yub$ma0lH<2oKWB8}qzV{vc}&Fy|SSf?DR8-RSD z9n6)=(VpsMd~rKPe++mr=rMlF$xAFT4iT=~li>%^FsVQwM-o){zC|B2; zn0boa_rjZai#qr^0#b#sMR-|!}eEcJd8ZbPF$rb zcyv6YGB!yh#^Yc3bo+D8HU%F+;|+>x7M{jhH>5?-`ZQj@LC&Ba*0@PimlL+TDS5$q z6OO$}ZfMmG%)Ci;esT(}Zb{6w6IF>Hj<%w;pq#(Ms2kRhLP(pJJMh{qDHR%>!rr%O z$R0S!40j~j@cn)q@7*QWv+6in-IKmT-(4u*r%=ds7q-4HO@Mhj@$!9YV^b~~A4r#6 zs^uE_T2?-}$*40-rem`FvkjY^O-y(w(e9-bFSFT%<-?D$K`UVvGv@zyKpneEC|MqQpQUpuDS z%v*(*^QB#Ie6mJ%zO^Fy{?La<(h5>sx6#^j*&6cT%_jH+Epud+9J_ zMWOu%a<#{{W5NfTf)~%joDVdTt8ZsEA9-wOvkk*PNi!VpZ#C*HEB@i*UwsX3tmnd> ze3HThn6?Ege35>*AKGjz{J=0EJI~nT`_C8IMw`tn{Ht_HDA9DI@#hx#UCR_Y4VL$c z*1oh+U~IaPnZ8T55}aR);ey;5hOT8R1$jNxx1UZOMvLR>wm%Aft&|nx4|@L_+mcM@ z>`E=&iKmlEsVnLKoYeGcl)iT*&XVLk&~zm>k!2S;@7hb2OVf#uWLfs4LzHV|`6HaB zYoGP92|g^wYkIjHErUfx4iUhACY~!IlSx_0N1)jZ^s<(BLwc%4d|@r$hsD!5*bY1X zrO;T8g7|;&Vo^B;f>N+XG5IYtn8wQ6$n8XkTF9o@$yX$>WMF5b+y)kB;4Y)Q8Vnh% zi?du^fKsuTUR+*0Fkue0bnN$UG&*9vL(KGfAH5VY{>7=CIaMQ=YI8#J9|TWM82tx9 z;Dp|P5b|adq0JwJkAb+vMRszr=A3W8{husn%x0%t@Mq$Ac7y?>(um#b#g=FWD2OPr!j* z@>O^=9vhaFy`ftw4k$^A-jAbqiqz{KGcmoC9OZp>1{sRBJbGoxs!N7ah79G;o$J3+ zm|R+>9VmJm8(l^&4gAzm8F><&BmF?ItkdM0YT$jra-uJ{S<~!f)lT;EPfRUOUa0d} zm1I`WTizy_m>|R zd)mvW8=k=3#kF4eq@4W5`FT&HE>u15VTd26R=JYRxt{E0c{yGv*0Kk&Pvz{PJ=pk) za$~{xt(#G&zELp5`xUa^@5XLdl4%xtJ%Pzpp~IMI7aR!*;cObyBEKf$F$y5>LcZOKb7+=Ngsk365Z%8wV%zp^1Rl? z2=Q94D37Ik$^N$g5cQ`ObSjkhEtH@9g3FJizg)hUDnE!2m)DoaY%c${-0xO9P)=*L zspYg*3+YX*Hi#GulN;0B1|(+FryO=B6S8fuiK)itTTUzXD}P?>AiK-{T!OvPGCJ#z zAA3_q`-%Fqpi})diRP+AIULo8G7411+7;F>z#r55keKHmVo&`vvF(0Z`*^AKb1kgj zJU^ao(Zc%8_G8uh%Ata7pR&IzSiP)P!SBAjfsTpzL?jK>UNf>KMiSt zuO`t$l_=*q@g;B4vGkXlbfhXjfDmt+FkhV9Uv6q!><{^CKAQYeAFWBt4xpMQ`S5J} z7K%;s!SDf;?Qo+0%(h;km{p-zHWz#8&BeMFme%5pcevOMqW%HI*LokwY)8tM1;H5~jUvZ+I}kHR%jwWRkhK~k zD*{B+5c{VlH*u44K)xm4Ma$u)I`gnYhEOAYQnkJg<0{iEt( z=vAyGcP{t&Hqm%{oIKdHyZX=UKivOT@T{`>l9Gov-^Ccgv2xVMT?*HX=ppJbo(jL%@kT2-;tM7bBd31Ist z%7Fruu8i*|(cnH+2~Cq_AAl;@akAV1CRf6xljT|Px+0q5$s33j(J4XBgbo$h#RT~; zfFk9vLXv!f8t7w^?BQ)v)GBBjlqqx7M&x$SLx_&kRIlHG1x=Od48}lze7#6^WF3=b zYY~!)vfk6>`htUzY{#;Re{Yo%$6un#KDaMc4u*Hu>`N;5ZO6)><4oBM6UtzxnQ~RA zTn7J{DZhcfrCDN{TvUM3rP!>0xRXnlSi9LW09`u3I;G2g05#n)3FRc%;)Zr}7zgb>qh(*(EV`2gFECP z@o)O^ZHLUn+uxnouAMRpVwZ1D7|rAd;xI}x?WPP{es#jpyX7)s#8)S_c(;5IVCg3u zdP@#wi}%R~1u^`y6L!m#2aAnAIN_yC*+;DR!HIp#lxb1A^9@^iP#y%3{${oP5m|sP zub5+w{8oU)uh1%&rfc&H)-abFZ-?jD?3jE9@EKM%=g)`7eeIxADt08UXn>vDPT<(%H*SB9u+48Ac@8^1p`p6|EXF^ff~-8r z-2ao?14JBWqw?e@0>tF9F3;qlLg`D#Ni->#n}KS0cX9}i`i;-zus6@;Edta(hAUpu z*n(sD@}=xk^+B$aI&_DY`CjlW_16I_Q}aU_y&ci>hEde7ou@GVlgq+i$+Y6WIuBdt zlRpVPis|`s4XAt+Pv^^JpzKlhCSRuIebKpeJ1-52E=O?D8%p@=2p*y*e{=VS)(0!l z`mNj?R%T+yxAGUOGDn>FEgIkP;5dUDj(#V1g!PB<$~(Efb#;609gVi#>9SYZDWo_- zI*9&_j>_|GML&gnPKu47G6lOIcG7kYwIjW?>6StIH1UxgiPR$zx=Z93j(9IeL-`|^ z`<_-HKFsO^4Q6X(Ew$abINN%Fh&;AI!q_T#K?a=2%Q{eNV1jJjJ5cb_??Q6(ARc) z-}d66?{WyZPDkm7yd2W@vb8^CS~AB>!~F&F3V6CZy_5qf_^a!naVZ_dS{_n z>@Fvr_D1qqsuaB zG`VMJ78z=zwvP+FK$rC~^kL2}SznsIPrNScJspZqa-tWU5y{`wbKSIwG7hcv`aWLn zD}r>Bew3uC**w>rA|09_^Mkj12BK3brdODz*SkX9xwxK~;mbBOD*8_Jb>(nH?+5L+ z;UYzU0QPTXovrjU1yHu&D{K7`2;Izf7SVr_+#gS-qNR-I2VBOibK;-V7i+=~7@9KH z<1vH2BoteRPYwEGC6d;1#>RARs->MFVLJJbP(#*0`p(X0$*R?7?DP^0T8ZbJ^rc+H zl}_sU@B+(03NkGfK7HkF5VR7ljrxkvVig7%_1B=|Qs&^S?+0*cDVyM;r&;RaB3$6A zzhWr9oErRuxx18M7V-<|hIc=`BhGfye}en8U+k{`ZUv9h*>rDxQ#sBp?Pp%sZmE0Y z@kH3`Lyg7v-j8UsHALg^{aq?f$%krjb`{d@6OBrDpb%crV6#GaScBsW;SLQ(6~dKw zv0XX+SJ>NuwJEPZF2RtQSgMM?8nl|p+Eme>R-knf`UL5RfOQg2D9$zo>AMSbNq|Ew zeM@MR$a>e((~j@5iOiv%-a&>%e>2}O{Xhx4N3nFX-d%)Zv20soeW((?b$gI@RS$hY zT)UTHuzYL)^+#%O4AFDtQS_JpGx*EV^pmIWrgVbM30jIBpgJeZ12L$j9^qqucD|*4 zngDsJc?$uw(BWI zx^Kru?9kf-Jh5d{cj?Or!Zfyl>CkTi}SkNA;z}1p3kV zsJ@|CyTFmnIjTP)h=aa6vY2D~^MW}4t0Oa=(4W=A)Y7OwulIyLWti`I{S6tWdoZ}F zuWAo%i((Cn-UkATu}&6!B*0^9w)Uz1WDy8rIM7|G$9BHge-`1#Hn!!n{usc!Eo|&J z{b4(y5vyyXbQR#`Beuj=p@8J`Lrk|*dI%}(i=A?ng7|rO(SbO|uC#bqhwCl&eK%Z*|m#C*PoN(y)}jVq_sTlpSIb-0;6t z$6AVw6|`8vWjwH6eWgOtrJEde{wFB=`I~TLeI*etEmt$d;tiA%@OhcaYQ2sYOk}JL zmt%(pN*!3F@v!X;lpqmaFVTvqG*ar*dGy69vc~^Zk#Q=l2U{26X0tLC{#&Fmw~SCe z+B-vrqmC}9qwh(Gx$yjPr3}`!gAxrT-DYWt{5rg&VcyLI`qPwJOFO1qXBIoxN$INC zcAVj;+sEI9(MQ_R$m;gweLHA6F6pJrfX=B{rMEKOHF}OCMbw8Hr4-u~o_O4l@Pqa$ z={x2<)7a(S3QbX~QkbQWaM>-kZuu5pI;z31J zx848PNRv;uVu`a9ra-wStnPfJx>a2L9)UU+qi1mrjrh@dq=F63`zSX%FIu(>`EKR?nlI5Z*!KRpsY~FVb zBsb}Zi%jAE$2quAvK&bTA^OAi zYP(d|kde43%~L~VHDsls`x@t)E>zGL=LKG*P|G_nQkE-!j$vC@DC=lp(1vwdt+)tu zsl&)MN@Wj)Hzxo1F+Q6vDKaFKrQ8qjA`}>(cfdnyl*6>wJ!P%p4Nu$ShP6s7ifM&) zN^#feJhzm6*>rr+oEyJ|-*80#3XHKBK*{u-d&D}$L#T_r*C`bRJC?pqG12>iws>m2 zvKdM@$MGAK8Xz^tog2st)r!WR8W z(rTwt*Ttb(;2$U4QjF!AQ+D*F1g_hu)T<>D%9XE27xn~w1Erp`PLWR#i6&J&@7fR& z2r`Z*jxM{)FT8J&j?&+ymzzYSH9>)K z6Mo#I^oPCS*ki9U$96*mZ!_&Hw(M}!?^7m#T{uqJr_hB8W?a8dxj-j{C+t^_Q^Cxc ziU(xY$KILBD!5yp8L|{wX*CGJj|Y?)bPdClY^6FpZGii;m1n@};@X3XC#VE7O*oI`yNu}(p@!hnDo^O z#-PKB7v$8zc88Uv!aDqVSV{484kmTUuV}j}ieFw-hg_OvmiY^PZkQrFgkXgn#Rrcc zQ4D3S)ziAf;(lGwrO2lV(&u~sW~=|50tLFc@-F;(M5#;{HkQv(Ol6{f^3T4;`NRKT z{z@31qx7N++Mebp7hv2l%sQ&nt+^w(FrSZCxZGNTc@Jn`ocDUJoI#NP+sDU$-lal1 z)jGKrGvz9y0D^;X({UvM)(5icCzSH^ZmR~1IjPK|lLpoC{V63DCRS(tPm^DUHq|iw zjB)~|RmGUI%1n3>fN#z!ALwqLymLxBp*=P@uY?&lRw1w7I`41E)_cdjB2Okn5;`8i64gSsTdKoU!;nhoWTp8x| zP^lxrK`-p|L>UR~yzuf95;|qlQn@Pn#q+7WiCwPoGs3$4al1u^=tOb*~h9 z5$nueyi#mM>!FUk=*Du6OnR%FkfEs!JNHSUx5fHm==X)DxP#8vreWekk4W}Ck$Ai!HaZvU?MD2*MR$bId?yWf?0G!V!9P|8}xJ8;@d znXUPu#0pmCf*NGu!Pe>CR)?kWKWgak;5X3=iwIWDtS(A?_?aY(5v*L?o_()DpUBd; zF~84YaqB7YalqMvRegbu>I+tX(Jh;mz^XXi#n=$6mJ9pvDOmM_aU!-5t#-n9Kx@hB z4Zr?GvT6ulL>4An-4})4=xc2iPLbLGYpXc0Ise^(rshkO_u20b>{C%II(Jio4Yjc< zFVLlVi)^j@g`@2M0SpfeIpy zI*zM#RBf%hqEE%WaMr!|zKDvWb$!+M{d4aF5q>{?H#y14$w_i@a&nU7*~)%8-A>~R zz1&N(8S~x&Bkm%yjC${2?BXED>2%Dvx`G^GiKXTfN8B)DYh3Om*OsJ<&x{vcWWO@y zj}(YvE+fyO0xIJv|4%yejC5Y|Al$Jv#7oZh+We?4j7BM9XvAhskBP%PqG~hHbDT|v z#Z=K-ZjDQL`g_Y&r4>(%v%KYSE9uT1I_D>M(@myo{<51i{UNpRmwW0Mt@f8&>UL0} zzg$IfyhqMe&E9bWGu0pUN@GjB@ZZz zd%3<31<&66O*x_R-%|Gr#c=P~Lf(gs z^*0f6Ln-4Z)odoelAatjdPmB?z>Q-+?T?b@>Dp6=Xt|oMiZLl#u2iUF$5@kw)M~y)JT3EIR1>F7ifc?O){9Rjw>`_>02DFFe8rc9q*pueZ{! zu5!5a>sI<-SG3>Et>oMd@T9F2)(!0(zmQMd&c?zyc z8Z=TqBE2CB{6Ss`f5*RnkP9)4_l=TgN#_<&>(O$K&Xp|3$StG`^Nn$1B@Ndj7~?ZC&=+q!93&J3Gxx0 zlsK1mO_JY9Q|Hju$?_WM>1^scMgCQ{*7$ykTvvxZ>zYYmFBWo1DE4DEZBLT@rLj1l zoFsRYBD0Ml$+D{iVp~s>3D*`snI_+s@~6?!ALZ84;!HB6B6)>O3QI-uhZ)9ssq*iZ zl^&!yKrQTvxjprB8F;xJ4M8|v-02^S3o^0|d1=&hx_pDxL^^~ZbZH!2$d>!J>{A3dn&4tiJ3xy{Y@sG>jgYt-Bp^1cr>`7~8_`ULhKP&JE8{E1 zEjH$3GjEv;{**jRo@Bp1vE+z08I~IPY#G})@241@=Ew`mC6__X;oaH4%Z{b@?g|kbAea!jAvl40nD<^%6z$N9|@cHC# z!v{;jGfTnCmMZYx_;2&)C#m7&;u877wsw=EU+FBSeW?%M*lmLf1ug(rVy z@v2f8(o2P_PW={P)lvu>mP)TL6@HocZGIoYf#ecxJhxN<-AaXhN`>!F`4-{UQsLNA z;r68n_&C|YBDrKI+lq*iVO}c3cctJ}ONC#T>O)&gg@=|3`%H33{-(g6622v1K&f!O zQeoRt;pbz&&A)i!x8ZK3!oQ6z)rONwA?RExT)$NKe5qbOw^TT`RQSf2ZwcC%Tq+_~ z8y3Z*;(V!I-LF*ox~0MsOQjDk75-SNQzqXT{VheKOC?xa3hq-1o?ohu^e>gZeyOm{ zx8Y=~`=h=kplT_E`K8);X{q$%N`-Cwzs2{cWRqcenrf2u(^soP&tR2|_AeoO!-c5* zSZdhp_4^j#s*(ti{`XR0=WlCh)wdKuStZja1HrtK5eTm=MSyQfc&fM=785P(#8w3DXt`*Ov_ivZn{;Jy9z2q z#AJHBO73AOk30qTUl&qHS#`3p({FM^E2+~&=Fd!3HcZ|mgEQt%jK$3NwKNt!*D znr@V*N_JS&Z{(9+1un7QqVAC zQjT0!CpmvlKWzshr9ExhE(c2g45C}xeH=-&M(YfyNv~hWxdYnucl_;p*U$K_hm++M#&AD4AfyPC-GpvP?NN_|ga#Z{J;pOjnSa_fSVvaegk<`rO3NNxbWW?@m2 z8ChT4S}+KPUMzu6LH%{7iKpbTl3N#gc}h-{GCR}2(^xC)>P8F1Z*XTidK&6IP6XMW zksUp6clufZz>IM_sAe897+88g5KHBV%K0SyRe5i(2mOK)cS$1MChy zut%fWn8JlEB{a4R)i@_tvhP#}N^aJC-vjDU4;$3M*!LV1ay+#$% z6@SN4)vkd2x7yJ^=VfoXzAq|=Q?lfKLGB_o=tPMZ5mT7`l9S1MRcGM7v*SaZ5ztDC`U@w8_~y$@;%t*Zd{TZZ+-0o8KIlkRY6mH!%c?j=Fb?D!JE=AV>mm+Q|J|7XYn-UirhxhwWTvx zuvl6`)>q};(yy&(_*FSZ>e`C7UzPowP6mo%R9ySbpTLzvudmA8r3$Sm{+c|<<4#L4 z2!*r4*`+wIE+k|AHk>j*ce>b;&Rvr|Z5tv<{#J2BAv^4cmh|5>EWjLFlk;`iOG3E8 zb*!1M#Zu?%XxZa&^wV`P#;PT)L%idNSmeD4-`Lo!oT9e45lc4!bBhqLKLJx}gnTTS z;LljHyCJ((vJ(jszRjGBIJNu3W8mKyioYSd>g;I94LK2u!86+i2iX8aMzyTJCx@Qh>cQutiffcTh379Q_Kg zYhi#|wzCG7@uTIw8bD`n%8oAkHF%5$w=0JKPG1D}*%~-N1A7;PVPU%ka32j^Ujqjf zgIiE<0j{Ni=Y*@Yg%^XJXcoY(rYb6J*Fcfj>rg2Ze0f@h_TK_+XEk_zt>)*7;kZp% zU|+6*#S5Rv{-GE=ojh;Lv0`uHwp`1}Mx+Av2o0{8g+BPxrrUCL$=Hx?-iARdFWOl7 zj=WxyTDPEc_h15B+|1bVzKoljCsD{lxsEW#J(PWQ&XoO79*UO@-anMR#Nc@($Cuk5 zC}dAH8vaObBK^;c)<1&fZ3S69mTTY^^^nJMZ#*mT^JCdhdf`dC9%EL3G4Qdx#l_ZB zkQOC&{w&lr@nv;VcaFzYi9EA{r$=3j1iP55y%{k6;g#botMat?sa)OV zp1a`R-VZ8&(w&Pt&T+c^6y*IupP#}CI)@AjLZc{Dk-cH2=!{T>TF9E(Ts5m_+ zLxE-T8IH**z`fT^(3W1bM}(AO*T`g8voIeFXhg&EW!DPcNTgypSA@luC||B7J#?kR z`ItDWQkiFRJ(ye?KZE(}mK%+E2E!x#2A3kN%Ql{ShRL_J(HUjo35dp+)G$88RDwT~ zVYY}DHwj|@0<)D0!8nqU0CTYbVz`)7BflN;n+)Bl(Q|nd_C}sPm%UwAIn~wn-C{G- ze8pB=#9lWQcP9D1kZZPU4|r_W9$&H1W->$}r0zjwHHt|+ESn4=h=|FHRQpy;gM!2- z5h;6ouL%*2R&WF`!BylguD+#{XkZ^ZHMW?w7aWb3UdXbfL&FqeUS4YaR4D(U^O7p4 zRaj9D_ykI!vvtN*DXN|1vV-y9YdK89Wgn)u$TX4M|AC1NP5+PVF5T4|jsM8&bh;?| z?j4{`#-w-hPD{^`Tt%rqK3#-TeGg3RY(*G5eu7m;mr3sbAx}?g@SkkNQTf;Z$&-cU z=d&zM;QaI%#^;^%;xm$D5&t5$*Tqn;F9^9ACw+lA*vsBZEu^cs?XjqkfkGOKLLQZ& zzfAHrUDE}FSS!!BmTJ=Ql1W=YeyT~2EjY^*>4ikQbj(e6fG+D;4DJ~Bl$blVXc|eZ zwRE_uF-u}x=cU)Fh+dUM)c>Oy(E|%(jwOqhbnEGp6*4Cooys!Y2sMSO$_TbGHkVnP z&dcF{p`y#|EQw>#TQiQwpJ*#%KjE^2`W$(}sS{_noX36)wGdbCiv7Q={l)E!ZCGp8 zNqYBzR#>xXo~a*H#On2zMGU$6%8a-(H7(EHdX9OorpYMT*vAUZX`+p7ZP;m@E`vPu z%tzPR*i_F(!pQZOHrs(UP*3exFHs$P_Fk7}^l@Ovba>N2sQ^mnkX1$StqZlTh!Dh3 zMb_2%eql+vi+kcpx>=ER!U^(V18a%VImN)-rT<>i5(Aqix`iV!^fWebWIyZh;K6Ap z*3k9W=b$?)cZGTKGOH)({@LX1%vu>501mMw2Cf-qG8ibune~-s>WvSaSrwgbDREa| z9!XVPS+3`ye61Nua>DU}nG*|kxH0JIvDDKYIiR(QZt-E4C7qY?CtvnZ5`wP^=(45hRoG%(8u zx){JFz@i#g6*&TpL#wi`I?spK)hr)M7GCdyIScm8s1HU#BW8jCd-jNdrLX(A~?CHL$NXkb)Yr$F`R?Zl=cjrGgPp$u5G8l$t*^rbI9s39cWrBAJt9IzYcivi^2U4xsd`?R`v04lEi%xfxj>oXRc$}eXEE^zD z$FkbK&v&bNu>OqAoIVQLfIiI^$9@r*fPlK5J3)_PnRgwpJO_(oVoIAXvSf$p5stwW zI0w}*8OCUlpN?sfi`2+oRKF!Vpj$>CTQWR=Lp575Z$tB4<`R$S)9QgrpmMxU{adk6 z$MOKF`iiAU1FgQk$?#z(ZED2^N!M)RcyoS13N7`Abc%Qer#{l1w}3_juOK zHg`v;$SQ=Y$?z+^k7w0wf7IgUsBviJ)`*MM;ufiK=;^Il8|l_|+TEH}#-`Jq)~p7k zU->qyx##(VpebvCR<4chL$Q(zy>LnVgoV7OQEgaL>E9gM+J;qwguK;;Mbw&}BkI4$ zS7YNub4cU#aD=p#zWVXrWaws$Ys)6-Jn#G^NH@+wtz*Q)q@OB^4c`4i6qpQK=}|lO zBOXl}+#YEU(}VUb!Kw9DQO@2BXtJ2gML_g+%-bE<6lvT!D(C=_@*PEWWJcHYv-TFs z^It@#z-lgk814%armaxjB{Fnkxq+89sf>FiI;Xg?{*;5zK;I?U;Tk{e)_;YHE$06^ zv2fiG3hT@QaFBaYXVwtXVr6G`-}&)rdsNQ^>x+d4tS^JK1@hU`w4@9BRVWx;S#OWe z>p`mM>4){{U(lZ52YPUH@FSDq&3ek|$|8hWrYmM32)Aymw)E*w+R%-;RJi+Rs6|97 zPH3hLgn9<*JD#Fz-PnEif^~xWJ-$Nojm=B*{i^z&UuV4Bo!MBjgkz$~tlA%=f?mu+ z+H;C{Z}yw?!wKW&-fXrcl{rG;-?3U!4QD(uhVhuciZ*`7TqTRcbmBXf;ru`3*J?J+ z4mGQ-dN_vueu#$lV}VkuLqz@9Fo_=^%l<67|AvG1LW>raOczAy)4as=pB?s#02pel z6pfWGR(|=T3sis}06d1E><&_G3u)Jo3+XKpt#pP*A8-jXQ@S@!7b5=O1GK(B>n9~2 zCH(;AXqUVq)Z$qBQX!RsO(p}B`vI(rBp;($12FNr?4wsmB{e@t@<5jFuX=AnVbDp{;viosU20$|q{q~;a{09;h0 z$#9wI{P)aJs8rvx*cxNCWMa)IuoSObdx-eF^sj44j6W=OM=<}I6^)|5*?c-;j~b{< z{<2r?K{5L1;}{?HtKBO7A!;O|gwvP$x>1VY zE1ZU`UhPta-*Y6|8I40!`?dpc%<2Zh!oOYMACzfz5x}@E~FQ?;(|vl1_^4uLqc7CL)fn8d^Jv|gtbJp zMS>m`Xp1lGvZbIb@fb&TSbIdMq*3Rw%sx33!DCiIBE6vBU!~u}2Vsya<439REooMW zD$#|2&g{CC3Sv{7_LRN9kEHBboaM5JQ&|>N% z#!ibFr^N&zroI+4K#K`LOpq4SUc}@@28fU-#bgMlf#X<>h6m@0#wxc{jK9Nkj#+I* zSeNhHPNy!fQ^HmXcw#xR$r6RE!j;zvz++Y!bb1{7UdoB5hT~ZSsR3?*9M3YOv$13v z5AA+#j?rTR8)%t430fISY>U#>8Wd4sGRT=~-C__UdOhm)E<=qOg_syE=8+aN1Tmwu zm69NNMTO6{!T|d zQdnop+$K88Nnslyocm2WuN5`kJ{;*aA{>Zw(;VkV(HW-H@p8v?k z;?~5zsaOjfqMuS(GwD_eolIrPc!{QE8gs>)p99k{6}?HOoHQ0@Ik}OJ{z+p!r9Hn> z`*h?Ar3vY*vGgj5cBCWsKWphzI`i;fkYr}@vBarD3H8p^>^q5wFPN@g1Q&{@2*ZA2 zb;}2fv`Ay8dYAmfYO@||Ay~7+I;^GLKe5RbewZpa5asJF7@}%IaF?0RM!?&IjMFh; zR$fE@OlQH8^%|;@fe|@~T4bP_*o(+u*$&?RXx7YsW8lswdi2&p3u=8%F^|}hPCW^8m)itviizWk>_gO#|NYk<~=?1REGl%T7G-w6=JCgqh#Y*-sVpV<1Nb`wITrFM7DifSseC*<9(; z5^6LL(|9f8xOog0k!8)Nti|Z(E$5T_5~$;^=27b<%u^b$h(<19Yo!$U;V)%BO7)4B zEM;e;L-T3qG7RTRKO0vsV=pDC{cM`Qob8vM&Y?~#*iotdEplJUrk1^U6Z2FOd9P&7 zWL(LHN?Ya_E3INJ@P=U)4gU=)$~gF6{l>B+o=weGgM^zi=;CVVB#UQI{2JC<+B$3Rl@|ATFk%1x&#>sWv3uQZyu4t4uE9e(<#lmB!I`V*#riD^c|dUi#UHl-S0Y-D)h z;K?*Pu^C#}o)oIIg=I^fQjA--ux9Y;okIU^!|Ekzs?j5dEw;435{Eg{?5+;a#Jh3E zJR`&XUl&@@t(_PI1!bxFF4%#(;=*s{BK4j?Lv~@UYCnMk8mg74bAmY zEFIbnP8=>n9dZG6q4~L3-UOGS$GObM<<}S?Yei(WcUVE@^=$1&o z?12XHIe|{>ff;EYIqYTMNz)Q2aWDFno)+#!8JC*Vg}rRNH17tr+Q(XpZOwg9mhHyU zj(sd0Z^ks<&z9Iv7$bOlY?tWMuq@QFpr`xU=}Pva?Xmt-E^Nc%FEye1rbn6)$T2*j&1dDzuK=EE?UL{Quj zjBPml9bu``;1R~xM_3u1&$QEaI9~s^xVs21e2Lq(a4DI|u&9YB0E%F;(eW5Ww{EI2 zAdkV#a5=p@4m7jL@dWEGHO`?iCs=*^F+;H+80)OAm%*dwLn!wI3#_oWAvE;9s^cE6 zzkuNay07{b9KJdyPSmy zPgjJU!Uvx8LaC@B?tD3LiUrv}57SUZX{c(oB;9EY>VIOX@oDD6>eW{ZJ{e1cPP01f zQ$0199ZSERW}#ANY_XkYjatkW(Ku&rGNfx?Xy3`&7m6CKeW85^YhU$EhF;ni+OmW8 zh4zJc@C*wR-S7nDlCE81_3ReZGUL)zoS(?+GV>SC_?N-h+r5kvFEeLJXGuR_W!3$j2EtHX z3B5SNbRKNo(jGm~a0rpw0yv>%T$T;&A6H=x?@8^hv9Z#<>U8WH4E5m@f1Nos4yvxE zg&JI6pVkAb266j^(1jB!m<$z)fdTroCT1WWa8ZHps?mz;%uTvpjrQVKw}-A@XYP%b zS1Uq@W7e1;RD^BKd44Pgw$-O?Gy`MIKp2~Du#X)kR|Nu9aE;c!(6I+=U+CDqv@eY2 z4%!!nLag?MR&A<%p(llkFL8Z*foOm!H(7j#n*l|L&ud>moTq&O@m}o+dHg>RG}k9-er4W zy0{0O6ch11_S`q4zJtXsvHL2X|2g1pk#<0zK28-0RwiH2lpPk+p6cFbHT(|L5_E)( z4*&su<1;_tpjXONwS13u=JG?@QO121V3;~iRa7u>{)J1*RAuyjB|3VadC4ED0F-T* zOV97KVD_o5z-hI!3i&@^5uV?-RcG5T9$&<3X?lxF;~^l7vo) znKX1Wdi0PDbM7qCsFPxx`ZYWNO@ls7gC4P}+<-WBje{-BN6f?JrB_kvN9vb3^;IuA z`-tV?${>0Sq4LC&jz4C-#oo~q_B+4gA&|i0b%w4zVP38q5f%d;ooAK$+0!>bEd)Cv zPuYm3H4%x*=+j^f7p21pX)@@vNb#DcQ|f0Nv0DUS>Svx%8864Mxq2W zvyRY-eD;0$9|Ra?kDDd~mRHYM6P+KWJY(Mn9&l0f>C?su8&~F0wL0^(NP)~MrM^X? zr#i{tZL|UwL&!qE+@3 zKhY5>icS@>s@OaFw-8oqtkhmX(SoPJYjzI}SMLq0?%K=&D(~0Jv#~zfp8}r1R6$eT zunrY2+oRUz#W&c3qdSoLZ(wB4Ae*-sYH*}@%YvYk4R{MP=o33S{ubLL=vx1$}!`);XWkFzDK#SVQ|s<4TImiMws%ME})%gJDBEc53zWqvz@I5jaYKyd~xgubZ;3MdGWu_xCkY+JHUOHTz z%5m;3Sp`v5&L>ExX47w+SCMAaqSNB{RyF#U^T8fLAAu>|)B&5!Vd69Me+lJdvYM)H zDlj%%^W}Wz2N4f_E!9}5JU8j=Q{N$?_~e&rc(&y~RInD&P;t{uiPhCH{pMfFvE_ZF z6F8Wo=ehjSKW0R5h|}|EUAocRj$hD8J$>mPdmbS*_N96b;K*cO8tTAzOHC`2Uj^?1U2yzwsX zo-7BSHeB`Ys5$8_ED3s!B`HAvgMMK?&k`C3xDXcyl%{>KXuSteiQ$wTI?9Iz8u)tK z`7co)oF7Lcm<;2|(~%F87JAbRN8V7n_kxZ&@=ju--w9Q^<3+8Vcw=du7tM6yGuW## zqJgc>dXkqj?;)+VrYX+6t(53Ve>?LgxzoHd98ry^vekRxNQjU+g{wfE?i&W-`DGBrr5_CkI#lJ@bDCQnN!(;MO%)zF*i< z-1v`9Hc?M6CxK3E#&W*p|uV|CuS71h#{%VMN) zbost-MWJ}KwW4^M@4O3L^xzFDIf>Y8s~#e;2ASugrGs%E0GqN@(~}3=ML!YD+n%A$ zmSK;b=?71~#^;ukJxCF?f@K!<$={{kd7J_k3#_kRQ>YhjB3*W-L@!=ndjE(vdvTX? zMr1P?j?q~!9%5PMvmIG^^QzJ=M+)*rHxVZ`c{{1KlVGkJofoj&Mf9IHuNjfG2*g2X zh?j+fl5mH-)k+bAvV-;syNr1vY4i}(3Q-JiLOWIHgRPA)8 zCzZIr=uVY+9a#UGRpxojp#q4&0~8g>!Iy_hHWew>mwVadK8K>TTy@G{;y{T4^rt;- z@a19B;q6r5%LAlO_GIt_`)AuzCqLd#>fk`T{CGXPoI6@uiv88>us8M#{dpzl{C9RL zALabkVt)=t6V;A6oErM`+7jLy8R^ffi)E!h_msNX({6u^kD3+fgFmkJb4DF%@o?#}ObcppJWC?ev05O=uRQ63xRZ24Cf6VyEY*-HJ_zxR zWXcHQp03ui#)ms+%*eZHyW5sB9SGtc($aEtH;9jQOD|VUdZAJS4+ZDPJW;9RA&Ovd=zLjYKy6-8r|U~$A^fpa*~;i!hkNNHdmTlG^18aJ#wnq^rX($~GH$5H zgYg)pCEcyht4nPysC)w+uWLo!8}Lz*g9V*#z?*P-TUNA4y)SmgiVb-Son>c8ncj`~ zVM_~q_%`P4rJ6dL&=|rz)`BkMm)HIe0|3TObgYJ9P&)J%C_Ri1vV4GumtlNOWuGs0 z5Wm>bkJuwD!Ad?J%gp})h7Zl492#M=qa96npyiVHcJ#Oj?_$~egB>+(3c0@V4GnC{ zTU+k_h$KyU4W9f_EvzdNylBcp__P-)y>19s3+MGKy8^x&H@M){@y^1u0e1*HXeavg zV6{hvrJ#uPaP*Q<4{1|4_q05OoM*#9_WZ`=8i6)D_<-Ugc#P#*q+AriZ(7=avco+^ ze3Il{NN<|)c+0x)?5J5JU#rWZ{78OBn)MHzh~j-LR|8e`XvmM-Z>du>?`1g*5!(@A zc@`h{qA?mTzNP=7d0oq9KpxthzqYK2kE$)WkJRA}#kJspQoT1csRbY8wHjhYa~610 z4bLBDk*G%gDs|k2je1R{7JRWZ`4ugR;p9Fxw~j@0`XhbXCvY|Y8a8sxb9~s3uP8ni zB5uYFN{fZ4Ecc4`#qtO&Hd{g*btxq8mb@o?kf*lf>!d4hDWDZ!B;DF+Jk*Nc)Je52 z8kfiOzjV4D)V>X0m|UmO?wgZM#hP!nRR$io!`55zAvr%JEg9bW^4qXaDfs&_-@;u> z!RucxYvEjsFrp)NX|u|Sn-Q|ZT0N%Zw$Q(3b)b7~c?N5|O(+3YIs0jJJILCnf6?Z4 zyiV(UY&6H=fUtMw;W(kGZ~d!|Mf%OI-EoLG+p6+@j5uh>0qDth9@<$%r@aH_@h{NZ z^ii*%A}#$>Q%(b7vA9+5&S}rLORJuf(w^7R&*>p#Z|($Wr#&b2`_7 zyNJsoIzZO1D?e7x>IXr0(yFCWdNaH5o2)uqnh1 zq~RTTZO@S&o(%!*lgxJMt&^SvqLQ&kas5@;(9Ju%)=+*^-;&+wxds*i0thE_b#9j zow%2e^X57hz59S-FhJFl%OOIoKtc?XRV|>6op^U?^aCU7%yV=SDaQR>cr_i%T`$@r zG%%mubmd2-CwFOAH%yI3?$V2HkVK2`7+t&bMmn*&>%rr_Tpxil*e~r@g5#Plk{({< zmiy=rI@ALb;qQ;=Ne@ifA0LrlPu^LY_mHOcI$uCfK;&74A_<*8&@i-~>AgFJ&(-hIu#%MtmXVUP(A znIm++7ymBg&!RL+xPU&#l&b9!W};2<535TgSQEhdn%6~}g|cgu*c%m}d7oDG=6=$~ z2Xvx0?=7{$V3)Jw)wpo_?9sen35YX?KEM-KtQx4)g zt5HT|`-6qfN{$97lM&fL`9u4*%82Z!EYrTrW<+*U=4jvLG9o)GX)e?-gS#dVL0m?( z1#mK@r~0kKH&@!K-x9v9l_>QaQ?WE*5 z8+j&AlcXlU(3~uO!}84;J37Bgsz}pja)b4_MepG|nx~93m}uopzCyBIN|D)o=s-K% zJ*VG+r*AWGI7*SsAqk;&%0Cq}m?c8(l_%y<8H740*UTX+ggPoG&7ragbyD`2L*)?a ztZb@aBKuj~J$be{nq^ojspfB<5vfzgnFH1tk&-gh94Ma=X{q!y2W&DT%P4Kk0o#m7 zE2Wt^pwEabtAv^Zb{Uc7lmK(UJ|j|A+{^)ojL7Cpu{DP(WJGdBXAV@%h_qJzanP!2 z$cQYjJT(U#Ga_x28|HvhMx?EB#=%5yX7Ow(ez9@dY(7pG7(M^JHoajA$o#Bc2qE^y zO@<9w>f%KhwA`|$!hE+h3wzR-QwL^IySco%wTDO`M1RFBS~Zss;`fgWQFB(AxsV)w z=JC>q1@zs|yaNA_C*q$e_vTa5&pgyxH$yBS;l+qYC-(i!J<88Tf?zc7GiCgIdipa| zK|dF&I*(U!_X8v@^Ie3xpi_gioLhs(xiV** zD*nIPTC>Ay9}#lL#scL)3Yj)Syks83oEDn$8A>q>m`7m=&k)SRX%WreDzvUh42Ajr zJkgD@SqK*flc8WbQsHzdouAJGtj8bK2yf-|g~}}8ez75Q-<#0om(4~VY%8sZ$r|Mi zPt*iL=@Ceb(!)jR*F?eqs#pg$$wh^hPP5Ic+H7TcO)0hRklGn~z?{Vlj z(LLqSd$F&Yc{lS=k6!8}$2iovbQWz}zVGfk=+a{36yp`3_%b&|*G_wXF&MWLss{q|1xB zw`CW^e^|`xO0#NE&=T%t`Pu%9vHcPrsx!1e#|=IZpZQU|8lQPX(Aa(!EnCW644!5X zO!-A1-&u5WDKC(IuTI8gys}fjjQ7I%HuX7fV4fm25AmO3lS!|a@nJP}_G%B95Vsp# z1$z%hWj@WkqO^R9SDg+d^^VK@hypRgB3cPGQRXjvpwxOgz50a@=qKB$dG#67%ZRhX zzY1^Agqq?!aaq*sA3wDXch3;Yl5kje0rR3WUkO6>QRmR0T`~OyzeB&dE360Ep#ds) zqcUG(TSBbA>OZF)zw&yL*H2XVD;6?UGs$l`7AT9MGB4-V-Dal0$D_&E5Qxj3phF(j z#RU{A9p2K?~3zZS|5XcTqQWFR|g~9;!$3i(=KsQ(L`sFjV zyr^Mv0eP+D&eHaM)LJkWCtpnW2`=HrEjZxeJwt=p<} z*ajj^*Y5di#R1p@DU`IDcaR#Tz`uq^S~h1Ua#;hz=hV9tv4(fh%g85&;u{Dh1zP=Y zYk18%Zg{!}N57r)JJNjB6CkMvq?kq+qWZMs;1B3Iq0%cG$|s@C^d~hTJtxNSw*TggZ&eL$6`FGqCoBZ zeuQ z|D89gHN|LW5wTw_v_Q}l51L9I5{Ur3xY!eq=<@G;aI&IS)Yd_{Uu0o80TWTnk(+Pa?C4mzmSSL?GIN)lWvP!&+e)dc1a zn{|&WY~b^x&bjo*22TFH?jlXG~F4*?Ef!y$Ova!4|0!87hoj;^D@MTQSc_Cq`5BHXc{i z`i;=~68FZy+R#_{DQp6vr*ecsbypcV5p+W*%nJK&2<_g+JK78fLdIy;G&| zWu!Zaj3R2J8byz`^APEmLFBT7yLrehEW|~x>5gjgX};lNkV83#;y2(gYPW+2^Jfi3 zR}Q;qSBGZq;C`MxMuIf(xC55qP^U7*g)_>+8!GwZ@LJLi-XY}KGkBT_^-mmcsiDDa z++pbhdX;Z3h!Yd}!4Vp=U6^N$yprW(eI1%)#2S0G8?7|*R*v4l1fijo(*L?zN~9Y} zJ7Kxll25&NLJv_6Fa1Y7GjN6~i^k z7b&8u;`Bo1A?4;(mB3t=5>?GZT$~_Cw81cQu6_z_*oA3-c_dxg#Y6o2L!l9*-vOsv z*nrdrSBgoER;z`F<8J;FElaqT|};dUpQlgqm}rH2Xv z3leX|Wevd9AZiy03))Cua(NYp-@BrVWFCev^H$lK+?VR@;ocr=&_x8cC||7h+V+L@ z319h-p=l~7hfu;E-la!=AB+b0&71daO@?b)ggBQVHmk(;nHJ-X81uP=94#gQG2U95 zRU+o=DTE-CVNM_N-^-(=*FVsRy}X&XVZ9j6h021LVqgf5m_{bUtKMR12a#~KH=W%J zGu7}P=(UpoRPRfR4A;X$7=Yu_gEe6P9bMdztCU!iR>*Tc0l0SgNWbPVfC` z&S-BY<08mVtI)LLy^`Ar*IScve6T7};P;#m1~ec35anML zr`o-hWmp7YSYU$oPCN|YJq@U&sqy+9QNE55`skyuRX7&>p|qXT7=i-(}V>X z)Ca)(43X%+zaY2CutEfYG&wUeK%agb@+E%=>H+LWRP2RH6%BjZ1|fU0CZo-!B9B^^ z0p`q^kwN;jU@aRVo8aIpECkSi(Kz)Xq)Gk=WLHiNcrRR?@Q!_2FAW{&sVT5j$3k8u z$i5gS=xHG6!Tc`h$r&bg}fC4gL8+kb}rKM6XD@Ht4Rh$6-SqPRSx&_kHI zT6d=*hq#x+^M=BU!i)-NF4v^Rhj#V^oo+PaFwaU}z6NSvR`dF?S++5mciMuUHElI|K*!M4s2WBoNK4T3} z5vk4VW1AUPmH}Psz@ThONRG|w>@A$c{m`1fAq&Jj@bm&6jB>U88z8BeC_Bbx-bL!5 zqSWcZ#mQ@xNN#OT?vLa#S-AvXbDjb*!7yQ-*$lUsvRnMXicybuZ&F`l!7<3h!RrpxE51F3hvNiN=U)gA|}ta_%IfR)X$yBH;)I>oX6a?(Q}XuOH7Y= z@$@hH_?sA*L$bqcCYKe_QEGHJ;?Ea@j9QMW@$~pH546ofFa{4iK>RDS`;pfZ?jlv} zMGc>De>yN28?75s>A_&$#jvf{dsA%o9*=v_NTJWbe5F`SGPWMVt#!2zce1c(nVlAr zA@piZ5wcTyV;NKAywI$hg}BdLb#n?np&V{ZSwp#7^1GXoa7`9|3$UJu$-U!INoX$_ ztA$Ac_Zesqu@`YNPlLQc8LhKdhkUSBrKIwgisMB>g}BU@V$3^e7}8yVp>_6#kOMd$ zDfE)vKfxO?SM2Y=HE;xwU_;Mu7;5|L1_~dBowzUks4v0}^HvC!#%JEk%tyCTat?l` ztYN%n?ce%g)r#3pEF8iy@_H;+b&B`bG7q6g3_OTlvmM<9Ub7HuIXgekw|r zzwa}39>J@(x!Fg)vR$}+(z7I8A! zQ9@^kY;jJlD*_hE-Thxo=xJbff^XO03xFws2fkn@3WpA%26h!4;ikDGyhN`CSz%g_ z1mzB(T;w-$oW4=U$gxqJ9H&rS`+u#{h98K=IwiY0(!uQ$MR10!74&Ppr4gjvUYx^oUwe4RDUov zPvG8d-n9_ZFWkQJb_)*;eVQ<2Va*o1R50uHK8tYCX-e4 z>L+p^uMTIOcu?sTh8$p0_IiA>f9@2lyMA2${JjCRs zq#~UNoWrRzWt=(SjYI6px+P`^W(CDPSqrGM!VeR*fS75OG1Y(#yD|dFJ&c?lz4H6S z(DL!zvHbf9NT)hnFNmUp2(`O*3v2hb8$F2p9Fi|%VK`q*7% zP*t^WwP{H|OyG{Oc{PMZAz^G>c8>2TNUDg;Bj}|msIS--+tm>lyktH=>%Cu~cGdUT zNf9@Pn_7dVdZ1tEu^)stSPrmZGkjrVg?~2o|v- zVlH}z8G1*A&m)ZA%!X0E?#g52hwOI8YhYJ+1FFZ5Hn|D)$AH)qBjBsUU2495og{vRymWSl?=}Ojb*4vrOq%) z-)KrohJpHMH`6yumAj*1bwj;ak| zmoZPtY(WE$^W+LKk-}7TG(T1dY0)fq8`AsZyp6sgtWVWNZwnJ0Ri;iS_@7c(2U<>yoVDTsOQ;HACuv?1{87J(hegWoBIxr; z9vIj^LS6ss(;UQHfYJ0O91+=5EOfYpw7yzaVkNbVY4xeoDY%T+m`MjuarX}O02E~x z;zJ#7sYmR36uq0J&8Rq8AyNs`+EIO4v|3M`DfQTZSVfOs0(O`#3KNk)w6-1voyI;` zqj2hQnlIDUrB|n6lUxTC`wSo8SXUSU{+BXYR_~Q;q`Lgqt4qtzz}clP?LEUialGW# z88}dflKyXQ(1jZP{^nzKw(}c{8jZp>6qlK!gEx3b7yk`Z;=50(74?(DM(E)uQpzi z!VYn5ns}aH)CE)g1^!eQM4=aXKm07Z2(p7{$3=dyb}ciH;GCLJWnT(Vn%%eq%@A}z zSdMC`Ep!!k2GycD$&ArU4;AhumxD*VkYy2RBxFx{*DsLbM0&BM6mlXQ$DvyYm zQAaSrP~ln#TJ2~|=CzoE_sYa&1xjL-F+uNVHpod z7y@Ee0)!G{vU~b=MV(To()=6T4|f*sz5!i0y(jtIgw5{W6pFnGKRw$d8gdh!9ff1* z&zo@J4xlSHc~zhIsVe>_UMha|LKjGCecBMrfk2uxmAr3ZRF9oXJ#NAKkS5dOTi8_^ zGnvlcg4f$`-O1`U9P^hoqM+Mo$^dG8o4d1HlT@s&7Sh<;{9KhvF~UdVsxmqlY*TB2 z2PB28X<%hrrH*=iWS-Ko1`WHzJ65?91UCt2=0cZ}0@ZIy0W4gyTOrL_-an}VKapBa9#D_6rMQkz*6p8T(+gEpd<~M-tLi6Fx?*`3BITJ{8 z@4{fdZ31n)i%tBQ6X^C`?7dVj&bF^IIp5>w950FH*M@WY9Q0E`>VazXnHuS8?-!+*H~{du3ackz*1He&Tz};M8JA6C|x)&jrh@Yq7MSg?bqJ zOAk6|;xnWr-511LSCyWXTQI@8lH||>Y3fQdx^KT^-B6N7Zz4NO>*|bk#gGiK`qYJ@ zEUjaui)CoGrL~W=rwjdMY28@r-GyFRS`U#fb*AoRtlK#>tOZkC_T&KNT3J*)J2a{@ z?JZ;NS1HL7oW!5LYMSo>&@6t>;a7P*Q_y5JtTUCdLh%lrsj-!Hgfyh4G1a5Xx&n7=>R@uhi#;{6|H+nFAJ%y!TOf8qB+%cw04sszNc1>*1e>AyXa3x>u_nw zcl6xRx|)-wX%`L1+jFbpfG2N8<%!3(<5*Qg)*#GHz3%IP3?|+=<0_uI9 zTPP@^Af*BlBBG+AAg!R--JNTpVuDzRwbrqF?XK%%y9T=Ux@&iWwf5Tn-*X3D{Ct0Z zUN1fO%!xU3=1e|w=d!*Hn(>p6p}A@--DeUJu~eW0U~DY;Fc^*74H&E)i?1*PHjAYx z40eg7&4AvM@@u~J5}I3Jjn6bY=4oCVOK+IOsm@fiB;b@-s>0ystaa4)H*>Tj2!6R`rl)=RvX#svS&!E`_zXLKq_xDz9Kz;jGTSn zAm@zFT~fTzib^)2yPjx&<(iPi3t}Nns9YYb<7IIb8a1IF47P4UnGAMmLaP~^+Jv$J zM=fcRPyNYUs4wu^P+!OholyhG?ukV1X5P~BlP5FsaZZ*D@~8adK8(DElNE#P z-Bfe?ucxcW=o2|zGw7jBDcu{kmTE&w4A_(oF!-%C-DFT~N?#Z(+>}a|2E;cvsxj!@ zlv*$t(3DacjBQGD7;M{=bih&Fn&vC>wMWRdC=R-zP}PlWQ}dJeGV;H8hY#c$26yTtO=%N@mz&ZV z246O%XAGK~kyIA2NHZ$O;FgwDo53$lsXK#3o6!UYOEsfafTMiakotX4d4gZZbIagP za1<)h$TloL`4l4;rxj}yN21d?#Zb&B^;IwcQ5M3@*atlfk{Q zG><_c4zEc97K)>r3^s2(8>h^@pXOIQ^)?inbGhQKd5UpUQ8YN&c+iEx*f^TNV00X< zWe~moDF)Nx=sAN^;z$dG<^}nC^-(zKoBQz**X*6Ad08Aa0;jM#js`KfGmhpki1A`K zgID9|I)gcJ^p(M)@#G!^&C&Tg-(PM*^JBdD$lQ#*IwOLLG^9@86w1fbI0i9ZtPVn` zREgKm1X*>1ALU^zX=Gvk{rCVn}Cfk_$Pu&ZuAoX&??oJ`~BQJ7_f!?{6N(Xu5; zRH1*pXlqM-@qTH>=XAIvRqXR8d#4W0U{-NrvQY>#9D5@@dq_Wp+Ssv&t}s|)FMVP#eJ{D5wuB2O_TqLe zOR$i;m!_V!6nApi2V;#xKcTs+zI}VG{$l@pFZNFa4r>!K4oV-Ilh3UBtK zX^waJJ2v?)y_fo(!7^dd9@=}x5+c0oL@&=+iVG=sNjhusE}FSVh0J>IG{`XZOmF8s zdhA)tB3#4XPk(sM(%(_ozEW@Tz;emtdToVjqh`c_IpW zx{oZOCLwbuR3Sj9&4do`m3 zbVR<(hBo$t6t*NC)SYsR#rpQA7K=}NR8lpPj*grGMbtFYPNSlQc!}Zq=(%+_{D~A1FrX|Dln?v`U!Pirgwm3qxK)gn4wPxAEe$ zFWzWjPJPTY0cppOXL(3phP-H_Kd&TpH3>~y=uN9gX|^FwE&iV>6eRyp;gE+IDjZwr z=IYXLlTfBHO$e7f1lz{6E?oL7*f*jzHKg}~r6Db^DNPen>rrTg)ICaR%qne#_X~KI zsVvV75s}D{2!=>`h+({%hqP12*uVv-i==~NdERhyg#$B}@m;lIWAJlGGf-_EM5TWd+1Oo_#M zgIX#Z)O+j~wjJOze#*(Re|)$C`!%T}RD8oDdZ^1?R2!@RLF{l%9$y||$Qn@k2N4Ma z>tYBhPTQlUU?~I4C@^Svb)lJYQlvPJ3pejVHyK)=qiPrOiI>KR7dsoOM|Y+j@lrK$ zHAic7rVsH_NzolB@}Je2+!Ca8=jNTbSuqz3vkG(Ov`(Zaz^s>`_J}~v5qPi`FOtu! zS;;@lde@O0YfI6hEttT2u_LvwEyao_IvVKsj$jVUK1c5Yj722;Vn3!g&1)+i6;Ah}_U)vN zVq%iPUn+^5+e^2^)I|$V z=pwxopT-&@{o<)XSE+NQn1(3mJN%x{c=~~s7rD1`PU4tRvlh^PAr34q__f7okYK~M z%(Jf2W_eDGYJ>Bof#9iz*=#o{O!y;~9(0r5C>ixt{6G-dh-poZrbpeS`a%l!i+V_& zqAhYk@}E)ExrY>D8G|b5!4hUh(efTrTVY)^+4Yn<2=k+AT}AZ zqWUIgZEJ>RjXYbz;fYy$;(2G)r52s+nf!4;W@GVxopH5|WbBZIb) zbh(%0S?n(;wBAJ8lQU3L9*iKCi6n>KlCR(tMb&#tiNb~mn%G-fBHW53|2~qZ`BEg} z4t%$2QnNl%xe!0#Ru6b37oQx(Ny2T+j-<@o+zQy_f?6}9{{zS7R%Ud3UN=JD*+<$g zh$pKXHSnbd4d^E|5$~bSpto~%`m>+(n{2M}qYAfGqcQ!Z2M(vIBI(<9Z)~Hoa)*Y~ z&;e3{U=F9F1ElLho$9oFpyVxvKra+^4Wn}dC3o>gH3O{?Mjr-BZsLHA23jnP+*72o z;`1to5&No9a*Fh;SdG_7QWgDiigd&zUJf(3(<+fZSjrUsilbUXBtN#)=raUWsB-e6 zP?|eLY9$urE({B$uS29D$32y~>+QU)gzgzOy{kx(sZxw%*-CIq2rJ4 zjtu?aei=%M!=y9fii$>Y94nC5aP)2cIeIjh`VW^X2<{bWXN5r7 zXH;i&Ry^yr{DMgyA$51S$f_pukaaflLGtGEG=7BS>Q)}fRy$YR+t$`y)&eW;%kH(q$m5)+6?sg zK|Fri`_aV=j2HU?4C*;w>N*CIyN;u)eD!H#q)0)Cs!Z#)NUekdWhr<(CO*x}k^fdi zqh5y6#!Ds2#g#L}XOuw^0&wmI2dGe1%pHNfZj6Mtw+2lnNCQ5C^8%P8i=S43jN)^;U z^79n%qTnp4m>7i*fq>_sC)Lk_m&$RGeV#NlOY#tJp)jD%@T9Xdq@uJtOOnLlJgu82 zwb!L0&hsR8Z0X;ets{-l>dL9%p7b#bJ%R^EWl!3xOU_hllH?@(7D3G?N#n%^yhL?9 z^xR2og&~(WYQ%i56zk@5G_ybsTczTHm$y+fKIuqL&bf=P6*HH9#4hC6gDsk?V<*7N zaIWfY*xIrbU7sRVbK2_lJxmK(JK_E-6vI-A{HIEfoF;hwM=FA90!eivpJ|e7sUsj+ z`+`09FZ2Y)*u-O<4bfdasnay6l6cO;$Z4i4EuV(LZx@e)c_nG#uc(S`Kz~$4*OGMZ zSE-FSoAcO|WL4o#O{YtRgEI0n9w>o~qw%84kD=1BkP$PVQEC{txCG6aj{bNKSJb}* z9i5J0|2>bHi7vEZhE!bK?q)D|b7A#WMXbirvM!{}luC)d9Q{_Ds?0>)+;cUU&lcx( zlQvTlMQ@ma+tLNm}R7W%df0g}r@$ksv?mrD!96RJUNZKkWsCGUWNK#lwZ%~0GC14=EgWnMQMd~l!5OpJ2>zBbw9 zuI3|K9VUE~37^9lzR!kmZhSH)nV6bOAU)Bc)P-j{5c;fTnOWbJ;+1#I8=JaN<=^0@ zD}|`dZ_-<_9}mlG1*z3aDZnusUSk~vW+$PN;jDQDY2iw#UisVT<+?$8uzOq}%!a;hKv)$kU|5LT>Pl~vyke?zLmqxpY^-Ulm-s$XmUwKk z*_AdGwUona2_3tQbsAW5Q}ZT4NPxlXz9}?$qcjsY;TgCLyxb;fsChB3$jq+_ZQ3No zn1|XJ^s2zWZjw@!J>bvl)3$w4^s$>IZjW_EDkM+oS|@!OsRh0r=)^l9&1TR|9Ve{KhuvhI#WB10VQ7 zq4g7_Qgm;-WHoOtXxKLWy+SK@NM71H;6KKWwn)9QLuzTB#<@QJtI*4d5N*9vDy)sj z&uRr})K00W`Q0ZYm$|?f@01#wS97;l1^#uXCV92b&L>?KN|cO-%+HUT%>rR zJ7|Cy%-tIrgZbZ_y6zoZtxILhQ#n5Doucp4abu#n7gu-njY4g#lAq(+_liw+MlveX ziO<9ryixQ8Rw=+F)Uh=@EGn-RHoDinLE2Wy#kM^x3D_$6+8%hNQ0g8yy3W6bNd$c9 z9+>RTs66FBSdxUTJ{I-0qDb^ZFl!V)jd= z%{ClA0^F#K8T+OB<`XXrrrJn+zF(?gcIP!H0Izfal~V%vkIFgwT%qmGI0RKm;CiP%7nLmxsjdXJ`ar=!d>H0=TEhWuqWwF0uca zLg!{kPBir(n&@bh9Ff=OnNeqS{h*|pd-Jp?FupyAnkvijBEV5o#i;rrsj9g)To1ur zPZdf#gidQL3j9-T4SuTVhYn#=%hn5FzJ80;QhfN>sID@9^XdwNGmPq@$EcpelAFKR zKZep@!1urN$64?ALkkZ ziyq|F)28F7rw%-^?gL&=pN~tbn8ee(9+2Y+sjRsmM_=F1tEN^bq!Mxp%KN>8x=&+H zNYg}*`wANv9iNcvAJRzC#G4(i&Rg+^^w~V?u40o6vig|Tp2QrnD{!EnbM;Fn(d*0h z_Y}6Jg3V5+#5?rl6qb$`!2;Cw4plr2i9_6*7jIMh(^5a>+8va1IW`8s()2dnJ}o(l z{W(k3+w|qM)J$Fdhv^fS=)%zz*Yz3arFfILh8LjW zHM;+&R9P$r2O;Mo*U0+<=0K?^0MJKQDfxobSPbT9=2hBw0n5`b&*{nq^zqfN(x(g3 z5asJ_6!)U>6+Wk(S1A22X}b9ChM}Rv6)O2RR<`<6>iRd<{FivFez-(6E=t?P=u3vD zD?X=>7o~2>bk+z&cJzO;Q}#vbdr7J;nl2lPMqi{ImoSHHf6;dS;x7j4_(j)U6oo3;*2W>U(56Owg%$A zJI|%adGfv?l`}s)XXN610gZHt%T`2<6;oWi`HH0$;%Vex2D{}n`QL$QtKrlJNtt)7{du6AKc#oM zBjuQcwx=lh9@cFqZ&A;C*w^{@ydk&r51M^X3Kyd}+VT&&eotyvzuhfl^On6GI@#&% z2_=6g7_c4lxFI;ugv_y z^OqBJ{J!KX-uS~%5`Ka{-p7v3-kS#c{5T~%K)C8ae~9ckPQxEa?M31|^^eoT2U3Ng zG5LA4<1oEH>$tJSVJu2J!(tdQ0hzMKaa;g-+A-oOPTYHlhCP*PDP7=P>jcCLwDmef zC!b1Qg7rAPcq$bYZ=#(b+2;_c&!lo<(PIYs<{(8qlM=-ToVxfR&3PtyMeamFtT(yx zJ_o<&{NMqbzE8o#FdQFyhYcrTl=TDxC-=!MBVjiZkV&5WyWGY}2WZ`MsfscMsP!Qik3B#ypG!ev zea@mBAm4wmoimp!IKQ8|{DU3*OqOAP)_#Jq@<0ab|D<{UV0Qk`0Xhf<@%076z@+{3 z_#Y`;Dg}Prjti6R_EX3Usi*jg>z}rdR=tqUEBp2;Hr;F@jLnW_f6=&?=w0UW+UvEK zPQH{z7x4j_JvQI`>(U+mI{m8Yw+fI=mq&}f-Sz0#Io{Z+ltsz#2rM*B}ZcjrOQ_Iw`bf{~%o$h~-1`93r zQR|OVpi9O+u>Z~2m-A(5HWI)$eH;Du5xYb~INER<-T#OmAUsY|%qOXmQWdqBTLYaH zyb-vUGCxTnN(5^9Q_ufi>e3Gh%9YZhCB{Hm#I<^e9`f(INM?z$kctIWO#P|N+ zutvCrm0>!p4BKJk{(cM9{46EAB<%rl0JCl*Uq>wfH`GtrLTf%tf$~<+^D4C=J}~}S z3NGRb4SYI?1Fwu%-J<(^!Q#{Q@Buy>6vl0$Eng)M+bi4nG*GC#Y4$g%RJp_34CU%3 zWcojwrM2c7U1BGE0T?QuZKT@Yr1Sn8w;E`Xjj-Z>H%n)6iIbe=#fDjNa-3KSsv*B* z!z_}$#oJp9Y`}(DN92pN961T3Sv4ZTao&@@1Mm}mC?Gofx z=FObPWnJEkFx*xytS-#Yd1WoNv6YL7MS1qtwKURJZXzD%rD?I2ZrIAj#W5%bjH|Mi zzS+uQqM4)b*0716r}%b*K|Q&KdfCZk#Z4TYzlIjr$-d%e?z--4=!~7*Li~$2tO9E& z*j}C_R^rrttLd1%94@}*?q0~fENIR)hX ziWRcBdONNiEWNOjIu(>}i!XmO<_TV_DXEYg;JKT%fZ_N_H}@7I;J!QmQV= zwZvn*oST=@cuB4(Zd-0p2P~x{l03i?v0lmBhg+i8lI0$@;;YpL!{~*yLzDN4UltkY zz6CVYK~4}uxbmJ0=#+!pRcW#c*fwH}uPmzUTd>NzxJvpCx6_(2i?^f!w3d<`^ zV#S3<`s=wA?I?E_C(JdRyL-OA(@~yaEB-snz+%Qmms z(StEe%x3JLNRx=NJrPVTCKNZm<=f56=xfxxC+7$R2W#q2 z8PoUOp3VIXmPfxDSy;xAzYpU0cqX@VEVc5HBelj8q5F4;rTD-z6UWj9AGwTJ38_F^ zj-~59=pRl_<0{6Izpq@p)N7#D7m&$qZ1m;PMo&JDGhG-%oqXjeF^;3-$IxcTh|M|L zc?|vOD@TggrWzVcjG>Z#@^9iej`q%=Km6oQ;gz<>h|j z@zI7A+6XEeESC~jPcYD&;Z!de%&Dkq=-4ux#s$j(Vmzk~8%}$J-QJ2MOx{7)2_x)>p{gmbJPMp+e5`^`BzVi@hNAji9m25K$Jezs}DmjTzf z2_=S6$q-bnEoc8Qlxl>?ZlW_xv(dEzn^@X>W+^>u`icDh^L1Wd6lw zW06DYU5H#=+%(qU`kYGDD$23tdUJF`>i;$Qc1OeHQJfHM=}iN%7bTDMszLV*q1?6wK77Y zA?gNp9vVc0D$Dgm2aa|hL}x0?p<)4ExN?I?s)D|&4-ayiL3-sXaxv@(^8mU%P;VM0 zPZC6Fl%cFnfBk7Sxs6G!g-#4#7~{)Ndv9tUF7Fc7O{5|<V zI8yE;)Eq=ZBIPLIV+!qylo#OpKrL#?mrPlDg(!KX$t2O1XpBPdj_RkP<;?|z?m0BF zjvQVo9c9Wnb>Iz~V*Q5a?+3?xv)_Enor(3NaTDz1a3KeLD>&bVbb47wb}4i95z>b9 zv>o|muN;FcyOtFv#*#ZzaH8xhEKJv1CCb+diRXtfr-j}bqDM5A$D4$HgXu&Qxv3B^ zm^_=xJ%wU}X=+osoA6)|gDzC0nVcZl527~Bf%Vz*|NW1G%{WQ6U zFmfjCOOpeI#Cj~RYT_rO3l6s~qu_LTo-n2^olb`X9jB7RXm~rhF5MX|7o+siva_Y$ zQrYH729$Z_rS3th;)K-PM2rX^JWpcmLCWPNNGs0M>KJLoC^SPZUThvC9L3!J$7l*E zha_I^Q5h)rh{?1%LmnVl63KOpTt&!Ca69NefxY_&mA~c@<}!)Oj9|wJUGfMQ8R6qX z5YBT|)$<5N#(}Vp5f*WRR~{jm5z-hTg%d8;=2lH+geXP` z4`X`RT{)HTFEZ~QQv3VE$Zx7Vx?I|vU??x0Iul%z1Nu*6z_ll2@foyE;~8*joxytof0B}g zLk|09$t{E{1F86I#5j&7Cu2oJYi7&Q_}19-*>XG6Myf~X{gMXIq&aduvYR722~YYn zzC`LeNA|*Jo3rM~{REAtiCIffl;{w7KQ){yPZ#d>rAKq+MA6!pSs(i9SE@cw{$zfO z!r+$5knr^sIbUvRYD5d?%Tw_Y(0~PUL(>pSUm!0PuJ$JHg>p^PLh7_o-XOg0MMW0D zuq}GCMe-AqYwjSX(*ACi;eu;D7_k4VKT8Zht+!hupEG%V9?Q^xx2eH4I2`^aKI3;2 zocAytsW@N_2VNVYH(Vyi2&S3(+!gX@Q!$6phJ+c)!D%~^0Vj;J6;{f1J=Yth2>7kj zPwHm(`k^jMU$#YpSuo(Dgj^r=2+_Dnt7Ht$ZR2K{@HeCA^)`7xk*c1C ziXea(b|pb*El)jlyWGnpjQ6HTJLCZ2{0J(#Q|_pFxie0CcLRjRxl`s&*+Z!1Me7;F z$0N_~lq(AlJ*bc_r)W%JLRJBGw^DqFldmU!a>LA}D9bIxshB5i(&eIJL5>#kq%%N0 z-g_9-4-AOE{B!xWLBb%CFiJPla1qOp$TsEV3*uc7~@8@t#TVTJC;*cQX%G|c+j4up-^K(#17?#jIW_{Y^h%@}7drq6z}F^2ccbz;x#<&k z%WF)++!7SJ7x~R}(dX@zJDcJjreHjtkc7dvJ<5i2)LHg!zXY?h+hrPN+pBnFYl&U# zKXn;y$&x?!0X6&`{%@(yI(T?m@WHX+Ieqll{c`(2q5Ern%~N?|wC$;{f?g?DSz@my zT}3BV86iN{W?Nxs7rH-CDN`b)x@@zL<(4yK z_G{R~mst???M|gr6fdD-SE`+&L<>#2(zFy@Np_|yy-!g}3YWW5(LqWdVMsR`H%N&U zrgft;gOp(5bT{2JSaCNANA{4{5G6)XI#Q1zN|;b<5B)Yo32^r7BHQHH4`HXBaHq=H zg4p~)cB?zk;~`2J;qTp4I8`a@?8Uei4gSux1hX7)wd_FkQN(sSZw|*>DSs=Lnxw$;^Yt1aDhz8|Z;D&8Q!k+`(&|m^-)NsYK%2cqh z!h>i7B37qZSmnDXE6e_6eTd=}j?&e_Z{l&FD@OOf>*ENd5~8g(Xx9doPssd?7Wyld z9HGR?_46eBkxjVXcZBk!pisZH-g>OEKoJt_)2A8A1z~0~otvo)5Z;ZVm|4mcq01=x zdzMm7Xi$#|&sH`FYwFUW*~%QDNL^}4N=tS0tnxM^2j=YuZc3t~q*OJ9&7Pz5Hyxt^ za}>fIDwes*d)ypjH&1CIxYeOn^OUisrgV3n5-0SmP37h*8*QCu33PqFk}RYrP~ZY3 zP$-Zup)m@|{ z3Yq)JYr@_+btO8ke?J&m942KUe zLcEX9Y~}p|@sLpi36ouiM_}@ZL#{O$ko!cE`+B9G;2Nd(TdxGzhCQ!hD9ii=6?em! zM8LJGjMeooWWzqH@*=AS1dl;m)*w402dLA->Cz^pvyfbkYHU^}3BT8%Q=63$LR1Z^ zvqhODtPiKVTa;l!P&l>Ss{AS}s7|l80xwlv|7DvpL2&xbo#kb}3?OoHqBpyD{XUMd z?Nq!&SCj`S3wh(}3Ur%UcHSB9?bY%8Mop)iL7;ZD8;$Pr+iiBSJiAjpwLEp+sWf0; zKep~v#yPewWoT~!5IH%CDc>GQ4Rysk%9V*{VdulXq49*{IM09N6zyHz$jXNQezr95 z|B;n<5bf5LAmMc&J<%0k;dmew-G%-oDUj;#LVBw}ee^B`ui5SOC(qrApD;I->h4zX zZl1s1eYeuuB<%E~<9n1);g+BNZI6;<5;R|`yH9ZuMhv1J`;@i9aUUwWUkMRr_z*VB ziwi@1sLOt(mQc}0U%Owyf~f9GJ>;M=Ll%#DvT}xA^VH9tR_>ZiV`%GHbhB-?QTRFK zqp+hCh2e*esB>;IU$y0Yjxai{2T0ici3K{=6z}ni80!oN7R9jK=9ZM#A-4~E{Vlg7 zdUB+$bkoEBRIZs#6LhB=io3n3t6u4@@{eE|te1J9WZPkm^*mQ8V;WCRkCjTMWJ-Lj z1ex4v_+vEk54C9hW95!Xp(#(4<)$7~;i>YA@G*jxKUMmeCQ{*N%5dDEGWD5q!W2c# zpDQCwM+v_SS1?T{^FK;?Q+ulRkCG}p3a6d_D4&GK)oI%cCB-yA_kF1(n@pbi&{s;9 z$uye^yiux{T2sw8N`$E-rM*!ig{xKQ@Ec`|sVt?uRf0#ot&AR*A4@-wwiUZKT`|$l z>069>#s0*Tp#MJAm}Nf{yzDC1(eP8Y{RCh*Vuq*Dcw)2WZ2RGOVsq$h`$2d@(BP>r zp4eV(wtWvg;qV%sI^hYwKH6kAuy2D$cJw*hz8Riy4hv5W@Wh6JZ2Lq!nT@AdJh8uQ z`xljd3=$#|F-Y)1GUJ;)Y%WTJ-zgP@dyfgnio#7R^xSt!imfS0Z~IZXYBF`8s-NM= zAnN^DsVICbPs=|m!KQ5e@6SpPlc^O&d{rtk-v9`&0%_e>^tt=!)>kFd6ry+krl=;9 z*Q`{vn()Yf$4>Px5qlI_W;Iy2dHd0{c$PphndhG$LWo)>RY-XlHxPjN35Mz;PJIO65ny0yuf$| zFCIq@;nhaRsg|EwNtkq8AL^(23Bu|vw9+5BbUa4a{MEW%hmS~kZwF`F53u1?6`yV2 z?!U(*N(@kAo4O!{ecs>&Dwux@jm_3HT=4b&TM*1(uRmwm-_Lu-CsrzY*UoD6<%jZ% zps+tEKm6b0X37mvBT8o=MIFl)UHod}F#GOC%IdrnXN)NIsBWO@=RNT7e+GO1r^w;I z$FE;$L7-YUdh1u%m1V!p0F7?oxw>~^R_S#N&$gcfVAzv6(A$~6A8nK;+kV`4O16DZ z3Jg*!yT&0UWe~rvH_R!RVcpoJi!dv+1dR?-Q-qC&=|hlON;qwc4+X34vFmIxvr4-5 zip{J7Ve{=ssNan zpuRE*${LEOqt+CXHc)yU)l+cTKsOqwUbgqwOVmC|Emo$-dKMuWtC`<%e%8RE+TpPu z9;e|=`5}0oOobBF@xq9$^lPG8TBx*@b|tFrCAM$LFZU8%`Y%+9m5QP5_rrVhXo4%l^0%E zvs%I#)&{DJ%sN7_IU}*%YT8&2jxD*GIkr@EJkn^DWRo3*U2||{NA>00-(9>L#Jnt~ z;xYFs7AN`U!FXSE6@@0NWrfWvsZBC8C$6N?$*NaG*WZ59$~xKqD((*u^R$k_W3J!- zYRz3i517`p6{OT>_O74`^;Ivw%FBP!$~yc1w9W%DPiwv9G^#$Lcjhu$QeSN=d|AZ< z>clE4%>rt{Dv1sys>Mq98Rh$4+E)LSHh2|{XrNXVcC6%*sVjLXCa&b6SmIBk4BsW~ zR{qHQ%5QpTLsd2je!3prNG(`Qh@3@9J=GvVTTCN+s?NgB#WbgZO8VllZkB|}qJ4~!YKKoTu@A2wx?Lb~vK{-0EMSpjQ=790i^#v1>Mlgg zqq@D+mO{rl`nq1~bbK87SG{H*b(*bf(cdMToLzHYu{ComcIPLi1jXp ziqrTxKyi~EZWnzV-?1X*ZuS+Y)7AcJYhmL-3LBsf6`yr5Bzk1g-T~@#S2_TtVf2&I zs+?udMCv(EjdTrTEZ1iL#B#g6p=HEGIsq0Tr8-F|Y7|D2D%MYw!z0<|FbrQox0ljZo7~&2{gQYH5=RtItttf-7FI$(um6o$=~h-YysBjkqb? z-b9;6sr7|&lgTzsttVWaM2*r=oHONVTN=`jXHkK4bttZ?Oix!E3cDui7t>X|OV==y zu8mf^Da+8{bD}30J>ISfR6j%Y#ciC!GSms9?xJbuj2Zvx+W|Hw$XPq?)wkSeW7!^! zfShcfnJN7@9l%|E@tGghG2X22$5+UwN_gRo1@2_~JN<)fUawT?P}&unF(=e9wwy(P zxRq(f1&iQn`9EAY0uAZV7fchI`Ea(s`~9p;=Uhh$)8;X%>!^#2o6Uqc_p~D~Vazw)0x{p(oum|*IsADy6%5`{vW_1Nj^ z7g5L@sK+c&_nKT!_Lu(u?%UYhUw2!Csg#h~4by!F2SiY0Ts!@JV#HEM71M2#RUB<%}yC26f1?{GQ%CqcanbzX~^S|>WOR;^j6a2Ltu z$-^$w=-evR(ZQ$MPrNTXQ|LPIZl}5Hz?;}PKkwzRpLqQ`ll^*_f4TBc$(uXT*!5~h zp;Kj=w@$55$byc^$gl4jwYZ#73C!I3oQ`-`0|R@3Ms#a~x?O0{P@lC??N&B+Qw-}; z>~jEOg70G??iMGZe4&>NFdSc_M&}8?$}7Q<*~{CXt;F3EGaum7Cya!VQC=5IQ5V%1 zp;I(Xyog!v`m6N!MYV37%xFXR?*P!aCzb(dWLmJ{_g!%Y$jCaL-9HP}-<3{ch9LtD zEu&Ku^|_>$VYe^MzND5H%0$ueOKM30bNz>x)HA}I?)uKlYHw#DH$X4_QoU|+wfO)4 z2IGrzy4!06qpj6XqH#I6=jEC&g}hb!+YYX3;2)(`ar61L0CgFr9#e7!Ng_Rz3{IeP>C?2GJQ5~^z zEd53GwLMe8q}TtVVu>6VN=v??`<%3u-hNes#1HPwUrvQQDBznqMH~VYk@l(#9r>o# zb7%q-SKef}V?F>b2lpM`n%N|8EDfPU@8Kq=k8V`Wq%9TQSrT4<$G)sda~DUs8E9EI zQUtB3c*fOGTN^vPg0@o7ys4p`o~tQA;xj^TM4RUr}>DL zIC`c8b+yxai6Tdvm!Ru*T7tNzgdtn71O?h_EyX9E2D;pZrrT@J#EZoZbVG5PP(TY3 zeO(MRr8pfdpy9Nihk-UIPWK9Ejl?ya`K>cW6x33%r)^LNJL~%kYF$jCGv_W;i~>Y$ ztXQ*{K^|I^_K2Fdm{Q6>lZsLfqZZ@n0Vf({*1C(cN^+_b<(R>|nWOGb^9V=UWzlMi&)_^zLmg*J+9=V@(ZDtop$QTz5l2&s&_PM7ELJaK zIQnjp*|HWV{>FXtpfDxN5dB=(5N%zUE;FhI7D~cR#tm?Nl?Tks> z2qRITkuvFp;fye@tG-P43u~F;Wyzo(kn}-Cw89?+ zg^kUaRX*8|9eBj81NYo{Gj(!8#yFP6GQ#(BXF6#fVl$2oHq(A5%@=2|zOQJVBF*&1 zNn0sCiC{a97Pf=F=5VcXHV%`qgp5Pwb3)VcVZ*FC?cmn?_J+2{ zwp6F2=A%@dVX?8+;Q4R2rSy_0eHLfQw59bWH5b86q2ndBlHw;`A@R2Ktfcl%Ocsn7 z8)`>SUA1^|Gq39RCJJ}cJd|-jts7CDsIwC$>gA?+R)5ISD)O|sCM;Nub&v77`-M~( zh-ok5C=F|J-(pIK1b17*+MXu*!%cH>w_)`A(2#qGEnAGA2Ea8OrXZhS6WNv0>WRPq zYSi8p8){Vw#hHq%K;39V<4b8?LRAay4Ap9hk7o*e6o1 zht|T}j_b+&Vxc5Yt)+l>u-1BN^Cb_Y_rPgBrw5-cRNqU>G~)~oD{KSc_q{ZKb1zs8 zyd-cJZ|$nNP$7d}<&%ZJdTX=Haa{A=z z;3r?j z8kisO^eb;I)Y?xAF!%Uq*uCtnMW5-XRWX^zeJ~Q*y|K{6a$1*?VZg0~jZJloCqKln zXPm)t^RtODS@36p>+Q6Usqi&auG4O}4ER-Ce#kiM28Lb(x zH+M94s=qe`E4&J+ba3qm(7Y;Kerw>3URhYTYyATj7;((rzr5V@>$hAlT(}E2zRNWD z{2^x!)Z#+QbTHdQW{(@lVjh2KRpgYy_`T!#h#$#}0>S4zgRL(u`j|j1$W-Fo8`#x@ z*|nYrc?##~_QFDEg0y)R4uJtC9{C4+yTNDlQ?Lj9RD8~(USGc@Wz}W<)Kbp3;2#Uk zE3Y*&U&brEkgM^JMSovjBdoAr)2|h@B(V>7e%)vEr~+my(_R>SrJs=&q8%-_td*JB z`4rhfI{7JbO~3@`d#=%0OU4+LZr^Ok?24MR*oxPj<5Tjeh;gAcN1r{R_=;MhdGQk? z>O2tViz;f>l^4&TuRWhoB|V{>irQ%9D(ta#Hk3N;drU(@G1|BeH?kl0n0AM1J}xdS z*sh^6a!>Kso@_@O^svYDIaKo#pFB6v0*@)ElD0#%L0!Z6_*{Bc2?I(66awhb9NJS^ zi+6B%XTkM7U#)&v*do~@ha9WGE!U6?^yDMzQAKOxEj&h+V_<2nj7AWd@u8?Xb|gQL zbcokb!XtWGMXN7<04D_hc}THg+MnWQUJs5B$)l>)$7OOZ^qfRixv~76A%9Mv^nlh> zh4jSNhIEAoWLr&(7M(cy;65c+(;ABPIhuK&)>qSXu^*Q`agTac*GdI@r5LhH@me>F z*2641j5tHImTrw`?VDpnYoQ#2FZG_jx4Kr*BqlsE@alKzLpVD4hY!fDhE`1YdWS04 z(5i|3?i=LYcW77*t+?2mqjT=i!WtOW+HiEh9s0cn=Br^G^}j=6O>LaG;tQ`z9@p)T+3=M()=2==pNL@;LE@Ye0{_ zNiQR{QbP5AsBkUKSMYsC;kC4~E(;ldCK>()RxYyEVL@1eHut)|AWHjP5Gv(TyI8Gc$G)uMeV|(%%f3>X zI|^4NBZtb@k^G#QSPNJAB0=nqgeF``#uaqLc{RvBN^jhppw~xDHn?dpXWj&}i8D93 zLbqbIQlj~mVO-!9Dj0{^l^Gep9@7=77^js_NazNM@vP}oaZ{P5Z zIt;L&&gRisnNi;x=79?H2KO@5O}I=O;rshvx zbe*xW-?efl-ZJ$1Geviqsg=2+S&#HB@mf`rSe(bZO%AD_8;0|ccX zIwk9L9&DBel$)rz2{BJdOwu;W)sQVaXABFP-lro;T2AO<9z!(&VsKXeQ2thCSLf@u zC;nZgfqgFX%pefq{37@0PF?M@Sf#z;JmoGutf%!A-QYM-XWgN;$yych7mni7_Dhm6 zi(Pfcp#FKAJnL)A#WQCOw9IWfQy-JcF%Ri+eN4_CqPCISiQDAV0Fl{|M`q_+*gn_Z zi#N^~LY;2Xw1$|{4>@n3J8n?TMhK0SZ47k64eHehvvfxU6U=FLgBCQx8ffwj1I@Wk zQe${+E6;!6bxLat+5V>tYTR|&&=|6{Ia=&G-Dr#$4CT!KTqFA?=oH5B7+igg5}RnT zVu|L4Z1Zb0zX{f~a}i_6*XNpks);6>#MY=t;DxW!-KNN?-w6YKaD~)n+AwheN84Ya z8O^lvN+!yWn^O%pdtIUP&EOL+uHgM;`V3SEyrsK0*JcRHT-MftctwX?q(dz=&tlzK zT4mO&uq)xhFBy4#{F^?u)B=Ltfabk`b?|Qs&PP}y5va!0C?ONSCIvie2LAM?@o1ws z6|vxNYSv0i6ZT%CtF5#kVcRvbwALyJtFBSa*4k=e^52x(8cThAZzHCSHd{&i3wck6 zMwHfafpXhut;}_h#!j^V_9xYAt2GmQqYD5U{U>d1tGNnOF3{PwSVA@A$-Kw4x^l*pR$#dk}UhAQ}+>a>1k7PbbYj}>9w%5j5PN9w>8>7(U z_fv2OEVVs(bTmCn3p;4D#10n?oz^o{ts~a4BhMM=h%+>}qc&J{;pmss^lwM4y?Neg zi%mo5I(Am?&`H~AGW#I%*kz4>o+QsMSU$ev7Ro2-Q5TF{BRQJ%2d(OgmN4s2L-}7P z$h{ki(`k=^CY_*F-7o+N92HN{lWtnH^56*EwgjCN)a%D7ygNcFm)qX$I8Ew~jS!E$ zhJvEU>1KCrK-nZr+^n}yN$QyW=pb-o`E<-TZwSdpXhm=B_t^a> zk@J1n8l8zvJf{(d(V?>+^6`ltENtH6hP&Ju#$k76$eM#J9?-`<`OD}+c0f0T;t$jM zK4@d5APla#N9lSWZC=m=pw@oSmD>(i%;!zZ&#^@IJ6LWVBQXthCba7?{q~DiQ%K%V z4}Z~ul$wS|K!g7Chsdih8rr%;hW=NFDY>uKS@egSL9KL%_V?8S#Dbh!;0V3xt95iZ z7{w{~hDnsku5_0#T(M}9YimL8yn{k4X|!ry6ie{GCdhbJG{PoV=axANy`_x+SL zK=UlJ5#eeTS>Nu9Yu{n*LcD!DK#LO3fB@w=xE^DmW@{1`;)WaG*Z1nqDcCv_7xKUe z*iG4kwMK>Ov%n|-_wwC&r)(<)4AH{H{@jo0RvIuwD=&=Ri$i80^6uV47l&w- zU4oeFK46)ZEAx?YKezJqE-IUfA>qL96qkzW(Mv1!0xp`t4`bTzq8X{!_PNWs9d^;Z zR4qz)_&fOw)vAlPdGdIjdJn};(q)d;)M>|1#F`^Vi|BM`s1{s)9#Csh6d<<{Ryhfo zH=d-y8zBfe>tj}@8}AwJX^E;p&RcgrGG-8vr#e#ecAC-1P&>Q2+ZL_cO9nZ17afg*j*!^s)k}To7^2p$a@8Q+&*|M^IQEU z);h?N&9>I=pxVQ=DzR5~LjE1IqY;<)Vus_k8hoG;-@-si4sJ!lU#z0X@gaI86S>5S z=D|f~?WE(wwUWZ%o%C?HRwiizleo?#+_*#yCUKG(X}x3U3}6Z6SSG7^LK6Bq>v@)N zo=^HBc$1yKotlr(Du|vH4DYquPBTYnek}?h2NWV;JEZO*qrCanx18Tx;F>->Acw$f z)^t|1*Zjryt}LM|Gvh8#Xu=YP8M*R=m>uLiQma@*WrV4WFp(3!Zl|^*vEj3Cw~=x5 zHrhNAgT?UebY~=nT_=|=K8ijfI`a?w5cO-k>G-$X zKlTK`Q)-J5(4V%`^)#)A=!Tj?>TjE=Ub+_O&~_bKEUp+SkeGQK$z3+nlyt3|_<55d zG-|2-EnO2#Vx6^y)Z>k0&OoQoeTjkY+eno&G%pWV*;o#CMQZEFHqlwT@>YNMeatMc z)Q$L&QEMeWSYt>zZlv28SX1uhMSZg2|Ksg`;F>J=$NvMOAx_ut-;7 zVUbQFqa<4i35vOd01In1N-D}(l-8}aib~6B6%{qCRn(!f+Bt`cifR>g`0qeKD(kGS z@9Ww|k$F1x`FwuA^EmIG*L~gB|NGt;c-^3kuHYv}?*tF4pHi|ac;!4EJj{Gb*;%2! zaP&99!+xhS;wJS;qdyEDKIc@*&uP3v~3&lS<6Z>PseCnar(k z?zx7aV+?I3h%Myl;+y#{(8xK4`0NwPnYXC(6W#LWPfw$CcA7`TDdmSpLe#l}(lEpQlcf<)7w9GhO|B zt5}t>c~dzz3SDRK4lMQ5rLW4);97 z?T|;&aDPN9QgLAh9O1$-mGV69e z(5<>VaQMI@%7yaq;o$YX>JjDo+j%E#4=(M(N0eu7=Zo>n!Mfi)to%&j0#x{JJbtDZ`v9-JNIGbwL8?e zjUEv^`|v}`vMRMX;)z{KO_f?Zdg0VSsp$_Xf3H%X7NLJs8G9!;SFt{jtyH@%xl_&W zXdAmTaGd|3a>rfjn8b0p+W$ z>XeAlPbsn6xXV2c1u9*0zjDns7Uhy-0*A})S03KR2o^uAe6vkGea?IL1+u?!1ixS& z$BhwqkCD41ALDtTuHxW#g3kxn^d*OD-red^;iI<&FX)r^Dd*h7huU4i7h?H+O6fi7 z%yE_Uy{9SoS$67u$_MwTvm?T*6@$Xny=h0FN5{QNwjw`_2OBQES1DKcn78r4z}cvK z6`!J>JNo(Ufx~xqD93GAAAQpF;Ms?1LjDY4?(osB31_q?1iww)%)PwlLhcxDvJL!M zh3)F2j(&!^d;Y^E z@q5+BCVVxKPI~0@mIOZ_oF2TgV-%(9UiFj(r%-#(m2wcL2hV@Ki;PLEQP+9FA6hob zj3qK7Etqk%9QSF#Reby&W$}G{>3d<9Ywdk%`?%3xD6;#JzKzPykE^pHDikH_3AH_< z?-u2oC)DReJadmS^GS8PT0cJU);l^s@aFQy-O4de_0otd?p8{i>bE1(rYgp#c$uW$ zq}=-yKk9HzQQmw?eNu#Nit^J_d`5U@t8&cK>hmJDY;|4rw0c5B)MmaAW^A6DqTE@d zJ~zr7JQ}HV*6?xegDU0JXVpg^Rrh?LOm5aJ{)u>h=huJp%e}sTE1k^0{~r;iT=T5@ z*rOc5G7Bjqe}De{p)woX{CjdymGbJd45I5a*LTmV&Eb=-xr56zqyEhWveN}JNp646klslA{o>xzuQS*5; zWj=p@_4r&b=cgqH>d3O6^E>?4d^mmvRSRQB-=Wm+;hVydcPJ0ls*gKv^e@G7zmUyN z3LMKSKX(SJWd`cKe|xar-)|4rd;fMhB-wnh-q(TS-_+B~{&s}w-5sj8|>!EZoPc z_62XzwLXrg-5NOe>wUB%Sa#U`S5+VCc4?^FMZs=kEs!gt=UQ^#RBH|sJvg-}? z>`2X(W5SdL4eCPW?7yjf5tFZX&23O?!y``eDU07!-x9H6lhX92`qqel-l(j6OZ{5J z?Kdd;x7GJVd{^$Odt3cdc*Kv_E2Z!7N&HqCe1{4x*D15!RcA!pbDdK5u3C3d%XRWy zZ{+)u6VK-Xz!5ypx8V~0g!0G1Gj9ja#Alp%CZF%$*l-4?-V2^`2Tvt&N-s}M=Tv?0 z)U($qJ@2ZQo^XS8OlUix>+F6Wl8~QDt9Y}#bts=77~Id9j4fG#4M7iCl`Gy;>umct z&#=6bUxrnx;jP%)79G~vdOD3Q=L-@&HU^8n9xVFHIGZ^2X7JRD!BfACa}TFp3Z8m0 zcq)}CB+Ds0Ko8A{V_Z=lb!_Cgb2su1zI?&0{0ZsU`PV7OH>yuQIhwpBTefHNi7#VQ z$H9ylKW@2AKH88m<6}zsXz%r|5eG7MWo#b%NjamJf75#IM^EMR|=WcWz-Klm)L_Acc{Jop)2E}EHYM(kjqM*!m>^}AN z?9RW^^=Oa!gYbxyLf19>)o+fBn7P)q;9GTf#L){1;Lc@h>Xy0hX5a18ESO+3GnUu?HBxT73V)NEx%Xlv zEnIUtzwb!7AzX7ug!N)2CPGs&`q&k6&@=a6q&yg*IZ6HYhqA?y4FTrvyHIJ1&>R=> z%0-H1gyy1%8?)~jqd8K!b%f^533pM^#B)}9ll)`T{A_Z;3T0-bX0>|s2Z1I=1(ZYV;8=U+6jzsd+m*;yJV89;I0~?gB=-di-S#ymaSYWOmIxLUU3? z#Os-^D@JS9het%uP`-%POo`~tr02~EE0V^9b^1l0=*kZKOskwXF2+0e)}_j>F`Dxu zv`dvA$7qgmpQ(I# zv?e9uiaT9ez2>;^=${K`${+L2{JBucn4(!Xamtr7!{&U~b=N?jkS`W?Q*LUA`kU+1 zDVkTJkI1zY739vD>)K(^ycQvUdZ;X)t*O-|&pF}5l({FJoO;TFGtNw3c$Qr4q5rv7 z-jQ%?xH2YL^Md+{!n_TZ{Jg@e*INp6^YV*b&n0VKk5E>fq`5+wI#-jdygOI3L$Ri4 z9#w8m)htq$&DE4CB`0cbb~T=)c`;o1;Y7_Qr7=}AO?fU=6Qk_eq8Y0keTt@EnVQ03 z^eLK&uGD#&gz(>Yv~a%WYbW9!bTo{wBlorJdD*8_~ z(aL?s7=BA|am-oD`1LU}l=|YBeC4&0m}sS}BXl1f8LldQdt@` zVU){PACs8iQa+DqKVtmCveM#Q{i*t?ru?h&Eh)-t|B7)On(4Z~HRkHkHcM`4eo5*1 z>5JziUzlH9vbJ!2(u`_`WY*e}lTt2QTbeY(pr2|sFF$wr zNhv3uu(U8Q-)x>5$eKD-@2X%sRHfRQ{LvBS9i`o;Gxr_M^Asw`MKX_7L2@5IrrnBJJ22v>PuOvd@j-h~rR zR+gquh*H*XViAu|pK#(xSI#*TZjE-0&zithZrwEDJf)*EcC1o2S{v)S=i&*kPaD0e zusA=rsA&2O;YxY{jn>QMW4q-yBztkE#a=JHL=bZrT)^`1lNjdVt0;EPFxTl z>q@>pwr8wMZ;!osoa?E}V%6b+$}TED818C)AhvFdtNMx9TNW#vOi@q7f33;K5de#`aDfEza)C4X1OwM zZmdel{0AexDo2wk593|EIhwsAm5hJJOmXd7t+^pm6TG!7d6~JT^5&X8UCGJQ%!vIZ zBb1O=ZJzRKWo(l2&pge@C^S41^Me;>(*&3qE z@}q|e>$&aLu3s~&WW!}i!90Wh1m*H|nzJUD(pQ?!Ib+#^Wf!f?;<#}t14WZ7I)fUZKrSqJGv94x|CP}MUiYIE7mFH!?o)+%|#<#yj_zz!j(E}V*PH#eom~`#lm-9;nE&E zF)_+jcb4{?iLMhb(H;|}ROf5wD>o0ukGGYr;)R*Xq)RU-$uB;$aQ*7FYnJ7&&M(ei zzbd~Zsc`k`lKj%ZI1KtyCbo{(*3iqhc&OY`hA7uup46YpyGc=T;pO?ON~Z?aIr=x{ zxRgw4R-j+{mi_&5K2$9_pKCI_x!?-__tt*XSg?}39hCa#wKI=dz1EU1*OCFOXU?-^ zS`IpJur^Q6>rr`jR=n06DmNoA69&2}uqdJ4sqkwsQH|`uvhr zxkdSB7UUKuts1JRSF%=Xrv=2(lU?!awC_YKp3T~$U8AnjCPXN`8?|S- zEM;0NU+6Y!9|)XMIHl$vue1{s+cjFASba`AMR|O=HpZpBR(o%_GV3<&WO{aeV%3g` zP&%*I9_Na;X}d-QPE0a{Ub1UfZ#+N0w3HWbQc-CEUwV|YH!&6Zp5^M>q)i=H|#XKHe+O9DTlJ(zn6i(cqfAhU+JQZGu$=eZtVplPE>xb(LN?C>Rsm%q>+ulT;up5*%BO>Iepa>HKk zkelTj_s4s+8l`ny-0{iSm z*RC3&_?xtMD}Vo38?B7{SUYKqd@)+Wcf^^L(ih`&u8sG_^(44R){Jo7 z_)^>hM=7_D=Y^1_Pl$3QeH!;;q;je+PN(F28F%uFEpZdrmmE4A?OO45oNd&osky~d znfpUu$4yY?cgAT|!B?n$l_hum8s+F~Vkay5UX9k()ET#Hl(MWZu2PwDY}`cGxc<0% zBc}iIaccJRl&Oa3jJ0dzm#(S7qjOiU4jv>cZ3p7!C^0qhN2_KpNzap?ig2njdob?U z!(^`?jGHo)ofRsbHC1_RkYCR8`$oPQjN3Xg`nu>VN)&HbT)gYKZ{xa0MVxI?s{L_W ztf5cyO9G$mlaz3E!UQF)Z&HHt#mxz0Y{B=#4Sbnm z8K+;cbn()2moJ?z-@*eQItvO*N|UBv9sKM!eMa!jI8-|L@iKq?RY}t?IDg@?r3;oU zqy!%d{;p zrlk0)S*r@Km_9#Lb3?I3jz70(?d+@O%np7ZGkd!HXe;Z@3ch+SD7Iwg7Uy1(#CiFJ ziqEXJ)%wsU)soQM0u9OLs5|{XH!)Oe#<1b@HLWy%Jzv<1^Gh~ZN>}o^Cy*{GTwjvE zQhp|2jDhj+(IzP{H(T+re&{vuF*?-F@BxLgf~y*O^{md7pR#^kJ-LQ~FKR5rtl$!q z1Sb%hZ)mOZ_>N=k`e0Gpsrp~41twgYe?`%(Yt|M`kLL1Tv5t43q@e=8enR;#vm3hQ zl9-S|Kdd{0{@Un*eEFSaiJqmnc6zpLW@hj{op}N4F;5@3Wb&@z6~YG>KE;%jP*Q#q zwDR1{taHv?dj2ey{<6XnJ{Ja-vN*q}u(*`(MgnCG@`LG&=<5RO`0HiRU(cGHyEym} zm4<^ajr`(bTVZk1^z_g-y!yh`dOm@!&gH{Oo<3<>-VF2lX(fDM49tVpe!Y;xuW|4e z2#soW(sca=OIMtesn_f0(HgafEx?RumUdR)Jz!O75+_a`x)OZ44PCw&a^)Fe;Z^yv z#881>KAn^nZ^)moe7$y3{EOof_??oxRFj5gG_>+df-m;abvOKSkIx9bf`cn#&{Kfb zE#livOOpIp703y^H0CS+xMb2%V<=$IpBR{-Vpb=#DwX5;G?8{qY^>`7O~Ti+U3Ci* zK8bKGS(p&9NLf=nQDalvJB5t$%|VCK@;K~}{Gqac#^LS#LHRQSogc1%Y{2wbr^q8J z2nXRNyhP&ePLWQO5-E?l-ncX2!f;!`vz?;y|A&Y=d>=N^S<@Ma;e*&qp8B~?Q51?t zsVpOzV>QYc${Vsyp5N0cBHf3N(w7gHZ#!J(f6x0*9qB@yI9@t@8#)GP;@qjP1VdvZ zVPV9Ykn+T)zZh1^ZwS?2k848d9K48F7CM&wq=iDJWsH*lS@4Q0;qHVL;Wp2KPSHw8 zRfCIGu`eoFuBBXUhPADyp4+-0$8NWMjrcv3zWYdP+ut{6TMklbNSpF~R z>a_BoJ4N$PouZ!TBhonDjW7Pm$o`p|;m;QSqjGWp+vt2JQA?;qr!W#a!t_VMi{Y07 zhGFSHtn^>XmC99!>=GHHy2NzcKC(+RhSKtQc-V#?{9mV2>8xJWC5py&i8M?a-z7S+ z2De9diI(Utn^4Dfi7=vbVwWhuOrnvr_fJML<^OEi-H0qzTFU>~vVn58|In};fH$E_yhB_?SO_y=BEJ2TamJr0ckG{O?1%){UH2xeA8D(< zq)Y528i{5?eQ7W{NgpJ_IF2G7Aze+>5Ou_ZIbEVGw@aiFrpvf9F`Eb{eGm_g0`k^T zCmkb+bkf>fZk9w2vWSMmL<)IPYrDkp>;AtAZkE5=c;;Umkni$8=;M+`XefChoU88M-A9sms3GF9c!a&HhjPzmYp}f39@+yWM?+m3ILbhUL zbFi%j+N=0imr%9-8i~PUuJIu!h8Oy?Y3nz?HvFIJ3=P0QSy^88oA@uT@z4PNQzJw9 z-min5q=X#GmmSKqznvSkqf6v<{)MppmBNRVZK6XNxQI4sh@D6e#f6G9=`%l63|Ia7?`Z+Tl$`~Ym)9%0_$DsikZ6s8L zH&kHA-&7tp`a{n<4jjJW-_@u6QdYtl8kjG%Dz+vP4mz-hP7FCzaCk%JVFURkKQwSH z?UaRgi%gF)PPh^3_q6XoKW6wW-|B#HyW{x z$Rmu*%KbfWyZ`<*>W=6ZEkqSj5K7DAv{3qNc`y|5!_qRZZ`7~n_J-2cAP3;zm^SXt!;*@TYN67TBIA!?3AEu2| z9vs$y^8P)OlU!*pBt(u_=3CP(OnKd69-%Af7JiOp`hOBC>iO5W?x{=ofbYa_SdviM)L^MedN)oO148JM)?MURbqnVm-NHz;PP?5E-AN{q zwT;1WQb*xd3VJwpGfQW+E83lKVT7&dOYUBx@r!P;9c5ILmNAob=~s**6m~Qa4dl0= zJU=`-$?NN-EuxC32t_u^X!?#3eoOs92KRj+Y`h_}JjCvZeY_Lw6Whc0iTV-22tyfG zB8xC^eqAVZ9LqRJbW$gWcrX<2ktf4AYM5v^nP2@g?A>?9(ICfZ0Hw@;{v zD$3N44@S0)gKWa9p)#Q&{Gn)4Q<2bX_ld>{3@m1!s3a|;g<~1!IA%q-C+-v5P==kf zjD|_9CS|Iq_jxGpCQpW)at6xSwEV{(yHEHCC(%IT$?=So*h`_pgkV&Wma&cFL>)^y zner&3fwYW*qghft^@#E*!Prh(M#D5ZJeEsI_(Rcf>^_^|KcbH)r$7ObNu&{BL{cIv zFr7{a1K~>w#vtWoe8pph8OO7N#E>#AqlRHE8c~;QZ%Ksh>l(AgG zisMlF&(!-bWo&`YWrMO{1sxn(;c$7fOcMhiyoh_1bQS486Op0ztrt_5Fq>_^@9@w8 z{9hk8nTPdhWAy*m9sHH{Y=f8X6aQYlPdHZnxv0(gwcPOZpRIpLIot0#jvUs(P~pSn z4W0Yn$@Tx=HSj;LADEQwkY(S=?6)1V0`^1796Dg@A?GcjV>6cK@@0mQb=+KPX%p>d zox5z=!lhX&l)-lsthSs_c>gDoh_GhfEm2R*nRUXfRNgSkKPCS&-T{dsB8}q$qLXyv zu+V=_Jz{$(ua9)4m-1imenix8+(^iuNDuqp)|PP1i=KqNkvYx#X_QDMGKlR&9g#e+ zPgE0SL~=i0q=+!mVL$8>Q3v;l=I<$ookSz)jGy>Q=%-_>mT97q*!q6B&XxXtf^n)X z>NKBdH2FmNIX=-zBro=f-9+YDKG8=UB=(-^6Lsl6(Lp3o{**MIsHaRa^@^7GL@KHm z5@-0tvIVq<`v^U80+CGK+T}hGcD7ICWKoy2LOyeMi317e#M)-p`h@$rKaQg)Q$k!u zocABfr-kxwdch}3iB-fhVgWJK{)}PiP@XMtGCp+T2>gzQ+K78Xc}<6OxQpX$Lq@U=)h;C#6RCurh$8w}t!AQ+GQ(q09huvSn?fgx4^wD(h5wXZS?jue%;bS^ z+merbVkpWQgXtEOaV6)Zjl}l%xgA3>JUx^*q&zot{&4A`ypXm);o+G>4gGJGZ4R|D zJUx^blpE@|8UOR+LpwS2SoZU~Jln8Q4h=*WvJ!b81j9ZoJ(M@3igT(^IUi|9sH~Gq z_R^mS+fYOQTMeN>$ae0c<3HIRKam_(@vo$Hht#tlrc?i6@_yR~*I$m-L1UMH=o3$e zl<7Ycku3M2R9F-+VD}Fn?bA$m67M8LIapTEN=zBaWMLL668Fa)>fwH_=Q)UDzX133)z=2)jVJF>Z4E#GLDT z#JkoWu?aoIK4Q&vuIu9`KRVWCys<|Z2pyp!{5SLnAK@iDgqv^@4#G}Y2@7E+OoWjz z5IRCdm}tXSPJO~d$YVD;2?t>hUX$GM~72&_00TN!qb3GYu5>CQF*a<6PAX*Jkl&I{BkA!v`SCEp$y=FnRIld5vTD zi)td7h$mW9`$ZX%NhFWkFVZyoMW1@V2tzfYCz6R4wd;vRlgEuvZXVC(>Y}B(C|7dU zJ8Y2$!JRJ|6j+enR zpUT9%$zLzaw(b`jHtZKgM19$Qv8$Ak5_>sL+sKFrS*H9N8X;OZt|oG>Wt4=>ljmi0 za$LVbS(HEddu8eB$!EK&S5F>&zJ~qP#ks{BXP1;%R+d^yX03AV-ZS|{m8fJm0g+5(5{(ZJh`xti%X%lTA2Dmm2Ls}3erwRPL^*MMCVA*_sggq}zy(uhnVr_42Pl5R`PZ>F-!vX-g5b-XTqlq>24UFsNH z=eGyMK_cqA1EP-DOEeQ1-;+;t9^@QRMpP1Yl-(^Qwug=n9ylP@6qfQ_hn~HLGfQ}2 zf-REk@;8PJU&g?$+^`GQuUpTKN`2<}i}h>s@?B4zsyk(rOP#Ju9=)h&;h-odGEW~A zRai~b5NT%(iWZ`eP-jqvs3NL~mUGA_^os^Xawu{Zx^7#dJ89JTVc$#2r0ccwbyJqx zbnDtg?Sil{%T;Z{i*|H89u`)MwYV4e;(qMoq4ZT{Z6Y!{JnT7)NA1Qo(TP`Lxgk6( z@tQW?eZ#{n=w1~T=D`Zu^S}2R4cLgL7pb4Y%w3#E_ntQ4K_9l**?XRWxR;-c7?{cZogL)Gac&|;^GDuiS zh?P%&^3DJRm zRCRODEaMmp(7dlr)S(w!(bLP!&u2jUIgkGR+-%!O82c%Jj_;UJ76maAt>3qaYPA2r zU4H>HKppCSY!g}N!)@sJiTdclunRdaSW$GN1HD*_rm%L=iWc;v!$v~4oRNgLi%c|+ zXcwhuMLRlhCmJK$g$Lc(hq{sNLd92lH>RK$O=uWJeRLc_N9c@d7s(efP&A=#bh{`( zH#*Q}k8T%DB&@1-5w(JXXhi3@c2S9j@$I5P=A$3YYC61_^O|;HLBj+FhPv2xk#6Sv z#CG1DnPD9H=$X_mw3kqBa=XYv-;qoRy+^l;mP>g3yQj1Z{iTfP7#c+Hw03?7N5Sa~ zXeAvbwTo(l8kwtV8d-cF~OX`RyX|GG=CEMbLk0yC_2I>8u!<(%VJqDh7x}Xj#Yr zPjUKE;b5^_Xp%o+7(BXy56pa@%5VYe?bf6oZXlo?lCeey!bGt|^;22ZUizf7A z4jL}u=0X!zq7xmcTG=jY(2>Kvg63RS5dG*w-DS*lEdxa@T35A;B(&tU+eA7ET|U=X z7C;Lc)^Lqw0d$~hEgi^w^q}c-Rz{v*M}wC$LkkU}VLbzt$At_ORYeRGeds{vm9&G7 zVg`!tVjCkR;U&X|ehgbj!zC;odN3RPSccwG8bbR9>Y)>T=s{l8VSd!2^D0&j-B-7Z z3e;_E7xiemhF6h1zLo)B!N6=JvPh_|W5#I3I&@smOwr5$ThLg}t7JVL-@t%Sw~2ws z;|k8B^QLwYUx+vJK7y)BuDLwEwOu&Taa+4+M8jrYRYeTc&P|Or&lYATGtiEz+qtRG zdq=x4U&#ou2;EiO#b~^ffuSG!PYSe?dDaoflG%;Xnnk0 zWS|?1(2Esle1a80CpK>2^{;x8nUG;|a?P)zgQvK5(xqmamj5Yyp7Bh9Zk&O8b*eR zX#9u{(DN~u2JN5n4u-zZxQ5rVLap2j=xk?Z=)r24-$8rmKtCEg>CnnRFb7p#TylAg zwrZKt%^L`s_i>Y5$4oEs1DJGCX8fd z9Y=HsJ$f)ju5?rf-?1|wEJAm52R~aU;Tzi_qRMGt90k#;=@8{;p3uS16c`Bl(68;_ zn`j0Y+aYq$iB|ODc9}o1gP&zk4iBOuzC)zn$R(OYhiF1OI?;)a$+iyBDGTU2gl-cf z#R4=Q*&()}`KS&th;GzY(819(h+Zr}lb&+u#CkMO=@6~xN9|42o7y2V(SHmRLgTa! zQG>o&9m0=h+w2aJbTb7p3k`ERL@oMHpksM_Vuw)QLP0d39W&627F4Blh)OhKHM-|g z56vfah~!GzK?{0L?hsX|O6?GJXv8M8SxEHB0;s-~3TQyXDRhJmERx6bJA?zBSdThm zhiE}Rs%~RIr*i4geHzyo9j9|?44^(IHAV^ZHk%b1lfQU=te8 z;-;}v;B1x*4H=wA(>dG&s9MB|Z6V*pwM63*>Y;Bb1Gt@zGPxw^TSh+G&*u`$WAvjc zi;3PrJxsiVo6nHVwIsugR`guVO@szBGn8J!y-`I2n2OfRSaS5PqCqs~(a@cAgeLT0 zDf+QW=I3)0qYwMgxVl5c-^GM6#YVzMA_q+c+{I{K$B5Bi#5LSXg)3Bg zsQZwc(?PqKj1J5|Qxg+Ie-p3&8WQ%8xt3`Bgo5{TqM3o9=Tlx*($8oR?Vq!x573a8 znW65>4zU}JU-7a-dnfM?57MEJOM%{Rd9|S1&&pM^LSuOJ2%Y0P*#}0xZDOZ5NWywF zCmy1q*`1;Wee-z+@L>jmT2vW3MH0F(9Sx^-iUN5a>(GlAy@cz&nwq2&S|M%#rK@?0RQmh)U7 z8nYSbqg;ZEcs>aY7gHZiW}X*B7DN-M2sn>Uk7IYNyaMTkF=&DX(M)yVrfPUPKW-Akr$Jetm zPcnh>PGLpWCZ6(olGnedf`-X3-o#QnS;Cun>KWQ~Ffp`Z3VQD6VM$bd!V1~s2@+v7R75SBo0$n(u@t>n zjjB&sGIV06JoeJyvy{h7bfN|QSc%3j7$|zaWI(9;ij{hf@|c8%mQGCiM!E_Zh4-E>wIYX$;Q&xQIHHRng!Pw4dLu#M;|tzDS~HV&@zH20`^co zicR>a;<>Zk=!|8L{Y%Vf5>Er5`6!-IL)A3)OQUZ(PZGUMelq9LG?%9c&~H110wgS_ zcZoi(B9F%fj1&ofo8(J|`Krpw})G!hofL^oQ{hm~l!fEl9WLiWJR=tZlYE$eSGLDZuc zjc?kR!4_sthVFJ|fTlZ`sVwMVhHo*_`?)0O!E&@bz|y1fL7sI%>oY9%+mx$e<(2Wi>|ATsH$7b|m*t?YfCl5-Z2eZ)I$N`mbNnd}=ai8!e8$Mp zf(_`yL7D$0FPDGN0G6WaEAD=Dq7OYST*H4dBg{ho*9-*Zvr-;(U@N-OFVACgBNODo ztUPqchqJ6CbUa|?LHXEF{QJzPgN{)?`%;CTZ@FvH&*LfD4`}dvIz$W4L{y>bN9v=K zhd0tc151sbjcmC`({(iTHTgDH0*&P~gno3O^+w8}xq=5#zMHbJbse~(ey48Xrtao z-J)FjG3Qa&%*vn>-RS?6YcKQLx`i#ZotuM%2|bvDUMxjFR-&q%8KMqr(d}b~9o&RH z+}&v90fQ_wjbPh7`f)G1+0O4n)kroVcG4~;qGJ@B4$&ROCUme(ZY<5Q@ZbN$< zTU&RNFvRoV0Jwr(Z}}GgXm;S zw01uYvrRP_O>AE^q3SYbiUur~`M3=&=tL{lqaB;j<{;5Y!ij!#qq>iKA)l@6=*MzY zt)U@wSa{3=4ePli{WMg_0MT2-0MU;=R9z`IpVDqI14GkBHmaf-o#?rSeg}B{o33TX z2dIcSXuqCojB?j`9qMl6nhr9sO>D?T>rHfsj!Lfiw={e!J7Lj{X7peYda(k1xE=lI zMAdDq0P3*mTVDS@5~}YQ=@tfnjz`(|j-K7j@Ox(JWZyixpJGcbnx0|F57I#m9iShp zQS~hMfILP&TAt%+mmg>!&FFZZ^XRYLC*ptP_yz6>8wu-+JS`wIuo>OxLqCT7n|s2= zwMG*rp&5;6t>f-S%S&7$G``Nj(ScEZ2L3k&j&^jSADhtAz#|<$QSMD1La89(C9xfK zZ&46E9xlnxRQx-8qfz%h14QSC3`8(MOhU^?%nWs(aBoOI~& zccb+S9?1z053{#$lSRn zjo(oL{kTmYf6t82jc&BErMd}yY@hB#=g-^&Xb`-bMo|y5&=kg=XtZJlI{E%rY$xGH zCwd~-RE^#dK9P6?6(ZS)hK@KkUZXLdt;%S|M)Xf&XEFaQuS)Oi+@C!B( zq8Urk|CLV+qUmb}G=X+76&+|oALiId_(_za>Ki&j9Xim8O=!nXbf6#IsMWGE|Dt2` zV-NB;M0h4qmzd{4my zW^jY&7$Z<)nsNSD2FOlkElY&ShfqIZya0xbd;aSK2P+; zv2_p)@jap*?dV5`jfDD0W{!zyoy0alc|5sCRG|B)9?>YB%AUfbXb25xI)<%;s7s_A zdeDvT6MIDR(aiiL_9vnrYtcKOO{RJ}Hui`V)Sb$84e3+h(%h=bF4{ToTBl4uAM(TAz%M-!?pW~oqzrD(=&Xu;iRM>l%V zE04_#YzAJ!)=>0bN;$NwWF^pps^geQPLD{pkuc}dFk16_L^V1tXWuCrEDYp$28brK zU;%p9b4}4-$Tc-Ez$>|A=tHNpl$AvDRn(hFJ6kC?ivc~!#$7T_uI6C z9^8(Oy$lp}jcg0MK+qyf?nK)eyoxCwkf@$nS^s{ zuSh(F2B!6jB6KG83OBm3QRZVS`q7W7<9mf^9_0+Zq7rqpIFF8b3~WB-(2Vx^oJa41 zUeSc+baoFL$;TA5c^CGIQWC1OdW9X0XVVZ`QFST}EutYbEM{P6Mmt)t8m(B1cHE0z zQ?F2;#=w{MiX60_+bf)C%SGEOIdd9T=hIRwTS zPIRKFfElA|U@2PAR!PE2!hv?IK_@n#8=KLC^6xQwG3*=~#CWtm zM1$zVdQ?5!E4*mLK6xIa7SS&1(1XdSdZbsRqv?@eo5&{NAfpQ1=tLhjpdXvju#*PS zgsR2N81-n_#if(SxE)oGa*a`k2j%f&+yf>CzMFdh%}+BCG(OAHFJT3qw{f$P@V&rD zm(t;jj10Yd7!VrVR6tcd9i7WeUgs`HUjsK`CJnsRD+Iz|&3llF`4 z=tK`%kKZqJ*)(9-FH+GkXTR{H8PykY9uv`xspvzK%s-QT>}XlYmUFZ(+Aj<%X!pGR z!io+v?XTeV?;+7bh7SkPc*%YdbukrCht|vYv(b=-Ec=BU-B)tnjO=yKM$dKog%kZ) zkGkvkizay=V^!AK%BeJ1&{JPdL$}=@TvJj_(tB>zLT2K6cSjFQHG^(J-}--_~fM;BkFo8~QV8 zU_Avd=o1Igc}bthDx|~wKG7^)(fxK2eAEl0GqrZj8E; z6+s2J~PW`Y;RqSb*k@ zee8Cl9o&w(YiS1!7+J!EF&@n}5(W}pEI=Px(PCvLXh#n^um%0s^|AYnJ5~`M08>*8p`{G1&vsaHa7_m2@kfQ7YEUYQCG2~H?VYQz+^OGI$AIr z-Dp8CmZKlHq3*^$u^Wx(MiVxo8C%hc2d|Q!|4FE>W`w9m52m0WGtjW9PnhL-EJ8~K zGndEcKo8cS^=AIeQyIsYh>lzOc=Ut(&74Q~wmzZVhzd6$ns$)C(MARd4;fx;LEXJ9 zA*$~06G_)F12m%hLGBfFR&$S_4_i_75Hmpos;;GB)T13!(1RK1ewdpZeOQTxN0@+( zgo#8Any~@>*e46@q(Lh)z+}|z;wD4$Q+;A5TCh%@M-Mu&72QvB?XTnf3*7DKd67$i zK5RsXi%X2Em-~cm=k?5xL>-#YgLXGJ3oB!Kg(XMNt8%2Q(7S!YhxWhs@f07v&+8mj zA2Y)n7%-aA*i47$`HXw#Mh4>LrbbgIua-@m?_$De@8b2}ATzpo6;v>C%tA*mD}WwU z-^7YwBC7UtDbT~8^s>u*tVSJwB&=2%)-U33=6poI$V1%`{lbaXG5zeOqdaEb!U~S- z7rW6h-o^IndFOtxMMl??A7g^F{`$Yj- zruPdgI+FTDmCQe`U+hHt@wA72L%--l^Q?Xmc^d<>&7q=9r1Xml^q$-=s!^BPFWhLy zR+*35%^aV?0MLy_RL$!bIWm8Kzi^-zYh?bZ)I-bZ{UXIqK4zdjtzVeYy?_Ct&38t> zXdq!sXGB}5u&`gGqVp^UgdP)1h1Mku2)#@Dg%925^$W}G)XVA@b!bKpy0H^27qFst zQ2s(XLQ6I)jlLDMU&TsZ%*s{C&;Mp-Oor#uei3#j4Xx}K2DD=udUCiVsLQ1sI{i0|qceCS48YIKP z-;DN2OZr9PHZ0}Rpm#&R*oL~R`$auEujv=+ySbL-EIpcU>=)b7jkRdJgNfY3`6>p4 z_Ivt8CHjRj(^f}iU?O22!tU!a8dh$Fv(So*m50ra3p+R`st(2s*?`kEzo&~7WQ0@Ss$a`$t-z27EENf(Gr&@;r8;7yal%^@B8wiKy!1Wq6|o6(PhXgI)%JWM;7gcdZS9kbEq zCQ(YlgO%t-2l}uE{n&u2K^jIK`lJV$`6FE0A6P*&qZ6G!vSMicH+TO|%KgmC7EM@- zR@{s3@Bv}m#p~ZkB6AlVL=3R8keOo{n$eCvtVa8Y0Z}W@M-GU+=#Cl?t!N%SAk>di zKbi(nhneU@3!29ah${48EgDq=q8Xj&f7C{W@dG05F_uP6N9fnmFq$R~@Rtr)!YKn{ z8=7%9I*u6-2hn-#fXH~9jxYz!GX_MBbS4eUe2jmB87B{jQuNLl5Oruck@nGu2W=!& zDRlHC8JLYuEJgcVDxe4Z(0tN>NO95-R-ox*Iz)Ra9m-?lfG|Bp2d51PC+Zf^0jknz z_h}|}7VV)fV?abc!-Ub6Ou|dTj6N(vKUPT384&eoSxki*I$FlkqT@nV3Y}PsrsZ4` zw4xW?*oUg@0g?DD6T>vLVix+b2n`nv@bCXJv4W0d0ra8=)z2|7OhnzqtPmP5<5Hli zkR_DI=tnCiJx@K%L2nV~rB`xK)Y4%wD}uUG+I@k6Vl4T!KkXnTw$CEB(Sa7MK`S=M^Ix#EuW=p|(T-_o`jVR&Jzp^}^taM+J^i#X@OobVrgjEE zh7Z%wk6CE#;3h#gR-&PEK)BI~VXw0y7>}wh9y~`QW}pRg(A~`?L-YOtF^CRSy}@xG z<krhF+p8+;t_yJ); zX9Ulyqa*TwXqCr!5Z$PkANi}&4_XTv{V5W(M?#=2phi%`s9%*q z&{EL2&k!$Y3TV1RE_4jwq1NG7r4BS~G>Ythu!E+8IymBEf6!9U2FAxABMnG+EUE;w z))_cx1Ly@%e;Fn5Io=dB4z$7jSEUrR(+3#=t@J~}XOW>9NDnkDHwX!Sft<`m6@U(g z;7vgN=c9-l@g|@K&_d8a&|1)F##cZC0chAt)IDhO>R%PFFX0ag5wbuB??wWkIa!Dg zwDx|y&{rsty=Z)(hU3Wi*XaL+ClRm-Z~7MMgz4L8rJ#egNa!0xd;ul!Edqj8fewP! zfhG^41ik|fS`9h~+5l>}hVX3HK?OlG+@*e;Cqzc=`jraMTF@rY(vkg2@b}#R?faFK z@3}6Z-vG2>biWdE4sSRHdJRAeL90NMoe&Vze{4Sv7NSVU^(%=#Ai-Pul{C;W&>YZ0 zxnC(|d~(0i02=4huNYe3e=7Wg8vOc|O3*?7exQkG`xRf%LeMPGO3)(ETF`RP^xeo1 zsKcIqCH-g6z5PltXbxx#XyIN8?KJpE5%Xzdry)Q}nMO~+zPun9U%~5c7$-a?<9A^` zR63YorkVJ40`p-k($Q(3l@zsh%x;5+9Jr`enZl8&32aakaEEokN~eon zL>b)%PyHGASxFn_31@n>+i;82zlctE8)Ee#OIwwnDKcMnrGgAnQHh|Bdl?f$pUi+mI$mOo<8d_cuF=asJjQ*w_5>i2(-aU#>I%e z2EA1v%~~N`Xy#&}xA#JrO9+#;n%49heBAO@L&pO!U9_XqCcFa|pO=kJSF)Op_8Qzg zD&hVpyQ^=x-QLkIYE&?+$?)TTXRGoQ?FkaMkg?a`E)^t^eV@TkpL18Ma+$0~qPV`d zksayoK7)teeQm3XDyvG1{ zXFSo-={Dfecx(Zl0Q?v72$cox>Noi42maBjd_XJzMAHB5H_Vo@@1u@>B-42xbYf_Q zsxZvCc$lT!S863c@NXZ-wl3J-NSU~cf(x0 zVRx%?nsz>nSH1YVVUkq7o38(E@bO^nBa=CQY6ab;HbZXb4fZ;n6WogE$v+GR+VF>A zx|EnphyF0cN)@?uj;SG!doLnNL6d27iwX7$!?$d+Fr?Ly$fRno1VaEX8mO z^$r-^^_j5mqgk0kP|%+SH>qwP#s7(SG3L{OKk=?{k3hQxJ^4HQH~eWZ=xbmrS zjd(g?uh#5wuuIuRwDoU8)I{eeq11xk9fsdIZVVbFFc*rv4RKxm8|B#l6gdtej|ERt z?4ZHVwia4dE?Lvb5yC)62Ek-fiB1pVWlD(7!GqL7WP1&T;$PCLyv;A~LU&&?%#lh< z=*Ts^WG`?djou*K=%;H2A(cN%*RL6t=nbX(QeU>BudlmqxJ91=dpNBejRs$E-4LQr zcn+F3XwNsCvFnCua>|RX%5=`TT5(&{ii?A_W}Hr!^&$l*XdF#1(r(4D(Jc=eTPCt! zG|rXq$vrUt7M-r3oc>avBIgX;8+8J?}g;oxdg zo7JRJU`<0KuY2Y2d9hJnRne*()2c4XO1QhZzS^oF0X4;V1YjOv7?0w8m7cN^0d6U9 zpI~xd0e7y3RJfwr!U)F2nXoL7lUL!xyxs|WAD$j8~P*nS+ zNJrOw)^U#R(nfnn*Cmclk&brDM%`h4l$o|WwE(h539FTC_Au)nL>YxKfhGFH<$y_hSx|Ch$uBGQmI;Q#PN zwAL-QVv#-xx_Ewp)s;T76>Ig4HBkFPdz@fjI6};n>fWM^5h7Gy0?j;k(jLVi=(7=A z47J?&RPHp|PE64^zRTQ19nqHCiP`!HXy$374bzd#3wC0X)c-!6wiDq}@rQKX4!Mr` z2-Ra60j>E`O{uZ)h9rm&q0mfMUD~^Tq;kaO!KMWv_rmrYt6yB%;DtmXt!hwtc!16ufCbF1>AiP<>_XMNuHt;!xw z+?B35h)Mcp*w1OLA#gNWL;epGKN>x)tc3@PS!*#me>YkzlpHRSiz6yL_#(wSa>iU* zl{K`%U7kcWj>5^F1)OA0y!=J#a1?87Yw>*MBE^mop7EFPYzI|CbG0n1|6Is}zypD+ z0|V@gIYC$n17@y_2w+~oLV(4ym=Q(S$DlO68Y5)eG&n^6Lcfm@;kK1{&bvgRPI&Ic zb3-fb#`E%E^flkh&~LO;@B=`w7Lc!JzKLc=GItoD|@XLmK zaeJ%sur`Q$j1^Nx)&gsU9;64f!c7?~3<3SXT%ile+-mrR?7Ve4XJFuFCwy}Q`&*T}*%gLkDMN@HU@BuaVb#D2fT_cS39AQI3=EZ}8V=h6tO}UQ zv|(qg7g#MY7OU7WW-}Ef`&+BB4pXcl&=p|f@9116ag;s!18anqsdrUhTHpv^IRmZA zQ41`QBmA>f!LX(p4x0wd8Q2L6EC*PX1?H+t(dmi+#z9pTzHs58!Ckrwt!MElHK&zu zbN~D1NX`JO9fmalOBz()NKFnLTW17TevQ^U3pbbgYhd}N7h^Y9^!!AH4#7=IQs}s| z@U%|Uwb2*O!ec^$Rh#mW8VwpYXc0U+NNqG?yqJ?)2c1`Xiy~@);~ASa<#SU2wakI# z=-ZTUEHImC;7_(~%6}~|S780XS}ibtV2vZ7sK)|}0M-HwIY%FX;Y1Pv8UdOs8)@p& zIKmNa^wW4T%{s)cjYhfPAsr9%T!gUB!NZ*{!oxabWE(x?BIZX{j%-uFm{p@j>W6*- z%p9p&k-+MJaRO|(NOFK(0CrLnh7Rr!BgkojaJ5ddZ=>lG#2o9uQEjwof|xHQI?%BR zB2LiNar>?cAo^qw(Y-*roFEbb2CqZ=nnQ&NOiX1-J=6eSvG6 za+qG209kIQo0uRCOr!&DEPc4qNjLa2Orkb75u~p%v?*UO&v&DFlZ5b#6Kx8LSv6cd z{Q)RID*>amQlHI_b+(DY*mL*fX0cp8UrdJX&Ur2w*qW41~dGyF)mL6a4E4i9| z(PY>IXFxj`3)o)t%w#cDDhr|yCZiGA%%<+i!bJ+3O}6eBxc!5noro)Kk_TtCc{Yjz zkUJ-bdf;Bv2`mBFY8v|;lFM}$BlQKaZ{*30i#D`{pshCr(@8`rInSZ9?hv~|=C&zc zY7-TA4`HVtfc*~|I|!NJRu3`RqZX>$Ugva{Iu=RNzfb{@qhernfW(smEpCCdvdiE} zuXqS=DSAGg^#BX1m`@!ZB1rNICD~JW>Z?Mb!$^~8H?qBU0dyQ`#qg3RiXm(vlqk`~ z3{0-Bd5WnXwUOwGLutOCrkMkK1B8Zzs5VT>H+Tsj+BQYpp-)-bru?OaZJz>x$|kM&FUUZ4chYe$5fzlbrcH6=xM7%e7KWgW0V`qvWhvdJCZ`Ht6>#fc zL$WtyoDk?`d;M@EM4%_U#Wbm6J-zLXZr1{JZ1ZT3GnPe0|3^5`XdhH#LmJKX5q`4! zHWNEq%nLf&M3>o)T`1cAHrfq8Qqnd$?jr)El5KR(2YpAEPUEHm$9h5dR5XFYbXq-C z__#Q4hlVT8BTO28h6N~#?ex@CvDGCQs@O1(R82bmOW_unLF0TyhNo^vn_^^_<#@Mp zyxY=I87!fqtLXf}gc^6yi@vCc9GvS5o$XKEouo4x zZOU!j5mO!Aa}ZAq1Osl2NejV49|g0+GaD|{bYKy{BH8~IN2doY{1?D2tDsHsV9zkz zcuRp50Sjl~#xw@<%Qi<>*fEKrnSNrVO9eb>V}>RkHzQzO0mb{Fh6WC_DcLSavni%831Vp;>L4=Zj{4sh2RPlp&UDW>E8Xb*$Hi)rj?^yq8;Vv3Y- zggj@UI?Inx{0#W3IYL`!phpitMVpZ>CWuK?F$1D@WeI&e1Jy84LVwLbb4`AR&IJn3 z(a9)~!AQta&$KC%v`OI605R7y}cl?EGG*7kJ8luG%NRK z$#W)HbNaKiWG3=a^(^gTdg)m@#&~8aeJ~ULE|k*MnJA3Z=O`c$_N-&Ho@xH`bSMz{ zF;;MX{3QQZ$#xdrGv(DbWgAPt23k1_lf2C1+@;m`shWj3A)nBmC0uN?Z-v;TKD+6C zq4dp@zVwlAA@?9*BZXCxPZ08eiE?a^aC6InyIQ&EhIgZlCg5G{z@m#QX?GBs=9v@Z zI9mkSqgU!mfP0-}JJv}~QtWKR6Z{%w%tl?sy++-$g^Op{Qm`l}l*7!zB<-iDb29_1 zNpQnN`s{45!fMsOn^gZA*$1PJT3#ccV8r89Me)IS=Ymu8U@+ppbc&7z!+-GWbeeJF z>(s&i%Kk&+=71(uQ|KJjtt*t$jia&qz|Qu}5mP31vYqpQ1q2=$Snuoru!CfE9c)%@ zY(LEr(=c&{k~v;~!P?+lFy-=PEZAW02+LROO^!&>Z z)La!*<+Z8SS@U6y_@GT0#i3m3;CwM8G!n} zHE?6YwI73tPILpE4n^(TeNKO2fYn!i-ljZ89v`9b9@`;1(82{64LZN%5pm~>=w|r~ zM55IE6`fmvs&e|8q%hEsugMQoPWZY_fedJBCTVIj@r89@1>Wv!$_PXG)_+Y$!_Ya<*)YZ+TaI9p+!G0e-nJ@d$ z6XC+cKJO!#NN#uUM_?hQv>&Pwd7;LYtRhjyA%CqbLlU z{hrhvCE}%gZwg;5R_PObFJrw!T`E7Z7#Yu>MrRj`P?s8iXr;qTvf=q0igNsdm zI6UhG&IGo>nj9;@Jb%6w45ciXq$L>RYl5NC%;Y%+v>u-OgDHFoN;7*d9aw_i-8`2* zTY@ll^QdD9N;`TUIW840`Zy>ZJjweuSomIww@z3JVXhwFD;k)&6r)UZ2pw9ADlUMc z!5f|pl1(T%#(-rMEV!(Es`*cefq$RW`!W~>57$$OVpt-_lYpQhcbSok?jM^|Ay>pe|h0e7)^4;{gj<3P~T&B*b4H12lH zQ)}V&5_cp6-E+H`WF2_sGOZXb-07v;#SDE4v>|TN7K^Xmj=C%S@G`b-z=LF(mnb5a z7#l8GY#(U#VL;^!09ThHAYw2LG+|g#T~TaW$@E=Q^2~% z-T_`!@jnW^1M-pY7qs;bj6QMDl9)*ARwIM2-T_{f_9cCG2L|1`ugP&WGs7lYvl{m3 z@95ZS5#-qjrHA(nB`WbgrfPigpR*N>^Lx6w8b#OiJ;`@+eLxvvG&5n0h<9QM)~1C{ z-zj!W`9D&4l8Dk@fKtRCY5NM)&kIRnrfufWmz96o(6N5QMCwTrLaJ^f$GgyT`mfOX zyF`Xm-brWg5-tHP(4L49SErM(SpdSng6$C6x-Ki2QmQ5a|E0hpx@g=QvC1~A`?4}` zJ{|MJM(Dvc5LA4p(%Wl<=fte3#-ZIUW@I@Tm|OvSn>N&m$>h9Nc)1P0K9-|J6)eMR z^BcFopU#(7t;HJ$`_k^UDA5>SBer+cv94+@#P?d**YF0kCtX=9yyZqe z66Ee)vjZ!F(t|5tI*1ItGiW2*;{xc&I@D-$0G(rd>P&K6kA`~zS|xL|QET0L z9&TsR?)6~UiL>Y!+&#-?Aw8sRVnr)4HCi%itD{{YpqyQ(fFQaGf07}HeC~!cSr}wg z-qY5VlkbL%;53`|-Yvqt8)q98ys9~#?dBH5?*(PgI`?4c<M;4m=U4~v0S z04riZ%2VUvbXj?{`(h)uXw`kWkd4ACJRfQ`QBJCH!v7%r^a8^c+7RY+KX71UOc+a{ zUcd&T>F7og;OBa)QET0s9Gy6hG`K|ro6r6+VdX;10hW0yg>Mp5Y2qfZv;HM)i4Dk( zF)F9nqx8a1m+^l98C?cFpp3(CA+W;g^kwwMCa}E3Sn5Vtz3&R>fz+6Zx?Zp$6?`)p z`aa15Jdp}cT(XurQW3IoJ$c@PesO6N#oq%?60?<#g4(t~H)p0D$&;|!W3yQp^iKB~ z!IC#@#^67HGqPLvPg=hjV?@YqI=UGRDr+B|-7Gdrf%_@wUU9#aeSnVND-O8iK({8B z0UOSC(?b}yiYPWs%#|DArtW>J<7SfD#<-LD=D=SO9ZN$8X)dC-nYI+sw`u4gHc!&^ zH1JL1lSZ6$P=}0VThOs$o~8%4U}G=uX``}%W(6XjZ*4(7tBdLU7VKj-L$@c#&5Yr8 zq{Ppq4`VzB&JzPuhl%A(uv-n>oDWmLR-_$sm|~eGAEwP)(b;ki)Bdd}yy_!#nyCZP z?^}_#L?U?`XeH5-ZOEgp#HhSa+yBNK>8WiP^YdVzrseJXZDN9L-ZMsJiw%XRV_w}-C-RbD{4 zM7a@@=FjJ0BzbtdnB3XM5<{S zD6Q02C_V%Dz$-?qZuD)!0R2)1_Rl*jQF`>g4YS7#;ca{7lu=nQp3Y9ky63zdV%o&2 zkD-y2Q$q1ZFa;B;1oqs}n)h_c?h|@@2c|ZepBR-O_OpQ(u6T1>EAj$_DgK16@4y~J z3H;1uKQIya)xfRp6AH-0Xp~nEWu{uDpULD*e@dq_#d?>lZ=oZU1Hky=SDTN&?5uQ zcDj>eh2ggBzaQ-e*mM=qcuWMaL0|=pp%A2f8q-Yzp4CBTcVPpr>2hyXSS3?iFqV(^~`ENK8? z=^_iteg6Ol@P|@Wd-C`PhW7jQsWwFnt%EUDNRp@Cys;-(`q=T0aM!_?C$v014~7Y z7TqsAL>U|fK(pa;vN?cq2kxT{V$a`?mnt05PM_Q_HdvR~wbS$m#I#A3&<^_u2g89m z-Y?~l0|@CgvYmE3AeQNCMz&+YSUoxS(*uZN5Dp`toA#Q(_ z*AV|Hrip^F?b?~suSjH*Nmfc4}!thjU&g0M388NKQmilf82mC!Jq3b?aEH_C`Nh@JcL0% z2KEN}as$NmFCRiLZ5U6#KP3EYbuR773J1#g%iuvvb09j{cv40Vx^?fAb}%=L#Lo0- z4wr%#UCqG?LkcwSp3r7W%O8fw)8s=L5A(<~m5x6w?zc~whUQ?+IU)IX$XQXl#a?~G z^mawz;&-E8c8fVuwm-S$q9{XVP;9PP!gAJAY}W%)rQFUAlCc_PR5KO2MICmp$SlOsHWG-pf z!zis_Iw&uESZh8tfQ+**L8Y2AC_ zUNOZ@H?Lh=g;afE@gCIX2-2EI5AKDyl?3-SER(@-93gNk522HLAu-fIYw`Wsa?ALA zV!B)Jf}2|hH`Pn_a&fgwcV0VkuAN;fm_CWe_GX|gS`KYAw z2s)H6R_ntep>$X)uThVnvdf|<=n+)jr6|gH1XHWP#qF4$p76p5SN(`^*T*esSDs;c z87th6fOVBEg}zvAb0=y)FT2OIW57baV##ekHZ0wj(d+xMxG@k5waom2F#P`6*m3WN zRJ32nv%FTc4{bPd9aO^2-2&q<+-vH9y8<6HtvNi3fv+*4U9r{b|J6safSH}xjzcb3 zbMT_E1>#P9#X9IFrm_0DOpZ0mBTf;5igJFmuC709FdjDZ5?ipveD0T$p`8%<`** z-8@KgI2#Nu&A@b~%7z%Fa|H%j?a%>C=bWD=$H&o?-HR#eappV4?KqK##_dV;I4b8- z37vi%gQQm}U4LAx@^gZI!&nQj6ky|3#8h>_(t+8VFfIkY1i&&r zcFM%h036}z=_kd`ph7)#;j#-12P%hSlI;zQaW1-A;O-+jl>a$XJl1jPuBXt@%O=s@ zr?8CZZ=jc%)*I-vr-WN5s~UcvL-MwJrM7*?oRhB`sDj$zci3&I;{_|}BpkIZ;R?7V z$|OH6VqJXQJBE(Wa5%eHASSre?x!K7XS>tUry=pBd(y{GL)7(}LfucJvlUMvxfqey=~)v67QE42h} z(L2fUD95*x{6KR{cR^D$`$a=ti}6{lK=>;MK9O-4uJl1*Rlvrni1x>Roll}c0JrR( zzQC%1nPp%07Y2;On+u4sgp<1IP`cYObe@jERCufaHWJTllJLt0R=$h6kBT)jlA!9^ zPj%5+mJx1Qz#L3GhD&}BSmyoEz0C(1!1|wsbXfHeeef)J+NB(lOCc8wKt*=Ew$AiO zshH_ExVz(~C6L4_^g5`|Hs^yYC=HlRE}iG_Nl>Nzls4q8d`?Vpsf6lmJ5#-v%tP@zm zFicks);0{|%Q0erncs!u^92@dfdvB#0~P`7W1Wts6hkWdqD)Mbnv1EU413MdMBy)p zr)#cIJK;QBR)1gZq+-cd>|c8KjJNn0K>3EVD-Qj zz?}{IO9R$F49fxLUVC$q76CI1!^(lV0vl(g)4GX2BCG-E^)3ax3=V(kG_8MG>~e|t zs6$!BDZ=FA$Jcihenf3Ai~UmZ$CU93+Enw$bl?>%7rB4Zp?tzG2oCfLUby5Y`|LTK z=}rtsPW2r_(>KPT=2sVHfn@=529^fwC0=avqEi)Og;aKyq*rmw-sy`Doal&L%<}Q8 zIA5Od6?1g;tBg-x#rjE6Q-{KH7&d|U6}^i*1AAFpnlv285}X~hz~c-de?pLO9I|rW zcOA-~I5dRgUB@xl2A-o2j$^Q>JO_RJ+9sjZzi~z_`G*drPyH5R0<8p~cWCLruB5tU z`@+8=(`LdxQv3R3WF^YL@Dt+YLr>n6Q3-Ld`WHG`iLz?>r31U17=>J^uM&+Z4NB!_ zQC}2z$f6TG!@NvePoObnU#0^mFdEgh)5#MeDk`s|LtFa9A(DO4z3NyKgQm-JdMU(! zvYXsD!~ND#?Cu5kTDYI-prDgTe*pe)zU>FRf96TNf5a8$2Yt87_?YY@27|gQboL}R zevH5!5S9&>WyuE+r>~IXYrF*0iIJCiVYFj{WK^@FE&1||5vYkcU< z*TgKzwTC)h6LWLV^mGi(#kdWe`4IU7_7I-gFxCXjx3@z(!)(I%PLpb2=#Q#le}lkM z`b^~lJ7Z3DsB>WE_?&@x0UH2@uq$BI40{fPL)lf_N1(rfB>)@z19uZx_)7&=G0>r8 zo3IGbY+%lRQg@YzT37aGhZ4zd(T;(9kSY?x635>RKTU9(!EP{&bpq=JHeE$DO!pBs zI{xZVY)lvr1kS+hfZ1{5Ku0*m)BnHe+f(2mRf8nGE<9}q2a)bA;KwJXw zhqnKI*ME?S{)x2vKO%I7(e27jqiWJ8I^7@JFDY5vGGJ2h;|pLK;qOV>vkLObwf|uD z?=bla@8^Gm9)Pb)>}gvyHZSwMpc$N2J`PVOs>SU1J2NgR=DKo4M0xc(-BZ9e;#rr# zT|mNzK9L`?TPfU}WH7qJmx1Mi}rk?_94cvl*Dd4~Sjl>*iA=kF6D*nq`=Na_z ze}$iY#M~iL$t-$1`C38e#XU{Tj$!4<_y8`Hmh z19S8X3+U<_7&i;T$?r|{*WgHse-ndEbrcK@W8p6qScnDY3pc)PCb5{h-$J8uJxp$I^SQahP~uK2{lF2Hzm57n zbA)!i4flMaV{c<~LiZs_@4#ODAqBjHmFO_&&tJpoV58=KbuiWB*TJ)>wmRCyew*s( z*gInGdRDE!i~XwABxSO9ey^M_F#JK?zAd}KFjfRC3>b4bHr$iTfyDsxW&qz#va}tD z$6DYiA5%~*B$>gFX>+YuG9&AgE6P;%2gC8jH6l)6o+^TPKvRHK0xMyO2&*NvV#*xd zXIHezxt7Oja~|vAw;XP_n!@LRwg9^T?1*~o^nrJ=PNBms0V}lPYkyZv$aOz^Mcdef zcPISHzC>1l=}plvRt+o$n94&;{_26{1G6lW7GQb9uwGy}z_{_V3C7RnD^xA8^$?tL zPm5VmWw2N#m;eu@77=mTrUEMgb_>UXMvDHWexR2F93$}6)4bRL_cNq^MilWLR*q7? zpp5shs5o8(5-6SZAbB2rL1ZISnohSC)3m;SkeAZXaMHJ`NrpWEXWoRl=tAtskbt z+5$gSa9gO2NB{f)tUT}AE0A;}kD%+ce;^j+W;f&B2o4LwFU40eWevkxfMr@>%)xts zr2`A%fNHvTt4jeKhr@TMcDT8*8w_Laz)FFQQxQ!-3I0xJt*dCJ;~#i7uxu(?F?$MB!kOBo+? zesJT)GVNIXcOT=BOf7ES*rtuOGd{se?S((DDEqZfNzy(M?k*vJUr|C$c?bdZ{Q<4y zZ#wpg2#qX&n|URQ3nd$F`M}K67sd*K(U# z9k+ChB###%iarXv^(E+Nd#zr~x2~}1q$~CKoTmm4qdpZA^@BE@_}ow}*RW58mvxc8 zlQw;d4JXD&<7(q1`uQ`= zI}!{u?teV07%2RISpG~FwEutLI4zigmXrZ z&rykKQ|a92B0~&J?bKSNT6ADQpq&@d`fzE;zqOB3A3cjhl6iieIHjp(@%ytFFpHt6~^d53Jk*VxR$*EqXlgxeWy{`2M6 zI46}lo34M2M&TRWiJqz+sol_oO7)*Z`w9s5i?ynals7dosBDg)$Lf_j3B>n zA&CvbZKFCj-Tp0@gZtu61!wtL8N`Wi#cZi}G5!24M;%R$-=R&l$I<%lkj0Q&JC#1I zeZKY`+NW_T?kCa0{q`Ng*)1c#X7Prt`#rc`#FdWmO7qC?#ng#`4|fi2moukm>;$I( zHby(@xb1u4Ep&Tv#|UTEWVn&=m0sDv_iFw8{qIo@jj-FO{cy!|LQf9oM6h>Wey27Q zQR_}yc;RT$@#{n!?0$xiHG9*6bKn7uMfBAB=g9(2B9I{gE9jm=@|{sG*%=rDP=8wLlimJsq|=PrAPfJyhmmNtHf6G!#}GhFRdwrJ~Ek*#8ZecYdD^1p%?ns)tO zX%!x}B>+CIZ0qn`qR?M>9@&fMLEIG-XK|u#d7GF#GVCv8!xs0jXj&l-wu$MY z09deH*U%@hVenE4ECJXGZCCqhn{b=l0xV@@*U&r|-gJrh^#jiy*+tVYi{+!ZI^zCD zVEZom@G^v+H2W^-1W-S*7;A*Gh7w#^G?RnExZ>9g&()(T-YDE6>)~dWow;oJR=GN0 zmb}9N?2LuKX!r{RRts#I#;59y{2hrSbsNF76P+l$9pgg1Qx_!3$ab7$tZv7;T-ewy z95KhXvNv6C#{eHTz6-r_Rw}+DSEtfu zuq~Y)1?Il+3I?!VZ`yc;7XZDxl&7_WU#G5M#WM!d&K2S2=iu9=t%@VV{BnGQohz^< zcxDrVUj?v4Uy?h)cx&KRuEn#b6U#)dez@01lY+kN#AuZ>y$hd`smelJy0D^}Hls^< zRBJGIbRpg90NULpqU6R|xc!C`Sn612Ej^(Q=-e3jM!eJ@I^Tst>JOrTZj5wxvuRB? zwy>Myx`xiCa&t(NtaMFrbiNxBOw)3bd$?d%PzKYim2|oXB6)#IU8uK5*vO?Taa9i| ziUm7qm$qWZT%pt&d}$RO=ml3`epnBC^ePJP#kN?atZV)_y+Z0xpDG3fva48%!X6Wxxs($)yjYQ$-@h z_CbtnfS*aK56w?7lmRp+(sA|^eFvTI6T9@8xb?}T+bHd-@XzI2p!`i?IIUn?E8V~_ zEC!e}ZiiZJ;V&6j3NUke&T!)k`qF`MLF?Aw`#5k5jp7=Vc2geu(CUGjnOSC zr2VnyYB*HD^EeaESUs?6V3re>7GPDtf-U^@0&4;0V1e0;Kp_AFhgS{9=L)O|m{6G+ z00#X5UKkcQ0vJbVnQ)>hLNms1lcq*U=YPe=JM4d_HY!f)$Bwsi5{38U(>|{xoZ!b< zOJCfp<$*A4IBb#~T22z3?H4Yq(&1*wBl6*v25heCTgzt&u;O7@C9pHVW|{nPp_~EM znM8Ac!ga9d(`mx*U#B;RVP9siM5I(OjabU9BEzzoCuaw|;&9()&_MO-c+ z7GaX$R-n0E{|)<^6?f5^-yxUQ!q0Io3om-^cYHnRzNTwv(=`QQQtXiquug4Hs4G++ zK?A>w2&rNXh5o@ubCYTJA3Qt3RbM|?Xsqk`1DtJeQ5Mu}L>r#HA$bVuneEZ+va)sHP z4{b5~ZX9`im%-YcE@&)Yc@5Ihs6jDbUx{n9l9(6c4aULK_CXvLugIt4gOJW^^Es!g zVwh`#Vya)dx2hvg^{h#Nhuq*-Emf6!JOwNph@I+DP|Hh^rY_oPDCz z=NFQUZLhECFG+T@ZNZgiBlOzWP_wM%S62Bp-x&G1c(Ny;Ujb7$aA9Yx5Lg1RP&~6? ztPEHVFms=b09FmGq!}u?jkzL?rhj!CNO^qH%+OCR*m_<(xh(sTQ4uSwj0w; zJ8a}-BfZ?f8lAe8+bmkl`?m5FedYLWY@w-NHGMuB1v+YkJWZc$=tebP+=N5qYe&d4 zR=Ij~56LT>uJ0uDWnh;13j-Dbtjv@b_Ll&x0T@`EYB-;%!0J8e+z6CQ%q;S=LwVE$ zb>p}kGT}+j+sV*cIlmk7uBuHz&D0e;d75ouRJZcD4Sxg(VPm8`-KBm>x3XW0SRL2w z1Zr(5?H(xy&B(-6YU=n2cQq$)D+R{mEgK$(Q-L)Di!^;MIZ}4sG6?%@)rS_Y9DaOb zx`)o_a9lOOf`Rcf8>S7w0)bgd#TS72TVUz%*KdmNN%HW<+dg40FViP2!xdgUeHl+z z?PaWg!~TrszH}7a-EqyEQPVMSd=%X4VYgCey$YPAwB^w5g+dI$?Qb|J&ngeA9AsyY zIN0Cg{H<0+f;~_G_aVQ2x;q*Y+^*8t&%j(qj+UoL^;Z;@O_S#tRfzpTQ+p+R0eZj-1Xy!Vev|^mRPD*@) zPL7jbwly5=R<@1QB6#Q)d5i7f;cn$WwsdwL)I3@_%MbB+%H7WLS9&L0Zgx>yaM?0m zo-Eb>iw=yJ@p0G7bb7qJ*Dv7&?k2-KvEk~!FbyhVfqkSRm_UK{1Is>1-7fMpdfG+4 zOLBgLEqiUN-tAUS_^8=53q#+kZORb%s`#=Eq@J64dFD*$zqP<35E)-hSugcaZV)tHI2mMrYa5#$T4a!? z<)+#844t&%GO>epwJcy}(Ty|<0Pnx9MXlXk<;PWYK#3A$<{o&hYww2D#zK0%~EYGlx!Nb4tuqYe8%%#NXWW!e$ zF!MVwRtPN90t*CI1}q(sOmLTHO{jsRxk_T-XoO=m9Pf6Qm*pBQLUL>|!Dz(5ELUEW zfn6AeWddsfX4&xafpL76ji&@y|1hi)m~NEXKyNgtGXNa`nrEq;nI>Q{z$W6E4P!=N ziCW+xY!Fz=FwAKVieMP#1uPrbjUq+*Apo-gn(K}ei364i%rfB=U^&3dvqJWl1*`y= zxxFw}04yKacr|-krb~ep0h?lhRROD5`S zFqu|+$#bRR$#lp|c5^XK?irflarcY~K{ZaM({Phq-RYbc#-0|>8>}n^e#+rzz?0m( z5udX+?e>;^a$CH6G!a4NmFg)0wHD*%qY3y7D_~#_z|2!twSa-S0-J#N*{B5!%nO)0 zjWuDVz!EGlU*J{qt*mu9KIG#g`>l$Y+H=!Eon8b;1{TV(!f?bkp{Pw@mNo1OtQeSi ze~u&e2UawdUPQc-jW3<`;X?7H4j&YBv@bbMm7&_(7jbLDKQwMhO$(t73b^kg6p*%n{O|x~ATRhqj4{UcD6djvqCA!Q{p4VM z$nqWt!Rnbm^|a86>GFJib3zY3Xi>kpcx}3T-^AL)8?TX!T+}T>e*iXGJJzwmU!JGW zUfqMORrRpod;W-{BB=+*lKPA|2s>qlJV!EOayvu*K(e`q(RGv=(LGo&S<^CS1^TvjlH=PWUJ*~?g?V+DaQF?y{K}zi}AbB>X zQ6UFt>ufYIyCd}WY;XksBRvY&2pi@Id~t8~5$b?juHhM6(5bp;4Y?d{1;DnO*Q(*h z?_3M~!m~Zfb(3Gl8i6&G_9#B4=?i0*fEk~=85;m*^L&qT#N;m+{v2Y^5zBgLU$8vK zui}LsCBq_;Bski<)T696VJQfZ4lJRZeh!v5hB~~`qx{Ahl)k{u>{3;X;}_!#fqP%= zQCM|8uPR!vvBI)q)F^hdTLxBqf_BeAk54*5N9V{s`mz%}N)+!q-a^fDWLLj4u)hMo zZ1`o05GENnq57x@IvZ#?Fo>;gbHOpnPg3|?In>37TT;z~Um*Or#)8dN(V@9=kgfYE z+7C5-)fG)&z|iA9N~W{V;*E|_c!Rp zdFa`JZ>sL(5F*>@{cCWKsy6Xh7=otY{uXTvkv&}u@1Y5rB4$~|D-P1mdvr7e^CaUL zTqdhca{5B#JM}TRi}gXRbMBZgd%NV|PFAxN#w8fM98KdRIzAsI*zgg3JYQZdd3{WB zD4JUICzKJ2!6UPt;=|=oa#$eSc~pMZqujxX^8&AhzQEdeR1@4b@zDWD?F(cqLIOLCYT8ySMTVV9{cS~b}vKnwu(pao_CcEJMU zI0AviHTFR7rP_nehJo4ZzUskNv3l;nZlUa|zW{rjwu!fNA?8e%zM+hTvY(&pceoPR zBL0w-5Vn9}6Gb)d_>TkD*i0WRM7%BE_b47b_wu6A;qoG>96F-IvE*^#NBS&W4xlsP zGBk&uXUklD=1=HY^m(}KM>7}6<0bzKv}6%RsECV9J?)t>`Q8qu^D`Y=gwifP(epn7Bt_=tm}eE!VDe<;Umy8g8!uR5ptAm)n7fzV|xA=Os42a@Ss7Z z2di)>8BcmVQudzgWYw!}*727oteh7IYPl4X?!caaRWE%JDKDGgYJ+Pt0kY}GuLh3Q zHoY`6O8(8(-x>F>+R(|vNFru2vpLsZuzQvLKd~6=7`3=`_e=hqTm5!@G@W0JP8sLZ zi|IWUH=rFS8W}E|Nvon!qP2m&SnyO2q(2AT)_q>D^5RHx+=QXAJzAccn-_r_In|tK z&7vv^YZ|~(EU-FYMqtc>*l-7I2Id@z>qS*W!#aUQ0K3xy)7^!R3d~Y&b_P}g406Za zs#lKC7hpL+Ghbya446|?uM%q!VFIu?U@I-KRE`jsd69)XZ8osFDC)jd4p`C;H%q~% z7H;l~dxw_CxT7`#3j-F&@v0}epmi=$DBF^cOEpXB?WI@_sE+AXzPE_9 zWi6(;%X){7WO7IE1y;F?Hpf6HX}ql$-^Qw<#hWqmty2FA=+Q#wNlBonWe|1i6X?NZ z7`z&AH?ud#tBRarl-PO6VnN7LB z3B7HS8i3BmVgk|$PnNTte7G4cFpjJQ*rfz=yiInCVz-&Vz`loeG#cQpTX}Ol7l83C z+2*)8o_=5h3A7dQ&MT=qPIhtew|Haq<>2PKlH8W#<=Aa_crN7@_=&Ix$5=10uwj_Z z1}k02Fw7NL@G#6DSl}=$VuO{N&N6c>fhNMEFFgLi8#U1Bu^e-P`ovykhBof3h?l)5 zR^p;{^DI9CVVpN&Y6Wbuwy$zL9)ef(YC0Q_mCV39d!Z3XRn4$$1tj&XyG$>PaQsq+ zO^`AzuuNcqz$$^6^i+JlLcT3GJNX6&<#09dQw+>3;WO3%tPGgiC17Xl0M})|ocoYs?|zIKW0+ zWv;DweV-uTB1Lba?gWTS^_y@tI!6M-t)K>e>o!rqO2}&2sT8{sg;tkJ8BCq-VY^IK zD`gug`5p${sBtBv$O_zPzkxi)U}0EUDGRCTUXoX_P?iS8bl|^E+u6Q)G|MBEo6(>% zz}I=72KOu6E>E3UgsbMw#lwD_?nO}p3mZBJr>CmhWiNf{gT0ExZ9vfPx61);$q)Bx zYa_QiIvgzb9hac+ zXT`hjz$+Rar6YI9eiI`KZuESXT~fB7kpufk+eH5R4%vIo8Q9I4=At_TKP|wv;@Ncm zTGeO~0c#7~0w3$eb_5i)dC>i>iPN9j|Z?d3BqeC61PwGfDdae>iVIet|?ZhkknIJG(N zfKU&t1o5z8ED%`E%e^;!#~Tf-1ekgEDG>gWfYrTBXV=O>@fXbgRl#NT&`NRz{Pe?Z z4o42dRaFbj{T1{U22}r23I|}fX1L`;2~;wgO9}iabm|1oKkrGFCrPOlbPTvuQbBJg z%R%$2D{inH1Hu+&VyghyT#i@mg{vU{-a3j;=&5ZV?u~Gl_%xp%S?^%!{ zd)p>_0O`}7zf&{N-V`**#0EN5_mwVLCf_k33Uf3VV)rXh3us>}k?wY~(iR zaoxB!_TU3EJ!NhNa~ibmQ`Yh|b%Ng5jERTq$Ufy;O?|(z89l7hz7K;Aq*E_iey==5 z){W`Y1`4&MB%`V!ZQ|$p5X68nbm(3#mx=WAy|Rys@5H_#QJr&I0YA|bNlxR;S!?LK=_H)Z!EllnQC1G_ zeadw01l&7YW$)ZxFI-a2alkM~$lHyRGr+LwuNuaRfw}th-K0Ld0$4dPc4wpZc3@?| zEP6ZUHH$xFiKrQFHdFhw83n$9 zw^{`7;n<=0VmShEL?yY9u&0t^I@~+qu8L1_j!vuK9s&1yxMSfsJRPjjX<8p2$z-iF z&;YHc%5>RFq|E5k_y)AVaHJs!l$D2-6X4a_x40v=V{CN@AfN3hLEnHrT#BgnI-Dh) zNJqEJ_PKF0Z_XJPL(Cq`yMbHo`6UBO0cJT_$pn@R%yN?}A6Oc&X^4jn$5#R@ADE?# zQwgkSW}n|p^W!rBYvIv6?~Op?(hrDWf)uNjlXv#i_2o@MubQZ9RMSZm6H!=Q5rfieT9@HV)VkS}nPjwan z`ITycof(ET0;?T{T>@4!3>yGeZGmw{9P-gqOc}BDg{68C9m|wm?rpH}$O$LHt$rAm z25fi+bAS!cU=c9O406Kdz>q<;1SoJPihz9#FM?+HY8sYmC$Pq0nC=mb2E#CCV8e6l z3(PXdoRctM$g!Fe+a%Qko!u$BEr>s)_W*u(JRiw4d)woEk%80XkB)pTIP zbDRfkc##$Z;~ZPYSFs>QLeiY0% zV#vJ@?)uCd_Q)*wuZp16_sg+Vn=@AI5< zmv_7GlAC1UX_|QN%*Jx&%dH$s@2LDb=rsL$kW>4=##(oz-ZWU>FwUYc?jK5npv>ob zbDY(&hWmlj=Ub%fwg>6Ty}@{zI20ewmk7>X#O(3bEqAMjFC8HR^XP(yyo*Q3Y2;l) z-o?-0O3AyEye70L{PNP@i{u5!o06m3@|TVFnP4?e+di2NB${rfBNMFjw88di{dT%_ zbJpBvX?ssUeZHx#onhTl<1k6rTs>eStqspSy=o#otG8Ft7M6)dXD3pQZw-ydnCtV< zB58vaA4&riyhxjij{){uGu+3WZN`%GFZ~a=*_x91n;M{h41~cAHZ=Oo`rhbpEH;r_aN8d1w*4S$u z===Jt85wgsR?{R==W+J+)2;TYuXUpD>7%Jz^utc`rqeB=-I4Vj`YQ4&y6U1CROyLcdi)HUJJhGQE}uc2xTc>z zH-jEjhWhIcGwE#-nuAs{lP-fZeR}6iE4SsuftS`lZ3*2Jk!R}XgQAqYH3M~>SyW%A zA$sU6YNykKdh#qf(A2|v&n!BtZhu%`Ios-W!!^a#mwZ>onWZ$0k!S8}c^PUgqXU~f z(+00_H+jDn>qWC^1>0lw(b=>j?;NM=lu(<^Ch4Ii^q%9c$<_3g_Rfm@tb{H@!@+90 z1)v|(pl`04LmOy~t#6-0&tiP@s?TrHr(4jQ#=GWN%^F3YufA}-!EJ?B(0w&|!3!7V zIl9YSE4Q<2Av$%@^)q+)3>CP7V&;05S4yog9UJ7mB-b6w=F-i7U}-h|q?hr_ow_~1p#%gs{Dd~&e)pRa`2Ct+G9`fsKJ@Sn8O4`=MGgkPL ze>FLC^W1q-FrF*?u8mA*vJa#_w>u>#c(6UDH;s~uq*r(^r`Kut(MQDZ%8zyEmC?aW zhY~-+CoOt4gzvpY{K{J5w>0^=;`eMLexdk56>lJc`dGkzrlK72=fNKWKb|T6U^Fli zzB@zwm-ro2dQF3`=rqQ!+E{>9#{Y`v+0ay+D$KXpf`Ip!80%2c4*22G;x7+4^{GR~ zA1VHK=;-(G?Z?EYS;NjNyQ8eR@L$9~!1+8CsWAd-hyDHu?R; zuZ7cgk?}ix1qE@1r4Nhl2sIaM+$6~dejy0y&J_JhRHJ5!uKx_ zf44yOfUjnX!M|k2ue;!fgW}(JnY6DSLcks*0jq@+7-uT#FTRa6G#`Gnhxo1FuQLsF z6+gX()Kg*d-Qs_a1^6gv8aOK(YZDs&C;WJo_?9^=O+{abpMwU{I?I~#?-BoQ932hd zyWz|8TBTaS5BhgYfw!fjst*G8U&Q}-m;{ExR}YDQKMto+rh(z&e~5afz>nW2z6Tv$ zYVr>{t01UeoGB$OJuba5x=??|)bP8EE)~X<)nf&Cu{K#@{Ob z56%M6_OH`LR-L_00!w%VrqvT{)6Hlk>aW^eD_fCuSCOtHuV>YzZ6Ho zc=mb!bKfq3q1a~6n+E!b{~k^w>*0snioXa)XC?gTNtylk-c8cc7<~T$@o%Xo{z+4R zEJu$2dN};jyULSj3sHX! zj6cIo0sggidJS(cJ-q=1>_Or`kK=fn>CoNcr()=x3tttAe~0rFlO8It)H@uZh16OZ+e7yUWDKEZ3mA>^dnB zzE1*U3ZoA`UNX=28IM|_2S<(OH33h|$(P0a19^Cs|`1b#Fxk zBjVRWMFsHHi{f{H-wl3vt@wkn?Qb*ntP%fS4B__|UhcH7ypKxYWEWYbK@^A4589(WZlH zo9M?{Nd2MhqPuUFeBXPb-$(xfZ-_Pv9Nau;{_iA;d>Q+j}HF2HG$2pnA$A9Fl}7(4Nml&x8)3 zgW+DXKyEZJ7jfTy$qzwC_KAKT+67$-op2V24wGf30`zc^TTX7FPo;vDi2I@MhxS0f z2pvcH;m{FivjuFd!Rrur_Tc99Z}*E0(l;jQTj%G}zI9ce|Cn^h{uh??YoY%nZ_0w2 zx~c3t?xW78eW2ZQvT42FN?up!@Cnf^pyg0fYQus{55Dpw{ZNv2Kj-u-_{UNycPCf` z-VYXoqrnN_H1HX45x4?e4{idtfR*4|!k~H=#{1xh;7;%pa4&ce{2V+29tTf?r@(K) zYVa)hn?oLH7t0zbK_Cq}6TAX+fsMcppc}jfY!4QKy}*9p9iX%2_|9YTHtE1N1l|Gv z4#vQ*7V{>fhZE4D3^~Jm0Uf?f^f72J;$K6@({V<^Fy({(0dY69#Ce<9JW zRTc~n5~yR&!bGyAKz+oc8R<@kzg;2m!~}_d5A7Z&`i#-zMgIov`%Lsx7#2g5MW=?P zKHpf;&*DT9drP!kF7bdf>xRzeStt;HLK2?eBEygu4b(LiJ}&Y4(BUznH*b^* z;t6R$J%$Ejb0ohB;+}=9>Av6*B)FD3Yoxf&i&A0aj1>3`ar>NTQ(^Q+(WZPdXuEg z1Y3d6f(yYia5ebyCO+;9f)&uNnbPFj(0*I=$IyXkq9?y6?Ztwk_aW{^{HW2BC4Lgx zH$(LP4stFHKkewCTHjXAQGOKoGYTY7VcX5pV05}v;KD`-O%z>i8i4)ZNO&if=jIol?06H;6bTeo*PV@>~;CYa5&gQYFB;E%39+aQ-tSo@pDc)}_3oIM) z&GlB(;^A8*#q+IHaUXQ(JJAs=lMC@j5x1eQ-iD#)wB$dIc;Xw;N(rwb- zT+m!Zo1NylZE_yh=&JpL)UyovUg&aYkCNMu&CrRnl3xj}QYHQ#wC{U~o1Mpn`aVJ2 z{>h04)gc(sGg9D7=)ljS6DE!de}j&sNrM@<+V}r1`DWV&kY5M!gfyrc8ST`skB@7d z_gp;Xvfx3CDD#%cifj9ZuszrXGSi~Ru=j6p;Fq3;0y&_?!%QO#v%3xH3am_YtC==tDUu;JgN-q)d{;3vYM@*?3&1bzTB zP;mpWIoK1t0~~?!BcR8F&w}PK4jqzRES>K8GwClLV@=~py2_w;jWS`duA$uYpCqtO zr?^Xbj!Fgm9Zej+Sli0JNV`d?6ccBaO7n~Uty5D-yBvKx^`R4PnQsE`xm8Q^mumE$X|v@->Hy23h z{4P33P~v(I8(%%ln3Wz5pWdM7iwSf68_ zSgc#VMs$_wB4)QTUBdL2=}P9TGJT3!QKoZWC!Q$N{g@4x=<&=xOLRFiutXnXmM+oR zTWG3EbP4SkdiSgJp<3S-t6}PiCAygWRM%2n#_?`TIez1ZR-Qhw#d4+km+EsIpS6^J zyn$G;R2MN%EY&5qAWX?$_*X z#6in-A=AG|7c=eUx{Nt#k>1G+FW2Xo(dD{jB{8vF7ct!{bP2Q13SG$ztk9>J;T1af z4PtDC?#DbszZuAE7}n*?Zee|hIVh~Nw-d`2=|bjKYM;4xkuGC?L+vv&wLZseqIJtR ziDSdMh#3y+66TJuu4K~p*PdcFT&Z*4B6?Tqe$4J#k7pKXUCtb%^&#enl{))vVrZo< zWLB)y#mx9hUB=8@rFSwttMobMpjEnMlsIdZE@D=!(k09jt8^u^;c9(~Iall4cZlBA zx*v1IYCWDATCK~O6|40jW_-2IewUcJMi(+YYjiQwzeblaLu>R-W^|1{$4sozE#D(H zT&s(i-RL`on1j~pO6J(L`V_NttKJhM*s zW4d3^td#-T$eEimFt~MyIh}Rt}oXucM%Vk>mp|6MqR?}woz9yM{Lxmn1@Pr?nhSJG`fc1 z=lY$sHzzMM7}_JJ12cS{fR^VAG_&PXiQ^41<%h=G#3~H!mcdMYx?A$S&|gB^&T4&;yUr=)v!(fG*#hm*2$EgOJf~iSIDlEBcJlwrI~jwCD7ovr_g2Lwa!V zf|ed+?l%Rb2fqD$sa3Ew{;}msOa0-fuHJ3k-88bGj#Iy#L?5(gK^;B~YI_e2oxdH` z3--{ovg~7e53|uRUGGz3^J99zr&gEVZWMBX3QWwGMr2874kxr>1UfWd8jF8QjdeVx ztGROTG2LOW)g{aOtW@IBqxM?)d2UD-7@sHM=sc+-x|iy>jXJuQ>i83Nbl?B3!;iAQ z|4>JGAJsAJnBKgP>Ufm;!*wJ~veS=7F~}$w0s|awpzZxs#S_Q$g8fv*4C)S3Q+Ezn zL-Twg>9e65T7_g8!Uw4EdTRdw71~DaGk4PZI7o$~NHz>X2T(YAkP3fBEgqyoUsH?! zApS;Midm;hFJN9>rS~wqROxz$i2bVc0Oq|EXFfu4<|K-LMw~}+<_d~`MqAv*mJ5J> z&~3?!(mCQHykk!&G^sN{?pFTckH1rX}@b$qd~|tI7L072Zxg`6~>D>L}z z_i|wKVNJJVsR?L4>>DbZKDH)to*$A&Ivbj=RB2jIN-i`{QlL30Db1ky9+K{eQ`$oF zu#%(V>IP`OKD<-AG)0QDRd*jdlz^1k0QuqtLDEOWo#1;_pd$G3Y_ale3Rf2a@vQ(9@7-Zj`<78PdauK6`JyO;hVfh&^g!`@@zz@rkCVhr&JpleUOL= zRjTVHiS(!qdV=KXCK>tpI;8Vj_PrlnG+pVB%wfmm5Nsk#q6WY>>-t{kj>s#J84H6@ zok=qXmZ8}sUTjs6S>Ap%D5u@ZO~OgV0Z2$7{w_6Wl|Z+WI4FFgODI3uy92LQes&!SknlQ~ zu~^~%s{5JG{@ECYJDeok7jfS#X>Voya3&(b27}tVEcY`(!cZdEX*b5wzly^V$ z6W~MOw4}UQtohhpjKDl_ZBpU}=&j(};JZnA??dkgkAPK4c_*NMCUX1gTNtX5tSYm_ z>ChIK4R%b*>k8c)>;d*o%DWBvK5$^8#!mZcVp5_F9Rg>7WuQ5?uZ6AvKLB@uWUJ9ebCW4sO)@U6jYdMw+gdwLg$>%PPNLwo9f}a zpw$&v`XR)Hc5X1$3-VFwkdpcsS5da!s$;i4YMHBV#&{f4nWt1_LfP! zv57AiT>u?hCAuwi0=g5lXNAPChmML4s@^bMNVwbRwNjuM+P6~lwhpp@5j3y>@z83C zKLH(BBYGmVjryiStMweGo%R`1z%l3;hW0|QhIVa`3SWXwtP@=U9os1SEok+!=ntT6 z=snQhS18UWTSJt3mD3+A=yx$+S5+77j$_< zhd@6zov(eGT&D!EWT76C=)O@HhYt4?9Yda{Bl0>6U0p!r`@sNcgYHGx8D|RfgiwvgrJ^kiOc&aQbCJhAqL&RFU$V8ZM*gBS8YFjT z<+sZkdzPOc(D!5NtnB=*S!TQ)r2DcAWMeJp*(7U6F?c$B?*4Z5bv!%YofU^2*I6~G zkQt*Bx-ZGA6z0kq4xD73h*7gnC6Su>uIxKkNQduSp?B8I?~)yji;l*1cCGv_S%LXC iI2{e>zO|^4v5;f+Y?7DTkoJ7}j9Ry?yKCjINckTHC5vkS From 8aaa3c4884d6ca3e3d46824fbcfa23bb974328d0 Mon Sep 17 00:00:00 2001 From: erorcun Date: Mon, 11 Jan 2021 01:10:24 +0300 Subject: [PATCH 062/152] Automobile: fix --- src/vehicles/Automobile.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 8f034126..ed187849 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -239,17 +239,17 @@ CAutomobile::ProcessControl(void) // Improve grip of vehicles in certain cases bool strongGrip1 = false; bool strongGrip2 = false; - if(FindPlayerVehicle() && this != FindPlayerVehicle() && + if(FindPlayerVehicle() && this != FindPlayerVehicle() && FindPlayerPed()->m_pWanted->m_nWantedLevel > 3 && (AutoPilot.m_nCarMission == MISSION_RAMPLAYER_FARAWAY || AutoPilot.m_nCarMission == MISSION_RAMPLAYER_CLOSE || - AutoPilot.m_nCarMission == MISSION_BLOCKPLAYER_FARAWAY || AutoPilot.m_nCarMission == MISSION_BLOCKPLAYER_CLOSE)){ - if(FindPlayerSpeed().Magnitude() > 0.3f){ - strongGrip1 = true; - if(FindPlayerSpeed().Magnitude() > 0.4f && - m_vecMoveSpeed.Magnitude() < 0.3f) - strongGrip2 = true; - else if((GetPosition() - FindPlayerCoors()).Magnitude() > 50.0f) - strongGrip2 = true; - } + AutoPilot.m_nCarMission == MISSION_BLOCKPLAYER_FARAWAY || AutoPilot.m_nCarMission == MISSION_BLOCKPLAYER_CLOSE) && + FindPlayerSpeed().Magnitude() > 0.3f){ + + strongGrip1 = true; + if(FindPlayerSpeed().Magnitude() > 0.4f && + m_vecMoveSpeed.Magnitude() < 0.3f) + strongGrip2 = true; + else if((GetPosition() - FindPlayerCoors()).Magnitude() > 50.0f) + strongGrip2 = true; } if(bIsBus) From 8a157eee0a106ed30e785e8da203a6413d562452 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Mon, 11 Jan 2021 01:01:15 +0100 Subject: [PATCH 063/152] audio: only use #pragma comment(lib, xxx.lib) on MSVC --- src/audio/oal/stream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index ccb17577..74ed86f4 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -4,7 +4,7 @@ #include "stream.h" #include "sampman.h" -#ifdef _WIN32 +#if defined _MSC_VER && !defined RE3_NO_AUTOLINK #ifdef AUDIO_OAL_USE_SNDFILE #pragma comment( lib, "libsndfile-1.lib" ) #endif From 2ff9270279e11ad559f0b71bf7212788b325f619 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 6 Dec 2020 13:54:06 +0100 Subject: [PATCH 064/152] cmake: make librw non-vendorable + rename Findmpg123 + create targets for dependencies --- CMakeLists.txt | 21 ++++++++-- cmake/FindMPG123.cmake | 28 ------------- cmake/FindSndFile.cmake | 87 ++++++++++++++++++++------------------- cmake/Findmpg123.cmake | 40 ++++++++++++++++++ cmake/re3-config.cmake.in | 5 +++ src/CMakeLists.txt | 79 +++++++++++++---------------------- 6 files changed, 136 insertions(+), 124 deletions(-) delete mode 100644 cmake/FindMPG123.cmake create mode 100644 cmake/Findmpg123.cmake create mode 100644 cmake/re3-config.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 5daf1d15..20a38595 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,12 +23,17 @@ if(RE3_INSTALL) set(RE3_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/re3") endif() -add_subdirectory("vendor/librw") +option(RE3_VENDORED_LIBRW "Use vendored librw" ON) +if(RE3_VENDORED_LIBRW) + add_subdirectory(vendor/librw) +else() + find_package(librw REQUIRED) +endif() add_subdirectory(src) if(RE3_INSTALL) include(CMakePackageConfigHelpers) - configure_package_config_file(re3-config.cmake.in re3-config.cmake + configure_package_config_file(cmake/re3-config.cmake.in re3-config.cmake INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}" ) install( @@ -40,5 +45,15 @@ if(RE3_INSTALL) DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" ) - include(CMakeCPack.cmake) + set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}") + set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "GTA III reversed") + set(CPACK_PACKAGE_VENDOR "GTAModding") + #FIXME: missing license (https://github.com/GTAmodding/re3/issues/794) + #set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/LICENSE") + #set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") + set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") + set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}") + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}") + + include(CPack) endif() diff --git a/cmake/FindMPG123.cmake b/cmake/FindMPG123.cmake deleted file mode 100644 index a9b6dd8b..00000000 --- a/cmake/FindMPG123.cmake +++ /dev/null @@ -1,28 +0,0 @@ -# - Find mpg123 -# Find the native mpg123 includes and library -# -# MPG123_INCLUDE_DIR - where to find mpg123.h -# MPG123_LIBRARIES - List of libraries when using mpg123. -# MPG123_FOUND - True if mpg123 found. - -IF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES) - # Already in cache, be silent - SET(MPG123_FIND_QUIETLY TRUE) -ENDIF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES) - -FIND_PATH(MPG123_INCLUDE_DIR mpg123.h - PATHS "${MPG123_DIR}" - PATH_SUFFIXES include - ) - -FIND_LIBRARY(MPG123_LIBRARIES NAMES mpg123 mpg123-0 - PATHS "${MPG123_DIR}" - PATH_SUFFIXES lib - ) - -# MARK_AS_ADVANCED(MPG123_LIBRARIES MPG123_INCLUDE_DIR) - -# handle the QUIETLY and REQUIRED arguments and set MPG123_FOUND to TRUE if -# all listed variables are TRUE -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(MPG123 DEFAULT_MSG MPG123_LIBRARIES MPG123_INCLUDE_DIR) diff --git a/cmake/FindSndFile.cmake b/cmake/FindSndFile.cmake index 8ae47b70..05ef0510 100644 --- a/cmake/FindSndFile.cmake +++ b/cmake/FindSndFile.cmake @@ -4,9 +4,11 @@ # # Once done this will define # -# SNDFILE_FOUND - system has libsndfile +# SNDFILE_FOUND - system has libsndfile # SNDFILE_INCLUDE_DIRS - the libsndfile include directory -# SNDFILE_LIBRARIES - Link these to use libsndfile +# SNDFILE_LIBRARIES - Link these to use libsndfile +# SNDFILE_CFLAGS - Compile options to use libsndfile +# SndFile::SNdFile - Imported library of libsndfile # # Copyright (C) 2006 Wengo # @@ -15,53 +17,54 @@ # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # -if (SNDFILE_LIBRARIES AND SNDFILE_INCLUDE_DIRS) - # in cache already - set(SNDFILE_FOUND TRUE) -else (SNDFILE_LIBRARIES AND SNDFILE_INCLUDE_DIRS) +find_package(PkgConfig QUIET) +if(PKG_CONFIG_FOUND) + pkg_search_module(PKG_SNDFILE "sndfile") +endif() - find_path(SNDFILE_INCLUDE_DIR +find_path(SNDFILE_INCLUDE_DIR NAMES - sndfile.h + sndfile.h + HINTS + ${PKG_SNDFILE_INCLUDE_DIRS} PATHS - /usr/include - /usr/local/include - /opt/local/include - /sw/include - ) - - find_library(SNDFILE_LIBRARY + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ) + +find_library(SNDFILE_LIBRARY NAMES - sndfile + sndfile + HINTS + ${PKG_SNDFILE_LIBRARIES} PATHS - /usr/lib - /usr/local/lib - /opt/local/lib - /sw/lib - ) + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib +) - set(SNDFILE_INCLUDE_DIRS - ${SNDFILE_INCLUDE_DIR} - ) - set(SNDFILE_LIBRARIES - ${SNDFILE_LIBRARY} - ) +set(SNDFILE_CFLAGS "${PKG_SNDFILE_CFLAGS_OTHER}" CACHE STRING "CFLAGS of libsndfile") - if (SNDFILE_INCLUDE_DIRS AND SNDFILE_LIBRARIES) - set(SNDFILE_FOUND TRUE) - endif (SNDFILE_INCLUDE_DIRS AND SNDFILE_LIBRARIES) +set(SNDFILE_INCLUDE_DIRS ${SNDFILE_INCLUDE_DIR}) +set(SNDFILE_LIBRARIES ${SNDFILE_LIBRARY}) - if (SNDFILE_FOUND) - if (NOT SndFile_FIND_QUIETLY) - message(STATUS "Found libsndfile: ${SNDFILE_LIBRARIES}") - endif (NOT SndFile_FIND_QUIETLY) - else (SNDFILE_FOUND) - if (SndFile_FIND_REQUIRED) - message(FATAL_ERROR "Could not find libsndfile") - endif (SndFile_FIND_REQUIRED) - endif (SNDFILE_FOUND) +if (SNDFILE_INCLUDE_DIRS AND SNDFILE_LIBRARIES) +set(SNDFILE_FOUND TRUE) +endif (SNDFILE_INCLUDE_DIRS AND SNDFILE_LIBRARIES) - # show the SNDFILE_INCLUDE_DIRS and SNDFILE_LIBRARIES variables only in the advanced view - mark_as_advanced(SNDFILE_INCLUDE_DIRS SNDFILE_LIBRARIES) -endif (SNDFILE_LIBRARIES AND SNDFILE_INCLUDE_DIRS) +# handle the QUIETLY and REQUIRED arguments and set SNdFile_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SndFile DEFAULT_MSG SNDFILE_INCLUDE_DIRS SNDFILE_LIBRARIES) + +if(NOT TARGET SndFile::SndFile) + add_library(__SndFile INTERFACE) + target_compile_options(__SndFile INTERFACE ${SNDFILE_CFLAGS}) + target_include_directories(__SndFile INTERFACE ${SNDFILE_INCLUDE_DIRS}) + target_link_libraries(__SndFile INTERFACE ${SNDFILE_LIBRARIES}) + add_library(SndFile::SndFile ALIAS __SndFile) +endif() diff --git a/cmake/Findmpg123.cmake b/cmake/Findmpg123.cmake new file mode 100644 index 00000000..365d65ff --- /dev/null +++ b/cmake/Findmpg123.cmake @@ -0,0 +1,40 @@ +# - Find mpg123 +# Find the native mpg123 includes and library +# +# mpg123_INCLUDE_DIR - Where to find mpg123.h +# mpg123_LIBRARIES - List of libraries when using mpg123. +# mpg123_CFLAGS - Compile options to use mpg123 +# mpg123_FOUND - True if mpg123 found. +# MPG123::libmpg123 - Imported library of libmpg123 + +find_package(PkgConfig QUIET) +if(PKG_CONFIG_FOUND) + pkg_search_module(PKG_MPG123 mpg123) +endif() + +find_path(mpg123_INCLUDE_DIR mpg123.h + HINTS ${PKG_MPG123_INCLUDE_DIRS} + PATHS "${mpg123_DIR}" + PATH_SUFFIXES include +) + +find_library(mpg123_LIBRARIES NAMES mpg123 mpg123-0 + HINTS ${PKG_MPG123_LIBRARIES} + PATHS "${mpg123_DIR}" + PATH_SUFFIXES lib +) + +set(mpg123_CFLAGS "${PKG_MPG123_CFLAGS_OTHER}" CACHE STRING "CFLAGS of mpg123") + +# handle the QUIETLY and REQUIRED arguments and set mpg123_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(mpg123 DEFAULT_MSG mpg123_LIBRARIES mpg123_INCLUDE_DIR) + +if(NOT TARGET MPG123::libmpg123) + add_library(__libmpg123 INTERFACE) + target_compile_options(__libmpg123 INTERFACE ${mpg123_CFLAGS}) + target_include_directories(__libmpg123 INTERFACE ${mpg123_INCLUDE_DIR}) + target_link_libraries(__libmpg123 INTERFACE ${mpg123_LIBRARIES}) + add_library(MPG123::libmpg123 ALIAS __libmpg123) +endif() diff --git a/cmake/re3-config.cmake.in b/cmake/re3-config.cmake.in new file mode 100644 index 00000000..37e81938 --- /dev/null +++ b/cmake/re3-config.cmake.in @@ -0,0 +1,5 @@ +include("${CMAKE_CURRENT_LIST_DIR}/re3-targets.cmake") + +set(RE3_AUDIO "@RE3_AUDIO@") +set(RE3_AUDIOS "@RE3_AUDIOS@") +set(RE3_PLATFORM @LIBRW_PLATFORM@) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ef322a9a..0b124958 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,66 +2,49 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) if(${RE3_AUDIO} STREQUAL "OAL") - find_package(OpenAL REQUIRED) - find_package(MPG123 REQUIRED) - find_package(SndFile REQUIRED) + find_package(OpenAL REQUIRED) + find_package(mpg123 REQUIRED) + find_package(SndFile REQUIRED) endif() -file(GLOB_RECURSE Sources "*.cpp" "*.h") +file(GLOB_RECURSE RE3_SOURCES "*.cpp" "*.h") -MACRO(HEADER_DIRECTORIES return_list) - FILE(GLOB_RECURSE new_list *.cpp) - SET(dir_list "animation" - "audio" - "collision" - "control" - "core" - "entities" - "extras" - "fakerw" - "math" - "modelinfo" - "objects" - "peds" - "render" - "rw" - "save" - "skel" - "text" - "vehicles" - "weapons") - FOREACH(file_path ${new_list}) - GET_FILENAME_COMPONENT(dir_path ${file_path} PATH) - SET(dir_list ${dir_list} ${dir_path}) - ENDFOREACH() - LIST(REMOVE_DUPLICATES dir_list) - SET(${return_list} ${dir_list}) -ENDMACRO() +function(header_directories RETURN_LIST) + file(GLOB_RECURSE ALL_SRCS *.h *.cpp *.c) + set(RELDIRS) + foreach(SRC ${ALL_SRCS}) + file(RELATIVE_PATH RELSRC "${CMAKE_CURRENT_SOURCE_DIR}" "${SRC}") + get_filename_component(RELDIR "${RELSRC}" DIRECTORY) + list(APPEND RELDIRS ${RELDIR}) + endforeach() + list(REMOVE_DUPLICATES RELDIRS) + set(${RETURN_LIST} ${RELDIRS} PARENT_SCOPE) +endfunction() -HEADER_DIRECTORIES(header_list) -include_directories(${header_list}) +header_directories(RE3_INCLUDES) +include_directories(${RE3_INCLUDES}) +add_executable(re3 ${RE3_SOURCES}) +target_link_libraries(re3 PRIVATE + librw::librw + Threads::Threads +) -add_executable(re3 ${Sources}) -target_link_libraries(re3 librw) -target_link_libraries(re3 Threads::Threads) - -if(${RE3_AUDIO} STREQUAL "OAL") - target_link_libraries(re3 ${OPENAL_LIBRARY}) - target_link_libraries(re3 ${MPG123_LIBRARIES}) - target_link_libraries(re3 ${SNDFILE_LIBRARIES}) +if(RE3_AUDIO STREQUAL "OAL") + target_link_libraries(re3 PRIVATE ${OPENAL_LIBRARY}) + target_link_libraries(re3 PRIVATE MPG123::libmpg123) + target_link_libraries(re3 PRIVATE SndFile::SndFile) endif() target_include_directories(re3 INTERFACE $ + $ ) target_compile_definitions(re3 PRIVATE "$,DEBUG,NDEBUG>" - PUBLIC - "RW_${RE3_PLATFORM}" ) target_compile_definitions(re3 PRIVATE LIBRW=1 AUDIO_OAL=1) @@ -71,7 +54,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang PRIVATE "-Wall" ) - if (NOT RE3_PLATFORM_PS2) + if (NOT LIBRW_PLATFORM_PS2) target_compile_options(re3 PRIVATE "-Wextra" @@ -94,15 +77,9 @@ set_target_properties(re3 CXX_STANDARD 11 CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON - PREFIX "" ) if(RE3_INSTALL) - target_include_directories(re3 - INTERFACE - $ - ) - install( TARGETS re3 EXPORT re3-targets From 2f48d0c828e9a279e578e10ed3e3294b58a00331 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 6 Dec 2020 15:42:15 +0100 Subject: [PATCH 065/152] cmake: null audio is not possible + add cmake opus support --- CMakeLists.txt | 6 +++-- src/CMakeLists.txt | 55 ++++++++++++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20a38595..76f4da89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,13 +4,15 @@ project(re3 C CXX) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") if(WIN32) - set(RE3_AUDIOS "NULL" "OAL" "MSS") + set(RE3_AUDIOS "OAL" "MSS") else() - set(RE3_AUDIOS "NULL" "OAL") + set(RE3_AUDIOS "OAL") endif() set(RE3_AUDIO "OAL" CACHE STRING "Audio") +option(RE3_WITH_OPUS "Build re3 with opus support" ON) + set_property(CACHE RE3_AUDIO PROPERTY STRINGS ${RE3_AUDIOS}) message(STATUS "RE3_AUDIO = ${RE3_AUDIO} (choices=${RE3_AUDIOS})") set("RE3_AUDIO_${RE3_AUDIO}" ON) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0b124958..3e666121 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,12 +1,6 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) -if(${RE3_AUDIO} STREQUAL "OAL") - find_package(OpenAL REQUIRED) - find_package(mpg123 REQUIRED) - find_package(SndFile REQUIRED) -endif() - file(GLOB_RECURSE RE3_SOURCES "*.cpp" "*.h") function(header_directories RETURN_LIST) @@ -22,32 +16,45 @@ function(header_directories RETURN_LIST) endfunction() header_directories(RE3_INCLUDES) -include_directories(${RE3_INCLUDES}) -add_executable(re3 ${RE3_SOURCES}) +add_executable(re3 WIN32 ${RE3_SOURCES}) target_link_libraries(re3 PRIVATE librw::librw Threads::Threads ) -if(RE3_AUDIO STREQUAL "OAL") - target_link_libraries(re3 PRIVATE ${OPENAL_LIBRARY}) - target_link_libraries(re3 PRIVATE MPG123::libmpg123) - target_link_libraries(re3 PRIVATE SndFile::SndFile) -endif() - target_include_directories(re3 - INTERFACE + PRIVATE $ - $ - ) + $ +) target_compile_definitions(re3 PRIVATE - "$,DEBUG,NDEBUG>" - ) + $,DEBUG,NDEBUG> + LIBRW +) -target_compile_definitions(re3 PRIVATE LIBRW=1 AUDIO_OAL=1) +if(RE3_AUDIO STREQUAL "OAL") + find_package(OpenAL REQUIRED) + target_include_directories(re3 PRIVATE ${OPENAL_INCLUDE_DIR}) + target_link_libraries(re3 PRIVATE ${OPENAL_LIBRARY}) + target_compile_definitions(re3 PRIVATE AUDIO_OAL) +elseif(RE3_AUDIO STREQUAL "MSS") + target_compile_definitions(re3 PRIVATE AUDIO_MSS) +endif() + +if(RE3_WITH_OPUS) + find_package(mpg123 REQUIRED) + find_package(SndFile REQUIRED) + target_link_libraries(re3 PRIVATE + MPG123::libmpg123 + SndFile::SndFile + ) + target_compile_definitions(re3 PRIVATE AUDIO_OPUS) +endif() + +target_compile_definitions(re3 PRIVATE ) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") target_compile_options(re3 @@ -57,15 +64,15 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang if (NOT LIBRW_PLATFORM_PS2) target_compile_options(re3 PRIVATE - "-Wextra" - "-Wdouble-promotion" - "-Wpedantic" + -Wextra + -Wdouble-promotion + -Wpedantic ) endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") target_compile_options(re3 PUBLIC - /wd4996 /wd4244 + /Zc:sizedDealloc- ) endif() From 9707eeb8cbe387724d9f00e651c9a880f513ff6e Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 6 Dec 2020 19:10:37 +0100 Subject: [PATCH 066/152] audio: only use #pragma comment(lib, "xxx.lib") on MSVC --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3e666121..502255df 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,6 +33,7 @@ target_compile_definitions(re3 PRIVATE $,DEBUG,NDEBUG> LIBRW + RE3_NO_AUTOLINK ) if(RE3_AUDIO STREQUAL "OAL") From 8d0b4ede684df25e142b94fede4cbb15e4f6fb57 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 6 Dec 2020 19:12:35 +0100 Subject: [PATCH 067/152] cmake: use openal/opusfile/mpg123/libsndfile correctly --- cmake/FindSndFile.cmake | 8 ++--- cmake/Findopusfile.cmake | 67 ++++++++++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 8 ++++- 3 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 cmake/Findopusfile.cmake diff --git a/cmake/FindSndFile.cmake b/cmake/FindSndFile.cmake index 05ef0510..f0e2883e 100644 --- a/cmake/FindSndFile.cmake +++ b/cmake/FindSndFile.cmake @@ -8,7 +8,7 @@ # SNDFILE_INCLUDE_DIRS - the libsndfile include directory # SNDFILE_LIBRARIES - Link these to use libsndfile # SNDFILE_CFLAGS - Compile options to use libsndfile -# SndFile::SNdFile - Imported library of libsndfile +# SndFile::SndFile - Imported library of libsndfile # # Copyright (C) 2006 Wengo # @@ -48,15 +48,15 @@ find_library(SNDFILE_LIBRARY set(SNDFILE_CFLAGS "${PKG_SNDFILE_CFLAGS_OTHER}" CACHE STRING "CFLAGS of libsndfile") -set(SNDFILE_INCLUDE_DIRS ${SNDFILE_INCLUDE_DIR}) -set(SNDFILE_LIBRARIES ${SNDFILE_LIBRARY}) +set(SNDFILE_INCLUDE_DIRS "${SNDFILE_INCLUDE_DIR}") +set(SNDFILE_LIBRARIES "${SNDFILE_LIBRARY}") if (SNDFILE_INCLUDE_DIRS AND SNDFILE_LIBRARIES) set(SNDFILE_FOUND TRUE) endif (SNDFILE_INCLUDE_DIRS AND SNDFILE_LIBRARIES) -# handle the QUIETLY and REQUIRED arguments and set SNdFile_FOUND to TRUE if +# handle the QUIETLY and REQUIRED arguments and set SndFile_FOUND to TRUE if # all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(SndFile DEFAULT_MSG SNDFILE_INCLUDE_DIRS SNDFILE_LIBRARIES) diff --git a/cmake/Findopusfile.cmake b/cmake/Findopusfile.cmake new file mode 100644 index 00000000..43d285eb --- /dev/null +++ b/cmake/Findopusfile.cmake @@ -0,0 +1,67 @@ +# - Try to find opusfile +# +# Once done this will define +# +# OPUSFILE_FOUND - system has opusfile +# OPUSFILE_INCLUDE_DIRS - the opusfile include directories +# OPUSFILE_LIBRARIES - Link these to use opusfile +# OPUSFILE_CFLAGS - Compile options to use opusfile +# opusfile::opusfile - Imported library of opusfile +# + +# FIXME: opusfile does not ship an official opusfile cmake script, +# rename this file/variables/target when/if it has. + +find_package(PkgConfig QUIET) +if(PKG_CONFIG_FOUND) + pkg_search_module(PKG_OPUSFILE "opusfile") +endif() + +find_path(OPUSFILE_INCLUDE_DIR + NAMES + opusfile.h + PATH_SUFFIXES + opusfile + HINTS + ${PKG_OPUSFILE_INCLUDE_DIRS} + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ) + +find_library(OPUSFILE_LIBRARY + NAMES + opusfile + HINTS + ${PKG_OPUSFILE_LIBRARIES} + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib +) + +set(OPUSFILE_CFLAGS "${PKG_OPUSFILE_CFLAGS_OTHER}" CACHE STRING "CFLAGS of opusfile") + +set(OPUSFILE_INCLUDE_DIRS "${OPUSFILE_INCLUDE_DIR}") +set(OPUSFILE_LIBRARIES "${OPUSFILE_LIBRARY}") + +if (OPUSFILE_INCLUDE_DIRS AND OPUSFILE_LIBRARIES) +set(OPUSFILE_FOUND TRUE) +endif (OPUSFILE_INCLUDE_DIRS AND OPUSFILE_LIBRARIES) + + +# handle the QUIETLY and REQUIRED arguments and set Opusfile_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(opusfile DEFAULT_MSG OPUSFILE_INCLUDE_DIRS OPUSFILE_LIBRARIES) + +if(NOT TARGET opusfile::opusfile) + add_library(__opusfile INTERFACE) + target_compile_options(__opusfile INTERFACE ${OPUSFILE_CFLAGS}) + target_include_directories(__opusfile INTERFACE ${OPUSFILE_INCLUDE_DIRS}) + target_link_libraries(__opusfile INTERFACE ${OPUSFILE_LIBRARIES}) + add_library(opusfile::opusfile ALIAS __opusfile) +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 502255df..e943b908 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,19 +40,25 @@ if(RE3_AUDIO STREQUAL "OAL") find_package(OpenAL REQUIRED) target_include_directories(re3 PRIVATE ${OPENAL_INCLUDE_DIR}) target_link_libraries(re3 PRIVATE ${OPENAL_LIBRARY}) + target_compile_definitions(re3 PRIVATE ${OPENAL_DEFINITIONS}) target_compile_definitions(re3 PRIVATE AUDIO_OAL) elseif(RE3_AUDIO STREQUAL "MSS") target_compile_definitions(re3 PRIVATE AUDIO_MSS) endif() if(RE3_WITH_OPUS) + find_package(opusfile REQUIRED) + target_link_libraries(re3 PRIVATE + opusfile::opusfile + ) + target_compile_definitions(re3 PRIVATE AUDIO_OPUS) +else() find_package(mpg123 REQUIRED) find_package(SndFile REQUIRED) target_link_libraries(re3 PRIVATE MPG123::libmpg123 SndFile::SndFile ) - target_compile_definitions(re3 PRIVATE AUDIO_OPUS) endif() target_compile_definitions(re3 PRIVATE ) From e9adfd86636af27b98a314f3f42a0d3312063732 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 3 Jan 2021 16:30:45 +0100 Subject: [PATCH 068/152] cmake: search for miles import library --- cmake/FindMilesSDK.cmake | 34 ++++++++++++++++++++++++++++++++++ cmake/FindSndFile.cmake | 9 +++------ cmake/Findmpg123.cmake | 2 -- cmake/Findopusfile.cmake | 3 --- src/CMakeLists.txt | 9 +++++++++ 5 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 cmake/FindMilesSDK.cmake diff --git a/cmake/FindMilesSDK.cmake b/cmake/FindMilesSDK.cmake new file mode 100644 index 00000000..57da3a6e --- /dev/null +++ b/cmake/FindMilesSDK.cmake @@ -0,0 +1,34 @@ +# - Find Miles SDK +# Find the Miles SDK header + import library +# +# MilesSDK_INCLUDE_DIR - Where to find mss.h +# MilesSDK_LIBRARIES - List of libraries when using MilesSDK. +# MilesSDK_FOUND - True if Miles SDK found. +# MilesSDK::MilesSDK - Imported library of Miles SDK + +find_path(MilesSDK_INCLUDE_DIR mss.h + PATHS "${MilesSDK_DIR}" + PATH_SUFFIXES include +) + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_miles_sdk_libname mss64) +else() + set(_miles_sdk_libname mss32) +endif() + +find_library(MilesSDK_LIBRARIES NAMES ${_miles_sdk_libname} + PATHS "${MilesSDK_DIR}" + PATH_SUFFIXES lib +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MilesSDK DEFAULT_MSG MilesSDK_LIBRARIES MilesSDK_INCLUDE_DIR) + +if(NOT TARGET MilesSDK::MilesSDK) + add_library(MilesSDK::MilesSDK UNKNOWN IMPORTED) + set_target_properties(MilesSDK::MilesSDK PROPERTIES + IMPORTED_LOCATION "${MilesSDK_LIBRARIES} + INTERFACE_INCLUDE_DIRECTORIES "${MilesSDK_INCLUDE_DIR}" + ) +endif() diff --git a/cmake/FindSndFile.cmake b/cmake/FindSndFile.cmake index f0e2883e..5381af48 100644 --- a/cmake/FindSndFile.cmake +++ b/cmake/FindSndFile.cmake @@ -51,13 +51,10 @@ set(SNDFILE_CFLAGS "${PKG_SNDFILE_CFLAGS_OTHER}" CACHE STRING "CFLAGS of libsndf set(SNDFILE_INCLUDE_DIRS "${SNDFILE_INCLUDE_DIR}") set(SNDFILE_LIBRARIES "${SNDFILE_LIBRARY}") -if (SNDFILE_INCLUDE_DIRS AND SNDFILE_LIBRARIES) -set(SNDFILE_FOUND TRUE) -endif (SNDFILE_INCLUDE_DIRS AND SNDFILE_LIBRARIES) +if(SNDFILE_INCLUDE_DIRS AND SNDFILE_LIBRARIES) + set(SNDFILE_FOUND TRUE) +endif() - -# handle the QUIETLY and REQUIRED arguments and set SndFile_FOUND to TRUE if -# all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(SndFile DEFAULT_MSG SNDFILE_INCLUDE_DIRS SNDFILE_LIBRARIES) diff --git a/cmake/Findmpg123.cmake b/cmake/Findmpg123.cmake index 365d65ff..c6fe56bb 100644 --- a/cmake/Findmpg123.cmake +++ b/cmake/Findmpg123.cmake @@ -26,8 +26,6 @@ find_library(mpg123_LIBRARIES NAMES mpg123 mpg123-0 set(mpg123_CFLAGS "${PKG_MPG123_CFLAGS_OTHER}" CACHE STRING "CFLAGS of mpg123") -# handle the QUIETLY and REQUIRED arguments and set mpg123_FOUND to TRUE if -# all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(mpg123 DEFAULT_MSG mpg123_LIBRARIES mpg123_INCLUDE_DIR) diff --git a/cmake/Findopusfile.cmake b/cmake/Findopusfile.cmake index 43d285eb..faae7645 100644 --- a/cmake/Findopusfile.cmake +++ b/cmake/Findopusfile.cmake @@ -52,9 +52,6 @@ if (OPUSFILE_INCLUDE_DIRS AND OPUSFILE_LIBRARIES) set(OPUSFILE_FOUND TRUE) endif (OPUSFILE_INCLUDE_DIRS AND OPUSFILE_LIBRARIES) - -# handle the QUIETLY and REQUIRED arguments and set Opusfile_FOUND to TRUE if -# all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(opusfile DEFAULT_MSG OPUSFILE_INCLUDE_DIRS OPUSFILE_LIBRARIES) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e943b908..a7c2a3d7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,6 +36,13 @@ target_compile_definitions(re3 RE3_NO_AUTOLINK ) +if(LIBRW_PLATFORM_D3D9) + target_compile_definitions(re3 + PUBLIC + USE_D3D9 + ) +endif() + if(RE3_AUDIO STREQUAL "OAL") find_package(OpenAL REQUIRED) target_include_directories(re3 PRIVATE ${OPENAL_INCLUDE_DIR}) @@ -43,7 +50,9 @@ if(RE3_AUDIO STREQUAL "OAL") target_compile_definitions(re3 PRIVATE ${OPENAL_DEFINITIONS}) target_compile_definitions(re3 PRIVATE AUDIO_OAL) elseif(RE3_AUDIO STREQUAL "MSS") + find_package(MilesSDK REQUIRED) target_compile_definitions(re3 PRIVATE AUDIO_MSS) + target_link_libraries(re3 PRIVATE MilesSDK::MilesSDK) endif() if(RE3_WITH_OPUS) From 54b88cdfbeb38c55c18cf6b4e789ad09ff12fa9e Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 3 Jan 2021 16:31:13 +0100 Subject: [PATCH 069/152] Add conanfile --- conanfile.py | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 conanfile.py diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 00000000..8d738311 --- /dev/null +++ b/conanfile.py @@ -0,0 +1,127 @@ +from conans import ConanFile, CMake, tools +from conans.errors import ConanException, ConanInvalidConfiguration +import os +import shutil +import textwrap + + +class Re3Conan(ConanFile): + name = "re3" + version = "master" + license = "???" # FIXME: https://github.com/GTAmodding/re3/issues/794 + settings = "os", "arch", "compiler", "build_type" + generators = "cmake", "cmake_find_package" + options = { + "audio": ["openal", "miles"], + "with_opus": [True, False], + } + default_options = { + "audio": "openal", + "with_opus": True, + "libsndfile:with_external_libs": False, + "mpg123:flexible_resampling": False, + "mpg123:network": False, + "mpg123:icy": False, + "mpg123:id3v2": False, + "mpg123:ieeefloat": False, + "mpg123:layer1": False, + "mpg123:layer2": False, + "mpg123:layer3": False, + "mpg123:moreinfo": False, + "mpg123:seektable": False, + "sdl2:vulkan": False, + "sdl2:opengl": True, + "sdl2:sdl2main": True, + } + no_copy_source = True + + @property + def _os_is_playstation2(self): + try: + return self.settings.os == "Playstation2" + except ConanException: + return False + + def requirements(self): + self.requires("librw/{}".format(self.version)) + if self.options.audio == "openal": + self.requires("openal/1.21.0") + if self.options.with_opus: + self.requires("opusfile/0.12") + else: + self.requires("mpg123/1.26.4") + self.requires("libsndfile/1.0.30") + if self.options.audio == "miles": + self.requires("miles-sdk/{}".format(self.version)) + + def export_sources(self): + for d in ("cmake", "src"): + shutil.copytree(src=d, dst=os.path.join(self.export_sources_folder, d)) + self.copy("CMakeLists.txt") + + def validate(self): + if self.options["librw"].platform == "gl3" and self.options["librw"].gl3_gfxlib != "glfw": + raise ConanInvalidConfiguration("Only `glfw` is supported as gl3_gfxlib.") + if not self.options.with_opus: + if not self.options["libsndfile"].with_external_libs: + raise ConanInvalidConfiguration("re3 with opus support requires a libsndfile built with external libs (=ogg/flac/opus/vorbis)") + + @property + def _re3_audio(self): + return { + "miles": "MSS", + "openal": "OAL", + }[str(self.options.audio)] + + def build(self): + if self.source_folder == self.build_folder: + raise Exception("cannot build with source_folder == build_folder") + os.unlink(os.path.join(self.install_folder, "Findlibrw.cmake")) + tools.save("FindOpenAL.cmake", + textwrap.dedent( + """ + set(OPENAL_FOUND ON) + set(OPENAL_INCLUDE_DIR ${OpenAL_INCLUDE_DIRS}) + set(OPENAL_LIBRARY ${OpenAL_LIBRARIES}) + set(OPENAL_DEFINITIONS ${OpenAL_DEFINITIONS}) + """), append=True) + if self.options["librw"].platform == "gl3" and self.options["librw"].gl3_gfxlib == "glfw": + tools.save("Findglfw3.cmake", + textwrap.dedent( + """ + if(NOT TARGET glfw) + message(STATUS "Creating glfw TARGET") + add_library(glfw INTERFACE IMPORTED) + set_target_properties(glfw PROPERTIES + INTERFACE_LINK_LIBRARIES CONAN_PKG::glfw) + endif() + """), append=True) + tools.save("CMakeLists.txt", + textwrap.dedent( + """ + cmake_minimum_required(VERSION 3.0) + project(cmake_wrapper) + + include("{}/conanbuildinfo.cmake") + conan_basic_setup(TARGETS) + + add_subdirectory("{}" re3) + """).format(self.install_folder.replace("\\", "/"), + self.source_folder.replace("\\", "/"))) + cmake = CMake(self) + cmake.definitions["RE3_AUDIO"] = self._re3_audio + cmake.definitions["RE3_WITH_OPUS"] = self.options.with_opus + cmake.definitions["RE3_INSTALL"] = True + cmake.definitions["RE3_VENDORED_LIBRW"] = False + env = {} + if self._os_is_playstation2: + cmake.definitions["CMAKE_TOOLCHAIN_FILE"] = self.deps_user_info["ps2dev-cmaketoolchain"].cmake_toolchain_file + env["PS2SDK"] = self.deps_cpp_info["ps2dev-ps2sdk"].rootpath + + with tools.environment_append(env): + cmake.configure(source_folder=self.build_folder) + cmake.build() + + def package(self): + cmake = CMake(self) + cmake.install() From 64b585efa11dd123750840e7b60c838c2fa21e2c Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 3 Jan 2021 16:32:00 +0100 Subject: [PATCH 070/152] cmake: let cpack create nice binary package --- CMakeLists.txt | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 76f4da89..08d407e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,15 +47,49 @@ if(RE3_INSTALL) DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" ) - set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}") + if(LIBRW_PLATFORM_NULL) + set(platform "-null") + elseif(LIBRW_PLATFORM_PS2) + set(platform "-ps2") + elseif(LIBRW_PLATFORM_GL3) + if(LIBRW_GL3_GFXLIB STREQUAL "GLFW") + set(platform "-gl3-glfw") + else() + set(platform "-gl3-sdl2") + endif() + elseif(LIBRW_PLATFORM_D3D9) + set(platform "-d3d9") + endif() + if(RE3_AUDIO_OAL) + set(audio "-oal") + elseif(RE3_AUDIO_MSS) + set(audio "-mss") + endif() + if(RE3_WITH_OPUS) + set(audio "${audio}-opus") + endif() + if(NOT LIBRW_PLATFORM_PS2) + if(WIN32) + set(os "-win") + elseif(APPLE) + set(os "-apple") + elseif(UNIX) + set(os "-linux") + else() + set(compiler "-UNK") + message(WARNING "Unknown os. Created cpack package will be wrong. (override using cpack -P)") + endif() + endif() + + set(CPACK_PACKAGE_NAME "${PROJECT_NAME}${platform}${audio}${os}${compiler}") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "GTA III reversed") set(CPACK_PACKAGE_VENDOR "GTAModding") - #FIXME: missing license (https://github.com/GTAmodding/re3/issues/794) - #set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/LICENSE") - #set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") + # FIXME: missing license (https://github.com/GTAmodding/re3/issues/794) + # set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/LICENSE") + # set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}") set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}") - + set(CPACK_GENERATOR "TXZ") include(CPack) endif() From d9f6a05b7eeba6316426b4efd6c1777d6fcc5741 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 3 Jan 2021 16:32:27 +0100 Subject: [PATCH 071/152] ci: build using github actions --- .github/workflows/build-cmake-conan.yml | 116 ++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 .github/workflows/build-cmake-conan.yml diff --git a/.github/workflows/build-cmake-conan.yml b/.github/workflows/build-cmake-conan.yml new file mode 100644 index 00000000..4bd2b08c --- /dev/null +++ b/.github/workflows/build-cmake-conan.yml @@ -0,0 +1,116 @@ +name: Build re3 using conan+cmake +on: + pull_request: + push: + release: + types: published +jobs: + build-cmake: + strategy: + matrix: + include: + - os: 'windows-latest' + platform: 'gl3' + gl3_gfxlib: 'glfw' + audio: 'openal' +# - os: 'windows-latest' +# platform: 'gl3' +# gl3_gfxlib: 'sdl2' +# audio: 'openal' + - os: 'windows-latest' + platform: 'd3d9' + audio: 'openal' +# - os: 'windows-latest' +# platform: 'd3d9' +# audio: 'miles' + - os: 'ubuntu-latest' + platform: 'gl3' + gl3_gfxlib: 'glfw' + audio: 'openal' +# - os: 'ubuntu-latest' +# platform: 'gl3' +# gl3_gfxlib: 'sdl2' +# audio: 'openal' + - os: 'macos-latest' + platform: 'gl3' + gl3_gfxlib: 'glfw' + audio: 'openal' +# - os: 'macos-latest' +# platform: 'gl3' +# gl3_gfxlib: 'sdl2' +# audio: 'openal' + runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.platform == 'ps2' || matrix.gl3_gfxlib == 'sdl2' || matrix.audio == 'miles' }} + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: "Checkout Miles SDK Import Library project" + uses: actions/checkout@v2 + if: ${{ matrix.audio == 'miles' }} + with: + repository: 'withmorten/re3mss' + path: 're3mss' + - uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: "Use XCode 11 as default (conan-center-index does not provide XCode 12 binaries at the moment)" + if: startsWith(matrix.os, 'macos') + run: | + sudo xcode-select --switch /Applications/Xcode_11.7.app + - name: "Setup conan" + run: | + python -m pip install conan + conan config init + conan config set log.print_run_commands=True + conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan + conan remote add madebr_ps2dev https://api.bintray.com/conan/madebr/ps2dev + - name: "Add os=playstation2 + gcc.version=3.2 to .conan/settings.yml" + shell: python + run: | + import os, yaml + settings_path = os.path.expanduser("~/.conan/settings.yml") + yml = yaml.safe_load(open(settings_path)) + yml["os"]["playstation2"] = None + yml["compiler"]["gcc"]["version"].append("3.2") + yml["compiler"]["gcc"]["version"].sort() + yaml.safe_dump(yml, open(settings_path, "w")) + - name: "Create host profile" + shell: bash + run: | + if test "${{ matrix.platform }}" = "ps2"; then + cp vendor/librw/conan/playstation2 host_profile + else + cp ~/.conan/profiles/default host_profile + fi + - name: "Export Playstation 2 CMake toolchain conan recipe" + run: | + conan export vendor/librw/cmake/ps2toolchain ps2dev-cmaketoolchain/master@ + - name: "Export librw conan recipe" + run: | + conan export vendor/librw librw/master@ + - name: "Export Miles SDK conan recipe" + if: ${{ matrix.audio == 'miles' }} + run: | + conan export re3mss miles-sdk/master@ + - name: "Download/build dependencies (conan install)" + run: | + conan install ${{ github.workspace }} re3/master@ -if build -o re3:audio=${{ matrix.audio }} -o librw:platform=${{ matrix.platform }} -o librw:gl3_gfxlib=${{ matrix.gl3_gfxlib || 'glfw' }} --build missing -pr:h ./host_profile -pr:b default + env: + CONAN_SYSREQUIRES_MODE: enabled + - name: "Build re3 (conan build)" + run: | + conan build ${{ github.workspace }} -if build -bf build -pf package + - name: "Package re3 (conan package)" + run: | + conan package ${{ github.workspace }} -if build -bf build -pf package + - name: "Create binary package (cpack)" + working-directory: ./build + run: | + cpack + - name: "Archive binary package (github artifacts)" + uses: actions/upload-artifact@v2 + with: + name: "${{ matrix.os }}-${{ matrix.platform }}" + path: build/*.tar.xz + if-no-files-found: error From b375e20c75194fc5559b2c54899f4841e7e2cb48 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Mon, 11 Jan 2021 01:29:43 +0100 Subject: [PATCH 072/152] cmake: opus is now optional + libsndfile only when using openal --- CMakeLists.txt | 1 + conanfile.py | 43 ++++++++++++++++++++++++------------------- src/CMakeLists.txt | 10 +++++++--- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08d407e8..8343f20c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ endif() set(RE3_AUDIO "OAL" CACHE STRING "Audio") option(RE3_WITH_OPUS "Build re3 with opus support" ON) +option(RE3_WITH_LIBSNDFILE "Build re3 with libsndfile (instead of internal decoder)" OFF) set_property(CACHE RE3_AUDIO PROPERTY STRINGS ${RE3_AUDIOS}) message(STATUS "RE3_AUDIO = ${RE3_AUDIO} (choices=${RE3_AUDIOS})") diff --git a/conanfile.py b/conanfile.py index 8d738311..c3a2b3ba 100644 --- a/conanfile.py +++ b/conanfile.py @@ -13,25 +13,26 @@ class Re3Conan(ConanFile): generators = "cmake", "cmake_find_package" options = { "audio": ["openal", "miles"], + "with_libsndfile": [True, False], "with_opus": [True, False], } default_options = { "audio": "openal", + "with_libsndfile": False, "with_opus": True, - "libsndfile:with_external_libs": False, - "mpg123:flexible_resampling": False, - "mpg123:network": False, - "mpg123:icy": False, - "mpg123:id3v2": False, - "mpg123:ieeefloat": False, - "mpg123:layer1": False, - "mpg123:layer2": False, - "mpg123:layer3": False, - "mpg123:moreinfo": False, - "mpg123:seektable": False, - "sdl2:vulkan": False, - "sdl2:opengl": True, - "sdl2:sdl2main": True, + # "libsndfile:with_external_libs": False, + # "mpg123:flexible_resampling": False, + # "mpg123:network": False, + # "mpg123:icy": False, + # "mpg123:id3v2": False, + # "mpg123:ieeefloat": False, + # "mpg123:layer1": False, + # "mpg123:layer2": False, + # "mpg123:layer3": False, + # "mpg123:moreinfo": False, + # "sdl2:vulkan": False, + # "sdl2:opengl": True, + # "sdl2:sdl2main": True, } no_copy_source = True @@ -42,17 +43,21 @@ class Re3Conan(ConanFile): except ConanException: return False + def configure(self): + if self.options.audio != "openal": + self.options.with_libsndfile = False + def requirements(self): self.requires("librw/{}".format(self.version)) + self.requires("mpg123/1.26.4") if self.options.audio == "openal": self.requires("openal/1.21.0") + elif self.options.audio == "miles": + self.requires("miles-sdk/{}".format(self.version)) + if self.options.with_libsndfile: + self.requires("libsndfile/1.0.30") if self.options.with_opus: self.requires("opusfile/0.12") - else: - self.requires("mpg123/1.26.4") - self.requires("libsndfile/1.0.30") - if self.options.audio == "miles": - self.requires("miles-sdk/{}".format(self.version)) def export_sources(self): for d in ("cmake", "src"): diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a7c2a3d7..0460a353 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -55,19 +55,23 @@ elseif(RE3_AUDIO STREQUAL "MSS") target_link_libraries(re3 PRIVATE MilesSDK::MilesSDK) endif() +find_package(mpg123 REQUIRED) +target_link_libraries(re3 PRIVATE + MPG123::libmpg123 +) if(RE3_WITH_OPUS) find_package(opusfile REQUIRED) target_link_libraries(re3 PRIVATE opusfile::opusfile ) target_compile_definitions(re3 PRIVATE AUDIO_OPUS) -else() - find_package(mpg123 REQUIRED) +endif() +if(RE3_WITH_LIBSNDFILE) find_package(SndFile REQUIRED) target_link_libraries(re3 PRIVATE - MPG123::libmpg123 SndFile::SndFile ) + target_compile_definitions(re3 PRIVATE AUDIO_OAL_USE_SNDFILE) endif() target_compile_definitions(re3 PRIVATE ) From a78e4a33664085a0ee68bfb23b7749f559563ac4 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 3 Jan 2021 19:08:17 +0100 Subject: [PATCH 073/152] conan: allow repeated executions of `conan build` --- conanfile.py | 61 +++++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/conanfile.py b/conanfile.py index c3a2b3ba..958ef689 100644 --- a/conanfile.py +++ b/conanfile.py @@ -81,38 +81,41 @@ class Re3Conan(ConanFile): def build(self): if self.source_folder == self.build_folder: raise Exception("cannot build with source_folder == build_folder") - os.unlink(os.path.join(self.install_folder, "Findlibrw.cmake")) - tools.save("FindOpenAL.cmake", - textwrap.dedent( - """ - set(OPENAL_FOUND ON) - set(OPENAL_INCLUDE_DIR ${OpenAL_INCLUDE_DIRS}) - set(OPENAL_LIBRARY ${OpenAL_LIBRARIES}) - set(OPENAL_DEFINITIONS ${OpenAL_DEFINITIONS}) - """), append=True) - if self.options["librw"].platform == "gl3" and self.options["librw"].gl3_gfxlib == "glfw": - tools.save("Findglfw3.cmake", + try: + os.unlink(os.path.join(self.install_folder, "Findlibrw.cmake")) + tools.save("FindOpenAL.cmake", textwrap.dedent( """ - if(NOT TARGET glfw) - message(STATUS "Creating glfw TARGET") - add_library(glfw INTERFACE IMPORTED) - set_target_properties(glfw PROPERTIES - INTERFACE_LINK_LIBRARIES CONAN_PKG::glfw) - endif() + set(OPENAL_FOUND ON) + set(OPENAL_INCLUDE_DIR ${OpenAL_INCLUDE_DIRS}) + set(OPENAL_LIBRARY ${OpenAL_LIBRARIES}) + set(OPENAL_DEFINITIONS ${OpenAL_DEFINITIONS}) """), append=True) - tools.save("CMakeLists.txt", - textwrap.dedent( - """ - cmake_minimum_required(VERSION 3.0) - project(cmake_wrapper) - - include("{}/conanbuildinfo.cmake") - conan_basic_setup(TARGETS) - - add_subdirectory("{}" re3) - """).format(self.install_folder.replace("\\", "/"), - self.source_folder.replace("\\", "/"))) + if self.options["librw"].platform == "gl3" and self.options["librw"].gl3_gfxlib == "glfw": + tools.save("Findglfw3.cmake", + textwrap.dedent( + """ + if(NOT TARGET glfw) + message(STATUS "Creating glfw TARGET") + add_library(glfw INTERFACE IMPORTED) + set_target_properties(glfw PROPERTIES + INTERFACE_LINK_LIBRARIES CONAN_PKG::glfw) + endif() + """), append=True) + tools.save("CMakeLists.txt", + textwrap.dedent( + """ + cmake_minimum_required(VERSION 3.0) + project(cmake_wrapper) + + include("{}/conanbuildinfo.cmake") + conan_basic_setup(TARGETS) + + add_subdirectory("{}" re3) + """).format(self.install_folder.replace("\\", "/"), + self.source_folder.replace("\\", "/"))) + except FileNotFoundError: + pass cmake = CMake(self) cmake.definitions["RE3_AUDIO"] = self._re3_audio cmake.definitions["RE3_WITH_OPUS"] = self.options.with_opus From 96e2ba19f8d26e029540fc6071f389cf6c02a72d Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 3 Jan 2021 19:08:59 +0100 Subject: [PATCH 074/152] cmake: add resource (settings windows icon) --- src/CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0460a353..2710b5a5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) -file(GLOB_RECURSE RE3_SOURCES "*.cpp" "*.h") +file(GLOB_RECURSE RE3_SOURCES "*.cpp" "*.h" "*.rc") function(header_directories RETURN_LIST) file(GLOB_RECURSE ALL_SRCS *.h *.cpp *.c) @@ -17,7 +17,10 @@ endfunction() header_directories(RE3_INCLUDES) -add_executable(re3 WIN32 ${RE3_SOURCES}) +add_executable(re3 WIN32 + ${RE3_SOURCES} +) + target_link_libraries(re3 PRIVATE librw::librw Threads::Threads From 6b8374f391dc4c56682cae44d142bc81d52de062 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 3 Jan 2021 20:38:53 +0100 Subject: [PATCH 075/152] cmake: install files ready for copying in game folder --- CMakeLists.txt | 19 +------------------ cmake/re3-config.cmake.in | 5 ----- src/CMakeLists.txt | 14 ++++++-------- 3 files changed, 7 insertions(+), 31 deletions(-) delete mode 100644 cmake/re3-config.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 8343f20c..665b85e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,11 +21,6 @@ if(NOT RE3_AUDIO IN_LIST RE3_AUDIOS) message(FATAL_ERROR "Illegal RE3_AUDIO=${RE3_AUDIO}") endif() -if(RE3_INSTALL) - include(GNUInstallDirs) - set(RE3_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/re3") -endif() - option(RE3_VENDORED_LIBRW "Use vendored librw" ON) if(RE3_VENDORED_LIBRW) add_subdirectory(vendor/librw) @@ -35,19 +30,7 @@ endif() add_subdirectory(src) if(RE3_INSTALL) - include(CMakePackageConfigHelpers) - configure_package_config_file(cmake/re3-config.cmake.in re3-config.cmake - INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}" - ) - install( - FILES "${CMAKE_CURRENT_BINARY_DIR}/re3-config.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" - ) - install( - EXPORT re3-targets - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" - ) - + install(DIRECTORY gamefiles/ DESTINATION ".") if(LIBRW_PLATFORM_NULL) set(platform "-null") elseif(LIBRW_PLATFORM_PS2) diff --git a/cmake/re3-config.cmake.in b/cmake/re3-config.cmake.in deleted file mode 100644 index 37e81938..00000000 --- a/cmake/re3-config.cmake.in +++ /dev/null @@ -1,5 +0,0 @@ -include("${CMAKE_CURRENT_LIST_DIR}/re3-targets.cmake") - -set(RE3_AUDIO "@RE3_AUDIO@") -set(RE3_AUDIOS "@RE3_AUDIOS@") -set(RE3_PLATFORM @LIBRW_PLATFORM@) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2710b5a5..a2052471 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -83,20 +83,20 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang target_compile_options(re3 PRIVATE "-Wall" - ) + ) if (NOT LIBRW_PLATFORM_PS2) target_compile_options(re3 PRIVATE -Wextra -Wdouble-promotion -Wpedantic - ) + ) endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") target_compile_options(re3 PUBLIC /Zc:sizedDealloc- - ) + ) endif() set_target_properties(re3 @@ -107,14 +107,12 @@ set_target_properties(re3 CXX_STANDARD 11 CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON - ) +) if(RE3_INSTALL) install( TARGETS re3 EXPORT re3-targets - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" - ) + RUNTIME DESTINATION "." + ) endif() From 3519cbd3e56cc7528d2fba4af4544ef7c14d40c5 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 3 Jan 2021 20:50:35 +0100 Subject: [PATCH 076/152] conan: build re3 + librw with RelWithDebInfo build_type --- .github/workflows/build-cmake-conan.yml | 4 ++-- conanfile.py | 2 +- src/CMakeLists.txt | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-cmake-conan.yml b/.github/workflows/build-cmake-conan.yml index 4bd2b08c..2d9b3a98 100644 --- a/.github/workflows/build-cmake-conan.yml +++ b/.github/workflows/build-cmake-conan.yml @@ -95,7 +95,7 @@ jobs: conan export re3mss miles-sdk/master@ - name: "Download/build dependencies (conan install)" run: | - conan install ${{ github.workspace }} re3/master@ -if build -o re3:audio=${{ matrix.audio }} -o librw:platform=${{ matrix.platform }} -o librw:gl3_gfxlib=${{ matrix.gl3_gfxlib || 'glfw' }} --build missing -pr:h ./host_profile -pr:b default + conan install ${{ github.workspace }} re3/master@ -if build -o re3:audio=${{ matrix.audio }} -o librw:platform=${{ matrix.platform }} -o librw:gl3_gfxlib=${{ matrix.gl3_gfxlib || 'glfw' }} --build missing -pr:h ./host_profile -pr:b default -s re3:build_type=RelWithDebInfo -s librw:build_type=RelWithDebInfo env: CONAN_SYSREQUIRES_MODE: enabled - name: "Build re3 (conan build)" @@ -107,7 +107,7 @@ jobs: - name: "Create binary package (cpack)" working-directory: ./build run: | - cpack + cpack -C RelWithDebInfo - name: "Archive binary package (github artifacts)" uses: actions/upload-artifact@v2 with: diff --git a/conanfile.py b/conanfile.py index 958ef689..f0d63a20 100644 --- a/conanfile.py +++ b/conanfile.py @@ -109,7 +109,7 @@ class Re3Conan(ConanFile): project(cmake_wrapper) include("{}/conanbuildinfo.cmake") - conan_basic_setup(TARGETS) + conan_basic_setup(TARGETS NO_OUTPUT_DIRS) add_subdirectory("{}" re3) """).format(self.install_folder.replace("\\", "/"), diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a2052471..2f663061 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -115,4 +115,7 @@ if(RE3_INSTALL) EXPORT re3-targets RUNTIME DESTINATION "." ) + if(MSVC) + install(FILES $ DESTINATION "." OPTIONAL) + endif() endif() From 08e5c8e0109649efc9660062357e25845ef66ca9 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Mon, 11 Jan 2021 17:22:07 +0300 Subject: [PATCH 077/152] fixes --- src/control/Script.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 3563a2b4..09a696cf 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -260,12 +260,12 @@ const tScriptCommandData commands[] = { REGISTER_COMMAND(COMMAND_SET_LVAR_INT_TO_VAR_INT, INPUT_ARGUMENTS(ARGTYPE_INT, ARGTYPE_INT,), OUTPUT_ARGUMENTS(), false, 0, " ="), REGISTER_COMMAND(COMMAND_CSET_VAR_INT_TO_VAR_FLOAT, INPUT_ARGUMENTS(ARGTYPE_INT, ARGTYPE_FLOAT,), OUTPUT_ARGUMENTS(), false, 0, " =#"), REGISTER_COMMAND(COMMAND_CSET_VAR_FLOAT_TO_VAR_INT, INPUT_ARGUMENTS(ARGTYPE_FLOAT, ARGTYPE_INT,), OUTPUT_ARGUMENTS(), false, 0, " =#"), - REGISTER_COMMAND(COMMAND_CSET_LVAR_INT_TO_LVAR_FLOAT, INPUT_ARGUMENTS(ARGTYPE_INT, ARGTYPE_FLOAT,), OUTPUT_ARGUMENTS(), false, 0, " =#"), - REGISTER_COMMAND(COMMAND_CSET_LVAR_FLOAT_TO_LVAR_INT, INPUT_ARGUMENTS(ARGTYPE_FLOAT, ARGTYPE_INT,), OUTPUT_ARGUMENTS(), false, 0, " =#"), + REGISTER_COMMAND(COMMAND_CSET_LVAR_INT_TO_VAR_FLOAT, INPUT_ARGUMENTS(ARGTYPE_INT, ARGTYPE_FLOAT, ), OUTPUT_ARGUMENTS(), false, 0, " =#"), + REGISTER_COMMAND(COMMAND_CSET_LVAR_FLOAT_TO_VAR_INT, INPUT_ARGUMENTS(ARGTYPE_FLOAT, ARGTYPE_INT, ), OUTPUT_ARGUMENTS(), false, 0, " =#"), REGISTER_COMMAND(COMMAND_CSET_VAR_INT_TO_LVAR_FLOAT, INPUT_ARGUMENTS(ARGTYPE_INT, ARGTYPE_FLOAT,), OUTPUT_ARGUMENTS(), false, 0, " =#"), REGISTER_COMMAND(COMMAND_CSET_VAR_FLOAT_TO_LVAR_INT, INPUT_ARGUMENTS(ARGTYPE_FLOAT, ARGTYPE_INT,), OUTPUT_ARGUMENTS(), false, 0, " =#"), - REGISTER_COMMAND(COMMAND_CSET_LVAR_INT_TO_VAR_FLOAT, INPUT_ARGUMENTS(ARGTYPE_INT, ARGTYPE_FLOAT,), OUTPUT_ARGUMENTS(), false, 0, " =#"), - REGISTER_COMMAND(COMMAND_CSET_LVAR_FLOAT_TO_VAR_INT, INPUT_ARGUMENTS(ARGTYPE_FLOAT, ARGTYPE_INT,), OUTPUT_ARGUMENTS(), false, 0, " =#"), + REGISTER_COMMAND(COMMAND_CSET_LVAR_INT_TO_LVAR_FLOAT, INPUT_ARGUMENTS(ARGTYPE_INT, ARGTYPE_FLOAT, ), OUTPUT_ARGUMENTS(), false, 0, " =#"), + REGISTER_COMMAND(COMMAND_CSET_LVAR_FLOAT_TO_LVAR_INT, INPUT_ARGUMENTS(ARGTYPE_FLOAT, ARGTYPE_INT, ), OUTPUT_ARGUMENTS(), false, 0, " =#"), REGISTER_COMMAND(COMMAND_ABS_VAR_INT, INPUT_ARGUMENTS(ARGTYPE_INT, ARGTYPE_INT,), OUTPUT_ARGUMENTS(), false, 0, " ABS"), REGISTER_COMMAND(COMMAND_ABS_LVAR_INT, INPUT_ARGUMENTS(ARGTYPE_INT, ARGTYPE_INT,), OUTPUT_ARGUMENTS(), false, 0, " ABS"), REGISTER_COMMAND(COMMAND_ABS_VAR_FLOAT, INPUT_ARGUMENTS(ARGTYPE_FLOAT, ARGTYPE_FLOAT,), OUTPUT_ARGUMENTS(), false, 0, " ABS"), From 31dd13507549dc0a4a8c763654f1c55725048a25 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Mon, 11 Jan 2021 20:51:18 +0300 Subject: [PATCH 078/152] fuck --- src/control/CarCtrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp index cb4229eb..edf367b8 100644 --- a/src/control/CarCtrl.cpp +++ b/src/control/CarCtrl.cpp @@ -2415,7 +2415,7 @@ void CCarCtrl::SteerAICarWithPhysicsHeadingForTarget(CVehicle* pVehicle, CPhysic *pHandbrake = true; float maxAngle = FindMaxSteerAngle(pVehicle); steerAngle = Min(maxAngle, Max(-maxAngle, steerAngle)); - float speedMultiplier = FindSpeedMultiplier(angleToTarget - angleForward, + float speedMultiplier = FindSpeedMultiplier(CGeneral::GetATanOfXY(targetX - pVehicle->GetPosition().x, targetY - pVehicle->GetPosition().y) - angleForward, MIN_ANGLE_FOR_SPEED_LIMITING, MAX_ANGLE_FOR_SPEED_LIMITING, MIN_LOWERING_SPEED_COEFFICIENT); float speedTarget = pVehicle->AutoPilot.m_nCruiseSpeed * speedMultiplier; float currentSpeed = pVehicle->GetMoveSpeed().Magnitude() * GAME_SPEED_TO_CARAI_SPEED; From 06fbbaa43fc841505b9a14ee076d28e3a7409869 Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Mon, 11 Jan 2021 21:12:11 +0300 Subject: [PATCH 079/152] fix explosion jet --- src/render/Particle.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/render/Particle.cpp b/src/render/Particle.cpp index 08137d0c..6c643caf 100644 --- a/src/render/Particle.cpp +++ b/src/render/Particle.cpp @@ -1839,9 +1839,9 @@ void CParticle::AddJetExplosion(CVector const &vecPos, float fPower, float fSize vecStepPos, CVector ( - CGeneral::GetRandomNumberInRange(-0.2f, 0.2f), - CGeneral::GetRandomNumberInRange(-0.2f, 0.2f), - CGeneral::GetRandomNumberInRange(-0.2f, 0.0f) + CGeneral::GetRandomNumberInRange(-0.02f, 0.02f), + CGeneral::GetRandomNumberInRange(-0.02f, 0.02f), + CGeneral::GetRandomNumberInRange(-0.02f, 0.0f) ), nil, fSize, color, 0, 0, 0, 0); From be1e09aad465878645768a1e515d6c7fa8a68e89 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 12 Jan 2021 02:25:51 +0200 Subject: [PATCH 080/152] Fix collective commands --- src/control/Script5.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/control/Script5.cpp b/src/control/Script5.cpp index 751fefa2..e74a1081 100644 --- a/src/control/Script5.cpp +++ b/src/control/Script5.cpp @@ -2355,7 +2355,7 @@ int CTheScripts::FindFreeSlotInCollectiveArray() void CTheScripts::SetObjectiveForAllPedsInCollective(int colIndex, eObjective objective, int16 p1, int16 p2) { for (int i = 0; i < MAX_NUM_COLLECTIVES; i++) { - if (CollectiveArray[i].colIndex = colIndex) { + if (CollectiveArray[i].colIndex == colIndex) { CPed* pPed = CPools::GetPedPool()->GetAt(CollectiveArray[i].pedIndex); if (pPed == nil) { CollectiveArray[i].colIndex = -1; @@ -2372,7 +2372,7 @@ void CTheScripts::SetObjectiveForAllPedsInCollective(int colIndex, eObjective ob void CTheScripts::SetObjectiveForAllPedsInCollective(int colIndex, eObjective objective, CVector p1, float p2) { for (int i = 0; i < MAX_NUM_COLLECTIVES; i++) { - if (CollectiveArray[i].colIndex = colIndex) { + if (CollectiveArray[i].colIndex == colIndex) { CPed* pPed = CPools::GetPedPool()->GetAt(CollectiveArray[i].pedIndex); if (pPed == nil) { CollectiveArray[i].colIndex = -1; @@ -2389,7 +2389,7 @@ void CTheScripts::SetObjectiveForAllPedsInCollective(int colIndex, eObjective ob void CTheScripts::SetObjectiveForAllPedsInCollective(int colIndex, eObjective objective, CVector p1) { for (int i = 0; i < MAX_NUM_COLLECTIVES; i++) { - if (CollectiveArray[i].colIndex = colIndex) { + if (CollectiveArray[i].colIndex == colIndex) { CPed* pPed = CPools::GetPedPool()->GetAt(CollectiveArray[i].pedIndex); if (pPed == nil) { CollectiveArray[i].colIndex = -1; @@ -2406,7 +2406,7 @@ void CTheScripts::SetObjectiveForAllPedsInCollective(int colIndex, eObjective ob void CTheScripts::SetObjectiveForAllPedsInCollective(int colIndex, eObjective objective, void* p1) { for (int i = 0; i < MAX_NUM_COLLECTIVES; i++) { - if (CollectiveArray[i].colIndex = colIndex) { + if (CollectiveArray[i].colIndex == colIndex) { CPed* pPed = CPools::GetPedPool()->GetAt(CollectiveArray[i].pedIndex); if (pPed == nil) { CollectiveArray[i].colIndex = -1; @@ -2423,7 +2423,7 @@ void CTheScripts::SetObjectiveForAllPedsInCollective(int colIndex, eObjective ob void CTheScripts::SetObjectiveForAllPedsInCollective(int colIndex, eObjective objective) { for (int i = 0; i < MAX_NUM_COLLECTIVES; i++) { - if (CollectiveArray[i].colIndex = colIndex) { + if (CollectiveArray[i].colIndex == colIndex) { CPed* pPed = CPools::GetPedPool()->GetAt(CollectiveArray[i].pedIndex); if (pPed == nil) { CollectiveArray[i].colIndex = -1; From 48ce6151f919d14731cfa79c1b814786b123a80b Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 12 Jan 2021 18:55:14 +0100 Subject: [PATCH 081/152] fix building with PED_SKIN --- src/entities/Entity.cpp | 2 ++ src/modelinfo/ClumpModelInfo.cpp | 2 +- src/rw/RwHelper.cpp | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index 7fcc3829..709f91c1 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -139,6 +139,7 @@ CEntity::DetachFromRwObject(void) m_matrix.Detach(); } +#ifdef PED_SKIN RpAtomic* AtomicRemoveAnimFromSkinCB(RpAtomic *atomic, void *data) { @@ -158,6 +159,7 @@ AtomicRemoveAnimFromSkinCB(RpAtomic *atomic, void *data) } return atomic; } +#endif void CEntity::DeleteRwObject(void) diff --git a/src/modelinfo/ClumpModelInfo.cpp b/src/modelinfo/ClumpModelInfo.cpp index ec64977b..44a62afb 100644 --- a/src/modelinfo/ClumpModelInfo.cpp +++ b/src/modelinfo/ClumpModelInfo.cpp @@ -120,7 +120,7 @@ CClumpModelInfo::SetClump(RpClump *clump) RpClumpForAllAtomics(clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPlayerCB); } #else - if(strcmp(GetModelName(), "playerh") == 0){ + if(strcmp(GetModelName(), "playerh") == 0) RpClumpForAllAtomics(clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPlayerCB); #endif } diff --git a/src/rw/RwHelper.cpp b/src/rw/RwHelper.cpp index 4ee3a0b3..dd356b96 100644 --- a/src/rw/RwHelper.cpp +++ b/src/rw/RwHelper.cpp @@ -2,6 +2,7 @@ #define WITHD3D #endif #include "common.h" +#include #include "RwHelper.h" #include "Timecycle.h" From 11ecab3ca14b642b8f5faff46cc744b979cd41d9 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Tue, 12 Jan 2021 21:38:55 +0100 Subject: [PATCH 082/152] Disable opus for now (as default option) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 665b85e5..df31a704 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ endif() set(RE3_AUDIO "OAL" CACHE STRING "Audio") -option(RE3_WITH_OPUS "Build re3 with opus support" ON) +option(RE3_WITH_OPUS "Build re3 with opus support" OFF) option(RE3_WITH_LIBSNDFILE "Build re3 with libsndfile (instead of internal decoder)" OFF) set_property(CACHE RE3_AUDIO PROPERTY STRINGS ${RE3_AUDIOS}) From 8929e55bffcfa1506cb1b58269190ba91e38fea4 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Tue, 12 Jan 2021 21:39:51 +0100 Subject: [PATCH 083/152] Shorten job name --- .github/workflows/build-cmake-conan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-cmake-conan.yml b/.github/workflows/build-cmake-conan.yml index 2d9b3a98..9f0d8c91 100644 --- a/.github/workflows/build-cmake-conan.yml +++ b/.github/workflows/build-cmake-conan.yml @@ -1,4 +1,4 @@ -name: Build re3 using conan+cmake +name: re3 conan+cmake on: pull_request: push: From 13d5c5e7e6058eb262ec5f3b6ebd5abfee4b5950 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Tue, 12 Jan 2021 21:54:15 +0100 Subject: [PATCH 084/152] A bit more of cleanup of CI --- .github/workflows/re3_msvc_amd64.yml | 2 +- .github/workflows/re3_msvc_x86.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/re3_msvc_amd64.yml b/.github/workflows/re3_msvc_amd64.yml index 8f22af56..63cea698 100644 --- a/.github/workflows/re3_msvc_amd64.yml +++ b/.github/workflows/re3_msvc_amd64.yml @@ -1,4 +1,4 @@ -name: re3_msvc_amd64 +name: re3 premake amd64 on: pull_request: diff --git a/.github/workflows/re3_msvc_x86.yml b/.github/workflows/re3_msvc_x86.yml index c0432280..045c4ec8 100644 --- a/.github/workflows/re3_msvc_x86.yml +++ b/.github/workflows/re3_msvc_x86.yml @@ -1,4 +1,4 @@ -name: re3_msvc_x86 +name: re3 premake x86 on: pull_request: From 3ae4c0056258570e8471685b58e93ffb288af567 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Tue, 12 Jan 2021 21:55:24 +0100 Subject: [PATCH 085/152] Disable building on travis --- .travis.yml | 44 -------------------------------------------- 1 file changed, 44 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c124a9f0..00000000 --- a/.travis.yml +++ /dev/null @@ -1,44 +0,0 @@ -language: cpp -dist: focal -os: linux -jobs: - include: - - env: TARGET=release_linux-amd64-librw_gl3_glfw-oal - os: linux - - env: TARGET=debug_linux-amd64-librw_gl3_glfw-oal - os: linux - - env: TARGET=release_macosx-amd64-librw_gl3_glfw-oal PREMAKE5=premake-5.0.0-alpha15 - compiler: clang - os: osx - osx_image: xcode12u - - env: TARGET=debug_macosx-amd64-librw_gl3_glfw-oal PREMAKE5=premake-5.0.0-alpha15 - compiler: clang - os: osx - osx_image: xcode12u -addons: - apt: - update: true - packages: - - linux-libc-dev - - libopenal-dev - - libglew-dev - - libglfw3-dev - - libsndfile1-dev - - libmpg123-dev - - gcc-8-multilib - - g++-8-multilib - homebrew: - packages: - - libsndfile - - mpg123 - - glew - - glfw - - openal-soft -script: - - mkdir -p "$TRAVIS_BUILD_DIR/build" - - cd "$TRAVIS_BUILD_DIR" - - if [ "$TRAVIS_OS_NAME" = linux ]; then ./premake5Linux --with-librw gmake2; fi - - if [ "$TRAVIS_OS_NAME" = osx ]; then curl -L -o "${PREMAKE5}.zip" "https://github.com/premake/premake-core/releases/download/v5.0.0-alpha15/${PREMAKE5}-src.zip" && unzip -q "${PREMAKE5}.zip" && cd "$PREMAKE5" && make -f Bootstrap.mak osx && cd .. && "./${PREMAKE5}/bin/release/premake5" --with-librw gmake2; fi - - cd build - - if [ "$TRAVIS_OS_NAME" = linux ]; then env CC=gcc-8 CXX=g++-8 make config=$TARGET -j4 verbose=1; fi - - if [ "$TRAVIS_OS_NAME" = osx ]; then make config=$TARGET -j4 verbose=1; fi From 4a96c7c9f2e564346ef4b85c3deaeffe6f940781 Mon Sep 17 00:00:00 2001 From: withmorten Date: Tue, 12 Jan 2021 23:25:12 +0100 Subject: [PATCH 086/152] fix CreateInstance virtual overload order --- src/modelinfo/BaseModelInfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modelinfo/BaseModelInfo.h b/src/modelinfo/BaseModelInfo.h index 3a94a83a..31c7f566 100644 --- a/src/modelinfo/BaseModelInfo.h +++ b/src/modelinfo/BaseModelInfo.h @@ -44,8 +44,8 @@ public: virtual ~CBaseModelInfo() {} virtual void Shutdown(void); virtual void DeleteRwObject(void) = 0; - virtual RwObject *CreateInstance(RwMatrix *) = 0; virtual RwObject *CreateInstance(void) = 0; + virtual RwObject *CreateInstance(RwMatrix *) = 0; virtual RwObject *GetRwObject(void) = 0; // one day it becomes virtual From 461e9fe5c2c751bf36cfb4d0ab48abbf81434168 Mon Sep 17 00:00:00 2001 From: shfil Date: Tue, 12 Jan 2021 23:41:11 +0100 Subject: [PATCH 087/152] Disable opus in conan file as default option --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index f0d63a20..ba7d920b 100644 --- a/conanfile.py +++ b/conanfile.py @@ -19,7 +19,7 @@ class Re3Conan(ConanFile): default_options = { "audio": "openal", "with_libsndfile": False, - "with_opus": True, + "with_opus": False, # "libsndfile:with_external_libs": False, # "mpg123:flexible_resampling": False, # "mpg123:network": False, From 4fe64d1b0d96bf5fdf8e202932815cb5bb1d2678 Mon Sep 17 00:00:00 2001 From: shfil Date: Tue, 12 Jan 2021 23:46:11 +0100 Subject: [PATCH 088/152] Fix --- conanfile.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conanfile.py b/conanfile.py index ba7d920b..cabcc4c2 100644 --- a/conanfile.py +++ b/conanfile.py @@ -67,9 +67,9 @@ class Re3Conan(ConanFile): def validate(self): if self.options["librw"].platform == "gl3" and self.options["librw"].gl3_gfxlib != "glfw": raise ConanInvalidConfiguration("Only `glfw` is supported as gl3_gfxlib.") - if not self.options.with_opus: - if not self.options["libsndfile"].with_external_libs: - raise ConanInvalidConfiguration("re3 with opus support requires a libsndfile built with external libs (=ogg/flac/opus/vorbis)") + #if not self.options.with_opus: + # if not self.options["libsndfile"].with_external_libs: + # raise ConanInvalidConfiguration("re3 with opus support requires a libsndfile built with external libs (=ogg/flac/opus/vorbis)") @property def _re3_audio(self): From c210e1bae653a51b1d5d6fda4098c74448a83fa3 Mon Sep 17 00:00:00 2001 From: withmorten Date: Wed, 13 Jan 2021 00:18:34 +0100 Subject: [PATCH 089/152] move stuff back into class; securom comments --- src/render/WaterLevel.h | 2 +- src/vehicles/Heli.cpp | 2 +- src/vehicles/Heli.h | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/render/WaterLevel.h b/src/render/WaterLevel.h index cf3537ae..b797f251 100644 --- a/src/render/WaterLevel.h +++ b/src/render/WaterLevel.h @@ -79,7 +79,7 @@ class CWaterLevel static int16 nGeomUsed; public: - static void Initialise(Const char *pWaterDat); + static void Initialise(Const char *pWaterDat); // out of class in III PC and later because of SecuROM static void Shutdown(); static void CreateWavyAtomic(); static void DestroyWavyAtomic(); diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp index 7008818b..56d6a8eb 100644 --- a/src/vehicles/Heli.cpp +++ b/src/vehicles/Heli.cpp @@ -785,7 +785,7 @@ CHeli::InitHelis(void) } CHeli* -GenerateHeli(bool catalina) +CHeli::GenerateHeli(bool catalina) { CHeli *heli; CVector heliPos; diff --git a/src/vehicles/Heli.h b/src/vehicles/Heli.h index cf3f791f..5fef799b 100644 --- a/src/vehicles/Heli.h +++ b/src/vehicles/Heli.h @@ -81,12 +81,13 @@ public: CObject *SpawnFlyingComponent(int32 component); static void InitHelis(void); + static CHeli *GenerateHeli(bool catalina); // out of class in III PC and later because of SecuROM static void UpdateHelis(void); static void SpecialHeliPreRender(void); static bool TestRocketCollision(CVector *coors); static bool TestBulletCollision(CVector *line0, CVector *line1, CVector *bulletPos, int32 damage); - static void StartCatalinaFlyBy(void); + static void StartCatalinaFlyBy(void); // out of class in III PC and later because of SecuROM static void RemoveCatalinaHeli(void); static CHeli *FindPointerToCatalinasHeli(void); static void CatalinaTakeOff(void); From 61036779140610c81688a636c3226c46571dbbef Mon Sep 17 00:00:00 2001 From: withmorten Date: Wed, 13 Jan 2021 00:28:07 +0100 Subject: [PATCH 090/152] more securom fixes --- src/control/Replay.cpp | 20 ++++++++++---------- src/control/Replay.h | 6 +----- src/vehicles/Cranes.h | 2 +- src/vehicles/Heli.cpp | 2 +- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index 05880162..2e87d1a7 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -1457,7 +1457,7 @@ void CReplay::SaveReplayToHD(void) CFileMgr::SetDir(""); } -void PlayReplayFromHD(void) +void CReplay::PlayReplayFromHD(void) { CFileMgr::SetDirMyDocuments(); int fr = CFileMgr::OpenFile("replay.rep", "rb"); @@ -1476,17 +1476,17 @@ void PlayReplayFromHD(void) return; } int slot; - for (slot = 0; CFileMgr::Read(fr, (char*)CReplay::Buffers[slot], sizeof(CReplay::Buffers[slot])); slot++) - CReplay::BufferStatus[slot] = CReplay::REPLAYBUFFER_PLAYBACK; - CReplay::BufferStatus[slot - 1] = CReplay::REPLAYBUFFER_RECORD; - while (slot < CReplay::NUM_REPLAYBUFFERS) - CReplay::BufferStatus[slot++] = CReplay::REPLAYBUFFER_UNUSED; + for (slot = 0; CFileMgr::Read(fr, (char*)Buffers[slot], sizeof(Buffers[slot])); slot++) + BufferStatus[slot] = REPLAYBUFFER_PLAYBACK; + BufferStatus[slot - 1] = REPLAYBUFFER_RECORD; + while (slot < NUM_REPLAYBUFFERS) + BufferStatus[slot++] = REPLAYBUFFER_UNUSED; CFileMgr::CloseFile(fr); CFileMgr::SetDir(""); - CReplay::TriggerPlayback(CReplay::REPLAYCAMMODE_ASSTORED, 0.0f, 0.0f, 0.0f, false); - CReplay::bPlayingBackFromFile = true; - CReplay::bAllowLookAroundCam = true; - CReplay::StreamAllNecessaryCarsAndPeds(); + TriggerPlayback(REPLAYCAMMODE_ASSTORED, 0.0f, 0.0f, 0.0f, false); + bPlayingBackFromFile = true; + bAllowLookAroundCam = true; + StreamAllNecessaryCarsAndPeds(); } void CReplay::StreamAllNecessaryCarsAndPeds(void) diff --git a/src/control/Replay.h b/src/control/Replay.h index aa2ecd86..68da9cc3 100644 --- a/src/control/Replay.h +++ b/src/control/Replay.h @@ -61,8 +61,6 @@ struct CStoredDetailedAnimationState uint16 aFlags2[NUM_PARTIAL_ANIMS_IN_REPLAY]; }; -void PlayReplayFromHD(void); - #ifdef GTA_REPLAY #define REPLAY_STUB #else @@ -323,11 +321,9 @@ private: static void EmptyAllPools(void); static void MarkEverythingAsNew(void); static void SaveReplayToHD(void); + static void PlayReplayFromHD(void); // out of class in III PC and later because of SecuROM static void FindFirstFocusCoordinate(CVector *coord); static void ProcessLookAroundCam(void); static size_t FindSizeOfPacket(uint8); - - /* Absolute nonsense, but how could this function end up being outside of class? */ - friend void PlayReplayFromHD(void); #endif }; diff --git a/src/vehicles/Cranes.h b/src/vehicles/Cranes.h index 0e134310..e9178105 100644 --- a/src/vehicles/Cranes.h +++ b/src/vehicles/Cranes.h @@ -89,7 +89,7 @@ public: static bool IsThisCarBeingCarriedByAnyCrane(CVehicle* pVehicle); static bool IsThisCarBeingTargettedByAnyCrane(CVehicle* pVehicle); static void Save(uint8* buf, uint32* size); - static void Load(uint8* buf, uint32 size); // on mobile it's CranesLoad outside of the class + static void Load(uint8* buf, uint32 size); // out of class in III PC and later because of SecuROM static uint32 CarsCollectedMilitaryCrane; static int32 NumCranes; diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp index 56d6a8eb..44e9a73f 100644 --- a/src/vehicles/Heli.cpp +++ b/src/vehicles/Heli.cpp @@ -830,7 +830,7 @@ CHeli::GenerateHeli(bool catalina) id++; found = true; for(i = 0; i < 4; i++) - if(CHeli::pHelis[i] && CHeli::pHelis[i]->m_nHeliId == id) + if(pHelis[i] && pHelis[i]->m_nHeliId == id) found = false; } heli->m_nHeliId = id; From 66b8c870f471d5a14c2e17ff8ce2b96c487cb293 Mon Sep 17 00:00:00 2001 From: shfil Date: Wed, 13 Jan 2021 02:35:05 +0100 Subject: [PATCH 091/152] Update README.md --- README.md | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 29f2529e..22242f36 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,42 @@ such that we have a working game at all times. ## How can I try it? - re3 requires game assets to work, so you **must** own [a copy of GTA III](https://store.steampowered.com/app/12100/Grand_Theft_Auto_III/). -- Build re3 or download it from one of the above links (Debug or Release). +- Build re3 or download [the latest nightly build](https://github.com/GTAmodding/re3/actions) (You must be logged in.) - (Optional) If you want to use optional features like Russian language or menu map, copy the files in /gamefiles folder to your game root folder. - Move re3.exe to GTA 3 directory and run it. -## Preparing the environment for building +## Building from Source +
Linux Premake +- For Linux using premake, proceed: [Building on Linux](https://github.com/GTAmodding/re3/wiki/Building-on-Linux) +
+ +
Linux Conan + +Obtain souce code. +``` +git clone https://github.com/GTAmodding/re3.git +cd re3 +git submodule init +git submodule update --recursive +``` +Install python and conan, and then run build. +``` +conan export vendor/librw librw/master@ +mkdir build +cd build +conan install .. re3/master@ -if build -o re3:audio=openal -o librw:platform=gl3 -o librw:gl3_gfxlib=glfw --build missing -s re3:build_type=RelWithDebInfo -s librw:build_type=RelWithDebInfo +conan build .. +``` +
+ +
FreeBSD +- For FreeBSD using premake, proceed: [Building on FreeBSD](https://github.com/GTAmodding/re3/wiki/Building-on-FreeBSD) +
+ +
Windows You may want to point GTA_III_RE_DIR environment variable to GTA3 root folder if you want executable to be moved there via post-build script. -- For Linux, proceed: [Building on Linux](https://github.com/GTAmodding/re3/wiki/Building-on-Linux) -- For FreeBSD, proceed: [Building on FreeBSD](https://github.com/GTAmodding/re3/wiki/Building-on-FreeBSD) - For Windows, assuming you have Visual Studio: - Clone the repo using the argument `--recursive`. - Run one of the `premake-vsXXXX.cmd` variants on root folder. @@ -29,9 +55,10 @@ You may want to point GTA_III_RE_DIR environment variable to GTA3 root folder if **If you use 64-bit D3D9**: We don't ship 64-bit Dx9 SDK. You need to download it from Microsoft if you don't have it(although it should come pre-installed after some Windows version) -There are various settings at the very bottom of [config.h](https://github.com/GTAmodding/re3/tree/master/src/core/config.h), you may want to take a look there. i.e. FIX_BUGS define fixes the bugs we've come across. +**If you choose OpenAL on Windows** You must read [Running OpenAL build on Windows](https://github.com/GTAmodding/re3/wiki/Running-OpenAL-build-on-Windows). +
-> :information_source: **If you choose OpenAL on Windows** You must read [Running OpenAL build on Windows](https://github.com/GTAmodding/re3/wiki/Running-OpenAL-build-on-Windows). +> :information_source: There are various settings at the very bottom of [config.h](https://github.com/GTAmodding/re3/tree/master/src/core/config.h), you may want to take a look there. i.e. FIX_BUGS define fixes the bugs we've come across. > :information_source: **Did you notice librw?** re3 uses completely homebrew RenderWare-replacement rendering engine; [librw](https://github.com/aap/librw/). librw comes as submodule of re3, but you also can use LIBRW enviorenment variable to specify path to your own librw. From 29172e9ee2b0b21ec47a2d9344ec82b53e89c715 Mon Sep 17 00:00:00 2001 From: shfil Date: Wed, 13 Jan 2021 02:38:50 +0100 Subject: [PATCH 092/152] Update README.md --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 22242f36..df109ba2 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,9 @@ such that we have a working game at all times. ## Building from Source
Linux Premake -- For Linux using premake, proceed: [Building on Linux](https://github.com/GTAmodding/re3/wiki/Building-on-Linux) + +For Linux using premake, proceed: [Building on Linux](https://github.com/GTAmodding/re3/wiki/Building-on-Linux) +
Linux Conan @@ -42,10 +44,13 @@ conan build ..
FreeBSD -- For FreeBSD using premake, proceed: [Building on FreeBSD](https://github.com/GTAmodding/re3/wiki/Building-on-FreeBSD) + +For FreeBSD using premake, proceed: [Building on FreeBSD](https://github.com/GTAmodding/re3/wiki/Building-on-FreeBSD) +
Windows + You may want to point GTA_III_RE_DIR environment variable to GTA3 root folder if you want executable to be moved there via post-build script. - For Windows, assuming you have Visual Studio: From ef0b2291a05c55cf49ed882bbe33d38b6cdc3730 Mon Sep 17 00:00:00 2001 From: shfil Date: Wed, 13 Jan 2021 02:39:53 +0100 Subject: [PATCH 093/152] Typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index df109ba2..bf38339b 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ For Linux using premake, proceed: [Building on Linux](https://github.com/GTAmodd
Linux Conan -Obtain souce code. +Obtain source code. ``` git clone https://github.com/GTAmodding/re3.git cd re3 From 4837969e09944c660b495dd92c9243b9c46f9e84 Mon Sep 17 00:00:00 2001 From: erorcun Date: Wed, 13 Jan 2021 05:05:19 +0300 Subject: [PATCH 094/152] Update README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index bf38339b..d40a6229 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,9 @@ such that we have a working game at all times. - (Optional) If you want to use optional features like Russian language or menu map, copy the files in /gamefiles folder to your game root folder. - Move re3.exe to GTA 3 directory and run it. -## Building from Source +## Building from Source + +Before starting you may want to point GTA_III_RE_DIR environment variable to GTA3 root folder, if you want executable to be moved there via post-build script.
Linux Premake @@ -51,12 +53,10 @@ For FreeBSD using premake, proceed: [Building on FreeBSD](https://github.com/GTA
Windows -You may want to point GTA_III_RE_DIR environment variable to GTA3 root folder if you want executable to be moved there via post-build script. - -- For Windows, assuming you have Visual Studio: - - Clone the repo using the argument `--recursive`. - - Run one of the `premake-vsXXXX.cmd` variants on root folder. - - Open the project via Visual Studio +Assuming you have Visual Studio: +- Clone the repo using the argument `--recursive`. +- Run one of the `premake-vsXXXX.cmd` variants on root folder. +- Open the project via Visual Studio **If you use 64-bit D3D9**: We don't ship 64-bit Dx9 SDK. You need to download it from Microsoft if you don't have it(although it should come pre-installed after some Windows version) From fb1bd1a5bd3ed6de91e4e86dd0ff9ae22d55dff6 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 13 Jan 2021 10:48:55 +0100 Subject: [PATCH 095/152] fix !FREE_CAM build --- src/peds/PlayerPed.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp index b104f14c..a8e2e972 100644 --- a/src/peds/PlayerPed.cpp +++ b/src/peds/PlayerPed.cpp @@ -1136,7 +1136,7 @@ CPlayerPed::ProcessPlayerWeapon(CPad *padUsed) #ifdef FREE_CAM else if ((CCamera::bFreeCam && weaponInfo->m_eWeaponFire == WEAPON_FIRE_MELEE) || (weaponInfo->IsFlagSet(WEAPONFLAG_CANAIM) && !CCamera::m_bUseMouse3rdPerson)) { #else - else if (weaponInfo->m_bCanAim && !CCamera::m_bUseMouse3rdPerson) { + else if (weaponInfo->IsFlagSet(WEAPONFLAG_CANAIM) && !CCamera::m_bUseMouse3rdPerson) { #endif if (padUsed->TargetJustDown()) FindWeaponLockOnTarget(); From 4097c20bdd66d03e0be454f1834e2d1bd4c54443 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Wed, 13 Jan 2021 12:15:22 +0100 Subject: [PATCH 096/152] Make cmake files more generic --- CMakeLists.txt | 37 +++++++++++++------------ src/CMakeLists.txt | 68 +++++++++++++++++++++++----------------------- 2 files changed, 54 insertions(+), 51 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index df31a704..ae6395c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,35 +1,38 @@ cmake_minimum_required(VERSION 3.8) -project(re3 C CXX) +set(EXECUTABLE re3) +set(PROJECT RE3) + +project(${EXECUTABLE} C CXX) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") if(WIN32) - set(RE3_AUDIOS "OAL" "MSS") + set(${PROJECT}_AUDIOS "OAL" "MSS") else() - set(RE3_AUDIOS "OAL") + set(${PROJECT}_AUDIOS "OAL") endif() -set(RE3_AUDIO "OAL" CACHE STRING "Audio") +set(${PROJECT}_AUDIO "OAL" CACHE STRING "Audio") -option(RE3_WITH_OPUS "Build re3 with opus support" OFF) -option(RE3_WITH_LIBSNDFILE "Build re3 with libsndfile (instead of internal decoder)" OFF) +option(${PROJECT}_WITH_OPUS "Build ${EXECUTABLE} with opus support" OFF) +option(${PROJECT}_WITH_LIBSNDFILE "Build ${EXECUTABLE} with libsndfile (instead of internal decoder)" OFF) -set_property(CACHE RE3_AUDIO PROPERTY STRINGS ${RE3_AUDIOS}) -message(STATUS "RE3_AUDIO = ${RE3_AUDIO} (choices=${RE3_AUDIOS})") -set("RE3_AUDIO_${RE3_AUDIO}" ON) -if(NOT RE3_AUDIO IN_LIST RE3_AUDIOS) - message(FATAL_ERROR "Illegal RE3_AUDIO=${RE3_AUDIO}") +set_property(CACHE ${PROJECT}_AUDIO PROPERTY STRINGS ${${PROJECT}_AUDIOS}) +message(STATUS "${PROJECT}_AUDIO = ${${PROJECT}_AUDIO} (choices=${${PROJECT}_AUDIOS})") +set("${PROJECT}_AUDIO_${${PROJECT}_AUDIO}" ON) +if(NOT ${PROJECT}_AUDIO IN_LIST ${PROJECT}_AUDIOS) + message(FATAL_ERROR "Illegal ${PROJECT}_AUDIO=${${PROJECT}_AUDIO}") endif() -option(RE3_VENDORED_LIBRW "Use vendored librw" ON) -if(RE3_VENDORED_LIBRW) +option(${PROJECT}_VENDORED_LIBRW "Use vendored librw" ON) +if(${PROJECT}_VENDORED_LIBRW) add_subdirectory(vendor/librw) else() find_package(librw REQUIRED) endif() add_subdirectory(src) -if(RE3_INSTALL) +if(${PROJECT}_INSTALL) install(DIRECTORY gamefiles/ DESTINATION ".") if(LIBRW_PLATFORM_NULL) set(platform "-null") @@ -44,12 +47,12 @@ if(RE3_INSTALL) elseif(LIBRW_PLATFORM_D3D9) set(platform "-d3d9") endif() - if(RE3_AUDIO_OAL) + if(${PROJECT}_AUDIO_OAL) set(audio "-oal") - elseif(RE3_AUDIO_MSS) + elseif(${PROJECT}_AUDIO_MSS) set(audio "-mss") endif() - if(RE3_WITH_OPUS) + if(${PROJECT}_WITH_OPUS) set(audio "${audio}-opus") endif() if(NOT LIBRW_PLATFORM_PS2) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2f663061..dc204d17 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) -file(GLOB_RECURSE RE3_SOURCES "*.cpp" "*.h" "*.rc") +file(GLOB_RECURSE ${PROJECT}_SOURCES "*.cpp" "*.h" "*.rc") function(header_directories RETURN_LIST) file(GLOB_RECURSE ALL_SRCS *.h *.cpp *.c) @@ -15,77 +15,77 @@ function(header_directories RETURN_LIST) set(${RETURN_LIST} ${RELDIRS} PARENT_SCOPE) endfunction() -header_directories(RE3_INCLUDES) +header_directories(${PROJECT}_INCLUDES) -add_executable(re3 WIN32 - ${RE3_SOURCES} +add_executable(${EXECUTABLE} WIN32 + ${${PROJECT}_SOURCES} ) -target_link_libraries(re3 PRIVATE +target_link_libraries(${EXECUTABLE} PRIVATE librw::librw Threads::Threads ) -target_include_directories(re3 +target_include_directories(${EXECUTABLE} PRIVATE $ - $ + $ ) -target_compile_definitions(re3 +target_compile_definitions(${EXECUTABLE} PRIVATE $,DEBUG,NDEBUG> LIBRW - RE3_NO_AUTOLINK + ${PROJECT}_NO_AUTOLINK ) if(LIBRW_PLATFORM_D3D9) - target_compile_definitions(re3 + target_compile_definitions(${EXECUTABLE} PUBLIC USE_D3D9 ) endif() -if(RE3_AUDIO STREQUAL "OAL") +if(${PROJECT}_AUDIO STREQUAL "OAL") find_package(OpenAL REQUIRED) - target_include_directories(re3 PRIVATE ${OPENAL_INCLUDE_DIR}) - target_link_libraries(re3 PRIVATE ${OPENAL_LIBRARY}) - target_compile_definitions(re3 PRIVATE ${OPENAL_DEFINITIONS}) - target_compile_definitions(re3 PRIVATE AUDIO_OAL) -elseif(RE3_AUDIO STREQUAL "MSS") + target_include_directories(${EXECUTABLE} PRIVATE ${OPENAL_INCLUDE_DIR}) + target_link_libraries(${EXECUTABLE} PRIVATE ${OPENAL_LIBRARY}) + target_compile_definitions(${EXECUTABLE} PRIVATE ${OPENAL_DEFINITIONS}) + target_compile_definitions(${EXECUTABLE} PRIVATE AUDIO_OAL) +elseif(${PROJECT}_AUDIO STREQUAL "MSS") find_package(MilesSDK REQUIRED) - target_compile_definitions(re3 PRIVATE AUDIO_MSS) - target_link_libraries(re3 PRIVATE MilesSDK::MilesSDK) + target_compile_definitions(${EXECUTABLE} PRIVATE AUDIO_MSS) + target_link_libraries(${EXECUTABLE} PRIVATE MilesSDK::MilesSDK) endif() find_package(mpg123 REQUIRED) -target_link_libraries(re3 PRIVATE +target_link_libraries(${EXECUTABLE} PRIVATE MPG123::libmpg123 ) -if(RE3_WITH_OPUS) +if(${PROJECT}_WITH_OPUS) find_package(opusfile REQUIRED) - target_link_libraries(re3 PRIVATE + target_link_libraries(${EXECUTABLE} PRIVATE opusfile::opusfile ) - target_compile_definitions(re3 PRIVATE AUDIO_OPUS) + target_compile_definitions(${EXECUTABLE} PRIVATE AUDIO_OPUS) endif() -if(RE3_WITH_LIBSNDFILE) +if(${PROJECT}_WITH_LIBSNDFILE) find_package(SndFile REQUIRED) - target_link_libraries(re3 PRIVATE + target_link_libraries(${EXECUTABLE} PRIVATE SndFile::SndFile ) - target_compile_definitions(re3 PRIVATE AUDIO_OAL_USE_SNDFILE) + target_compile_definitions(${EXECUTABLE} PRIVATE AUDIO_OAL_USE_SNDFILE) endif() -target_compile_definitions(re3 PRIVATE ) +target_compile_definitions(${EXECUTABLE} PRIVATE ) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - target_compile_options(re3 + target_compile_options(${EXECUTABLE} PRIVATE "-Wall" ) if (NOT LIBRW_PLATFORM_PS2) - target_compile_options(re3 + target_compile_options(${EXECUTABLE} PRIVATE -Wextra -Wdouble-promotion @@ -93,13 +93,13 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang ) endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - target_compile_options(re3 + target_compile_options(${EXECUTABLE} PUBLIC /Zc:sizedDealloc- ) endif() -set_target_properties(re3 +set_target_properties(${EXECUTABLE} PROPERTIES C_STANDARD 11 C_EXTENSIONS OFF @@ -109,13 +109,13 @@ set_target_properties(re3 CXX_STANDARD_REQUIRED ON ) -if(RE3_INSTALL) +if(${PROJECT}_INSTALL) install( - TARGETS re3 - EXPORT re3-targets + TARGETS ${EXECUTABLE} + EXPORT ${EXECUTABLE}-targets RUNTIME DESTINATION "." ) if(MSVC) - install(FILES $ DESTINATION "." OPTIONAL) + install(FILES $ DESTINATION "." OPTIONAL) endif() endif() From 57201187de74da42437dfa984a6cd36fe663a5e4 Mon Sep 17 00:00:00 2001 From: erorcun Date: Wed, 13 Jan 2021 14:22:31 +0300 Subject: [PATCH 097/152] Fix build without FIX_BUGS, divide to 0 fixes --- src/core/config.h | 6 +++++- src/entities/Physical.cpp | 37 ++++++++++++++++++++++++++++++++++++- src/rw/MemoryMgr.cpp | 2 +- src/rw/RwHelper.cpp | 9 +++++---- src/text/Text.cpp | 8 ++++---- src/text/Text.h | 4 ++-- 6 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/core/config.h b/src/core/config.h index a2b2b6fc..ce7ee1e3 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -226,11 +226,15 @@ enum Config { # define TIMEBARS // print debug timers #endif -#define FIX_BUGS // fixes bugs that we've came across during reversing +#define FIX_BUGS // fixes bugs that we've came across during reversing. You can undefine this only on release builds. #define MORE_LANGUAGES // Add more translations to the game #define COMPATIBLE_SAVES // this allows changing structs while keeping saves compatible #define LOAD_INI_SETTINGS // as the name suggests. fundamental for CUSTOM_FRONTEND_OPTIONS +#if defined(__LP64__) || defined(_WIN64) +#define FIX_BUGS_64 // Must have fixes to be able to run 64 bit build +#endif + // Just debug menu entries #ifdef DEBUGMENU #define MISSION_SWITCHER // from debug menu diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index 0bd87dbc..24017e19 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -783,9 +783,13 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl if(B->GetStatus() == STATUS_PLAYER) pointposB *= 0.8f; if(CWorld::bNoMoreCollisionTorque){ - // BUG: the game actually uses A here, but this can't be right +#ifdef FIX_BUGS B->ApplyFrictionMoveForce(fB*-0.3f); B->ApplyFrictionTurnForce(fB*-0.3f, pointposB); +#else + A->ApplyFrictionMoveForce(fB*-0.3f); + A->ApplyFrictionTurnForce(fB*-0.3f, pointposB); +#endif } } if(!A->bInfiniteMass){ @@ -881,7 +885,13 @@ CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint) fOtherSpeedA = vOtherSpeedA.Magnitude(); fOtherSpeedB = vOtherSpeedB.Magnitude(); +#ifdef FIX_BUGS // division by 0 + frictionDir = vOtherSpeedA; + frictionDir.Normalise(); +#else frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA); +#endif + speedSum = (B->m_fMass*fOtherSpeedB + A->m_fMass*fOtherSpeedA)/(B->m_fMass + A->m_fMass); if(fOtherSpeedA > speedSum){ impulseA = (speedSum - fOtherSpeedA) * A->m_fMass; @@ -911,7 +921,12 @@ CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint) fOtherSpeedA = vOtherSpeedA.Magnitude(); fOtherSpeedB = vOtherSpeedB.Magnitude(); +#ifdef FIX_BUGS // division by 0 + frictionDir = vOtherSpeedA; + frictionDir.Normalise(); +#else frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA); +#endif float massB = B->GetMass(pointposB, frictionDir); speedSum = (massB*fOtherSpeedB + A->m_fMass*fOtherSpeedA)/(massB + A->m_fMass); if(fOtherSpeedA > speedSum){ @@ -939,7 +954,12 @@ CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint) fOtherSpeedA = vOtherSpeedA.Magnitude(); fOtherSpeedB = vOtherSpeedB.Magnitude(); +#ifdef FIX_BUGS // division by 0 + frictionDir = vOtherSpeedA; + frictionDir.Normalise(); +#else frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA); +#endif float massA = A->GetMass(pointposA, frictionDir); speedSum = (B->m_fMass*fOtherSpeedB + massA*fOtherSpeedA)/(B->m_fMass + massA); if(fOtherSpeedA > speedSum){ @@ -967,7 +987,12 @@ CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint) fOtherSpeedA = vOtherSpeedA.Magnitude(); fOtherSpeedB = vOtherSpeedB.Magnitude(); +#ifdef FIX_BUGS // division by 0 + frictionDir = vOtherSpeedA; + frictionDir.Normalise(); +#else frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA); +#endif float massA = A->GetMass(pointposA, frictionDir); float massB = B->GetMass(pointposB, frictionDir); speedSum = (massB*fOtherSpeedB + massA*fOtherSpeedA)/(massB + massA); @@ -1004,7 +1029,12 @@ CPhysical::ApplyFriction(float adhesiveLimit, CColPoint &colpoint) fOtherSpeed = vOtherSpeed.Magnitude(); if(fOtherSpeed > 0.0f){ +#ifdef FIX_BUGS // division by 0 + frictionDir = vOtherSpeed; + frictionDir.Normalise(); +#else frictionDir = vOtherSpeed * (1.0f/fOtherSpeed); +#endif // not really impulse but speed // maybe use ApplyFrictionMoveForce instead? fImpulse = -fOtherSpeed; @@ -1022,7 +1052,12 @@ CPhysical::ApplyFriction(float adhesiveLimit, CColPoint &colpoint) fOtherSpeed = vOtherSpeed.Magnitude(); if(fOtherSpeed > 0.0f){ +#ifdef FIX_BUGS // division by 0 + frictionDir = vOtherSpeed; + frictionDir.Normalise(); +#else frictionDir = vOtherSpeed * (1.0f/fOtherSpeed); +#endif fImpulse = -fOtherSpeed * m_fMass; impulseLimit = adhesiveLimit*CTimer::GetTimeStep() * 1.5; if(fImpulse < -impulseLimit) fImpulse = -impulseLimit; diff --git a/src/rw/MemoryMgr.cpp b/src/rw/MemoryMgr.cpp index e2f6f144..2379692c 100644 --- a/src/rw/MemoryMgr.cpp +++ b/src/rw/MemoryMgr.cpp @@ -93,7 +93,7 @@ MemoryMgrFree(void *ptr) void * RwMallocAlign(RwUInt32 size, RwUInt32 align) { -#ifdef FIX_BUGS +#if defined (FIX_BUGS) || defined(FIX_BUGS_64) uintptr ptralign = align-1; void *mem = (void *)MemoryMgrMalloc(size + sizeof(uintptr) + ptralign); diff --git a/src/rw/RwHelper.cpp b/src/rw/RwHelper.cpp index dd356b96..d004656c 100644 --- a/src/rw/RwHelper.cpp +++ b/src/rw/RwHelper.cpp @@ -291,7 +291,8 @@ SkinGetBonePositionsToTable(RpClump *clump, RwV3d *boneTable) parent = stack[sp--]; else parent = i; - assert(parent >= 0 && parent < numBones); + + //assert(parent >= 0 && parent < numBones); } } @@ -299,7 +300,7 @@ RpHAnimAnimation* HAnimAnimationCreateForHierarchy(RpHAnimHierarchy *hier) { int i; -#ifdef FIX_BUGS +#if defined FIX_BUGS || defined LIBRW int numNodes = hier->numNodes*2; // you're supposed to have at least two KFs per node #else int numNodes = hier->numNodes; @@ -313,7 +314,7 @@ HAnimAnimationCreateForHierarchy(RpHAnimHierarchy *hier) frame->q.real = 1.0f; frame->q.imag.x = frame->q.imag.y = frame->q.imag.z = 0.0f; frame->t.x = frame->t.y = frame->t.z = 0.0f; -#ifdef FIX_BUGS +#if defined FIX_BUGS || defined LIBRW // times are subtracted and divided giving NaNs // so they can't both be 0 frame->time = i/hier->numNodes; @@ -401,7 +402,7 @@ CameraSize(RwCamera * camera, RwRect * rect, RwRaster *zRaster; // BUG: game just changes camera raster's sizes, but this is a hack -#ifdef FIX_BUGS +#if defined FIX_BUGS || defined LIBRW /* * Destroy rasters... */ diff --git a/src/text/Text.cpp b/src/text/Text.cpp index 0c63ced7..fe37d0f1 100644 --- a/src/text/Text.cpp +++ b/src/text/Text.cpp @@ -97,7 +97,7 @@ CText::Unload(void) wchar* CText::Get(const char *key) { -#ifdef FIX_BUGS +#if defined (FIX_BUGS) || defined(FIX_BUGS_64) return keyArray.Search(key, data.chars); #else return keyArray.Search(key); @@ -201,7 +201,7 @@ CKeyArray::Unload(void) void CKeyArray::Update(wchar *chars) { -#ifndef FIX_BUGS +#if !defined(FIX_BUGS) && !defined(FIX_BUGS_64) int i; for(i = 0; i < numEntries; i++) entries[i].value = (wchar*)((uint8*)chars + (uintptr)entries[i].value); @@ -229,7 +229,7 @@ CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 hi } wchar* -#ifdef FIX_BUGS +#if defined (FIX_BUGS) || defined(FIX_BUGS_64) CKeyArray::Search(const char *key, wchar *data) #else CKeyArray::Search(const char *key) @@ -239,7 +239,7 @@ CKeyArray::Search(const char *key) char errstr[25]; int i; -#ifdef FIX_BUGS +#if defined (FIX_BUGS) || defined(FIX_BUGS_64) found = BinarySearch(key, entries, 0, numEntries-1); if(found) return (wchar*)((uint8*)data + found->valueOffset); diff --git a/src/text/Text.h b/src/text/Text.h index ed978a8b..ab6d1809 100644 --- a/src/text/Text.h +++ b/src/text/Text.h @@ -7,7 +7,7 @@ void TextCopy(wchar *dst, const wchar *src); struct CKeyEntry { -#ifdef FIX_BUGS +#if defined(FIX_BUGS) || defined(FIX_BUGS_64) uint32 valueOffset; #else wchar *value; @@ -30,7 +30,7 @@ public: void Unload(void); void Update(wchar *chars); CKeyEntry *BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high); -#ifdef FIX_BUGS +#if defined (FIX_BUGS) || defined(FIX_BUGS_64) wchar *Search(const char *key, wchar *data); #else wchar *Search(const char *key); From b9dc81d600004f59022e0dddcd46f247da78b3df Mon Sep 17 00:00:00 2001 From: shfil Date: Wed, 13 Jan 2021 12:22:55 +0100 Subject: [PATCH 098/152] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d40a6229..b9e447d3 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ such that we have a working game at all times. ## Building from Source -Before starting you may want to point GTA_III_RE_DIR environment variable to GTA3 root folder, if you want executable to be moved there via post-build script. +Before starting you may want to point GTA_III_RE_DIR environment variable to GTA3 root folder, if you want executable to be moved there via post-build script. (premake)
Linux Premake From 7c3e43aa2ed659a84a83a50a6d55d36b6ae614ba Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 13 Jan 2021 13:01:11 +0100 Subject: [PATCH 099/152] rename m_vehEnterType -> m_vehDoor --- src/core/Camera.cpp | 4 +- src/core/PlayerInfo.cpp | 4 +- src/peds/Ped.cpp | 98 ++++++++++----------- src/peds/Ped.h | 2 +- src/peds/PedAI.cpp | 182 +++++++++++++++++++-------------------- src/vehicles/Train.cpp | 2 +- src/vehicles/Vehicle.cpp | 12 +-- 7 files changed, 152 insertions(+), 152 deletions(-) diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index b46bd2da..7a831068 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -2212,7 +2212,7 @@ CCamera::StartTransition(int16 newMode) while(deltaBeta < -PI) deltaBeta += 2*PI; deltaBeta = Abs(deltaBeta); - door = FindPlayerPed()->m_vehEnterType; + door = FindPlayerPed()->m_vehDoor; if(deltaBeta > HALFPI){ if(((CPed*)pTargetEntity)->m_carInObjective){ if(((CPed*)pTargetEntity)->m_carInObjective->IsUpsideDown()){ @@ -2293,7 +2293,7 @@ CCamera::StartTransition(int16 newMode) } #endif - door = FindPlayerPed()->m_vehEnterType; + door = FindPlayerPed()->m_vehDoor; if(deltaBeta > HALFPI){ if(((CVehicle*)pTargetEntity)->IsUpsideDown()){ if(door == CAR_DOOR_LF || door == CAR_DOOR_LR) // BUG: game checks LF twice diff --git a/src/core/PlayerInfo.cpp b/src/core/PlayerInfo.cpp index 07424736..1af8f924 100644 --- a/src/core/PlayerInfo.cpp +++ b/src/core/PlayerInfo.cpp @@ -222,8 +222,8 @@ CPlayerInfo::Process(void) m_pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, carBelow); } else if (carBelow->IsBoat()) { if (!carBelow->pDriver) { - m_pPed->m_vehEnterType = 0; - m_pPed->SetEnterCar(carBelow, m_pPed->m_vehEnterType); + m_pPed->m_vehDoor = 0; + m_pPed->SetEnterCar(carBelow, m_pPed->m_vehDoor); } } else { m_pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, carBelow); diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 4b55e5ce..c520c4ee 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -105,7 +105,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_fRotationCur = 0.0f; m_headingRate = 15.0f; m_fRotationDest = 0.0f; - m_vehEnterType = CAR_DOOR_LF; + m_vehDoor = CAR_DOOR_LF; m_walkAroundType = 0; m_pCurrentPhysSurface = nil; m_vecOffsetFromPhysSurface = CVector(0.0f, 0.0f, 0.0f); @@ -288,7 +288,7 @@ CPed::~CPed(void) CWorld::Remove(this); CRadar::ClearBlipForEntity(BLIP_CHAR, CPools::GetPedPool()->GetIndex(this)); if (InVehicle()){ - uint8 door_flag = GetCarDoorFlag(m_vehEnterType); + uint8 door_flag = GetCarDoorFlag(m_vehDoor); if (m_pMyVehicle->pDriver == this) m_pMyVehicle->pDriver = nil; else { @@ -3642,11 +3642,11 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) #ifdef NEW_WALK_AROUND_ALGORITHM else { CVector tl = obj->GetMatrix() * CVector(adjustedColMin.x, adjustedColMax.y, 0.0f) - GetPosition(); - if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) { + if (goingToEnterCar && (m_vehDoor == CAR_DOOR_LF || m_vehDoor == CAR_DOOR_LR)) { cornerToGo = tl; m_walkAroundType = 1; - if (m_vehEnterType == CAR_DOOR_LR) + if (m_vehDoor == CAR_DOOR_LR) iWouldPreferGoingBack = 1; } else if(CanWeSeeTheCorner(tl, GetForward())){ cornerToGo = tl; @@ -3680,11 +3680,11 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) else { CVector tr = obj->GetMatrix() * CVector(adjustedColMax.x, adjustedColMax.y, 0.0f) - GetPosition(); if (tr.Magnitude2D() < cornerToGo.Magnitude2D()) { - if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) { + if (goingToEnterCar && (m_vehDoor == CAR_DOOR_RF || m_vehDoor == CAR_DOOR_RR)) { cornerToGo = tr; m_walkAroundType = 2; - if (m_vehEnterType == CAR_DOOR_RR) + if (m_vehDoor == CAR_DOOR_RR) iWouldPreferGoingBack = 2; } else if (CanWeSeeTheCorner(tr, GetForward())) { cornerToGo = tr; @@ -3721,7 +3721,7 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) if (iWouldPreferGoingBack == 2) m_walkAroundType = 4; else if (br.Magnitude2D() < cornerToGo.Magnitude2D()) { - if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) { + if (goingToEnterCar && (m_vehDoor == CAR_DOOR_RF || m_vehDoor == CAR_DOOR_RR)) { cornerToGo = br; m_walkAroundType = 5; } else if (CanWeSeeTheCorner(br, GetForward())) { @@ -3759,7 +3759,7 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) if (iWouldPreferGoingBack == 1) m_walkAroundType = 7; else if (bl.Magnitude2D() < cornerToGo.Magnitude2D()) { - if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) { + if (goingToEnterCar && (m_vehDoor == CAR_DOOR_LF || m_vehDoor == CAR_DOOR_LR)) { cornerToGo = bl; m_walkAroundType = 6; } else if (CanWeSeeTheCorner(bl, GetForward())) { @@ -3789,7 +3789,7 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) if (Abs(angleDiffBtwObjCenterAndForward) >= objTopRightHeading) { if (PI - objTopRightHeading >= Abs(angleDiffBtwObjCenterAndForward)) { if ((angleDiffBtwObjCenterAndForward <= 0.0f || objUpsideDown) && (angleDiffBtwObjCenterAndForward < 0.0f || !objUpsideDown)) { - if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) { + if (goingToEnterCar && (m_vehDoor == CAR_DOOR_RF || m_vehDoor == CAR_DOOR_RR)) { m_walkAroundType = 0; } else { if (CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) >= 0.0f) { @@ -3807,7 +3807,7 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) } } } else { - if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) { + if (goingToEnterCar && (m_vehDoor == CAR_DOOR_LF || m_vehDoor == CAR_DOOR_LR)) { m_walkAroundType = 0; } else { if (CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) <= 0.0f) { @@ -3825,7 +3825,7 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) } } } - } else if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) + } else if (goingToEnterCar && (m_vehDoor == CAR_DOOR_LF || m_vehDoor == CAR_DOOR_LR) || CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) < 0.0f) { if (entityOnTopLeftOfObj == 1 || entityOnTopLeftOfObj && !entityOnTopRightOfObj && !entityOnBottomRightOfObj) { m_walkAroundType = 3; @@ -3833,7 +3833,7 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) } else if (entityOnTopRightOfObj == 1 || entityOnTopRightOfObj && !entityOnTopLeftOfObj && !entityOnBottomLeftOfObj) { m_walkAroundType = 4; } - } else if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) + } else if (goingToEnterCar && (m_vehDoor == CAR_DOOR_LF || m_vehDoor == CAR_DOOR_LR) || CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) > 0.0f) { if (entityOnBottomLeftOfObj == 1 || entityOnBottomLeftOfObj && !entityOnTopRightOfObj && !entityOnBottomRightOfObj) { m_walkAroundType = 2; @@ -3866,13 +3866,13 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) nextWalkAround = 7; } - CVector nextPosToHead = objMat * LocalPosForWalkAround(adjustedColMin, adjustedColMax, nextWalkAround, goingToEnterCar ? m_vehEnterType : 0, goingToEnterCarAndItsVan); + CVector nextPosToHead = objMat * LocalPosForWalkAround(adjustedColMin, adjustedColMax, nextWalkAround, goingToEnterCar ? m_vehDoor : 0, goingToEnterCarAndItsVan); bool nextRouteIsClear = CWorld::GetIsLineOfSightClear(GetPosition(), nextPosToHead, true, true, true, true, true, true, false); if(nextRouteIsClear) m_walkAroundType = nextWalkAround; else { - CVector posToHead = objMat * LocalPosForWalkAround(adjustedColMin, adjustedColMax, m_walkAroundType, goingToEnterCar ? m_vehEnterType : 0, goingToEnterCarAndItsVan); + CVector posToHead = objMat * LocalPosForWalkAround(adjustedColMin, adjustedColMax, m_walkAroundType, goingToEnterCar ? m_vehDoor : 0, goingToEnterCarAndItsVan); bool currentRouteIsClear = CWorld::GetIsLineOfSightClear(GetPosition(), posToHead, true, true, true, true, true, true, false); @@ -3902,15 +3902,15 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) } } - localPosToHead = LocalPosForWalkAround(adjustedColMin, adjustedColMax, m_walkAroundType, goingToEnterCar ? m_vehEnterType : 0, goingToEnterCarAndItsVan); + localPosToHead = LocalPosForWalkAround(adjustedColMin, adjustedColMax, m_walkAroundType, goingToEnterCar ? m_vehDoor : 0, goingToEnterCarAndItsVan); #else if (Abs(angleDiffBtwObjCenterAndForward) < objTopRightHeading) { if (goingToEnterCar) { if (goingToEnterCarAndItsVan) { - if (m_vehEnterType == CAR_DOOR_LR || m_vehEnterType == CAR_DOOR_RR) + if (m_vehDoor == CAR_DOOR_LR || m_vehDoor == CAR_DOOR_RR) return; } - if (m_vehEnterType != CAR_DOOR_LF && m_vehEnterType != CAR_DOOR_LR && (!entityOnBottomRightOfObj || entityOnBottomLeftOfObj)) { + if (m_vehDoor != CAR_DOOR_LF && m_vehDoor != CAR_DOOR_LR && (!entityOnBottomRightOfObj || entityOnBottomLeftOfObj)) { m_fRotationDest = CGeneral::LimitRadianAngle(dirToSet - HALFPI); localPosToHead.x = adjustedColMax.x; localPosToHead.z = 0.0f; @@ -3939,9 +3939,9 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) } else { if (PI - objTopRightHeading >= Abs(angleDiffBtwObjCenterAndForward)) { if (angleDiffBtwObjCenterAndForward <= 0.0f) { - if (!goingToEnterCar || !goingToEnterCarAndItsVan || m_vehEnterType != CAR_DOOR_LR && m_vehEnterType != CAR_DOOR_RR) { + if (!goingToEnterCar || !goingToEnterCarAndItsVan || m_vehDoor != CAR_DOOR_LR && m_vehDoor != CAR_DOOR_RR) { if (goingToEnterCar) { - if (m_vehEnterType == CAR_DOOR_RF || (m_vehEnterType == CAR_DOOR_RR && !goingToEnterCarAndItsVan)) + if (m_vehDoor == CAR_DOOR_RF || (m_vehDoor == CAR_DOOR_RR && !goingToEnterCarAndItsVan)) return; } if (m_walkAroundType == 4 || m_walkAroundType == 3 @@ -3963,14 +3963,14 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) localPosToHead.z = 0.0f; localPosToHead.y = adjustedColMin.y; } - } else if (goingToEnterCar && goingToEnterCarAndItsVan && (m_vehEnterType == CAR_DOOR_LR || m_vehEnterType == CAR_DOOR_RR)) { + } else if (goingToEnterCar && goingToEnterCarAndItsVan && (m_vehDoor == CAR_DOOR_LR || m_vehDoor == CAR_DOOR_RR)) { m_fRotationDest = CGeneral::LimitRadianAngle(PI + dirToSet); localPosToHead.x = adjustedColMin.x; localPosToHead.z = 0.0f; localPosToHead.y = adjustedColMin.y; } else { if (goingToEnterCar) { - if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR && !goingToEnterCarAndItsVan) + if (m_vehDoor == CAR_DOOR_LF || m_vehDoor == CAR_DOOR_LR && !goingToEnterCarAndItsVan) return; } if (m_walkAroundType == 1 || m_walkAroundType == 2 @@ -3988,8 +3988,8 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) } } } else { - if (goingToEnterCar && (!goingToEnterCarAndItsVan || m_vehEnterType != CAR_DOOR_LR && m_vehEnterType != CAR_DOOR_RR)) { - if (m_vehEnterType != CAR_DOOR_LF && m_vehEnterType != CAR_DOOR_LR && (!entityOnTopRightOfObj || entityOnTopLeftOfObj)) { + if (goingToEnterCar && (!goingToEnterCarAndItsVan || m_vehDoor != CAR_DOOR_LR && m_vehDoor != CAR_DOOR_RR)) { + if (m_vehDoor != CAR_DOOR_LF && m_vehDoor != CAR_DOOR_LR && (!entityOnTopRightOfObj || entityOnTopLeftOfObj)) { m_fRotationDest = CGeneral::LimitRadianAngle(dirToSet - HALFPI); localPosToHead.x = adjustedColMax.x; @@ -4162,7 +4162,7 @@ CPed::PedSetOutCarCB(CAnimBlendAssociation *animAssoc, void *arg) #endif ped->bInVehicle = false; - if (veh && veh->IsCar() && !veh->IsRoomForPedToLeaveCar(ped->m_vehEnterType, nil)) { + if (veh && veh->IsCar() && !veh->IsRoomForPedToLeaveCar(ped->m_vehDoor, nil)) { ped->PositionPedOutOfCollision(); } @@ -4247,7 +4247,7 @@ CPed::PedSetOutCarCB(CAnimBlendAssociation *animAssoc, void *arg) } } } - veh->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); + veh->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehDoor); if (veh->pDriver == ped) { veh->RemoveDriver(); #ifndef FIX_BUGS // RemoveDriver does it anyway @@ -4263,7 +4263,7 @@ CPed::PedSetOutCarCB(CAnimBlendAssociation *animAssoc, void *arg) if (veh->bIsBus && !veh->IsUpsideDown() && !veh->IsOnItsSide()) { float angleAfterExit; - if (ped->m_vehEnterType == CAR_DOOR_LF) { + if (ped->m_vehDoor == CAR_DOOR_LF) { angleAfterExit = HALFPI + veh->GetForward().Heading(); } else { angleAfterExit = veh->GetForward().Heading() - HALFPI; @@ -4321,7 +4321,7 @@ CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) vehicle = ped->m_pMyVehicle; if (vehicle) { - vehicle->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); + vehicle->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehDoor); if (vehicle->pDriver == ped) { vehicle->RemoveDriver(); @@ -4541,7 +4541,7 @@ CPed::PedSetInCarCB(CAnimBlendAssociation *animAssoc, void *arg) if (veh->bIsBus) { veh->AddPassenger(ped); } else { - switch (ped->m_vehEnterType) { + switch (ped->m_vehDoor) { case CAR_DOOR_RF: veh->AddPassenger(ped, 0); break; @@ -4567,7 +4567,7 @@ CPed::PedSetInCarCB(CAnimBlendAssociation *animAssoc, void *arg) #endif } - veh->m_nGettingInFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); + veh->m_nGettingInFlags &= ~GetCarDoorFlag(ped->m_vehDoor); if (veh->bIsBus && !veh->m_nGettingInFlags) ((CAutomobile*)veh)->SetBusDoorTimer(1000, 1); @@ -4955,13 +4955,13 @@ void CPed::Idle(void) { CVehicle *veh = m_pMyVehicle; - if (veh && veh->m_nGettingOutFlags && m_vehEnterType) { + if (veh && veh->m_nGettingOutFlags && m_vehDoor) { - if (veh->m_nGettingOutFlags & GetCarDoorFlag(m_vehEnterType)) { + if (veh->m_nGettingOutFlags & GetCarDoorFlag(m_vehDoor)) { if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { - CVector doorPos = GetPositionToOpenCarDoor(veh, m_vehEnterType); + CVector doorPos = GetPositionToOpenCarDoor(veh, m_vehDoor); CVector doorDist = GetPosition() - doorPos; if (doorDist.MagnitudeSqr() < sq(0.5f)) { @@ -6632,7 +6632,7 @@ CPed::SetSeekCar(CVehicle *car, uint32 doorNode) m_pMyVehicle = car; m_pMyVehicle->RegisterReference((CEntity**) &m_pMyVehicle); // m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); - m_vehEnterType = doorNode; + m_vehDoor = doorNode; m_distanceToCountSeekDone = 0.5f; SetPedState(PED_SEEK_CAR); @@ -6649,9 +6649,9 @@ CPed::SeekCar(void) } if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - if (m_vehEnterType && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (m_vehDoor && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { if (IsRoomToBeCarJacked()) { - dest = GetPositionToOpenCarDoor(vehToSeek, m_vehEnterType); + dest = GetPositionToOpenCarDoor(vehToSeek, m_vehDoor); } else if (m_nPedType == PEDTYPE_COP) { dest = GetPositionToOpenCarDoor(vehToSeek, CAR_DOOR_RF); } else { @@ -6736,7 +6736,7 @@ CPed::SeekCar(void) else if (2.0f * vehToSeek->GetColModel()->boundingBox.max.x > distToDestSqr) bCanPedEnterSeekedCar = true; - if (vehToSeek->m_nGettingInFlags & GetCarDoorFlag(m_vehEnterType)) + if (vehToSeek->m_nGettingInFlags & GetCarDoorFlag(m_vehDoor)) bVehEnterDoorIsBlocked = true; else bVehEnterDoorIsBlocked = false; @@ -6746,7 +6746,7 @@ CPed::SeekCar(void) if (!foundBetterPosToSeek) { if (1.5f + GetPosition().z > dest.z && GetPosition().z - 0.5f < dest.z) { if (vehToSeek->IsTrain()) { - SetEnterTrain(vehToSeek, m_vehEnterType); + SetEnterTrain(vehToSeek, m_vehDoor); } else { m_fRotationCur = m_fRotationDest; if (!bVehEnterDoorIsBlocked) { @@ -6764,24 +6764,24 @@ CPed::SeekCar(void) case STATUS_PHYSICS: case STATUS_PLAYER_DISABLED: if (!vehToSeek->bIsBus && (!m_leader || m_leader != vehToSeek->pDriver) && - (m_vehEnterType == CAR_DOOR_LF && vehToSeek->pDriver || m_vehEnterType == CAR_DOOR_RF && vehToSeek->pPassengers[0] || m_vehEnterType == CAR_DOOR_LR && vehToSeek->pPassengers[1] || m_vehEnterType == CAR_DOOR_RR && vehToSeek->pPassengers[2])) { + (m_vehDoor == CAR_DOOR_LF && vehToSeek->pDriver || m_vehDoor == CAR_DOOR_RF && vehToSeek->pPassengers[0] || m_vehDoor == CAR_DOOR_LR && vehToSeek->pPassengers[1] || m_vehDoor == CAR_DOOR_RR && vehToSeek->pPassengers[2])) { SetCarJack(vehToSeek); - if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && m_vehEnterType != CAR_DOOR_LF) + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && m_vehDoor != CAR_DOOR_LF) vehToSeek->pDriver->bFleeAfterExitingCar = true; } else { - SetEnterCar(vehToSeek, m_vehEnterType); + SetEnterCar(vehToSeek, m_vehDoor); } break; case STATUS_ABANDONED: - if (m_vehEnterType == CAR_DOOR_RF && vehToSeek->pPassengers[0]) { + if (m_vehDoor == CAR_DOOR_RF && vehToSeek->pPassengers[0]) { if (vehToSeek->pPassengers[0]->bDontDragMeOutCar) { if (IsPlayer()) - SetEnterCar(vehToSeek, m_vehEnterType); + SetEnterCar(vehToSeek, m_vehDoor); } else { SetCarJack(vehToSeek); } } else { - SetEnterCar(vehToSeek, m_vehEnterType); + SetEnterCar(vehToSeek, m_vehDoor); } break; case STATUS_WRECKED: @@ -7675,7 +7675,7 @@ CPed::SetSolicit(uint32 time) if (CharCreatedBy != MISSION_CHAR && m_carInObjective->m_nNumGettingIn == 0 && CTimer::GetTimeInMilliseconds() < m_objectiveTimer) { - if (m_vehEnterType == CAR_DOOR_LF) { + if (m_vehDoor == CAR_DOOR_LF) { m_fRotationDest = m_carInObjective->GetForward().Heading() - HALFPI; } else { m_fRotationDest = m_carInObjective->GetForward().Heading() + HALFPI; @@ -7696,7 +7696,7 @@ void CPed::Solicit(void) { if (m_standardTimer >= CTimer::GetTimeInMilliseconds() && m_carInObjective) { - CVector doorPos = GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType, 0.0f); + CVector doorPos = GetPositionToOpenCarDoor(m_carInObjective, m_vehDoor, 0.0f); SetMoveState(PEDMOVE_STILL); // Game uses GetAngleBetweenPoints and converts it to radian @@ -7826,7 +7826,7 @@ CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) bool canHeadToRf = NTVF_RF <= 0.0f || NTVF_RF >= HALFPI; // Only order of conditions are different among enterTypes. - if (m_vehEnterType == CAR_DOOR_RR) { + if (m_vehDoor == CAR_DOOR_RR) { if (canHeadToRr) { foundPos = rightRearPos; foundIt = true; @@ -7840,7 +7840,7 @@ CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) foundPos = leftFrontPos; foundIt = true; } - } else if(m_vehEnterType == CAR_DOOR_RF) { + } else if(m_vehDoor == CAR_DOOR_RF) { if (canHeadToRf) { foundPos = rightFrontPos; foundIt = true; @@ -7854,7 +7854,7 @@ CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) foundPos = leftRearPos; foundIt = true; } - } else if (m_vehEnterType == CAR_DOOR_LF) { + } else if (m_vehDoor == CAR_DOOR_LF) { if (canHeadToLf) { foundPos = leftFrontPos; foundIt = true; @@ -7868,7 +7868,7 @@ CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) foundPos = rightRearPos; foundIt = true; } - } else if (m_vehEnterType == CAR_DOOR_LR) { + } else if (m_vehDoor == CAR_DOOR_LR) { if (canHeadToLr) { foundPos = leftRearPos; foundIt = true; diff --git a/src/peds/Ped.h b/src/peds/Ped.h index d27853d6..17f81512 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -443,7 +443,7 @@ public: float m_fRotationCur; float m_fRotationDest; float m_headingRate; - uint16 m_vehEnterType; + uint16 m_vehDoor; int16 m_walkAroundType; CPhysical *m_pCurrentPhysSurface; CVector m_vecOffsetFromPhysSurface; diff --git a/src/peds/PedAI.cpp b/src/peds/PedAI.cpp index 3dc64e2e..6d12c909 100644 --- a/src/peds/PedAI.cpp +++ b/src/peds/PedAI.cpp @@ -1038,19 +1038,19 @@ CPed::ProcessObjective(void) if (m_nPedType == PEDTYPE_COP || vehOfTarget->bIsBus) { GoToNearestDoor(vehOfTarget); } else { - m_vehEnterType = 0; + m_vehDoor = 0; if (m_pedInObjective == vehOfTarget->pDriver || vehOfTarget->bIsBus) { - m_vehEnterType = CAR_DOOR_LF; + m_vehDoor = CAR_DOOR_LF; } else if (m_pedInObjective == vehOfTarget->pPassengers[0]) { - m_vehEnterType = CAR_DOOR_RF; + m_vehDoor = CAR_DOOR_RF; } else if (m_pedInObjective == vehOfTarget->pPassengers[1]) { - m_vehEnterType = CAR_DOOR_LR; + m_vehDoor = CAR_DOOR_LR; } else if (m_pedInObjective == vehOfTarget->pPassengers[2]) { - m_vehEnterType = CAR_DOOR_RR; + m_vehDoor = CAR_DOOR_RR; } // Unused - // GetPositionToOpenCarDoor(vehOfTarget, m_vehEnterType); - SetSeekCar(vehOfTarget, m_vehEnterType); + // GetPositionToOpenCarDoor(vehOfTarget, m_vehDoor); + SetSeekCar(vehOfTarget, m_vehDoor); SetMoveState(PEDMOVE_RUN); } } @@ -1381,26 +1381,26 @@ CPed::ProcessObjective(void) if (m_carInObjective->pPassengers[2] || m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RR) { foundSeat = false; } else { - m_vehEnterType = CAR_DOOR_RR; + m_vehDoor = CAR_DOOR_RR; foundSeat = true; } } else { - m_vehEnterType = CAR_DOOR_LR; + m_vehDoor = CAR_DOOR_LR; foundSeat = true; } } else { - m_vehEnterType = CAR_DOOR_RF; + m_vehDoor = CAR_DOOR_RF; foundSeat = true; } for (int i = 2; i < m_carInObjective->m_nNumMaxPassengers; ++i) { if (!m_carInObjective->pPassengers[i] && !(m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RF)) { - m_vehEnterType = CAR_DOOR_RF; + m_vehDoor = CAR_DOOR_RF; foundSeat = true; } } if (foundSeat) { - SetPosition(GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType)); - SetEnterCar(m_carInObjective, m_vehEnterType); + SetPosition(GetPositionToOpenCarDoor(m_carInObjective, m_vehDoor)); + SetEnterCar(m_carInObjective, m_vehDoor); } } m_objectiveTimer = 0; @@ -2228,7 +2228,7 @@ CPed::PedAnimAlignCB(CAnimBlendAssociation *animAssoc, void *arg) eDoors enterDoor; AnimationId enterAnim; - switch (ped->m_vehEnterType) { + switch (ped->m_vehDoor) { case CAR_DOOR_RF: itsVan = false; enterDoor = DOOR_FRONT_RIGHT; @@ -2305,7 +2305,7 @@ CPed::PedAnimAlignCB(CAnimBlendAssociation *animAssoc, void *arg) ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_QJACK); ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); - veh->pDriver->SetBeingDraggedFromCar(veh, ped->m_vehEnterType, true); + veh->pDriver->SetBeingDraggedFromCar(veh, ped->m_vehDoor, true); if (veh->pDriver->IsGangMember()) veh->pDriver->RegisterThreatWithGangPeds(ped); @@ -2351,7 +2351,7 @@ CPed::PedAnimDoorOpenCB(CAnimBlendAssociation* animAssoc, void* arg) eDoors door; CPed *pedInSeat = nil; - switch (ped->m_vehEnterType) { + switch (ped->m_vehDoor) { case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; pedInSeat = veh->pPassengers[0]; break; case CAR_DOOR_RR: door = DOOR_REAR_RIGHT; pedInSeat = veh->pPassengers[2]; break; case CAR_DOOR_LF: door = DOOR_FRONT_LEFT; pedInSeat = veh->pDriver; break; @@ -2392,21 +2392,21 @@ CPed::PedAnimDoorOpenCB(CAnimBlendAssociation* animAssoc, void* arg) if (veh->m_vecMoveSpeed.Magnitude() > 0.2f) { ped->QuitEnteringCar(); - if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) + if (ped->m_vehDoor != CAR_DOOR_LF && ped->m_vehDoor != CAR_DOOR_LR) ped->SetFall(1000, ANIM_KO_SPIN_R, false); else ped->SetFall(1000, ANIM_KO_SPIN_L, false); return; } - veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_OPEN_LHS, 1.0f); + veh->ProcessOpenDoor(ped->m_vehDoor, ANIM_CAR_OPEN_LHS, 1.0f); - if (ped->m_vehEnterType == CAR_DOOR_LF || ped->m_vehEnterType == CAR_DOOR_RF) + if (ped->m_vehDoor == CAR_DOOR_LF || ped->m_vehDoor == CAR_DOOR_RF) isVan = false; if (ped->m_nPedState != PED_CARJACK || isBus) { AnimationId animToPlay; - if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { + if (ped->m_vehDoor != CAR_DOOR_LF && ped->m_vehDoor != CAR_DOOR_LR) { if (isVan) { animToPlay = ANIM_VAN_GETIN; @@ -2430,7 +2430,7 @@ CPed::PedAnimDoorOpenCB(CAnimBlendAssociation* animAssoc, void* arg) ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); } else { CPed *pedToDragOut = nil; - switch (ped->m_vehEnterType) { + switch (ped->m_vehDoor) { case CAR_DOOR_RF: pedToDragOut = veh->pPassengers[0]; break; case CAR_DOOR_RR: pedToDragOut = veh->pPassengers[2]; break; case CAR_DOOR_LF: pedToDragOut = veh->pDriver; break; @@ -2444,7 +2444,7 @@ CPed::PedAnimDoorOpenCB(CAnimBlendAssociation* animAssoc, void* arg) ((CCopPed*)ped)->SetArrestPlayer(ped->m_pedInObjective); } - if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { + if (ped->m_vehDoor != CAR_DOOR_LF && ped->m_vehDoor != CAR_DOOR_LR) { if (pedToDragOut && !pedToDragOut->bDontDragMeOutCar) { if (pedToDragOut->m_nPedState != PED_DRIVING) { ped->QuitEnteringCar(); @@ -2500,7 +2500,7 @@ CPed::PedAnimDoorOpenCB(CAnimBlendAssociation* animAssoc, void* arg) } if (pedToDragOut) { - pedToDragOut->SetBeingDraggedFromCar(veh, ped->m_vehEnterType, false); + pedToDragOut->SetBeingDraggedFromCar(veh, ped->m_vehDoor, false); if (pedToDragOut->IsGangMember()) pedToDragOut->RegisterThreatWithGangPeds(ped); } @@ -2575,7 +2575,7 @@ CPed::PedAnimPullPedOutCB(CAnimBlendAssociation* animAssoc, void* arg) if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { AnimationId animToPlay; - if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { + if (ped->m_vehDoor != CAR_DOOR_LF && ped->m_vehDoor != CAR_DOOR_LR) { if (isLow) animToPlay = ANIM_CAR_GETIN_LOW_RHS; else @@ -2628,7 +2628,7 @@ CPed::PedAnimGetInCB(CAnimBlendAssociation *animAssoc, void *arg) } return; } - if (ped->IsPlayer() && ped->m_vehEnterType == CAR_DOOR_LF + if (ped->IsPlayer() && ped->m_vehDoor == CAR_DOOR_LF && (Pads[0].GetAccelerate() >= 255.0f || Pads[0].GetBrake() >= 255.0f) && veh->IsCar()) { if (((CAutomobile*)veh)->Damage.GetDoorStatus(DOOR_FRONT_LEFT) != DOOR_STATUS_MISSING) @@ -2641,7 +2641,7 @@ CPed::PedAnimGetInCB(CAnimBlendAssociation *animAssoc, void *arg) bool isBus = !!veh->bIsBus; bool isLow = !!veh->bLowVehicle; eDoors enterDoor; - switch (ped->m_vehEnterType) { + switch (ped->m_vehDoor) { case CAR_DOOR_RF: isVan = false; enterDoor = DOOR_FRONT_RIGHT; @@ -2682,7 +2682,7 @@ CPed::PedAnimGetInCB(CAnimBlendAssociation *animAssoc, void *arg) ped->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 400; return; } - if (driver != ped && ped->m_vehEnterType != CAR_DOOR_LF) { + if (driver != ped && ped->m_vehDoor != CAR_DOOR_LF) { if (!driver->IsPlayer()) { driver->bUsePedNodeSeek = true; driver->m_pLastPathNode = nil; @@ -2749,10 +2749,10 @@ CPed::PedAnimDoorCloseCB(CAnimBlendAssociation *animAssoc, void *arg) bool isLow = !!veh->bLowVehicle; if (!veh->bIsBus) - veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_CLOSEDOOR_LHS, 1.0f); + veh->ProcessOpenDoor(ped->m_vehDoor, ANIM_CAR_CLOSEDOOR_LHS, 1.0f); eDoors door; - switch (ped->m_vehEnterType) { + switch (ped->m_vehDoor) { case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; break; case CAR_DOOR_RR: door = DOOR_REAR_RIGHT; break; case CAR_DOOR_LF: door = DOOR_FRONT_LEFT; break; @@ -2765,7 +2765,7 @@ CPed::PedAnimDoorCloseCB(CAnimBlendAssociation *animAssoc, void *arg) if (door == DOOR_FRONT_LEFT || ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || veh->bIsBus) { PedSetInCarCB(nil, ped); - } else if (ped->m_vehEnterType == CAR_DOOR_RF + } else if (ped->m_vehDoor == CAR_DOOR_RF && (veh->m_nGettingInFlags & CAR_DOOR_FLAG_LF || (veh->pDriver != nil && (veh->pDriver->m_objective != OBJECTIVE_LEAVE_CAR @@ -2902,7 +2902,7 @@ CPed::PedAnimStepOutCarCB(CAnimBlendAssociation* animAssoc, void* arg) veh->m_vecMoveSpeed += CVector(0.001f, 0.001f, 0.001f); veh->m_vecTurnSpeed += CVector(0.001f, 0.001f, 0.001f); if (!veh->bIsBus) - veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_GETOUT_LHS, 1.0f); + veh->ProcessOpenDoor(ped->m_vehDoor, ANIM_CAR_GETOUT_LHS, 1.0f); /* // Duplicate and only in PC for some reason @@ -2912,7 +2912,7 @@ CPed::PedAnimStepOutCarCB(CAnimBlendAssociation* animAssoc, void* arg) } */ eDoors door; - switch (ped->m_vehEnterType) { + switch (ped->m_vehDoor) { case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; break; @@ -3052,7 +3052,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) if (veh->GetUp().z <= -0.8f) vehIsUpsideDown = true; - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { + if (m_vehDoor == CAR_DOOR_RF || m_vehDoor == CAR_DOOR_RR) { if (vehIsUpsideDown) { m_fRotationDest = -PI + veh->GetForward().Heading(); } else if (veh->bIsBus) { @@ -3060,7 +3060,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) } else { m_fRotationDest = veh->GetForward().Heading(); } - } else if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { + } else if (m_vehDoor == CAR_DOOR_LF || m_vehDoor == CAR_DOOR_LR) { if (vehIsUpsideDown) { m_fRotationDest = veh->GetForward().Heading(); } else if (veh->bIsBus) { @@ -3163,7 +3163,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) if (phase == LINE_UP_TO_CAR_2) { neededPos = GetPosition(); } else { - neededPos = GetPositionToOpenCarDoor(veh, m_vehEnterType, seatPosMult); + neededPos = GetPositionToOpenCarDoor(veh, m_vehDoor, seatPosMult); } CVector autoZPos = neededPos; @@ -3273,7 +3273,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) SetHeading(m_fRotationCur); } else { CMatrix vehDoorMat(veh->GetMatrix()); - vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, GetLocalPositionToOpenCarDoor(veh, m_vehEnterType, 0.0f)); + vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, GetLocalPositionToOpenCarDoor(veh, m_vehDoor, 0.0f)); // VC couch anims are inverted, so they're fixing it here. GetMatrix() = vehDoorMat; } @@ -3290,7 +3290,7 @@ CPed::SetCarJack(CVehicle* car) if (car->IsBoat()) return; - switch (m_vehEnterType) { + switch (m_vehDoor) { case CAR_DOOR_RF: doorFlag = CAR_DOOR_FLAG_RF; door = DOOR_FRONT_RIGHT; @@ -3329,7 +3329,7 @@ CPed::SetCarJack(CVehicle* car) if (m_nPedState != PED_CARJACK && !m_pVehicleAnim) if ((car->IsDoorReady(door) || car->IsDoorFullyOpen(door))) if (!car->bIsBeingCarJacked && !(doorFlag & car->m_nGettingInFlags) && !(doorFlag & car->m_nGettingOutFlags)) - SetCarJack_AllClear(car, m_vehEnterType, doorFlag); + SetCarJack_AllClear(car, m_vehDoor, doorFlag); } void @@ -3349,7 +3349,7 @@ CPed::SetCarJack_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) Say(m_nPedType == PEDTYPE_COP ? SOUND_PED_ARREST_COP : SOUND_PED_CAR_JACKING); CVector carEnterPos; - carEnterPos = GetPositionToOpenCarDoor(car, m_vehEnterType); + carEnterPos = GetPositionToOpenCarDoor(car, m_vehDoor); car->m_nGettingInFlags |= doorFlag; m_vecOffsetSeek = carEnterPos - GetPosition(); @@ -3357,7 +3357,7 @@ CPed::SetCarJack_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) float zDiff = Max(0.0f, carEnterPos.z - GetPosition().z); bUsesCollision = false; - if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) + if (m_vehDoor == CAR_DOOR_LF || m_vehDoor == CAR_DOOR_LR) m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, zDiff > 4.4f ? ANIM_CAR_ALIGNHI_LHS : ANIM_CAR_ALIGN_LHS, 4.0f); else m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, zDiff > 4.4f ? ANIM_CAR_ALIGNHI_RHS : ANIM_CAR_ALIGN_RHS, 4.0f); @@ -3377,8 +3377,8 @@ CPed::SetBeingDraggedFromCar(CVehicle *veh, uint32 vehEnterType, bool quickJack) SetMoveState(PEDMOVE_STILL); m_pSeekTarget = veh; m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); - m_vehEnterType = vehEnterType; - if (m_vehEnterType == CAR_DOOR_LF) { + m_vehDoor = vehEnterType; + if (m_vehDoor == CAR_DOOR_LF) { if (veh->pDriver && veh->pDriver->IsPlayer()) veh->SetStatus(STATUS_PLAYER_DISABLED); else @@ -3396,7 +3396,7 @@ CPed::SetBeingDraggedFromCar(CVehicle *veh, uint32 vehEnterType, bool quickJack) Say(SOUND_PED_CAR_JACKED); SetRadioStation(); - veh->m_nGettingOutFlags |= GetCarDoorFlag(m_vehEnterType); + veh->m_nGettingOutFlags |= GetCarDoorFlag(m_vehDoor); } void @@ -3421,7 +3421,7 @@ CPed::BeingDraggedFromCar(void) if (animAssoc) animAssoc->blendDelta = -1000.0f; - if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { + if (m_vehDoor == CAR_DOOR_LF || m_vehDoor == CAR_DOOR_LR) { if (bWillBeQuickJacked) { enterAnim = ANIM_CAR_QJACKED; } else if (m_pMyVehicle->bLowVehicle) { @@ -3429,7 +3429,7 @@ CPed::BeingDraggedFromCar(void) } else { enterAnim = ANIM_CAR_JACKED_LHS; } - } else if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { + } else if (m_vehDoor == CAR_DOOR_RF || m_vehDoor == CAR_DOOR_RR) { if (m_pMyVehicle->bLowVehicle) enterAnim = ANIM_CAR_LJACKED_RHS; else @@ -3454,7 +3454,7 @@ CPed::BeingDraggedFromCar(void) #ifdef VC_PED_PORTS if (m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) { if (m_pMyVehicle) { - m_pMyVehicle->ProcessOpenDoor(m_vehEnterType, NUM_ANIMS, m_pVehicleAnim->currentTime * 5.0f); + m_pMyVehicle->ProcessOpenDoor(m_vehDoor, NUM_ANIMS, m_pVehicleAnim->currentTime * 5.0f); } } #endif @@ -3469,7 +3469,7 @@ CPed::SetEnterCar(CVehicle *car, uint32 unused) } else { uint8 doorFlag; eDoors door; - switch (m_vehEnterType) { + switch (m_vehDoor) { case CAR_DOOR_RF: doorFlag = CAR_DOOR_FLAG_RF; door = DOOR_FRONT_RIGHT; @@ -3496,7 +3496,7 @@ CPed::SetEnterCar(CVehicle *car, uint32 unused) || doorFlag && !car->IsDoorReady(door) && !car->IsDoorFullyOpen(door)) SetMoveState(PEDMOVE_STILL); else - SetEnterCar_AllClear(car, m_vehEnterType, doorFlag); + SetEnterCar_AllClear(car, m_vehDoor, doorFlag); } } @@ -3512,9 +3512,9 @@ CPed::SetEnterCar_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) m_pSeekTarget = car; m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); - m_vehEnterType = doorNode; + m_vehDoor = doorNode; SetPedState(PED_ENTER_CAR); - if (m_vehEnterType == CAR_DOOR_RF && m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && car->m_vehType != VEHICLE_TYPE_BIKE) { + if (m_vehDoor == CAR_DOOR_RF && m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && car->m_vehType != VEHICLE_TYPE_BIKE) { car->bIsBeingCarJacked = true; } @@ -3522,7 +3522,7 @@ CPed::SetEnterCar_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) m_pMyVehicle->RegisterReference((CEntity**) &m_pMyVehicle); ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; bUsesCollision = false; - CVector doorOpenPos = GetPositionToOpenCarDoor(car, m_vehEnterType); + CVector doorOpenPos = GetPositionToOpenCarDoor(car, m_vehDoor); // Because buses have stairs if (!m_pMyVehicle->bIsBus) @@ -3554,13 +3554,13 @@ CPed::SetEnterCar_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) CWaterLevel::AllocateBoatWakeArray(); } else { if (zDiff > 4.4f) { - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + if (m_vehDoor == CAR_DOOR_RF || m_vehDoor == CAR_DOOR_RR) m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_RHS, 4.0f); else m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_LHS, 4.0f); } else { - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + if (m_vehDoor == CAR_DOOR_RF || m_vehDoor == CAR_DOOR_RR) m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_RHS, 4.0f); else m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_LHS, 4.0f); @@ -3577,11 +3577,11 @@ CPed::EnterCar(void) CVehicle *veh = (CVehicle*)m_pSeekTarget; // Not used. - // CVector posForDoor = GetPositionToOpenCarDoor(veh, m_vehEnterType); + // CVector posForDoor = GetPositionToOpenCarDoor(veh, m_vehDoor); if (veh->CanPedOpenLocks(this)) { - if (m_vehEnterType && m_pVehicleAnim) { - veh->ProcessOpenDoor(m_vehEnterType, m_pVehicleAnim->animId, m_pVehicleAnim->currentTime); + if (m_vehDoor && m_pVehicleAnim) { + veh->ProcessOpenDoor(m_vehDoor, m_pVehicleAnim->animId, m_pVehicleAnim->currentTime); } } bIsInTheAir = false; @@ -3616,7 +3616,7 @@ CPed::QuitEnteringCar(void) RestorePreviousObjective(); #endif - veh->m_nGettingInFlags &= ~GetCarDoorFlag(m_vehEnterType); + veh->m_nGettingInFlags &= ~GetCarDoorFlag(m_vehDoor); } bUsesCollision = true; @@ -3681,10 +3681,10 @@ CPed::SetExitBoat(CVehicle *boat) if (boat->GetModelIndex() == MI_SPEEDER && boat->IsUpsideDown()) { m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS, 8.0f); m_pVehicleAnim->SetFinishCallback(PedSetOutCarCB, this); - m_vehEnterType = CAR_DOOR_RF; + m_vehDoor = CAR_DOOR_RF; SetPedState(PED_EXIT_CAR); } else { - m_vehEnterType = CAR_DOOR_RF; + m_vehDoor = CAR_DOOR_RF; PedSetOutCarCB(nil, this); bIsStanding = true; m_pCurSurface = boat; @@ -3703,7 +3703,7 @@ CPed::SetExitBoat(CVehicle *boat) newPos = { 0.0f, 0.0f, boatCol->boundingBox.min.z }; newPos = boat->GetMatrix() * newPos; newPos.z += 1.0f; - m_vehEnterType = CAR_DOOR_RF; + m_vehDoor = CAR_DOOR_RF; PedSetOutCarCB(nil, this); bIsStanding = true; m_pCurSurface = boat; @@ -3714,7 +3714,7 @@ CPed::SetExitBoat(CVehicle *boat) if (boat->m_modelIndex == MI_SKIMMER) newPos.z += 2.0f */ - m_vehEnterType = CAR_DOOR_RF; + m_vehDoor = CAR_DOOR_RF; PedSetOutCarCB(nil, this); bIsStanding = true; m_pCurSurface = boat; @@ -3726,7 +3726,7 @@ CPed::SetExitBoat(CVehicle *boat) newPos.z = FEET_OFFSET + foundCol.point.z; /* // VC specific } else { - m_vehEnterType = CAR_DOOR_RF; + m_vehDoor = CAR_DOOR_RF; PedSetOutCarCB(nil, this); bIsStanding = true; SetMoveState(PEDMOVE_STILL); @@ -3921,7 +3921,7 @@ CPed::SetExitCar(CVehicle *veh, uint32 wantedDoorNode) bUsesCollision = false; m_pSeekTarget = veh; m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); - m_vehEnterType = optedDoorNode; + m_vehDoor = optedDoorNode; SetPedState(PED_EXIT_CAR); if (m_pVehicleAnim && m_pVehicleAnim->flags & ASSOC_PARTIAL) m_pVehicleAnim->blendDelta = -1000.0f; @@ -3963,7 +3963,7 @@ CPed::SetExitCar(CVehicle *veh, uint32 wantedDoorNode) if (veh->GetModelIndex() == MI_YARDIE) addDoorSmoke = true; - switch (m_vehEnterType) { + switch (m_vehDoor) { case CAR_DOOR_RF: if (veh->bIsBus) { m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_COACH_OUT_L); @@ -4012,7 +4012,7 @@ CPed::SetExitCar(CVehicle *veh, uint32 wantedDoorNode) break; } if (!bBusJacked) { - switch (m_vehEnterType) { + switch (m_vehDoor) { case CAR_DOOR_RF: veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_RF; break; @@ -4031,9 +4031,9 @@ CPed::SetExitCar(CVehicle *veh, uint32 wantedDoorNode) } m_pVehicleAnim->SetFinishCallback(PedAnimStepOutCarCB, this); } else { - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { + if (m_vehDoor == CAR_DOOR_RF || m_vehDoor == CAR_DOOR_RR) { m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS2); - } else if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { + } else if (m_vehDoor == CAR_DOOR_LF || m_vehDoor == CAR_DOOR_LR) { m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS); } m_pVehicleAnim->SetFinishCallback(PedSetOutCarCB, this); @@ -4062,7 +4062,7 @@ CPed::ExitCar(void) AnimationId exitAnim = (AnimationId) m_pVehicleAnim->animId; float animTime = m_pVehicleAnim->currentTime; - m_pMyVehicle->ProcessOpenDoor(m_vehEnterType, exitAnim, animTime); + m_pMyVehicle->ProcessOpenDoor(m_vehDoor, exitAnim, animTime); if (m_pSeekTarget) { // Car is upside down @@ -4123,10 +4123,10 @@ void CPed::GetNearestDoor(CVehicle *veh, CVector &posToOpen) { CVector *enterOffset = nil; - if (m_vehEnterType == CAR_DOOR_LF && veh->pDriver - || m_vehEnterType == CAR_DOOR_RF && veh->pPassengers[0] - || m_vehEnterType == CAR_DOOR_LR && veh->pPassengers[1] - || m_vehEnterType == CAR_DOOR_RR && veh->pPassengers[2]) + if (m_vehDoor == CAR_DOOR_LF && veh->pDriver + || m_vehDoor == CAR_DOOR_RF && veh->pPassengers[0] + || m_vehDoor == CAR_DOOR_LR && veh->pPassengers[1] + || m_vehDoor == CAR_DOOR_RR && veh->pPassengers[2]) { enterOffset = &vecPedQuickDraggedOutCarAnimOffset; } @@ -4138,10 +4138,10 @@ CPed::GetNearestDoor(CVehicle *veh, CVector &posToOpen) if ((lfPos - GetPosition()).MagnitudeSqr2D() < (rfPos - GetPosition()).MagnitudeSqr2D()) { if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { - m_vehEnterType = CAR_DOOR_LF; + m_vehDoor = CAR_DOOR_LF; posToOpen = lfPos; } else if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, enterOffset)) { - m_vehEnterType = CAR_DOOR_RF; + m_vehDoor = CAR_DOOR_RF; posToOpen = rfPos; } } else { @@ -4154,14 +4154,14 @@ CPed::GetNearestDoor(CVehicle *veh, CVector &posToOpen) && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset) || (veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { - m_vehEnterType = CAR_DOOR_LF; + m_vehDoor = CAR_DOOR_LF; posToOpen = lfPos; } else { - m_vehEnterType = CAR_DOOR_RF; + m_vehDoor = CAR_DOOR_RF; posToOpen = rfPos; } } else if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { - m_vehEnterType = CAR_DOOR_LF; + m_vehDoor = CAR_DOOR_LF; posToOpen = lfPos; } } @@ -4177,7 +4177,7 @@ CPed::GetNearestPassengerDoor(CVehicle *veh, CVector &posToOpen) switch (veh->GetModelIndex()) { case MI_BUS: - m_vehEnterType = CAR_DOOR_RF; + m_vehDoor = CAR_DOOR_RF; posToOpen = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF); return true; case MI_RHINO: @@ -4220,15 +4220,15 @@ CPed::GetNearestPassengerDoor(CVehicle *veh, CVector &posToOpen) CVector2D nextToCompare = rfPosDist; posToOpen = rfPos; - m_vehEnterType = CAR_DOOR_RF; + m_vehDoor = CAR_DOOR_RF; if (lrPosDist.MagnitudeSqr() < nextToCompare.MagnitudeSqr()) { - m_vehEnterType = CAR_DOOR_LR; + m_vehDoor = CAR_DOOR_LR; posToOpen = lrPos; nextToCompare = lrPosDist; } if (rrPosDist.MagnitudeSqr() < nextToCompare.MagnitudeSqr()) { - m_vehEnterType = CAR_DOOR_RR; + m_vehDoor = CAR_DOOR_RR; posToOpen = rrPos; } return canEnter; @@ -4335,7 +4335,7 @@ CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *animAssoc, void ped->bUsesCollision = true; ped->RestartNonPartialAnims(); draggedOutOffset = vecPedQuickDraggedOutCarAnimOffset; - if (ped->m_vehEnterType == CAR_DOOR_RF || ped->m_vehEnterType == CAR_DOOR_RR) + if (ped->m_vehDoor == CAR_DOOR_RF || ped->m_vehDoor == CAR_DOOR_RR) draggedOutOffset.x = -draggedOutOffset.x; finalPos = Multiply3x3(pedMat, draggedOutOffset) + ped->GetPosition(); @@ -4348,7 +4348,7 @@ CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *animAssoc, void ped->m_fRotationCur = ped->m_fRotationDest; ped->CalculateNewOrientation(); - if (!veh->IsRoomForPedToLeaveCar(ped->m_vehEnterType, &vecPedQuickDraggedOutCarAnimOffset)) + if (!veh->IsRoomForPedToLeaveCar(ped->m_vehDoor, &vecPedQuickDraggedOutCarAnimOffset)) ped->PositionPedOutOfCollision(); } @@ -4425,7 +4425,7 @@ CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* animAssoc, void* arg) ped->RestartNonPartialAnims(); bool itsRearDoor = false; - if (ped->m_vehEnterType == CAR_DOOR_RF || ped->m_vehEnterType == CAR_DOOR_RR) + if (ped->m_vehDoor == CAR_DOOR_RF || ped->m_vehDoor == CAR_DOOR_RR) itsRearDoor = true; CMatrix pedMat(ped->GetMatrix()); @@ -4438,7 +4438,7 @@ CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* animAssoc, void* arg) ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); ped->SetPosition(posAfterBeingDragged); - if (ped->m_pMyVehicle && !ped->m_pMyVehicle->IsRoomForPedToLeaveCar(ped->m_vehEnterType, &vecPedDraggedOutCarAnimOffset)) { + if (ped->m_pMyVehicle && !ped->m_pMyVehicle->IsRoomForPedToLeaveCar(ped->m_vehDoor, &vecPedDraggedOutCarAnimOffset)) { ped->PositionPedOutOfCollision(); } @@ -4516,7 +4516,7 @@ CPed::GetNearestTrainDoor(CVehicle *train, CVector &doorPos) CVehicleModelInfo* trainModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(train->m_modelIndex); CMatrix trainMat = CMatrix(train->GetMatrix()); - doorPos = trainModel->m_positions[m_vehEnterType]; + doorPos = trainModel->m_positions[m_vehDoor]; doorPos.x -= 1.5f; doorPos = Multiply3x3(trainMat, doorPos); doorPos += train->GetPosition(); @@ -4566,17 +4566,17 @@ CPed::GetNearestTrainPedPosition(CVehicle *train, CVector &enterPos) if (distMidEntry < distLeftEntry) { if (distMidEntry < distRightEntry) { enterPos = midEntryPos; - m_vehEnterType = TRAIN_POS_MID_ENTRY; + m_vehDoor = TRAIN_POS_MID_ENTRY; } else { enterPos = rightEntryPos; - m_vehEnterType = TRAIN_POS_RIGHT_ENTRY; + m_vehDoor = TRAIN_POS_RIGHT_ENTRY; } } else if (distRightEntry < distLeftEntry) { enterPos = rightEntryPos; - m_vehEnterType = TRAIN_POS_RIGHT_ENTRY; + m_vehDoor = TRAIN_POS_RIGHT_ENTRY; } else { enterPos = leftEntryPos; - m_vehEnterType = TRAIN_POS_LEFT_ENTRY; + m_vehDoor = TRAIN_POS_LEFT_ENTRY; } return 1; @@ -5198,7 +5198,7 @@ CPed::SeekBoatPosition(void) m_vecSeekPos = boatMat * enterOffset; if (Seek()) { // We arrived to the boat - m_vehEnterType = 0; + m_vehDoor = 0; SetEnterCar(m_carInObjective, 0); } } else diff --git a/src/vehicles/Train.cpp b/src/vehicles/Train.cpp index 4250f6f4..be546c70 100644 --- a/src/vehicles/Train.cpp +++ b/src/vehicles/Train.cpp @@ -373,7 +373,7 @@ CTrain::TrainHitStuff(CPtrList &list) void CTrain::AddPassenger(CPed *ped) { - int i = ped->m_vehEnterType; + int i = ped->m_vehDoor; if((i == TRAIN_POS_LEFT_ENTRY || i == TRAIN_POS_MID_ENTRY || i == TRAIN_POS_RIGHT_ENTRY) && pPassengers[i] == nil){ pPassengers[i] = ped; m_nNumPassengers++; diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index 465d9a9e..6696f4a6 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -794,13 +794,13 @@ CVehicle::ShufflePassengersToMakeSpace(void) if (!pPassengers[2] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RR)) { pPassengers[2] = pPassengers[1]; pPassengers[1] = nil; - pPassengers[2]->m_vehEnterType = CAR_DOOR_RR; + pPassengers[2]->m_vehDoor = CAR_DOOR_RR; return true; } if (!pPassengers[0] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RF)) { pPassengers[0] = pPassengers[1]; pPassengers[1] = nil; - pPassengers[0]->m_vehEnterType = CAR_DOOR_RF; + pPassengers[0]->m_vehDoor = CAR_DOOR_RF; return true; } return false; @@ -811,13 +811,13 @@ CVehicle::ShufflePassengersToMakeSpace(void) if (!pPassengers[1] && !(m_nGettingInFlags & CAR_DOOR_FLAG_LR)) { pPassengers[1] = pPassengers[2]; pPassengers[2] = nil; - pPassengers[1]->m_vehEnterType = CAR_DOOR_LR; + pPassengers[1]->m_vehDoor = CAR_DOOR_LR; return true; } if (!pPassengers[0] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RF)) { pPassengers[0] = pPassengers[2]; pPassengers[2] = nil; - pPassengers[0]->m_vehEnterType = CAR_DOOR_RF; + pPassengers[0]->m_vehDoor = CAR_DOOR_RF; return true; } return false; @@ -828,13 +828,13 @@ CVehicle::ShufflePassengersToMakeSpace(void) if (!pPassengers[1] && !(m_nGettingInFlags & CAR_DOOR_FLAG_LR)) { pPassengers[1] = pPassengers[0]; pPassengers[0] = nil; - pPassengers[1]->m_vehEnterType = CAR_DOOR_LR; + pPassengers[1]->m_vehDoor = CAR_DOOR_LR; return true; } if (!pPassengers[2] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RR)) { pPassengers[2] = pPassengers[0]; pPassengers[0] = nil; - pPassengers[2]->m_vehEnterType = CAR_DOOR_RR; + pPassengers[2]->m_vehDoor = CAR_DOOR_RR; return true; } return false; From 083aa700e99c922a741fda947a9a1502fb1242cc Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 13 Jan 2021 13:06:31 +0100 Subject: [PATCH 100/152] anim velocity union --- src/animation/AnimBlendClumpData.cpp | 2 +- src/animation/AnimBlendClumpData.h | 6 ++++-- src/animation/FrameUpdate.cpp | 28 ++++++++++++++-------------- src/objects/CutsceneObject.cpp | 2 +- src/peds/Ped.cpp | 3 +-- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/animation/AnimBlendClumpData.cpp b/src/animation/AnimBlendClumpData.cpp index 92515427..702ee811 100644 --- a/src/animation/AnimBlendClumpData.cpp +++ b/src/animation/AnimBlendClumpData.cpp @@ -7,7 +7,7 @@ CAnimBlendClumpData::CAnimBlendClumpData(void) { numFrames = 0; - velocity = nil; + velocity2d = nil; frames = nil; link.Init(); } diff --git a/src/animation/AnimBlendClumpData.h b/src/animation/AnimBlendClumpData.h index fc74b42d..acfd006f 100644 --- a/src/animation/AnimBlendClumpData.h +++ b/src/animation/AnimBlendClumpData.h @@ -3,7 +3,6 @@ #include "AnimBlendList.h" -// TODO: put somewhere else struct AnimBlendFrameData { enum { @@ -38,7 +37,10 @@ public: #ifdef PED_SKIN int32 modelNumber; // doesn't seem to be used #endif - CVector *velocity; + union { + CVector2D *velocity2d; + CVector *velocity3d; + }; // order of frames is determined by RW hierarchy AnimBlendFrameData *frames; diff --git a/src/animation/FrameUpdate.cpp b/src/animation/FrameUpdate.cpp index 6e5501cb..c7d347b3 100644 --- a/src/animation/FrameUpdate.cpp +++ b/src/animation/FrameUpdate.cpp @@ -29,7 +29,7 @@ FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg) AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg; if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION && - gpAnimBlendClump->velocity){ + gpAnimBlendClump->velocity2d){ if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION_3D) FrameUpdateCallBackWith3dVelocityExtractionNonSkinned(frame, arg); else @@ -138,11 +138,11 @@ FrameUpdateCallBackWithVelocityExtractionNonSkinned(AnimBlendFrameData *frame, v } if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ - gpAnimBlendClump->velocity->x = transx - curx; - gpAnimBlendClump->velocity->y = transy - cury; + gpAnimBlendClump->velocity2d->x = transx - curx; + gpAnimBlendClump->velocity2d->y = transy - cury; if(looped){ - gpAnimBlendClump->velocity->x += endx; - gpAnimBlendClump->velocity->y += endy; + gpAnimBlendClump->velocity2d->x += endx; + gpAnimBlendClump->velocity2d->y += endy; } mat->pos.x = pos.x - transx; mat->pos.y = pos.y - transy; @@ -218,9 +218,9 @@ FrameUpdateCallBackWith3dVelocityExtractionNonSkinned(AnimBlendFrameData *frame, } if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ - *gpAnimBlendClump->velocity = trans - cur; + *gpAnimBlendClump->velocity3d = trans - cur; if(looped) - *gpAnimBlendClump->velocity += end; + *gpAnimBlendClump->velocity3d += end; mat->pos.x = (pos - trans).x + frame->resetPos.x; mat->pos.y = (pos - trans).y + frame->resetPos.y; mat->pos.z = (pos - trans).z + frame->resetPos.z; @@ -241,7 +241,7 @@ FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg) AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg; if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION && - gpAnimBlendClump->velocity){ + gpAnimBlendClump->velocity2d){ if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION_3D) FrameUpdateCallBackWith3dVelocityExtractionSkinned(frame, arg); else @@ -353,11 +353,11 @@ FrameUpdateCallBackWithVelocityExtractionSkinned(AnimBlendFrameData *frame, void } if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ - gpAnimBlendClump->velocity->x = transx - curx; - gpAnimBlendClump->velocity->y = transy - cury; + gpAnimBlendClump->velocity2d->x = transx - curx; + gpAnimBlendClump->velocity2d->y = transy - cury; if(looped){ - gpAnimBlendClump->velocity->x += endx; - gpAnimBlendClump->velocity->y += endy; + gpAnimBlendClump->velocity2d->x += endx; + gpAnimBlendClump->velocity2d->y += endy; } xform->t.x = pos.x - transx; xform->t.y = pos.y - transy; @@ -433,9 +433,9 @@ FrameUpdateCallBackWith3dVelocityExtractionSkinned(AnimBlendFrameData *frame, vo } if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ - *gpAnimBlendClump->velocity = trans - cur; + *gpAnimBlendClump->velocity3d = trans - cur; if(looped) - *gpAnimBlendClump->velocity += end; + *gpAnimBlendClump->velocity3d += end; xform->t.x = (pos - trans).x + frame->resetPos.x; xform->t.y = (pos - trans).y + frame->resetPos.y; xform->t.z = (pos - trans).z + frame->resetPos.z; diff --git a/src/objects/CutsceneObject.cpp b/src/objects/CutsceneObject.cpp index 5c10d37d..64e57805 100644 --- a/src/objects/CutsceneObject.cpp +++ b/src/objects/CutsceneObject.cpp @@ -35,7 +35,7 @@ CCutsceneObject::SetModelIndex(uint32 id) CEntity::SetModelIndex(id); assert(RwObjectGetType(m_rwObject) == rpCLUMP); RpAnimBlendClumpInit((RpClump*)m_rwObject); - (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = &m_vecMoveSpeed; + (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity3d = &m_vecMoveSpeed; (*RPANIMBLENDCLUMPDATA(m_rwObject))->frames[0].flag |= AnimBlendFrameData::VELOCITY_EXTRACTION_3D; } diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index c520c4ee..0797d196 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -330,8 +330,7 @@ CPed::SetModelIndex(uint32 mi) m_animGroup = (AssocGroupId) modelInfo->m_animGroup; CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE); - // This is a mistake by R*, velocity is CVector, whereas m_vecAnimMoveDelta is CVector2D. - (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = (CVector*) &m_vecAnimMoveDelta; + (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity2d = &m_vecAnimMoveDelta; #ifdef PED_SKIN if(modelInfo->GetHitColModel() == nil) From 6aab948be2fe3a1c09984ced7a48e56ec145c23e Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 13 Jan 2021 13:41:24 +0100 Subject: [PATCH 101/152] more renames --- src/peds/Ped.cpp | 53 ++++++++++++++++++++++--------------------- src/peds/Ped.h | 4 ++-- src/peds/PedAI.cpp | 4 ++-- src/peds/PedFight.cpp | 12 +++++----- 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 0797d196..269aa084 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -97,9 +97,9 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_attackTimer = 0; m_timerUnused = 0; m_lookTimer = 0; - m_standardTimer = 0; + m_chatTimer = 0; m_shootTimer = 0; - m_hitRecoverTimer = 0; + m_carJackTimer = 0; m_duckAndCoverTimer = 0; m_moved = CVector2D(0.0f, 0.0f); m_fRotationCur = 0.0f; @@ -1141,7 +1141,8 @@ CPed::ScanForInterestingStuff(void) if (LookForInterestingNodes()) return; - if (m_nPedType == PEDTYPE_CRIMINAL && m_hitRecoverTimer < CTimer::GetTimeInMilliseconds()) { + if (m_nPedType == PEDTYPE_CRIMINAL && m_carJackTimer < CTimer::GetTimeInMilliseconds()) { + // Find a car to steal or a ped to mug if we haven't already decided to steal a car if (CGeneral::GetRandomNumber() % 100 < 10) { int mostExpensiveVehAround = -1; int bestMonetaryValue = 0; @@ -1164,10 +1165,10 @@ CPed::ScanForInterestingStuff(void) } if (bestMonetaryValue > 2000 && mostExpensiveVehAround != -1 && vehicles[mostExpensiveVehAround]) { SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, vehicles[mostExpensiveVehAround]); - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; + m_carJackTimer = CTimer::GetTimeInMilliseconds() + 5000; return; } - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; + m_carJackTimer = CTimer::GetTimeInMilliseconds() + 5000; } else if (m_objective != OBJECTIVE_MUG_CHAR && !(CGeneral::GetRandomNumber() & 7)) { CPed *charToMug = nil; for (int i = 0; i < m_numNearPeds; ++i) { @@ -1189,22 +1190,22 @@ CPed::ScanForInterestingStuff(void) if (charToMug) SetObjective(OBJECTIVE_MUG_CHAR, charToMug); - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; + m_carJackTimer = CTimer::GetTimeInMilliseconds() + 5000; } } if (m_nPedState == PED_WANDER_PATH) { #ifndef VC_PED_PORTS - if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { + if (CTimer::GetTimeInMilliseconds() > m_chatTimer) { // += 2 is weird for (int i = 0; i < m_numNearPeds; i += 2) { if (m_nearPeds[i]->m_nPedState == PED_WANDER_PATH && WillChat(m_nearPeds[i])) { if (CGeneral::GetRandomNumberInRange(0, 100) >= 100) - m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; + m_chatTimer = CTimer::GetTimeInMilliseconds() + 30000; else { if ((GetPosition() - m_nearPeds[i]->GetPosition()).Magnitude() >= 1.8f) { - m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; + m_chatTimer = CTimer::GetTimeInMilliseconds() + 30000; } else if (CanSeeEntity(m_nearPeds[i])) { int time = CGeneral::GetRandomNumber() % 4000 + 10000; SetChat(m_nearPeds[i], time); @@ -1217,7 +1218,7 @@ CPed::ScanForInterestingStuff(void) } #else if (CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < 0.5f) { - if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { + if (CTimer::GetTimeInMilliseconds() > m_chatTimer) { for (int i = 0; i < m_numNearPeds; i ++) { if (m_nearPeds[i] && m_nearPeds[i]->m_nPedState == PED_WANDER_PATH) { if ((GetPosition() - m_nearPeds[i]->GetPosition()).Magnitude() < 1.8f @@ -1234,7 +1235,7 @@ CPed::ScanForInterestingStuff(void) } } } else { - m_standardTimer = CTimer::GetTimeInMilliseconds() + 200; + m_chatTimer = CTimer::GetTimeInMilliseconds() + 200; } #endif } @@ -5604,7 +5605,7 @@ CPed::ClearFlee(void) { RestorePreviousState(); bUsePedNodeSeek = false; - m_standardTimer = 0; + m_chatTimer = 0; m_fleeTimer = 0; } @@ -5641,7 +5642,7 @@ CPed::Flee(void) if (m_nPedStateTimer < CTimer::GetTimeInMilliseconds() && m_collidingThingTimer < CTimer::GetTimeInMilliseconds()) { - if (m_pNextPathNode && CTimer::GetTimeInMilliseconds() > m_standardTimer) { + if (m_pNextPathNode && CTimer::GetTimeInMilliseconds() > m_chatTimer) { curDirectionShouldBe = CGeneral::GetNodeHeadingFromVector(GetPosition().x - ms_vec2DFleePosition.x, GetPosition().y - ms_vec2DFleePosition.y); if (m_nPathDir < curDirectionShouldBe) @@ -5684,7 +5685,7 @@ CPed::Flee(void) if (m_pNextPathNode && m_pNextPathNode != realLastNode && m_pNextPathNode != m_pLastPathNode && curDirectionShouldBe - nextDirection != 4) { m_nPathDir = nextDirection; - m_standardTimer = CTimer::GetTimeInMilliseconds() + 2000; + m_chatTimer = CTimer::GetTimeInMilliseconds() + 2000; } else { bUsePedNodeSeek = false; SetMoveState(PEDMOVE_RUN); @@ -6398,7 +6399,7 @@ CPed::SetChat(CEntity *chatWith, uint32 time) m_lookTimer = 0; #endif SetLookFlag(chatWith, true); - m_standardTimer = CTimer::GetTimeInMilliseconds() + time; + m_chatTimer = CTimer::GetTimeInMilliseconds() + time; m_lookTimer = CTimer::GetTimeInMilliseconds() + 3000; } @@ -6450,9 +6451,9 @@ CPed::Chat(void) Say(SOUND_PED_CHAT); } } - if (m_standardTimer && CTimer::GetTimeInMilliseconds() > m_standardTimer) { + if (m_chatTimer && CTimer::GetTimeInMilliseconds() > m_chatTimer) { ClearChat(); - m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; + m_chatTimer = CTimer::GetTimeInMilliseconds() + 30000; } } @@ -6659,7 +6660,7 @@ CPed::SeekCar(void) } else GetNearestDoor(vehToSeek, dest); } else { - if (m_hitRecoverTimer > CTimer::GetTimeInMilliseconds()) { + if (m_carJackTimer > CTimer::GetTimeInMilliseconds()) { SetMoveState(PEDMOVE_STILL); return; } @@ -6703,7 +6704,7 @@ CPed::SeekCar(void) if (IsPlayer()) { ClearObjective(); } else if (CharCreatedBy == RANDOM_CHAR) { - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 30000; + m_carJackTimer = CTimer::GetTimeInMilliseconds() + 30000; } SetMoveState(PEDMOVE_STILL); TheCamera.ClearPlayerWeaponMode(); @@ -7038,7 +7039,7 @@ CPed::LookForInterestingNodes(void) C2dEffect *effect; CMatrix *objMat; - if ((CTimer::GetFrameCounter() + (m_randomSeed % 256)) & 7 || CTimer::GetTimeInMilliseconds() <= m_standardTimer) { + if ((CTimer::GetFrameCounter() + (m_randomSeed % 256)) & 7 || CTimer::GetTimeInMilliseconds() <= m_chatTimer) { return false; } bool found = false; @@ -7148,7 +7149,7 @@ CPed::LookForInterestingNodes(void) float angleToFace = CGeneral::GetRadianAngleBetweenPoints(effectFrontLocal.x, effectFrontLocal.y, 0.0f, 0.0f); randVal = CGeneral::GetRandomNumber() % 256; if (randVal <= m_randomSeed % 256) { - m_standardTimer = CTimer::GetTimeInMilliseconds() + 2000; + m_chatTimer = CTimer::GetTimeInMilliseconds() + 2000; SetLookFlag(angleToFace, true); SetLookTimer(1000); return false; @@ -7224,7 +7225,7 @@ CPed::SetWaitState(eWaitState state, void *time) if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) { ClearObjective(); RestorePreviousState(); - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 30000; + m_carJackTimer = CTimer::GetTimeInMilliseconds() + 30000; } break; case WAITSTATE_TURN180: @@ -7253,7 +7254,7 @@ CPed::SetWaitState(eWaitState state, void *time) if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) { ClearObjective(); RestorePreviousState(); - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 30000; + m_carJackTimer = CTimer::GetTimeInMilliseconds() + 30000; } break; case WAITSTATE_LOOK_ABOUT: @@ -7681,7 +7682,7 @@ CPed::SetSolicit(uint32 time) } if (Abs(m_fRotationDest - m_fRotationCur) < HALFPI) { - m_standardTimer = CTimer::GetTimeInMilliseconds() + time; + m_chatTimer = CTimer::GetTimeInMilliseconds() + time; if(!m_carInObjective->bIsVan && !m_carInObjective->bIsBus) m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_HOOKERTALK, 4.0f); @@ -7694,7 +7695,7 @@ CPed::SetSolicit(uint32 time) void CPed::Solicit(void) { - if (m_standardTimer >= CTimer::GetTimeInMilliseconds() && m_carInObjective) { + if (m_chatTimer >= CTimer::GetTimeInMilliseconds() && m_carInObjective) { CVector doorPos = GetPositionToOpenCarDoor(m_carInObjective, m_vehDoor, 0.0f); SetMoveState(PEDMOVE_STILL); @@ -7758,7 +7759,7 @@ CPed::SetBuyIceCream(void) m_fRotationDest = m_carInObjective->GetForward().Heading() - HALFPI; if (Abs(m_fRotationDest - m_fRotationCur) < HALFPI) { - m_standardTimer = CTimer::GetTimeInMilliseconds() + 3000; + m_chatTimer = CTimer::GetTimeInMilliseconds() + 3000; SetPedState(PED_BUY_ICECREAM); } } diff --git a/src/peds/Ped.h b/src/peds/Ped.h index 17f81512..c2641a0f 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -493,10 +493,10 @@ public: uint32 m_leaveCarTimer; uint32 m_getUpTimer; uint32 m_lookTimer; - uint32 m_standardTimer; + uint32 m_chatTimer; uint32 m_attackTimer; uint32 m_shootTimer; // shooting is a part of attack - uint32 m_hitRecoverTimer; + uint32 m_carJackTimer; uint32 m_objectiveTimer; uint32 m_duckTimer; uint32 m_duckAndCoverTimer; diff --git a/src/peds/PedAI.cpp b/src/peds/PedAI.cpp index 6d12c909..46476e55 100644 --- a/src/peds/PedAI.cpp +++ b/src/peds/PedAI.cpp @@ -1754,7 +1754,7 @@ CPed::ProcessObjective(void) if (bInVehicle) { bScriptObjectiveCompleted = true; RestorePreviousObjective(); - } else if (m_hitRecoverTimer < CTimer::GetTimeInMilliseconds()) { + } else if (m_carJackTimer < CTimer::GetTimeInMilliseconds()) { CVehicle *carToSteal = nil; float closestCarDist = ENTER_CAR_MAX_DIST; CVector pos = GetPosition(); @@ -1780,7 +1780,7 @@ CPed::ProcessObjective(void) } if (carToSteal) { SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, carToSteal); - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; + m_carJackTimer = CTimer::GetTimeInMilliseconds() + 5000; } else { RestorePreviousObjective(); RestorePreviousState(); diff --git a/src/peds/PedFight.cpp b/src/peds/PedFight.cpp index b57f1943..8625f23e 100644 --- a/src/peds/PedFight.cpp +++ b/src/peds/PedFight.cpp @@ -1793,7 +1793,7 @@ CPed::SetInvestigateEvent(eEventType event, CVector2D pos, float distanceToCount SetStoredState(); bFindNewNodeAfterStateRestore = false; SetPedState(PED_INVESTIGATE); - m_standardTimer = CTimer::GetTimeInMilliseconds() + time; + m_chatTimer = CTimer::GetTimeInMilliseconds() + time; m_eventType = event; m_eventOrThreat = pos; m_distanceToCountSeekDone = distanceToCountDone; @@ -1816,13 +1816,13 @@ CPed::InvestigateEvent(void) if (m_nWaitState == WAITSTATE_TURN180) return; - if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { + if (CTimer::GetTimeInMilliseconds() > m_chatTimer) { - if (m_standardTimer) { + if (m_chatTimer) { if (m_eventType < EVENT_ASSAULT_NASTYWEAPON) SetWaitState(WAITSTATE_TURN180, nil); - m_standardTimer = 0; + m_chatTimer = 0; } else { ClearInvestigateEvent(); } @@ -1882,7 +1882,7 @@ CPed::InvestigateEvent(void) Say(SOUND_PED_CHAT_EVENT); } else { - m_standardTimer = 0; + m_chatTimer = 0; } } else if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { @@ -2021,7 +2021,7 @@ CPed::ClearInvestigateEvent(void) animAssoc->flags |= ASSOC_DELETEFADEDOUT; } if (m_eventType > EVENT_EXPLOSION) - m_standardTimer = CTimer::GetTimeInMilliseconds() + 15000; + m_chatTimer = CTimer::GetTimeInMilliseconds() + 15000; bGonnaInvestigateEvent = false; m_pEventEntity = nil; From e8727cf4a15014ac179a185a662e70f0a98cde52 Mon Sep 17 00:00:00 2001 From: withmorten Date: Wed, 13 Jan 2021 14:34:58 +0100 Subject: [PATCH 102/152] remove scriptspath from premake --- premake5.lua | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/premake5.lua b/premake5.lua index 0d77ae2c..d4ef5198 100644 --- a/premake5.lua +++ b/premake5.lua @@ -171,11 +171,10 @@ workspace "re3" filter {} - function setpaths (gamepath, exepath, scriptspath) - scriptspath = scriptspath or "" + function setpaths (gamepath, exepath) if (gamepath) then postbuildcommands { - '{COPYFILE} "%{cfg.buildtarget.abspath}" "' .. gamepath .. scriptspath .. '%{cfg.buildtarget.name}"' + '{COPYFILE} "%{cfg.buildtarget.abspath}" "' .. gamepath .. '%{cfg.buildtarget.name}"' } debugdir (gamepath) if (exepath) then @@ -185,7 +184,6 @@ workspace "re3" debugdir (gamepath .. (dir or "")) end end - --targetdir ("bin/%{prj.name}/" .. scriptspath) end if(_OPTIONS["with-librw"]) then @@ -307,7 +305,7 @@ project "re3" filter {} if(os.getenv("GTA_III_RE_DIR")) then - setpaths("$(GTA_III_RE_DIR)/", "%(cfg.buildtarget.name)", "") + setpaths("$(GTA_III_RE_DIR)/", "%(cfg.buildtarget.name)") end filter "platforms:win*" From 7f15e11b1bdc9d4f93b9ab97130924eeedaf0b53 Mon Sep 17 00:00:00 2001 From: erorcun Date: Wed, 13 Jan 2021 16:54:36 +0300 Subject: [PATCH 103/152] fix save loading, hopefully --- src/skel/win/win.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index 388090fc..53844319 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -651,7 +651,7 @@ psInitialize(void) C_PcSave::SetSaveDirectory(_psGetUserFilesFolder()); InitialiseLanguage(); -#if GTA_VERSION >= GTA3_PC_11 +#if GTA_VERSION < GTA3_PC_11 FrontEndMenuManager.LoadSettings(); #endif From a844cbbc3d1dade48a7de6112ae1a9b092d9c3e8 Mon Sep 17 00:00:00 2001 From: erorcun Date: Wed, 13 Jan 2021 23:07:12 +0300 Subject: [PATCH 104/152] hud ammo fix --- src/render/Hud.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index ae7b7eb3..b718c163 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -509,10 +509,10 @@ void CHud::Draw() /* DrawAmmo */ - uint32 AmmoAmount = CWeaponInfo::GetWeaponInfo(FindPlayerPed()->GetWeapon()->m_eWeaponType)->m_nAmountofAmmunition; - uint32 AmmoInClip = FindPlayerPed()->m_weapons[FindPlayerPed()->m_currentWeapon].m_nAmmoInClip; - uint32 TotalAmmo = FindPlayerPed()->m_weapons[FindPlayerPed()->m_currentWeapon].m_nAmmoTotal; - uint32 Ammo, Clip; + int32 AmmoAmount = CWeaponInfo::GetWeaponInfo(FindPlayerPed()->GetWeapon()->m_eWeaponType)->m_nAmountofAmmunition; + int32 AmmoInClip = FindPlayerPed()->m_weapons[FindPlayerPed()->m_currentWeapon].m_nAmmoInClip; + int32 TotalAmmo = FindPlayerPed()->m_weapons[FindPlayerPed()->m_currentWeapon].m_nAmmoTotal; + int32 Ammo, Clip; if (AmmoAmount <= 1 || AmmoAmount >= 1000) sprintf(sTemp, "%d", TotalAmmo); @@ -520,18 +520,12 @@ void CHud::Draw() if (WeaponType == WEAPONTYPE_FLAMETHROWER) { Clip = AmmoInClip / 10; - if ((TotalAmmo - AmmoInClip) / 10 <= 9999) - Ammo = (TotalAmmo - AmmoInClip) / 10; - else - Ammo = 9999; + Ammo = Min((TotalAmmo - AmmoInClip) / 10, 9999); } else { Clip = AmmoInClip; - if ((TotalAmmo - AmmoInClip) > 9999) - Ammo = 9999; - else - Ammo = TotalAmmo - AmmoInClip; + Ammo = Min(TotalAmmo - AmmoInClip, 9999); } sprintf(sTemp, "%d-%d", Ammo, Clip); From ad908f5ddead2276cde8c46df10203be36ef30b4 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Thu, 14 Jan 2021 00:16:55 +0300 Subject: [PATCH 105/152] fix --- src/control/Script6.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/Script6.cpp b/src/control/Script6.cpp index 811b537f..31be6987 100644 --- a/src/control/Script6.cpp +++ b/src/control/Script6.cpp @@ -426,7 +426,7 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command) #ifdef USE_MEASUREMENTS_IN_METERS UpdateCompareFlag(true); #else - UpdateCompareFlag(false) + UpdateCompareFlag(false); #endif return 0; case COMMAND_CONVERT_METRES_TO_FEET: From 260591cc543c3deb7f414d201d46f0742c82e756 Mon Sep 17 00:00:00 2001 From: shfil Date: Thu, 14 Jan 2021 18:00:22 +0100 Subject: [PATCH 106/152] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b9e447d3..7b8619e2 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ such that we have a working game at all times. ## Building from Source -Before starting you may want to point GTA_III_RE_DIR environment variable to GTA3 root folder, if you want executable to be moved there via post-build script. (premake) +If you gonna use premake, then pefore starting you may want to point GTA_III_RE_DIR environment variable to GTA3 root folder, if you want executable to be moved there via post-build script.
Linux Premake @@ -41,7 +41,7 @@ conan export vendor/librw librw/master@ mkdir build cd build conan install .. re3/master@ -if build -o re3:audio=openal -o librw:platform=gl3 -o librw:gl3_gfxlib=glfw --build missing -s re3:build_type=RelWithDebInfo -s librw:build_type=RelWithDebInfo -conan build .. +conan build .. -if build -bf build -pf package ```
From a06bd7f735f2df7b3f908de39ccace85f9823b12 Mon Sep 17 00:00:00 2001 From: shfil Date: Thu, 14 Jan 2021 18:02:28 +0100 Subject: [PATCH 107/152] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b8619e2..50af40df 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ such that we have a working game at all times. ## Building from Source -If you gonna use premake, then pefore starting you may want to point GTA_III_RE_DIR environment variable to GTA3 root folder, if you want executable to be moved there via post-build script. +If you gonna use premake, then before starting you may want to point GTA_III_RE_DIR environment variable to GTA3 root folder, if you want executable to be moved there via post-build script.
Linux Premake From caa7d3177c691a83ba3642737eb58c1fe5eb600f Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 16 Jan 2021 16:05:27 +0200 Subject: [PATCH 108/152] Use of sized bool types for CFont --- src/core/common.h | 4 ++ src/render/Font.cpp | 159 +++++++++++++++++++++++++++++++++++++++----- src/render/Font.h | 78 ++++++++-------------- 3 files changed, 176 insertions(+), 65 deletions(-) diff --git a/src/core/common.h b/src/core/common.h index 9253a465..7213b140 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -79,6 +79,10 @@ typedef int64_t int64; // hardcode ucs-2 typedef uint16_t wchar; +typedef uint8 bool8; +typedef uint16 bool16; +typedef uint32 bool32; + #if defined(_MSC_VER) typedef ptrdiff_t ssize_t; #endif diff --git a/src/render/Font.cpp b/src/render/Font.cpp index 8c183641..7eed0933 100644 --- a/src/render/Font.cpp +++ b/src/render/Font.cpp @@ -34,7 +34,7 @@ UnicodeStrlen(const wchar *str) } CFontDetails CFont::Details; -int16 CFont::NewLine; +bool16 CFont::NewLine; CSprite2d CFont::Sprite[MAX_FONTS]; #ifdef MORE_LANGUAGES @@ -454,7 +454,7 @@ CFont::InitPerFrame(void) CSprite2d::GetBank(15, Sprite[3].m_pTexture); #endif SetDropShadowPosition(0); - NewLine = 0; + NewLine = false; #ifdef BUTTON_ICONS PS2Symbol = BUTTON_NONE; #endif @@ -1048,7 +1048,6 @@ CFont::PrintString(float x, float y, wchar *start, wchar *end, float spwidth) } #endif -#ifdef XBOX_SUBTITLES void CFont::PrintStringFromBottom(float x, float y, wchar *str) { @@ -1061,6 +1060,7 @@ CFont::PrintStringFromBottom(float x, float y, wchar *str) PrintString(x, y, str); } +#ifdef XBOX_SUBTITLES void CFont::PrintOutlinedString(float x, float y, wchar *str, float outlineStrength, bool fromBottom, CRGBA outlineColor) { @@ -1263,7 +1263,6 @@ CFont::GetStringWidth(wchar *s, bool spaces) return w; } - #ifdef MORE_LANGUAGES float CFont::GetStringWidth_Jap(wchar* s) @@ -1384,7 +1383,7 @@ CFont::ParseToken(wchar *s, wchar*) switch(*s){ case 'N': case 'n': - NewLine = 1; + NewLine = true; break; case 'b': SetColor(CRGBA(128, 167, 243, 255)); break; case 'g': SetColor(CRGBA(95, 160, 106, 255)); break; @@ -1430,14 +1429,6 @@ CFont::DrawFonts(void) #endif } -wchar -CFont::character_code(uint8 c) -{ - if(c < 128) - return c; - return foreign_table[c-128]; -} - void CFont::SetScale(float x, float y) @@ -1453,9 +1444,16 @@ CFont::SetScale(float x, float y) } void -CFont::SetBackgroundColor(CRGBA col) +CFont::SetSlantRefPoint(float x, float y) { - Details.backgroundColor = col; + Details.slantRefX = x; + Details.slantRefY = y; +} + +void +CFont::SetSlant(float s) +{ + Details.slant = s; } void @@ -1466,6 +1464,123 @@ CFont::SetColor(CRGBA col) Details.color.a *= Details.alphaFade / 255.0f; } +void +CFont::SetJustifyOn(void) +{ + Details.justify = true; + Details.centre = false; + Details.rightJustify = false; +} + +void +CFont::SetJustifyOff(void) +{ + Details.justify = false; + Details.rightJustify = false; +} + +void +CFont::SetCentreOn(void) +{ + Details.centre = true; + Details.justify = false; + Details.rightJustify = false; +} + +void +CFont::SetCentreOff(void) +{ + Details.centre = false; +} + +void +CFont::SetWrapx(float x) +{ + Details.wrapX = x; +} + +void +CFont::SetCentreSize(float s) +{ + Details.centreSize = s; +} + +void +CFont::SetBackgroundOn(void) +{ + Details.background = true; +} + +void +CFont::SetBackgroundOff(void) +{ + Details.background = false; +} + +void +CFont::SetBackgroundColor(CRGBA col) +{ + Details.backgroundColor = col; +} + +void +CFont::SetBackGroundOnlyTextOn(void) +{ + Details.backgroundOnlyText = true; +} + +void +CFont::SetBackGroundOnlyTextOff(void) +{ + Details.backgroundOnlyText = false; +} + +void +CFont::SetRightJustifyOn(void) +{ + Details.rightJustify = true; + Details.justify = false; + Details.centre = false; +} + +void +CFont::SetRightJustifyOff(void) +{ + Details.rightJustify = false; + Details.justify = false; + Details.centre = false; +} + +void +CFont::SetPropOn(void) +{ + Details.proportional = true; +} + +void +CFont::SetPropOff(void) +{ + Details.proportional = false; +} + +void +CFont::SetFontStyle(int16 style) +{ + Details.style = style; +} + +void +CFont::SetRightJustifyWrap(float wrap) +{ + Details.rightJustifyWrap = wrap; +} + +void +CFont::SetAlphaFade(float fade) +{ + Details.alphaFade = fade; +} + void CFont::SetDropColor(CRGBA col) { @@ -1473,3 +1588,17 @@ CFont::SetDropColor(CRGBA col) if (Details.alphaFade < 255.0f) Details.dropColor.a *= Details.alphaFade / 255.0f; } + +void +CFont::SetDropShadowPosition(int16 pos) +{ + Details.dropShadowPosition = pos; +} + +wchar +CFont::character_code(uint8 c) +{ + if(c < 128) + return c; + return foreign_table[c-128]; +} \ No newline at end of file diff --git a/src/render/Font.h b/src/render/Font.h index bd7e98bb..a7a4b487 100644 --- a/src/render/Font.h +++ b/src/render/Font.h @@ -13,12 +13,12 @@ struct CFontDetails float slant; float slantRefX; float slantRefY; - bool justify; - bool centre; - bool rightJustify; - bool background; - bool backgroundOnlyText; - bool proportional; + bool8 justify; + bool8 centre; + bool8 rightJustify; + bool8 background; + bool8 backgroundOnlyText; + bool8 proportional; float alphaFade; CRGBA backgroundColor; float wrapX; @@ -97,7 +97,7 @@ class CFont #else static int16 Size[MAX_FONTS][193]; #endif - static int16 NewLine; + static bool16 NewLine; public: static CSprite2d Sprite[MAX_FONTS]; static CFontDetails Details; @@ -116,8 +116,8 @@ public: static void InitPerFrame(void); static void PrintChar(float x, float y, wchar c); static void PrintString(float x, float y, wchar *s); -#ifdef XBOX_SUBTITLES static void PrintStringFromBottom(float x, float y, wchar *str); +#ifdef XBOX_SUBTITLES static void PrintOutlinedString(float x, float y, wchar *str, float outlineStrength, bool fromBottom, CRGBA outlineColor); #endif static int GetNumberLines(float xstart, float ystart, wchar *s); @@ -142,49 +142,27 @@ public: static void DrawFonts(void); static uint16 character_code(uint8 c); - static CFontDetails GetDetails() { return Details; } static void SetScale(float x, float y); - static void SetSlantRefPoint(float x, float y) { Details.slantRefX = x; Details.slantRefY = y; } - static void SetSlant(float s) { Details.slant = s; } - static void SetJustifyOn(void) { - Details.justify = true; - Details.centre = false; - Details.rightJustify = false; - } - static void SetJustifyOff(void) { - Details.justify = false; - Details.rightJustify = false; - } - static void SetRightJustifyOn(void) { - Details.rightJustify = true; - Details.justify = false; - Details.centre = false; - } - static void SetRightJustifyOff(void) { - Details.rightJustify = false; - Details.justify = false; - Details.centre = false; - } - static void SetCentreOn(void) { - Details.centre = true; - Details.justify = false; - Details.rightJustify = false; - } - static void SetCentreOff(void) { - Details.centre = false; - } - static void SetWrapx(float x) { Details.wrapX = x; } - static void SetCentreSize(float s) { Details.centreSize = s; } - static void SetBackgroundOn(void) { Details.background = true; } - static void SetBackgroundOff(void) { Details.background = false; } - static void SetBackGroundOnlyTextOn(void) { Details.backgroundOnlyText = true; } - static void SetBackGroundOnlyTextOff(void) { Details.backgroundOnlyText = false; } - static void SetPropOn(void) { Details.proportional = true; } - static void SetPropOff(void) { Details.proportional = false; } - static void SetFontStyle(int16 style) { Details.style = style; } - static void SetRightJustifyWrap(float wrap) { Details.rightJustifyWrap = wrap; } - static void SetAlphaFade(float fade) { Details.alphaFade = fade; } - static void SetDropShadowPosition(int16 pos) { Details.dropShadowPosition = pos; } + static void SetSlantRefPoint(float x, float y); + static void SetSlant(float s); + static void SetJustifyOn(void); + static void SetJustifyOff(void); + static void SetRightJustifyOn(void); + static void SetRightJustifyOff(void); + static void SetCentreOn(void); + static void SetCentreOff(void); + static void SetWrapx(float x); + static void SetCentreSize(float s); + static void SetBackgroundOn(void); + static void SetBackgroundOff(void); + static void SetBackGroundOnlyTextOn(void); + static void SetBackGroundOnlyTextOff(void); + static void SetPropOn(void); + static void SetPropOff(void); + static void SetFontStyle(int16 style); + static void SetRightJustifyWrap(float wrap); + static void SetAlphaFade(float fade); + static void SetDropShadowPosition(int16 pos); static void SetBackgroundColor(CRGBA col); static void SetColor(CRGBA col); static void SetDropColor(CRGBA col); From 357b67e3f5ba130f00cd965aeab0eb05fc94d51d Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 17 Jan 2021 10:00:34 +0100 Subject: [PATCH 109/152] vehicle fixes --- src/vehicles/Automobile.cpp | 50 ++++++++++++++++++------------------- src/vehicles/HandlingMgr.h | 4 +-- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index ed187849..d5a0fefa 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -592,7 +592,7 @@ CAutomobile::ProcessControl(void) float fwdSpeed = Abs(DotProduct(m_vecMoveSpeed, GetForward())); CVector contactPoints[4]; // relative to model CVector contactSpeeds[4]; // speed at contact points - CVector springDirections[4]; // normalized, in model space + CVector springDirections[4]; // normalized, in world space for(i = 0; i < 4; i++){ // Set spring under certain circumstances @@ -759,10 +759,10 @@ CAutomobile::ProcessControl(void) CVector wheelRight = Multiply3x3(GetMatrix(), CVector(c, s, 0.0f)); if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f){ - if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier)) - fThrust = 0.0f; - else + if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier)) fThrust = acceleration; + else + fThrust = 0.0f; m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceA = SURFACE_WHEELBASE; float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_LEFT])*traction; @@ -793,10 +793,10 @@ CAutomobile::ProcessControl(void) } if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){ - if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier)) - fThrust = 0.0f; - else + if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier)) fThrust = acceleration; + else + fThrust = 0.0f; m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceA = SURFACE_WHEELBASE; float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_RIGHT])*traction; @@ -830,9 +830,7 @@ CAutomobile::ProcessControl(void) // Process front wheels off ground if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){ - if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) - m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f; - else{ + if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){ if(acceleration > 0.0f){ if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] < 2.0f) m_aWheelSpeed[CARWHEEL_FRONT_LEFT] -= 0.2f; @@ -840,13 +838,13 @@ CAutomobile::ProcessControl(void) if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] > -2.0f) m_aWheelSpeed[CARWHEEL_FRONT_LEFT] += 0.1f; } + }else{ + m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f; } m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT]; } if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){ - if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) - m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f; - else{ + if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){ if(acceleration > 0.0f){ if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] < 2.0f) m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] -= 0.2f; @@ -854,6 +852,8 @@ CAutomobile::ProcessControl(void) if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] > -2.0f) m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] += 0.1f; } + }else{ + m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f; } m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT]; } @@ -874,10 +874,10 @@ CAutomobile::ProcessControl(void) #endif if(m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f){ - if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier)) - fThrust = 0.0f; - else + if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier)) fThrust = acceleration; + else + fThrust = 0.0f; m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceA = SURFACE_WHEELBASE; float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_LEFT])*traction; @@ -908,10 +908,10 @@ CAutomobile::ProcessControl(void) } if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f){ - if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier)) - fThrust = 0.0f; - else + if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier)) fThrust = acceleration; + else + fThrust = 0.0f; m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceA = SURFACE_WHEELBASE; float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_RIGHT])*traction; @@ -945,9 +945,7 @@ CAutomobile::ProcessControl(void) // Process rear wheels off ground if(m_aWheelTimer[CARWHEEL_REAR_LEFT] <= 0.0f){ - if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) - m_aWheelSpeed[CARWHEEL_REAR_LEFT] *= 0.95f; - else{ + if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){ if(acceleration > 0.0f){ if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] < 2.0f) m_aWheelSpeed[CARWHEEL_REAR_LEFT] -= 0.2f; @@ -955,13 +953,13 @@ CAutomobile::ProcessControl(void) if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] > -2.0f) m_aWheelSpeed[CARWHEEL_REAR_LEFT] += 0.1f; } + }else{ + m_aWheelSpeed[CARWHEEL_REAR_LEFT] *= 0.95f; } m_aWheelRotation[CARWHEEL_REAR_LEFT] += m_aWheelSpeed[CARWHEEL_REAR_LEFT]; } if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] <= 0.0f){ - if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) - m_aWheelSpeed[CARWHEEL_REAR_RIGHT] *= 0.95f; - else{ + if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){ if(acceleration > 0.0f){ if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] < 2.0f) m_aWheelSpeed[CARWHEEL_REAR_RIGHT] -= 0.2f; @@ -969,6 +967,8 @@ CAutomobile::ProcessControl(void) if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] > -2.0f) m_aWheelSpeed[CARWHEEL_REAR_RIGHT] += 0.1f; } + }else{ + m_aWheelSpeed[CARWHEEL_REAR_RIGHT] *= 0.95f; } m_aWheelRotation[CARWHEEL_REAR_RIGHT] += m_aWheelSpeed[CARWHEEL_REAR_RIGHT]; } diff --git a/src/vehicles/HandlingMgr.h b/src/vehicles/HandlingMgr.h index 05876201..9848bb74 100644 --- a/src/vehicles/HandlingMgr.h +++ b/src/vehicles/HandlingMgr.h @@ -149,8 +149,8 @@ public: void DisplayHandlingData(CVehicle *, tHandlingData *, uint8, bool); int32 GetHandlingId(const char *name); tHandlingData *GetHandlingData(tVehicleType id) { return &HandlingData[id]; } - bool HasRearWheelDrive(tVehicleType id) { return HandlingData[id].Transmission.nDriveType == 'R'; } - bool HasFrontWheelDrive(tVehicleType id) { return HandlingData[id].Transmission.nDriveType == 'F'; } + bool HasRearWheelDrive(tVehicleType id) { return HandlingData[id].Transmission.nDriveType != 'F'; } + bool HasFrontWheelDrive(tVehicleType id) { return HandlingData[id].Transmission.nDriveType != 'R'; } }; VALIDATE_SIZE(cHandlingDataMgr, 0x3030); extern cHandlingDataMgr mod_HandlingManager; From 5a47379bf5f011a65c1d0f88a0cb5f2130feb9db Mon Sep 17 00:00:00 2001 From: erorcun Date: Sat, 16 Jan 2021 16:44:59 +0300 Subject: [PATCH 110/152] Includes overhaul, fix some compiler warnings --- src/audio/PoliceRadio.cpp | 1 + src/audio/PoliceRadio.h | 2 +- src/audio/sampman.h | 1 - src/audio/sampman_miles.cpp | 6 ++--- src/audio/sampman_oal.cpp | 33 ++++++++++-------------- src/collision/TempColModels.cpp | 1 + src/collision/TempColModels.h | 2 +- src/control/Darkel.cpp | 2 +- src/control/Garages.h | 3 +-- src/control/Script.h | 4 +-- src/control/Script3.cpp | 1 + src/control/Script4.cpp | 1 + src/core/ControllerConfig.cpp | 8 ++---- src/core/Frontend.cpp | 14 +--------- src/core/Game.cpp | 5 ---- src/core/Lists.h | 2 -- src/core/Pad.cpp | 9 +------ src/core/PlayerInfo.h | 2 +- src/core/World.cpp | 5 ---- src/core/World.h | 6 +---- src/core/Zones.h | 4 +-- src/core/common.h | 39 +++++++++++++++++----------- src/core/re3.cpp | 5 +++- src/extras/custompipes.cpp | 2 +- src/extras/custompipes_d3d9.cpp | 2 +- src/extras/postfx.cpp | 3 +-- src/extras/screendroplets.cpp | 2 +- src/fakerw/fake.cpp | 2 +- src/modelinfo/BaseModelInfo.cpp | 2 +- src/modelinfo/BaseModelInfo.h | 2 +- src/modelinfo/ModelInfo.h | 1 + src/modelinfo/PedModelInfo.h | 1 + src/peds/Ped.cpp | 1 + src/peds/Ped.h | 1 + src/render/MBlur.cpp | 1 - src/render/Renderer.cpp | 2 +- src/rw/RwHelper.cpp | 2 -- src/save/MemoryCard.cpp | 1 + src/skel/glfw/glfw.cpp | 45 +++++++++++++-------------------- src/skel/win/win.cpp | 19 ++++++-------- src/vehicles/Automobile.cpp | 1 + src/vehicles/Vehicle.h | 5 ++-- 42 files changed, 105 insertions(+), 146 deletions(-) diff --git a/src/audio/PoliceRadio.cpp b/src/audio/PoliceRadio.cpp index 37421904..94143746 100644 --- a/src/audio/PoliceRadio.cpp +++ b/src/audio/PoliceRadio.cpp @@ -13,6 +13,7 @@ #include "World.h" #include "Zones.h" #include "sampman.h" +#include "Wanted.h" const int channels = ARRAY_SIZE(cAudioManager::m_asActiveSamples); const int policeChannel = channels + 1; diff --git a/src/audio/PoliceRadio.h b/src/audio/PoliceRadio.h index c01f21ce..368708b6 100644 --- a/src/audio/PoliceRadio.h +++ b/src/audio/PoliceRadio.h @@ -1,6 +1,6 @@ #pragma once -#include "Wanted.h" +#include "Crime.h" struct cAMCrime { int32 type; diff --git a/src/audio/sampman.h b/src/audio/sampman.h index 72c3eb7f..a5f6c7e2 100644 --- a/src/audio/sampman.h +++ b/src/audio/sampman.h @@ -1,5 +1,4 @@ #pragma once -#include "common.h" #include "AudioSamples.h" #define MAX_VOLUME 127 diff --git a/src/audio/sampman_miles.cpp b/src/audio/sampman_miles.cpp index db38da64..82886c66 100644 --- a/src/audio/sampman_miles.cpp +++ b/src/audio/sampman_miles.cpp @@ -1,8 +1,5 @@ -#include "common.h" - #ifdef AUDIO_MSS -#include -#include +#include #include #include @@ -11,6 +8,7 @@ #include "eax-util.h" #include "mss.h" +#include "common.h" #include "sampman.h" #include "AudioManager.h" #include "MusicManager.h" diff --git a/src/audio/sampman_oal.cpp b/src/audio/sampman_oal.cpp index bb7f0aac..798ea287 100644 --- a/src/audio/sampman_oal.cpp +++ b/src/audio/sampman_oal.cpp @@ -1,17 +1,11 @@ //#define JUICY_OAL #ifdef AUDIO_OAL -#include "sampman.h" - #include #include "eax.h" #include "eax-util.h" -#define WITHWINDOWS -#include "common.h" -#include "crossplatform.h" - #ifdef _WIN32 #include #include @@ -19,8 +13,22 @@ #include #include #include + +#pragma comment(lib, "OpenAL32.lib") + +// for user MP3s +#include +#include +#include +#else +#define _getcwd getcwd #endif +#include "common.h" +#include "crossplatform.h" + +#include "sampman.h" + #include "oal/oal_utils.h" #include "oal/aldlist.h" #include "oal/channel.h" @@ -38,19 +46,6 @@ //TODO: max channels //TODO: loop count -#ifdef _WIN32 -#pragma comment( lib, "OpenAL32.lib" ) -#endif - -// for user MP3s -#ifdef _WIN32 -#include -#include -#include -#else -#define _getcwd getcwd -#endif - cSampleManager SampleManager; bool _bSampmanInitialised = false; diff --git a/src/collision/TempColModels.cpp b/src/collision/TempColModels.cpp index dabb6ebb..494c148d 100644 --- a/src/collision/TempColModels.cpp +++ b/src/collision/TempColModels.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "TempColModels.h" +#include "Game.h" CColModel CTempColModels::ms_colModelPed1; CColModel CTempColModels::ms_colModelPed2; diff --git a/src/collision/TempColModels.h b/src/collision/TempColModels.h index 3e1dd5e1..057728af 100644 --- a/src/collision/TempColModels.h +++ b/src/collision/TempColModels.h @@ -1,6 +1,6 @@ #pragma once -#include "Collision.h" +#include "ColModel.h" class CTempColModels { diff --git a/src/control/Darkel.cpp b/src/control/Darkel.cpp index 91d2163d..9f6809df 100644 --- a/src/control/Darkel.cpp +++ b/src/control/Darkel.cpp @@ -126,7 +126,7 @@ CDarkel::DrawMessages() #if defined(PS2_HUD) || defined(FIX_BUGS) #ifdef FIX_BUGS CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(34.0f - 1.0f), SCREEN_SCALE_Y(108.0f + 1.0f), gUString); - #else - + #else CFont::PrintString(SCREEN_WIDTH-(34.0f - 1.0f), 108.0f + 1.0f, gUString); #endif #else diff --git a/src/control/Garages.h b/src/control/Garages.h index ee5ac4d3..3a8bc08d 100644 --- a/src/control/Garages.h +++ b/src/control/Garages.h @@ -1,11 +1,10 @@ #pragma once -#include "Automobile.h" #include "audio_enums.h" #include "Camera.h" #include "config.h" +#include "Lists.h" class CVehicle; -class CCamera; enum eGarageState { diff --git a/src/control/Script.h b/src/control/Script.h index c0b69e0f..ff1a9706 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -1,7 +1,5 @@ #pragma once -#include "common.h" #include "Font.h" -#include "Ped.h" #include "PedType.h" #include "Text.h" #include "Sprite2d.h" @@ -36,9 +34,11 @@ void FlushLog(); #define SPHERE_MARKER_PULSE_FRACTION (0.1f) #ifdef USE_PRECISE_MEASUREMENT_CONVERTION +#define MILES_IN_METER (0.000621371192f) #define METERS_IN_FOOT (0.3048f) #define FEET_IN_METER (3.28084f) #else +#define MILES_IN_METER (1 / 1670.f) #define METERS_IN_FOOT (0.3f) #define FEET_IN_METER (3.33f) #endif diff --git a/src/control/Script3.cpp b/src/control/Script3.cpp index 27277f0e..6e6e15bf 100644 --- a/src/control/Script3.cpp +++ b/src/control/Script3.cpp @@ -32,6 +32,7 @@ #include "WaterLevel.h" #include "Weather.h" #include "Zones.h" +#include "Wanted.h" int8 CRunningScript::ProcessCommands500To599(int32 command) { diff --git a/src/control/Script4.cpp b/src/control/Script4.cpp index d17334a9..6fea8807 100644 --- a/src/control/Script4.cpp +++ b/src/control/Script4.cpp @@ -38,6 +38,7 @@ #include "WaterLevel.h" #include "World.h" #include "Zones.h" +#include "Wanted.h" int8 CRunningScript::ProcessCommands800To899(int32 command) { diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp index bf4893ea..600738ee 100644 --- a/src/core/ControllerConfig.cpp +++ b/src/core/ControllerConfig.cpp @@ -1,11 +1,7 @@ -#if defined RW_D3D9 || defined RWLIBS -#define DIRECTINPUT_VERSION 0x0800 -#include -#endif - +#define WITHDINPUT #include "common.h" #include "platform.h" -#include "crossplatform.h" // for Windows version +#include "crossplatform.h" #include "ControllerConfig.h" #include "Pad.h" #include "FileMgr.h" diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 7bf4be84..b1d6c43d 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -1,10 +1,6 @@ -#if defined RW_D3D9 || defined RWLIBS -#define DIRECTINPUT_VERSION 0x0800 -#include -#endif - #define FORCE_PC_SCALING #define WITHWINDOWS +#define WITHDINPUT #include "common.h" #ifndef PS2_MENU #include "crossplatform.h" @@ -145,14 +141,6 @@ int8 CMenuManager::m_nDisplayMSAALevel = 0; int8 CMenuManager::m_PrefsIslandLoading = ISLAND_LOADING_LOW; #endif -#ifdef USE_PRECISE_MEASUREMENT_CONVERTION -#define MILES_IN_METER 0.000621371192f -#define FEET_IN_METER 3.28084f -#else -#define MILES_IN_METER (1 / 1670.f) -#define FEET_IN_METER 3.33f -#endif - int32 CMenuManager::OS_Language = LANG_ENGLISH; int8 CMenuManager::m_PrefsUseVibration; int8 CMenuManager::m_DisplayControllerOnFoot; diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 7961b981..4fd30b53 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -1,6 +1,3 @@ -#pragma warning( push ) -#pragma warning( disable : 4005) -#pragma warning( pop ) #include "common.h" #include "platform.h" @@ -10,7 +7,6 @@ #include "Accident.h" #include "Antennas.h" #include "Bridge.h" -#include "Camera.h" #include "CarCtrl.h" #include "CarGen.h" #include "CdStream.h" @@ -67,7 +63,6 @@ #include "Shadows.h" #include "Skidmarks.h" #include "SpecialFX.h" -#include "Sprite2d.h" #include "Stats.h" #include "Streaming.h" #include "SurfaceTable.h" diff --git a/src/core/Lists.h b/src/core/Lists.h index ecf24740..7572e882 100644 --- a/src/core/Lists.h +++ b/src/core/Lists.h @@ -1,7 +1,5 @@ #pragma once -#include "common.h" - class CPtrNode { public: diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index 7187efac..5e5f1326 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -1,11 +1,4 @@ -#pragma warning( push ) -#pragma warning( disable : 4005) -#if defined RW_D3D9 || defined RWLIBS -#define DIRECTINPUT_VERSION 0x0800 -#include -#endif -#pragma warning( pop ) - +#define WITHDINPUT #include "common.h" #include "crossplatform.h" #include "platform.h" diff --git a/src/core/PlayerInfo.h b/src/core/PlayerInfo.h index 49424b8b..956756e4 100644 --- a/src/core/PlayerInfo.h +++ b/src/core/PlayerInfo.h @@ -1,6 +1,6 @@ #pragma once -#include "Collision.h" +#include "ColModel.h" enum eWastedBustedState { diff --git a/src/core/World.cpp b/src/core/World.cpp index 67992035..6ecc294a 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -4,7 +4,6 @@ #include "CopPed.h" #include "CutsceneMgr.h" #include "DMAudio.h" -#include "Entity.h" #include "EventList.h" #include "Explosion.h" #include "Fire.h" @@ -12,10 +11,7 @@ #include "Glass.h" #include "Messages.h" #include "ModelIndices.h" -#include "Object.h" #include "ParticleObject.h" -#include "Ped.h" -#include "PlayerPed.h" #include "Population.h" #include "ProjectileInfo.h" #include "Record.h" @@ -24,7 +20,6 @@ #include "RpAnimBlend.h" #include "Shadows.h" #include "TempColModels.h" -#include "Vehicle.h" #include "WaterLevel.h" #include "World.h" diff --git a/src/core/World.h b/src/core/World.h index 9d62e79b..3d553752 100644 --- a/src/core/World.h +++ b/src/core/World.h @@ -3,6 +3,7 @@ #include "Game.h" #include "Lists.h" #include "PlayerInfo.h" +#include "Collision.h" /* Sectors span from -2000 to 2000 in x and y. * With 100x100 sectors, each is 40x40 units. */ @@ -48,11 +49,6 @@ public: VALIDATE_SIZE(CSector, 0x28); -class CEntity; -struct CColPoint; -struct CColLine; -struct CStoredCollPoly; - class CWorld { static CPtrList ms_bigBuildingsList[NUM_LEVELS]; diff --git a/src/core/Zones.h b/src/core/Zones.h index 6549dad5..aa0466e8 100644 --- a/src/core/Zones.h +++ b/src/core/Zones.h @@ -105,8 +105,8 @@ public: static void SetPedGroup(uint16 zoneid, uint8 day, uint16 pedgroup); static int16 FindAudioZone(CVector *pos); static eLevelName FindZoneForPoint(const CVector &pos); - static CZone *GetPointerForZoneIndex(int32 i) { return i == -1 ? nil : &ZoneArray[i]; } - static int32 GetIndexForZonePointer(CZone *zone) { return zone == nil ? -1 : zone - ZoneArray; } + static CZone *GetPointerForZoneIndex(ssize_t i) { return i == -1 ? nil : &ZoneArray[i]; } + static ssize_t GetIndexForZonePointer(CZone *zone) { return zone == nil ? -1 : zone - ZoneArray; } static void AddZoneToAudioZoneArray(CZone *zone); static void InitialiseAudioZoneArray(void); static void SaveAllZones(uint8 *buffer, uint32 *length); diff --git a/src/core/common.h b/src/core/common.h index 7213b140..8b5f6b3c 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -11,17 +11,34 @@ #include #include -#if defined _WIN32 && defined WITHWINDOWS +#if !defined RW_D3D9 && defined LIBRW +#undef WITHD3D +#undef WITHDINPUT +#endif + +#if (defined WITHD3D && !defined LIBRW) +#define WITHWINDOWS +#endif + +#if defined _WIN32 && defined WITHWINDOWS && !defined _INC_WINDOWS #include #endif -#if defined _WIN32 && defined WITHD3D -#include -#ifndef USE_D3D9 -#include -#else -#include +#ifdef WITHD3D + #ifdef LIBRW + #define WITH_D3D // librw includes d3d9 itself via this right now + #else + #ifndef USE_D3D9 + #include + #else + #include + #endif + #endif #endif + +#ifdef WITHDINPUT +#define DIRECTINPUT_VERSION 0x0800 +#include #endif #include @@ -52,14 +69,6 @@ #define rwVENDORID_ROCKSTAR 0x0253F2 -// Get rid of bullshit windows definitions, we're not running on an 8086 -#ifdef far -#undef far -#endif -#ifdef near -#undef near -#endif - #define Max(a,b) ((a) > (b) ? (a) : (b)) #define Min(a,b) ((a) < (b) ? (a) : (b)) diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 6117462a..a4b76269 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -1,7 +1,6 @@ #include #define WITHWINDOWS #include "common.h" -#include "crossplatform.h" #include "Renderer.h" #include "Credits.h" #include "Camera.h" @@ -36,6 +35,10 @@ #include "ControllerConfig.h" #endif +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS +#include "crossplatform.h" +#endif + #ifndef _WIN32 #include "assert.h" #include diff --git a/src/extras/custompipes.cpp b/src/extras/custompipes.cpp index e6dff12a..092b3e23 100644 --- a/src/extras/custompipes.cpp +++ b/src/extras/custompipes.cpp @@ -1,4 +1,4 @@ -#define WITH_D3D +#define WITHD3D #include "common.h" #ifdef EXTENDED_PIPELINES diff --git a/src/extras/custompipes_d3d9.cpp b/src/extras/custompipes_d3d9.cpp index 1f4ee07d..4242c630 100644 --- a/src/extras/custompipes_d3d9.cpp +++ b/src/extras/custompipes_d3d9.cpp @@ -1,4 +1,4 @@ -#define WITH_D3D +#define WITHD3D #include "common.h" #ifdef RW_D3D9 diff --git a/src/extras/postfx.cpp b/src/extras/postfx.cpp index d3b8b8ac..51b91060 100644 --- a/src/extras/postfx.cpp +++ b/src/extras/postfx.cpp @@ -1,5 +1,4 @@ -#define WITHWINDOWS -#define WITH_D3D +#define WITHD3D #include "common.h" #ifdef EXTENDED_COLOURFILTER diff --git a/src/extras/screendroplets.cpp b/src/extras/screendroplets.cpp index ac3a17b2..74c44da0 100644 --- a/src/extras/screendroplets.cpp +++ b/src/extras/screendroplets.cpp @@ -1,4 +1,4 @@ -#define WITH_D3D +#define WITHD3D #include "common.h" #ifdef SCREEN_DROPLETS diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp index 6585032b..c1150931 100644 --- a/src/fakerw/fake.cpp +++ b/src/fakerw/fake.cpp @@ -1,5 +1,5 @@ #define _CRT_SECURE_NO_WARNINGS -#define WITH_D3D +#define WITH_D3D // not WITHD3D, so it's librw define #include #include #include diff --git a/src/modelinfo/BaseModelInfo.cpp b/src/modelinfo/BaseModelInfo.cpp index a2779107..f1c7d050 100644 --- a/src/modelinfo/BaseModelInfo.cpp +++ b/src/modelinfo/BaseModelInfo.cpp @@ -4,7 +4,7 @@ #include "TxdStore.h" #include "2dEffect.h" #include "BaseModelInfo.h" - +#include "ColModel.h" CBaseModelInfo::CBaseModelInfo(ModelInfoType type) { diff --git a/src/modelinfo/BaseModelInfo.h b/src/modelinfo/BaseModelInfo.h index 31c7f566..f46cea84 100644 --- a/src/modelinfo/BaseModelInfo.h +++ b/src/modelinfo/BaseModelInfo.h @@ -1,6 +1,6 @@ #pragma once -#include "Collision.h" +struct CColModel; #define MAX_MODEL_NAME (24) diff --git a/src/modelinfo/ModelInfo.h b/src/modelinfo/ModelInfo.h index 65cfa4e7..4fe1ebb0 100644 --- a/src/modelinfo/ModelInfo.h +++ b/src/modelinfo/ModelInfo.h @@ -10,6 +10,7 @@ #include "VehicleModelInfo.h" #include "XtraCompsModelInfo.h" #include "Instance.h" +#include "Game.h" class CModelInfo { diff --git a/src/modelinfo/PedModelInfo.h b/src/modelinfo/PedModelInfo.h index f467fe8a..26ab3c3f 100644 --- a/src/modelinfo/PedModelInfo.h +++ b/src/modelinfo/PedModelInfo.h @@ -1,6 +1,7 @@ #pragma once #include "ClumpModelInfo.h" +#include "ColModel.h" #include "PedType.h" enum PedNode { diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 269aa084..a9529d2d 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -31,6 +31,7 @@ #include "ParticleObject.h" #include "Floater.h" #include "Range2D.h" +#include "Wanted.h" CPed *gapTempPedList[50]; uint16 gnNumTempPedList; diff --git a/src/peds/Ped.h b/src/peds/Ped.h index c2641a0f..0617a7bb 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -9,6 +9,7 @@ #include "Physical.h" #include "Weapon.h" #include "WeaponInfo.h" +#include "Collision.h" #define FEET_OFFSET 1.04f #define CHECK_NEARBY_THINGS_MAX_DIST 15.0f diff --git a/src/render/MBlur.cpp b/src/render/MBlur.cpp index de15358e..a7d07ad9 100644 --- a/src/render/MBlur.cpp +++ b/src/render/MBlur.cpp @@ -1,4 +1,3 @@ -#define WITHWINDOWS #ifndef LIBRW #define WITHD3D #endif diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 131e77fe..d41f27e3 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1,4 +1,4 @@ -#define WITH_D3D +#define WITHD3D #include "common.h" #include "main.h" diff --git a/src/rw/RwHelper.cpp b/src/rw/RwHelper.cpp index d004656c..65e342ed 100644 --- a/src/rw/RwHelper.cpp +++ b/src/rw/RwHelper.cpp @@ -1,6 +1,4 @@ -#if defined RW_D3D9 || defined RWLIBS #define WITHD3D -#endif #include "common.h" #include diff --git a/src/save/MemoryCard.cpp b/src/save/MemoryCard.cpp index c8ebcd86..d6e95d33 100644 --- a/src/save/MemoryCard.cpp +++ b/src/save/MemoryCard.cpp @@ -1,6 +1,7 @@ #define WITHWINDOWS #include "common.h" #ifdef PS2_MENU +#include "crossplatform.h" #include "MemoryCard.h" #include "main.h" #include "DMAudio.h" diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 93bfde5a..683407aa 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -1,22 +1,30 @@ #if defined RW_GL3 && !defined LIBRW_SDL2 #ifdef _WIN32 -#include +#include +#include #include +#include #include #include -#include -#include -#include + +DWORD _dwOperatingSystemVersion; +#include "resource.h" +#else +long _dwOperatingSystemVersion; +#ifndef __APPLE__ +#include +#else +#include +#include +#endif +#include +#include +#include +#include #endif -#define WITHWINDOWS #include "common.h" - -#pragma warning( push ) -#pragma warning( disable : 4005) -#pragma warning( pop ) - #if (defined(_MSC_VER)) #include #endif /* (defined(_MSC_VER)) */ @@ -73,23 +81,6 @@ static psGlobalType PsGlobal; size_t _dwMemAvailPhys; RwUInt32 gGameState; -#ifdef _WIN32 -DWORD _dwOperatingSystemVersion; -#include "resource.h" -#else -long _dwOperatingSystemVersion; -#ifndef __APPLE__ -#include -#else -#include -#include -#endif -#include -#include -#include -#include -#endif - #ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS char gSelectedJoystickName[128] = ""; #endif diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index 53844319..d373a8b5 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -2,7 +2,6 @@ #define _WIN32_WINDOWS 0x0500 #define WINVER 0x0500 -#define DIRECTINPUT_VERSION 0x0800 #include #include @@ -20,13 +19,7 @@ #pragma warning( push ) #pragma warning( disable : 4005) -#ifdef USE_D3D9 -#include -#else -#include -#endif #include -#include #include #pragma warning( pop ) @@ -41,6 +34,9 @@ #pragma comment( lib, "strmiids.lib" ) #pragma comment( lib, "dinput8.lib" ) +#define WITHD3D +#define WITHDINPUT +#include "common.h" #if (defined(_MSC_VER)) #include #endif /* (defined(_MSC_VER)) */ @@ -82,7 +78,6 @@ static psGlobalType PsGlobal; #define JIF(x) if (FAILED(hr=(x))) \ {debug(TEXT("FAILED(hr=0x%x) in ") TEXT(#x) TEXT("\n"), hr); return;} -#include "common.h" #include "main.h" #include "FileMgr.h" #include "Text.h" @@ -93,12 +88,14 @@ static psGlobalType PsGlobal; #include "Frontend.h" #include "Game.h" #include "PCSave.h" -#include "MemoryCard.h" -#include "Sprite2d.h" #include "AnimViewer.h" -#include "Font.h" #include "MemoryMgr.h" +#ifdef PS2_MENU +#include "MemoryCard.h" +#include "Font.h" +#endif + VALIDATE_SIZE(psGlobalType, 0x28); // DirectShow interfaces diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index d5a0fefa..966042e2 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -44,6 +44,7 @@ #include "PlayerPed.h" #include "Object.h" #include "Automobile.h" +#include "Wanted.h" bool bAllCarCheat; // unused diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index 7066a0ea..a6a4f815 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -3,8 +3,9 @@ #include "Physical.h" #include "AutoPilot.h" #include "ModelIndices.h" -#include "AnimManager.h" -#include "Weapon.h" +#include "AnimationId.h" +#include "WeaponType.h" +#include "Collision.h" class CPed; class CFire; From 448e41ecaa66483c4cf764fdeb66a857a42719cf Mon Sep 17 00:00:00 2001 From: erorcun Date: Fri, 15 Jan 2021 04:40:34 +0300 Subject: [PATCH 111/152] Store all settings in .INI --- src/core/ControllerConfig.cpp | 2 +- src/core/Frontend.cpp | 61 +++-- src/core/Frontend.h | 7 +- src/core/MenuScreensCustom.cpp | 30 +-- src/core/main.h | 2 + src/core/re3.cpp | 416 ++++++++++++++++++++++++++------- src/extras/frontendoption.cpp | 10 +- src/extras/frontendoption.h | 6 +- src/skel/glfw/glfw.cpp | 5 + src/skel/win/win.cpp | 5 + 10 files changed, 417 insertions(+), 127 deletions(-) diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp index 600738ee..ee3cb959 100644 --- a/src/core/ControllerConfig.cpp +++ b/src/core/ControllerConfig.cpp @@ -2797,7 +2797,7 @@ void CControllerConfigManager::ResetSettingOrder(e_ControllerAction action) for (int32 k = 0; k < MAX_CONTROLLERTYPES; k++) { int32 setorder = m_aSettings[action][k].m_ContSetOrder; - if (setorder > i && setorder != KEYBOARD) + if (setorder > i && setorder != 0) { if (init) { diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index b1d6c43d..65eab125 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -862,7 +862,11 @@ CMenuManager::CheckCodesForControls(int typeOfControl) m_bWaitingForNewKeyBind = false; m_KeyPressedCode = -1; m_bStartWaitingForKeyBind = false; +#ifdef LOAD_INI_SETTINGS + SaveINIControllerSettings(); +#else SaveSettings(); +#endif } if (escPressed) { @@ -870,7 +874,11 @@ CMenuManager::CheckCodesForControls(int typeOfControl) m_bWaitingForNewKeyBind = false; m_KeyPressedCode = -1; m_bStartWaitingForKeyBind = false; +#ifdef LOAD_INI_SETTINGS + SaveINIControllerSettings(); +#else SaveSettings(); +#endif } } @@ -3570,13 +3578,21 @@ CMenuManager::LoadAllTextures() DMAudio.ChangeMusicMode(MUSICMODE_FRONTEND); DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_STARTING, 0); m_nCurrOption = 0; + +#ifdef FIX_BUGS + static bool firstTime = true; + if (firstTime) { + DMAudio.SetRadioInCar(m_PrefsRadioStation); + firstTime = false; + } else +#endif m_PrefsRadioStation = DMAudio.GetRadioInCar(); if (DMAudio.IsMP3RadioChannelAvailable()) { if (m_PrefsRadioStation > USERTRACK) - m_PrefsRadioStation = CGeneral::GetRandomNumber() % 10; + m_PrefsRadioStation = CGeneral::GetRandomNumber() % (USERTRACK + 1); } else if (m_PrefsRadioStation > CHATTERBOX) - m_PrefsRadioStation = CGeneral::GetRandomNumber() % 9; + m_PrefsRadioStation = CGeneral::GetRandomNumber() % (CHATTERBOX + 1); CFileMgr::SetDir(""); //CFileMgr::SetDir(""); @@ -3711,6 +3727,11 @@ CMenuManager::LoadSettings() CFileMgr::CloseFile(fileHandle); CFileMgr::SetDir(""); +#ifdef LOAD_INI_SETTINGS + LoadINISettings(); + LoadINIControllerSettings(); // Calling that after LoadINISettings is important because of gSelectedJoystickName loading +#endif + m_PrefsVsync = m_PrefsVsyncDisp; CRenderer::ms_lodDistScale = m_PrefsLOD; @@ -3749,15 +3770,12 @@ CMenuManager::LoadSettings() strcpy(m_PrefsSkinFile, DEFAULT_SKIN_NAME); strcpy(m_aSkinName, DEFAULT_SKIN_NAME); } - -#ifdef LOAD_INI_SETTINGS - LoadINISettings(); // needs frontend options to be loaded -#endif } void CMenuManager::SaveSettings() { +#ifndef LOAD_INI_SETTINGS static char RubbishString[48] = "stuffmorestuffevenmorestuff etc"; CFileMgr::SetDirMyDocuments(); @@ -3807,7 +3825,13 @@ CMenuManager::SaveSettings() CFileMgr::CloseFile(fileHandle); CFileMgr::SetDir(""); -#ifdef LOAD_INI_SETTINGS +#else + static bool firstTime = true; + // In other conditions we already call SaveINIControllerSettings explicitly. + if (firstTime) { + SaveINIControllerSettings(); + firstTime = false; + } SaveINISettings(); #endif } @@ -4117,19 +4141,19 @@ CMenuManager::Process(void) MouseButtonJustClicked = false; if (CPad::GetPad(0)->GetLeftMouseJustDown()) - MouseButtonJustClicked = 1; + MouseButtonJustClicked = rsMOUSELEFTBUTTON; else if (CPad::GetPad(0)->GetRightMouseJustUp()) - MouseButtonJustClicked = 3; + MouseButtonJustClicked = rsMOUSERIGHTBUTTON; else if (CPad::GetPad(0)->GetMiddleMouseJustUp()) - MouseButtonJustClicked = 2; + MouseButtonJustClicked = rsMOUSMIDDLEBUTTON; else if (CPad::GetPad(0)->GetMouseWheelUpJustUp()) - MouseButtonJustClicked = 4; + MouseButtonJustClicked = rsMOUSEWHEELUPBUTTON; else if (CPad::GetPad(0)->GetMouseWheelDownJustUp()) - MouseButtonJustClicked = 5; + MouseButtonJustClicked = rsMOUSEWHEELDOWNBUTTON; else if (CPad::GetPad(0)->GetMouseX1JustUp()) - MouseButtonJustClicked = 6; + MouseButtonJustClicked = rsMOUSEX1BUTTON; else if (CPad::GetPad(0)->GetMouseX2JustUp()) - MouseButtonJustClicked = 7; + MouseButtonJustClicked = rsMOUSEX2BUTTON; JoyButtonJustClicked = ControlsManager.GetJoyButtonJustDown(); @@ -5047,6 +5071,9 @@ CMenuManager::ProcessButtonPresses(void) CVehicle::m_bDisableMouseSteering = true; TheCamera.m_bHeadBob = false; SaveSettings(); +#ifdef LOAD_INI_SETTINGS + SaveINIControllerSettings(); +#endif } SetHelperText(2); break; @@ -5098,7 +5125,8 @@ CMenuManager::ProcessButtonPresses(void) *option.m_CFO->value = option.m_CFOSelect->lastSavedValue = option.m_CFOSelect->displayedValue; - if (option.m_CFOSelect->save) + // Now everything is saved in .ini, and LOAD_INI_SETTINGS is fundamental for CFO + // if (option.m_CFOSelect->save) SaveSettings(); if (option.m_CFOSelect->displayedValue != oldValue && option.m_CFOSelect->changeFunc) @@ -5332,7 +5360,8 @@ CMenuManager::ProcessButtonPresses(void) *option.m_CFO->value = option.m_CFOSelect->lastSavedValue = option.m_CFOSelect->displayedValue; - if (option.m_CFOSelect->save) + // Now everything is saved in .ini, and LOAD_INI_SETTINGS is fundamental for CFO + // if (option.m_CFOSelect->save) SaveSettings(); if (option.m_CFOSelect->displayedValue != oldValue && option.m_CFOSelect->changeFunc) diff --git a/src/core/Frontend.h b/src/core/Frontend.h index 36647899..b0100fdc 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -494,6 +494,7 @@ struct CCustomScreenLayout { struct CCFO { int8 *value; + const char *saveCat; const char *save; }; @@ -508,11 +509,12 @@ struct CCFOSelect : CCFO bool disableIfGameLoaded; CCFOSelect() {}; - CCFOSelect(int8* value, const char* save, const char** rightTexts, int8 numRightTexts, bool onlyApplyOnEnter, ChangeFunc changeFunc = nil, bool disableIfGameLoaded = false){ + CCFOSelect(int8* value, const char* saveCat, const char* save, const char** rightTexts, int8 numRightTexts, bool onlyApplyOnEnter, ChangeFunc changeFunc = nil, bool disableIfGameLoaded = false){ this->value = value; if (value) this->lastSavedValue = this->displayedValue = *value; + this->saveCat = saveCat; this->save = save; this->rightTexts = (char**)rightTexts; this->numRightTexts = numRightTexts; @@ -528,8 +530,9 @@ struct CCFODynamic : CCFO ButtonPressFunc buttonPressFunc; CCFODynamic() {}; - CCFODynamic(int8* value, const char* save, DrawFunc drawFunc, ButtonPressFunc buttonPressFunc){ + CCFODynamic(int8* value, const char* saveCat, const char* save, DrawFunc drawFunc, ButtonPressFunc buttonPressFunc){ this->value = value; + this->saveCat = saveCat; this->save = save; this->drawFunc = drawFunc; this->buttonPressFunc = buttonPressFunc; diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp index 4303e4b6..07223608 100644 --- a/src/core/MenuScreensCustom.cpp +++ b/src/core/MenuScreensCustom.cpp @@ -24,51 +24,51 @@ #ifdef CUSTOM_FRONTEND_OPTIONS #ifdef IMPROVED_VIDEOMODE - #define VIDEOMODE_SELECTOR MENUACTION_CFO_SELECT, "FEM_SCF", { new CCFOSelect((int8*)&FrontEndMenuManager.m_nPrefsWindowed, nil, screenModes, 2, true, ScreenModeAfterChange, true) }, + #define VIDEOMODE_SELECTOR MENUACTION_CFO_SELECT, "FEM_SCF", { new CCFOSelect((int8*)&FrontEndMenuManager.m_nPrefsWindowed, "VideoMode", "Windowed", screenModes, 2, true, ScreenModeAfterChange, true) }, #else #define VIDEOMODE_SELECTOR #endif #ifdef MULTISAMPLING - #define MULTISAMPLING_SELECTOR MENUACTION_CFO_DYNAMIC, "FED_AAS", { new CCFODynamic((int8*)&FrontEndMenuManager.m_nPrefsMSAALevel, "MultiSampling", MultiSamplingDraw, MultiSamplingButtonPress) }, + #define MULTISAMPLING_SELECTOR MENUACTION_CFO_DYNAMIC, "FED_AAS", { new CCFODynamic((int8*)&FrontEndMenuManager.m_nPrefsMSAALevel, "Graphics", "MultiSampling", MultiSamplingDraw, MultiSamplingButtonPress) }, #else #define MULTISAMPLING_SELECTOR #endif #ifdef CUTSCENE_BORDERS_SWITCH - #define CUTSCENE_BORDERS_TOGGLE MENUACTION_CFO_SELECT, "FEM_CSB", { new CCFOSelect((int8 *)&CMenuManager::m_PrefsCutsceneBorders, "CutsceneBorders", off_on, 2, false) }, + #define CUTSCENE_BORDERS_TOGGLE MENUACTION_CFO_SELECT, "FEM_CSB", { new CCFOSelect((int8 *)&CMenuManager::m_PrefsCutsceneBorders, "Display", "CutsceneBorders", off_on, 2, false) }, #else #define CUTSCENE_BORDERS_TOGGLE #endif #ifdef FREE_CAM - #define FREE_CAM_TOGGLE MENUACTION_CFO_SELECT, "FEC_FRC", { new CCFOSelect((int8*)&TheCamera.bFreeCam, "FreeCam", off_on, 2, false) }, + #define FREE_CAM_TOGGLE MENUACTION_CFO_SELECT, "FEC_FRC", { new CCFOSelect((int8*)&TheCamera.bFreeCam, "Display", "FreeCam", off_on, 2, false) }, #else #define FREE_CAM_TOGGLE #endif #ifdef PS2_ALPHA_TEST - #define DUALPASS_SELECTOR MENUACTION_CFO_SELECT, "FEM_2PR", { new CCFOSelect((int8*)&gPS2alphaTest, "PS2AlphaTest", off_on, 2, false) }, + #define DUALPASS_SELECTOR MENUACTION_CFO_SELECT, "FEM_2PR", { new CCFOSelect((int8*)&gPS2alphaTest, "Graphics", "PS2AlphaTest", off_on, 2, false) }, #else #define DUALPASS_SELECTOR #endif #ifdef NO_ISLAND_LOADING - #define ISLAND_LOADING_SELECTOR MENUACTION_CFO_SELECT, "FEM_ISL", { new CCFOSelect((int8*)&CMenuManager::m_PrefsIslandLoading, "IslandLoading", islandLoadingOpts, ARRAY_SIZE(islandLoadingOpts), true, IslandLoadingAfterChange) }, + #define ISLAND_LOADING_SELECTOR MENUACTION_CFO_SELECT, "FEM_ISL", { new CCFOSelect((int8*)&CMenuManager::m_PrefsIslandLoading, "Graphics", "IslandLoading", islandLoadingOpts, ARRAY_SIZE(islandLoadingOpts), true, IslandLoadingAfterChange) }, #else #define ISLAND_LOADING_SELECTOR #endif #ifdef EXTENDED_COLOURFILTER #define POSTFX_SELECTORS \ - MENUACTION_CFO_SELECT, "FED_CLF", { new CCFOSelect((int8*)&CPostFX::EffectSwitch, "ColourFilter", filterNames, ARRAY_SIZE(filterNames), false) }, \ - MENUACTION_CFO_SELECT, "FED_MBL", { new CCFOSelect((int8*)&CPostFX::MotionBlurOn, "MotionBlur", off_on, 2, false) }, + MENUACTION_CFO_SELECT, "FED_CLF", { new CCFOSelect((int8*)&CPostFX::EffectSwitch, "Graphics", "ColourFilter", filterNames, ARRAY_SIZE(filterNames), false) }, \ + MENUACTION_CFO_SELECT, "FED_MBL", { new CCFOSelect((int8*)&CPostFX::MotionBlurOn, "Graphics", "MotionBlur", off_on, 2, false) }, #else #define POSTFX_SELECTORS #endif #ifdef INVERT_LOOK_FOR_PAD - #define INVERT_PAD_SELECTOR MENUACTION_CFO_SELECT, "FEC_IVP", { new CCFOSelect((int8*)&CPad::bInvertLook4Pad, "InvertPad", off_on, 2, false) }, + #define INVERT_PAD_SELECTOR MENUACTION_CFO_SELECT, "FEC_IVP", { new CCFOSelect((int8*)&CPad::bInvertLook4Pad, "Controller", "InvertPad", off_on, 2, false) }, #else #define INVERT_PAD_SELECTOR #endif @@ -405,7 +405,7 @@ CMenuScreenCustom aScreens[MENUPAGES] = { CUTSCENE_BORDERS_TOGGLE FREE_CAM_TOGGLE MENUACTION_SUBTITLES, "FED_SUB", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, - MENUACTION_CFO_DYNAMIC, "FET_DEF", { new CCFODynamic(nil, nil, nil, RestoreDefDisplay) }, + MENUACTION_CFO_DYNAMIC, "FET_DEF", { new CCFODynamic(nil, nil, nil, nil, RestoreDefDisplay) }, MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, }, #endif @@ -418,9 +418,9 @@ CMenuScreenCustom aScreens[MENUPAGES] = { MENUACTION_LANG_ITA, "FEL_ITA", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS }, MENUACTION_LANG_SPA, "FEL_SPA", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS }, #ifdef MORE_LANGUAGES - MENUACTION_CFO_DYNAMIC, "FEL_POL", { new CCFODynamic(nil, nil, nil, LangPolSelect) }, - MENUACTION_CFO_DYNAMIC, "FEL_RUS", { new CCFODynamic(nil, nil, nil, LangRusSelect) }, - MENUACTION_CFO_DYNAMIC, "FEL_JAP", { new CCFODynamic(nil, nil, nil, LangJapSelect) }, + MENUACTION_CFO_DYNAMIC, "FEL_POL", { new CCFODynamic(nil, nil, nil, nil, LangPolSelect) }, + MENUACTION_CFO_DYNAMIC, "FEL_RUS", { new CCFODynamic(nil, nil, nil, nil, LangRusSelect) }, + MENUACTION_CFO_DYNAMIC, "FEL_JAP", { new CCFODynamic(nil, nil, nil, nil, LangJapSelect) }, #endif MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, }, @@ -828,7 +828,7 @@ CMenuScreenCustom aScreens[MENUPAGES] = { MENUACTION_TRAILS, "FED_TRA", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, #endif // re3.cpp inserts here pipeline selectors if neo/neo.txd exists and EXTENDED_PIPELINES defined - MENUACTION_CFO_DYNAMIC, "FET_DEF", { new CCFODynamic(nil, nil, nil, RestoreDefGraphics) }, + MENUACTION_CFO_DYNAMIC, "FET_DEF", { new CCFODynamic(nil, nil, nil, nil, RestoreDefGraphics) }, MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, }, #endif @@ -839,7 +839,7 @@ CMenuScreenCustom aScreens[MENUPAGES] = { new CCustomScreenLayout({MENUSPRITE_MAINMENU, 40, 60, 20, FONT_BANK, FESCREEN_LEFT_ALIGN, false, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE}), nil, MENUACTION_LABEL, "FEC_JPR", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, - MENUACTION_CFO_DYNAMIC, "FEC_JDE", { new CCFODynamic(nil, nil, DetectJoystickDraw, nil) }, + MENUACTION_CFO_DYNAMIC, "FEC_JDE", { new CCFODynamic(nil, nil, nil, DetectJoystickDraw, nil) }, MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, }, #endif diff --git a/src/core/main.h b/src/core/main.h index 37a82fb2..eacfd8e1 100644 --- a/src/core/main.h +++ b/src/core/main.h @@ -47,6 +47,8 @@ void TheModelViewer(void); #ifdef LOAD_INI_SETTINGS void LoadINISettings(); void SaveINISettings(); +void LoadINIControllerSettings(); +void SaveINIControllerSettings(); #endif #ifdef NEW_RENDERER diff --git a/src/core/re3.cpp b/src/core/re3.cpp index a4b76269..d7bf88ea 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -30,10 +30,9 @@ #include "custompipes.h" #include "MemoryHeap.h" #include "FileMgr.h" - -#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS +#include "Camera.h" +#include "MBlur.h" #include "ControllerConfig.h" -#endif #ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS #include "crossplatform.h" @@ -91,16 +90,16 @@ CustomFrontendOptionsPopulate(void) if (fd) { #ifdef GRAPHICS_MENU_OPTIONS FrontendOptionSetCursor(MENUPAGE_GRAPHICS_SETTINGS, -3, false); - FrontendOptionAddSelect("FED_VPL", vehPipelineNames, ARRAY_SIZE(vehPipelineNames), (int8*)&CustomPipes::VehiclePipeSwitch, false, nil, "VehiclePipeline"); - FrontendOptionAddSelect("FED_PRM", off_on, 2, (int8*)&CustomPipes::RimlightEnable, false, nil, "NeoRimLight"); - FrontendOptionAddSelect("FED_WLM", off_on, 2, (int8*)&CustomPipes::LightmapEnable, false, nil, "NeoLightMaps"); - FrontendOptionAddSelect("FED_RGL", off_on, 2, (int8*)&CustomPipes::GlossEnable, false, nil, "NeoRoadGloss"); + FrontendOptionAddSelect("FED_VPL", vehPipelineNames, ARRAY_SIZE(vehPipelineNames), (int8*)&CustomPipes::VehiclePipeSwitch, false, nil, "Graphics", "VehiclePipeline"); + FrontendOptionAddSelect("FED_PRM", off_on, 2, (int8*)&CustomPipes::RimlightEnable, false, nil, "Graphics", "NeoRimLight"); + FrontendOptionAddSelect("FED_WLM", off_on, 2, (int8*)&CustomPipes::LightmapEnable, false, nil, "Graphics", "NeoLightMaps"); + FrontendOptionAddSelect("FED_RGL", off_on, 2, (int8*)&CustomPipes::GlossEnable, false, nil, "Graphics", "NeoRoadGloss"); #else FrontendOptionSetCursor(MENUPAGE_DISPLAY_SETTINGS, -3, false); - FrontendOptionAddSelect("FED_VPL", vehPipelineNames, ARRAY_SIZE(vehPipelineNames), (int8*)&CustomPipes::VehiclePipeSwitch, false, nil, "VehiclePipeline"); - FrontendOptionAddSelect("FED_PRM", off_on, 2, (int8*)&CustomPipes::RimlightEnable, false, nil, "NeoRimLight"); - FrontendOptionAddSelect("FED_WLM", off_on, 2, (int8*)&CustomPipes::LightmapEnable, false, nil, "NeoLightMaps"); - FrontendOptionAddSelect("FED_RGL", off_on, 2, (int8*)&CustomPipes::GlossEnable, false, nil, "NeoRoadGloss"); + FrontendOptionAddSelect("FED_VPL", vehPipelineNames, ARRAY_SIZE(vehPipelineNames), (int8*)&CustomPipes::VehiclePipeSwitch, false, nil, "Graphics", "VehiclePipeline"); + FrontendOptionAddSelect("FED_PRM", off_on, 2, (int8*)&CustomPipes::RimlightEnable, false, nil, "Graphics", "NeoRimLight"); + FrontendOptionAddSelect("FED_WLM", off_on, 2, (int8*)&CustomPipes::LightmapEnable, false, nil, "Graphics", "NeoLightMaps"); + FrontendOptionAddSelect("FED_RGL", off_on, 2, (int8*)&CustomPipes::GlossEnable, false, nil, "Graphics", "NeoRoadGloss"); #endif CFileMgr::CloseFile(fd); } @@ -113,53 +112,293 @@ CustomFrontendOptionsPopulate(void) #include "ini_parser.hpp" linb::ini cfg; -int CheckAndReadIniInt(const char *cat, const char *key, int original) +bool ReadIniIfExists(const char *cat, const char *key, uint32 *out) { - std::string strval = cfg.get(cat, key, ""); + std::string strval = cfg.get(cat, key, "\xBA"); const char *value = strval.c_str(); - if (value && value[0] != '\0') - return atoi(value); - - return original; + char *endPtr; + if (value && value[0] != '\xBA') { + *out = strtoul(value, &endPtr, 0); + return true; + } + return false; } -float CheckAndReadIniFloat(const char *cat, const char *key, float original) +bool ReadIniIfExists(const char *cat, const char *key, bool *out) { - std::string strval = cfg.get(cat, key, ""); + std::string strval = cfg.get(cat, key, "\xBA"); const char *value = strval.c_str(); - if (value && value[0] != '\0') - return atof(value); - - return original; + char *endPtr; + if (value && value[0] != '\xBA') { + *out = strtoul(value, &endPtr, 0); + return true; + } + return false; } -void CheckAndSaveIniInt(const char *cat, const char *key, int val, bool &changed) +bool ReadIniIfExists(const char *cat, const char *key, int32 *out) +{ + std::string strval = cfg.get(cat, key, "\xBA"); + const char *value = strval.c_str(); + char *endPtr; + if (value && value[0] != '\xBA') { + *out = strtol(value, &endPtr, 0); + return true; + } + return false; +} + +bool ReadIniIfExists(const char *cat, const char *key, int8 *out) +{ + std::string strval = cfg.get(cat, key, "\xBA"); + const char *value = strval.c_str(); + char *endPtr; + if (value && value[0] != '\xBA') { + *out = strtol(value, &endPtr, 0); + return true; + } + return false; +} + +bool ReadIniIfExists(const char *cat, const char *key, float *out) +{ + std::string strval = cfg.get(cat, key, "\xBA"); + const char *value = strval.c_str(); + if (value && value[0] != '\xBA') { + *out = atof(value); + return true; + } + return false; +} + +bool ReadIniIfExists(const char *cat, const char *key, char *out, int size) +{ + std::string strval = cfg.get(cat, key, "\xBA"); + const char *value = strval.c_str(); + if (value && value[0] != '\xBA') { + strncpy(out, value, size); + return true; + } + return false; +} + +void StoreIni(const char *cat, const char *key, uint32 val) { char temp[10]; - if (atoi(cfg.get(cat, key, "xxx").c_str()) != val) { // if .ini doesn't have our key, compare with xxx and forcefully add it - changed = true; - sprintf(temp, "%u", val); - cfg.set(cat, key, temp); + sprintf(temp, "%u", val); + cfg.set(cat, key, temp); +} + +void StoreIni(const char *cat, const char *key, uint8 val) +{ + char temp[10]; + sprintf(temp, "%u", (uint32)val); + cfg.set(cat, key, temp); +} + +void StoreIni(const char *cat, const char *key, int32 val) +{ + char temp[10]; + sprintf(temp, "%d", val); + cfg.set(cat, key, temp); +} + +void StoreIni(const char *cat, const char *key, int8 val) +{ + char temp[10]; + sprintf(temp, "%d", (int32)val); + cfg.set(cat, key, temp); +} + +void StoreIni(const char *cat, const char *key, float val) +{ + char temp[10]; + sprintf(temp, "%f", val); + cfg.set(cat, key, temp); +} + +void StoreIni(const char *cat, const char *key, char *val, int size) +{ + cfg.set(cat, key, val); +} + +const char *iniControllerActions[] = { "PED_FIREWEAPON", "PED_CYCLE_WEAPON_RIGHT", "PED_CYCLE_WEAPON_LEFT", "GO_FORWARD", "GO_BACK", "GO_LEFT", "GO_RIGHT", "PED_SNIPER_ZOOM_IN", + "PED_SNIPER_ZOOM_OUT", "VEHICLE_ENTER_EXIT", "CAMERA_CHANGE_VIEW_ALL_SITUATIONS", "PED_JUMPING", "PED_SPRINT", "PED_LOOKBEHIND", +#ifdef BIND_VEHICLE_FIREWEAPON + "VEHICLE_FIREWEAPON", +#endif + "VEHICLE_ACCELERATE", "VEHICLE_BRAKE", "VEHICLE_CHANGE_RADIO_STATION", "VEHICLE_HORN", "TOGGLE_SUBMISSIONS", "VEHICLE_HANDBRAKE", "PED_1RST_PERSON_LOOK_LEFT", + "PED_1RST_PERSON_LOOK_RIGHT", "VEHICLE_LOOKLEFT", "VEHICLE_LOOKRIGHT", "VEHICLE_LOOKBEHIND", "VEHICLE_TURRETLEFT", "VEHICLE_TURRETRIGHT", "VEHICLE_TURRETUP", "VEHICLE_TURRETDOWN", + "PED_CYCLE_TARGET_LEFT", "PED_CYCLE_TARGET_RIGHT", "PED_CENTER_CAMERA_BEHIND_PLAYER", "PED_LOCK_TARGET", "NETWORK_TALK", "PED_1RST_PERSON_LOOK_UP", "PED_1RST_PERSON_LOOK_DOWN", + "_CONTROLLERACTION_36", "TOGGLE_DPAD", "SWITCH_DEBUG_CAM_ON", "TAKE_SCREEN_SHOT", "SHOW_MOUSE_POINTER_TOGGLE" }; + +const char *iniControllerTypes[] = { "kbd:", "2ndKbd:", "mouse:", "joy:" }; + +const char *iniMouseButtons[] = {"LEFT","MIDDLE","RIGHT","WHLUP","WHLDOWN","X1","X2"}; + +const char *iniKeyboardButtons[] = {"ESC","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12", + "INS","DEL","HOME","END","PGUP","PGDN","UP","DOWN","LEFT","RIGHT","DIVIDE","TIMES","PLUS","MINUS","PADDEL", + "PADEND","PADDOWN","PADPGDN","PADLEFT","PAD5","NUMLOCK","PADRIGHT","PADHOME","PADUP","PADPGUP","PADINS", + "PADENTER", "SCROLL","PAUSE","BACKSP","TAB","CAPSLK","ENTER","LSHIFT","RSHIFT","SHIFT","LCTRL","RCTRL","LALT", + "RALT", "LWIN", "RWIN", "APPS", "NULL"}; + +void LoadINIControllerSettings() +{ + for (int32 i = 0; i < MAX_CONTROLLERACTIONS; i++) { + char value[128]; + if (ReadIniIfExists("Bindings", iniControllerActions[i], value, 128)) { + for (int32 j = 0; j < MAX_CONTROLLERTYPES; j++){ + ControlsManager.ClearSettingsAssociatedWithAction((e_ControllerAction)i, (eControllerType)j); + } + + for (char *binding = strtok(value,", "); binding != nil; binding = strtok(nil, ", ")) { + int contType = -1; + for (int32 k = 0; k < ARRAY_SIZE(iniControllerTypes); k++) { + int len = strlen(iniControllerTypes[k]); + if (strncmp(binding, iniControllerTypes[k], len) == 0) { + contType = k; + binding += len; + break; + } + } + if (contType == -1) + continue; + + int contKey; + if (contType == JOYSTICK) { + char *temp; + contKey = strtol(binding, &temp, 0); + + } else if (contType == KEYBOARD || contType == OPTIONAL_EXTRA) { + if (strlen(binding) == 1) { + contKey = binding[0]; + } else if(strcmp(binding, "SPC") == 0) { + contKey = ' '; + } else { + for (int32 k = 0; k < ARRAY_SIZE(iniKeyboardButtons); k++) { + if(strcmp(binding, iniKeyboardButtons[k]) == 0) { + contKey = 1000 + k; + break; + } + } + } + } else if (contType == MOUSE) { + for (int32 k = 0; k < ARRAY_SIZE(iniMouseButtons); k++) { + if(strcmp(binding, iniMouseButtons[k]) == 0) { + contKey = 1 + k; + break; + } + } + } + + ControlsManager.SetControllerKeyAssociatedWithAction((e_ControllerAction)i, contKey, (eControllerType)contType); + } + } } } -void CheckAndSaveIniFloat(const char *cat, const char *key, float val, bool &changed) +void SaveINIControllerSettings() { - char temp[10]; - if (atof(cfg.get(cat, key, "xxx").c_str()) != val) { // if .ini doesn't have our key, compare with xxx and forcefully add it - changed = true; - sprintf(temp, "%f", val); - cfg.set(cat, key, temp); + for (int32 i = 0; i < MAX_CONTROLLERACTIONS; i++) { + char value[128] = { '\0' }; + + // upper limit should've been GetNumOfSettingsForAction(i), but sadly even R* doesn't use it's own system correctly, and there are gaps between orders. + for (int32 j = SETORDER_1; j < MAX_SETORDERS; j++){ + + // We respect the m_ContSetOrder, and join/implode/order the bindings according to that; using comma as seperator. + for (int32 k = 0; k < MAX_CONTROLLERTYPES; k++){ + if (ControlsManager.m_aSettings[i][k].m_ContSetOrder == j) { + char next[32]; + if (k == JOYSTICK) { + snprintf(next, 32, "%s%d,", iniControllerTypes[k], ControlsManager.m_aSettings[i][k].m_Key); + + } else if (k == KEYBOARD || k == OPTIONAL_EXTRA) { + if (ControlsManager.m_aSettings[i][k].m_Key == ' ') + snprintf(next, 32, "%sSPC,", iniControllerTypes[k]); + else if (ControlsManager.m_aSettings[i][k].m_Key < 256) + snprintf(next, 32, "%s%c,", iniControllerTypes[k], ControlsManager.m_aSettings[i][k].m_Key); + else + snprintf(next, 32, "%s%s,", iniControllerTypes[k], iniKeyboardButtons[ControlsManager.m_aSettings[i][k].m_Key - 1000]); + + } else if (k == MOUSE) { + snprintf(next, 32, "%s%s,", iniControllerTypes[k], iniMouseButtons[ControlsManager.m_aSettings[i][k].m_Key - 1]); + } + strcat(value, next); + break; + } + } + } + int len = strlen(value); + if (len > 0) + value[len - 1] = '\0'; // to remove comma + + StoreIni("Bindings", iniControllerActions[i], value, 128); } + + cfg.write_file("re3.ini"); } void LoadINISettings() { cfg.load_file("re3.ini"); +#ifdef IMPROVED_VIDEOMODE + ReadIniIfExists("VideoMode", "Width", &FrontEndMenuManager.m_nPrefsWidth); + ReadIniIfExists("VideoMode", "Height", &FrontEndMenuManager.m_nPrefsHeight); + ReadIniIfExists("VideoMode", "Depth", &FrontEndMenuManager.m_nPrefsDepth); + ReadIniIfExists("VideoMode", "Subsystem", &FrontEndMenuManager.m_nPrefsSubsystem); + // Windowed mode is loaded below in CUSTOM_FRONTEND_OPTIONS section +#else + ReadIniIfExists("Graphics", "VideoMode", &FrontEndMenuManager.m_nDisplayVideoMode); +#endif + ReadIniIfExists("Controller", "HeadBob1stPerson", &TheCamera.m_bHeadBob); + ReadIniIfExists("Controller", "VerticalMouseSens", &TheCamera.m_fMouseAccelVertical); + ReadIniIfExists("Controller", "HorizantalMouseSens", &TheCamera.m_fMouseAccelHorzntl); + ReadIniIfExists("Controller", "InvertMouseVertically", &MousePointerStateHelper.bInvertVertically); + ReadIniIfExists("Controller", "DisableMouseSteering", &CVehicle::m_bDisableMouseSteering); + ReadIniIfExists("Audio", "SfxVolume", &FrontEndMenuManager.m_PrefsSfxVolume); + ReadIniIfExists("Audio", "MusicVolume", &FrontEndMenuManager.m_PrefsMusicVolume); + ReadIniIfExists("Audio", "Radio", &FrontEndMenuManager.m_PrefsRadioStation); + ReadIniIfExists("Audio", "SpeakerType", &FrontEndMenuManager.m_PrefsSpeakers); + ReadIniIfExists("Audio", "Provider", &FrontEndMenuManager.m_nPrefsAudio3DProviderIndex); + ReadIniIfExists("Audio", "DynamicAcoustics", &FrontEndMenuManager.m_PrefsDMA); + ReadIniIfExists("Display", "Brightness", &FrontEndMenuManager.m_PrefsBrightness); + ReadIniIfExists("Display", "DrawDistance", &FrontEndMenuManager.m_PrefsLOD); + ReadIniIfExists("Display", "Subtitles", &FrontEndMenuManager.m_PrefsShowSubtitles); + ReadIniIfExists("Graphics", "AspectRatio", &FrontEndMenuManager.m_PrefsUseWideScreen); + ReadIniIfExists("Graphics", "VSync", &FrontEndMenuManager.m_PrefsVsyncDisp); + ReadIniIfExists("Graphics", "FrameLimiter", &FrontEndMenuManager.m_PrefsFrameLimiter); + ReadIniIfExists("Graphics", "Trails", &CMBlur::BlurOn); + ReadIniIfExists("General", "SkinFile", FrontEndMenuManager.m_PrefsSkinFile, 256); + ReadIniIfExists("Controller", "Method", &FrontEndMenuManager.m_ControlMethod); + ReadIniIfExists("General", "Language", &FrontEndMenuManager.m_PrefsLanguage); + +#ifdef EXTENDED_COLOURFILTER + ReadIniIfExists("CustomPipesValues", "PostFXIntensity", &CPostFX::Intensity); +#endif +#ifdef EXTENDED_PIPELINES + ReadIniIfExists("CustomPipesValues", "NeoVehicleShininess", &CustomPipes::VehicleShininess); + ReadIniIfExists("CustomPipesValues", "NeoVehicleSpecularity", &CustomPipes::VehicleSpecularity); + ReadIniIfExists("CustomPipesValues", "RimlightMult", &CustomPipes::RimlightMult); + ReadIniIfExists("CustomPipesValues", "LightmapMult", &CustomPipes::LightmapMult); + ReadIniIfExists("CustomPipesValues", "GlossMult", &CustomPipes::GlossMult); +#endif + +#ifdef PROPER_SCALING + ReadIniIfExists("Draw", "ProperScaling", &CDraw::ms_bProperScaling); +#endif +#ifdef FIX_RADAR + ReadIniIfExists("Draw", "FixRadar", &CDraw::ms_bFixRadar); +#endif +#ifdef FIX_SPRITES + ReadIniIfExists("Draw", "FixSprites", &CDraw::ms_bFixSprites); +#endif + #ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS // Written by assuming the codes below will run after _InputInitialiseJoys(). - strcpy(gSelectedJoystickName, cfg.get("DetectJoystick", "JoystickName", "").c_str()); + std::string strval = cfg.get("Controller", "JoystickName", ""); + const char *value = strval.c_str(); + strcpy(gSelectedJoystickName, value); if(gSelectedJoystickName[0] != '\0') { for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) { @@ -182,6 +421,7 @@ void LoadINISettings() CFileMgr::CloseFile(gta3set); } CFileMgr::SetDir(""); + // We call LoadINIControllerSettings after this func., so calling here isn't needed break; } } @@ -198,7 +438,7 @@ void LoadINISettings() // CFO check if (option.m_Action < MENUACTION_NOTHING && option.m_CFO->save) { // CFO only supports saving uint8 right now - *option.m_CFO->value = CheckAndReadIniInt("FrontendOptions", option.m_CFO->save, *option.m_CFO->value); + ReadIniIfExists(option.m_CFO->saveCat, option.m_CFO->save, option.m_CFO->value); if (option.m_Action == MENUACTION_CFO_SELECT) { option.m_CFOSelect->lastSavedValue = option.m_CFOSelect->displayedValue = *option.m_CFO->value; } @@ -206,38 +446,64 @@ void LoadINISettings() } } #endif - -#ifdef EXTENDED_COLOURFILTER - CPostFX::Intensity = CheckAndReadIniFloat("CustomPipesValues", "PostFXIntensity", CPostFX::Intensity); -#endif -#ifdef EXTENDED_PIPELINES - CustomPipes::VehicleShininess = CheckAndReadIniFloat("CustomPipesValues", "NeoVehicleShininess", CustomPipes::VehicleShininess); - CustomPipes::VehicleSpecularity = CheckAndReadIniFloat("CustomPipesValues", "NeoVehicleSpecularity", CustomPipes::VehicleSpecularity); - CustomPipes::RimlightMult = CheckAndReadIniFloat("CustomPipesValues", "RimlightMult", CustomPipes::RimlightMult); - CustomPipes::LightmapMult = CheckAndReadIniFloat("CustomPipesValues", "LightmapMult", CustomPipes::LightmapMult); - CustomPipes::GlossMult = CheckAndReadIniFloat("CustomPipesValues", "GlossMult", CustomPipes::GlossMult); -#endif - -#ifdef PROPER_SCALING - CDraw::ms_bProperScaling = CheckAndReadIniInt("Draw", "ProperScaling", CDraw::ms_bProperScaling); -#endif -#ifdef FIX_RADAR - CDraw::ms_bFixRadar = CheckAndReadIniInt("Draw", "FixRadar", CDraw::ms_bFixRadar); -#endif -#ifdef FIX_SPRITES - CDraw::ms_bFixSprites = CheckAndReadIniInt("Draw", "FixSprites", CDraw::ms_bFixSprites); -#endif } void SaveINISettings() { - bool changed = false; +#ifdef IMPROVED_VIDEOMODE + StoreIni("VideoMode", "Width", FrontEndMenuManager.m_nPrefsWidth); + StoreIni("VideoMode", "Height", FrontEndMenuManager.m_nPrefsHeight); + StoreIni("VideoMode", "Depth", FrontEndMenuManager.m_nPrefsDepth); + StoreIni("VideoMode", "Subsystem", FrontEndMenuManager.m_nPrefsSubsystem); + // Windowed mode is loaded below in CUSTOM_FRONTEND_OPTIONS section +#else + StoreIni("Graphics", "VideoMode", FrontEndMenuManager.m_nDisplayVideoMode); +#endif + StoreIni("Controller", "HeadBob1stPerson", TheCamera.m_bHeadBob); + StoreIni("Controller", "VerticalMouseSens", TheCamera.m_fMouseAccelVertical); + StoreIni("Controller", "HorizantalMouseSens", TheCamera.m_fMouseAccelHorzntl); + StoreIni("Controller", "InvertMouseVertically", MousePointerStateHelper.bInvertVertically); + StoreIni("Controller", "DisableMouseSteering", CVehicle::m_bDisableMouseSteering); + StoreIni("Audio", "SfxVolume", FrontEndMenuManager.m_PrefsSfxVolume); + StoreIni("Audio", "MusicVolume", FrontEndMenuManager.m_PrefsMusicVolume); + StoreIni("Audio", "Radio", FrontEndMenuManager.m_PrefsRadioStation); + StoreIni("Audio", "SpeakerType", FrontEndMenuManager.m_PrefsSpeakers); + StoreIni("Audio", "Provider", FrontEndMenuManager.m_nPrefsAudio3DProviderIndex); + StoreIni("Audio", "DynamicAcoustics", FrontEndMenuManager.m_PrefsDMA); + StoreIni("Display", "Brightness", FrontEndMenuManager.m_PrefsBrightness); + StoreIni("Display", "DrawDistance", FrontEndMenuManager.m_PrefsLOD); + StoreIni("Display", "Subtitles", FrontEndMenuManager.m_PrefsShowSubtitles); + StoreIni("Graphics", "AspectRatio", FrontEndMenuManager.m_PrefsUseWideScreen); + StoreIni("Graphics", "VSync", FrontEndMenuManager.m_PrefsVsyncDisp); + StoreIni("Graphics", "FrameLimiter", FrontEndMenuManager.m_PrefsFrameLimiter); + StoreIni("Graphics", "Trails", CMBlur::BlurOn); + StoreIni("General", "SkinFile", FrontEndMenuManager.m_PrefsSkinFile, 256); + StoreIni("Controller", "Method", FrontEndMenuManager.m_ControlMethod); + StoreIni("General", "Language", FrontEndMenuManager.m_PrefsLanguage); + +#ifdef EXTENDED_COLOURFILTER + StoreIni("CustomPipesValues", "PostFXIntensity", CPostFX::Intensity); +#endif +#ifdef EXTENDED_PIPELINES + StoreIni("CustomPipesValues", "NeoVehicleShininess", CustomPipes::VehicleShininess); + StoreIni("CustomPipesValues", "NeoVehicleSpecularity", CustomPipes::VehicleSpecularity); + StoreIni("CustomPipesValues", "RimlightMult", CustomPipes::RimlightMult); + StoreIni("CustomPipesValues", "LightmapMult", CustomPipes::LightmapMult); + StoreIni("CustomPipesValues", "GlossMult", CustomPipes::GlossMult); +#endif + +#ifdef PROPER_SCALING + StoreIni("Draw", "ProperScaling", CDraw::ms_bProperScaling); +#endif +#ifdef FIX_RADAR + StoreIni("Draw", "FixRadar", CDraw::ms_bFixRadar); +#endif +#ifdef FIX_SPRITES + StoreIni("Draw", "FixSprites", CDraw::ms_bFixSprites); +#endif #ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS - if (strncmp(cfg.get("DetectJoystick", "JoystickName", "").c_str(), gSelectedJoystickName, strlen(gSelectedJoystickName)) != 0) { - changed = true; - cfg.set("DetectJoystick", "JoystickName", gSelectedJoystickName); - } + StoreIni("Controller", "JoystickName", gSelectedJoystickName, 128); #endif #ifdef CUSTOM_FRONTEND_OPTIONS for (int i = 0; i < MENUPAGES; i++) { @@ -248,35 +514,13 @@ void SaveINISettings() if (option.m_Action < MENUACTION_NOTHING && option.m_CFO->save) { // Beware: CFO only supports saving uint8 right now - CheckAndSaveIniInt("FrontendOptions", option.m_CFO->save, *option.m_CFO->value, changed); + StoreIni(option.m_CFO->saveCat, option.m_CFO->save, *option.m_CFO->value); } } } #endif -#ifdef EXTENDED_COLOURFILTER - CheckAndSaveIniFloat("CustomPipesValues", "PostFXIntensity", CPostFX::Intensity, changed); -#endif -#ifdef EXTENDED_PIPELINES - CheckAndSaveIniFloat("CustomPipesValues", "NeoVehicleShininess", CustomPipes::VehicleShininess, changed); - CheckAndSaveIniFloat("CustomPipesValues", "NeoVehicleSpecularity", CustomPipes::VehicleSpecularity, changed); - CheckAndSaveIniFloat("CustomPipesValues", "RimlightMult", CustomPipes::RimlightMult, changed); - CheckAndSaveIniFloat("CustomPipesValues", "LightmapMult", CustomPipes::LightmapMult, changed); - CheckAndSaveIniFloat("CustomPipesValues", "GlossMult", CustomPipes::GlossMult, changed); -#endif - -#ifdef PROPER_SCALING - CheckAndSaveIniInt("Draw", "ProperScaling", CDraw::ms_bProperScaling, changed); -#endif -#ifdef FIX_RADAR - CheckAndSaveIniInt("Draw", "FixRadar", CDraw::ms_bFixRadar, changed); -#endif -#ifdef FIX_SPRITES - CheckAndSaveIniInt("Draw", "FixSprites", CDraw::ms_bFixSprites, changed); -#endif - - if (changed) - cfg.write_file("re3.ini"); + cfg.write_file("re3.ini"); } #endif diff --git a/src/extras/frontendoption.cpp b/src/extras/frontendoption.cpp index a966de97..5d388bfd 100644 --- a/src/extras/frontendoption.cpp +++ b/src/extras/frontendoption.cpp @@ -123,7 +123,7 @@ void FrontendOptionAddBuiltinAction(const char* gxtKey, int action, int targetMe option.m_TargetMenu = targetMenu; } -void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveName, bool disableIfGameLoaded) +void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveCat, const char* saveKey, bool disableIfGameLoaded) { int8 screenOptionOrder = RegisterNewOption(); @@ -139,13 +139,14 @@ void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 n option.m_CFOSelect->displayedValue = *var; option.m_CFOSelect->lastSavedValue = *var; } - option.m_CFOSelect->save = saveName; + option.m_CFOSelect->saveCat = saveCat; + option.m_CFOSelect->save = saveKey; option.m_CFOSelect->onlyApplyOnEnter = onlyApplyOnEnter; option.m_CFOSelect->changeFunc = changeFunc; option.m_CFOSelect->disableIfGameLoaded = disableIfGameLoaded; } -void FrontendOptionAddDynamic(const char* gxtKey, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, const char* saveName) +void FrontendOptionAddDynamic(const char* gxtKey, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, const char* saveCat, const char* saveKey) { int8 screenOptionOrder = RegisterNewOption(); @@ -156,7 +157,8 @@ void FrontendOptionAddDynamic(const char* gxtKey, DrawFunc drawFunc, int8 *var, option.m_CFODynamic->drawFunc = drawFunc; option.m_CFODynamic->buttonPressFunc = buttonPressFunc; option.m_CFODynamic->value = var; - option.m_CFODynamic->save = saveName; + option.m_CFODynamic->saveCat = saveCat; + option.m_CFODynamic->save = saveKey; } uint8 FrontendScreenAdd(const char* gxtKey, eMenuSprites sprite, int prevPage, int columnWidth, int headerHeight, int lineHeight, diff --git a/src/extras/frontendoption.h b/src/extras/frontendoption.h index dbd1a300..8b64335a 100644 --- a/src/extras/frontendoption.h +++ b/src/extras/frontendoption.h @@ -82,10 +82,10 @@ uint8 GetNumberOfMenuOptions(int screen); void FrontendOptionSetCursor(int screen, int8 option, bool overwrite = false); -// 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 +// var is optional in AddDynamic, enables you to save them in an INI file(also needs passing char array to and saveCat saveKey param. obv), otherwise pass nil/0 void FrontendOptionAddBuiltinAction(const char* gxtKey, int action, int targetMenu = MENUPAGE_NONE, int saveSlot = SAVESLOT_NONE); -void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveName = nil, bool disableIfGameLoaded = false); -void FrontendOptionAddDynamic(const char* gxtKey, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, const char* saveName = nil); +void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveCat = nil, const char* saveKey = nil, bool disableIfGameLoaded = false); +void FrontendOptionAddDynamic(const char* gxtKey, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, const char* saveCat = nil, const char* saveKey = nil); 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 diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 683407aa..5f87d600 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -1598,6 +1598,7 @@ main(int argc, char *argv[]) SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &NewStickyKeys, SPIF_SENDCHANGE); #endif + // This part is needed because controller initialisation overwrites loaded settings. { CFileMgr::SetDirMyDocuments(); @@ -1610,6 +1611,10 @@ main(int argc, char *argv[]) } CFileMgr::SetDir(""); + +#ifdef LOAD_INI_SETTINGS + LoadINIControllerSettings(); +#endif } #ifdef _WIN32 diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index d373a8b5..5a0c7db2 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -2142,6 +2142,7 @@ WinMain(HINSTANCE instance, ShowWindow(PSGLOBAL(window), cmdShow); UpdateWindow(PSGLOBAL(window)); + // This part is needed because controller initialisation overwrites loaded settings. { CFileMgr::SetDirMyDocuments(); @@ -2154,6 +2155,10 @@ WinMain(HINSTANCE instance, } CFileMgr::SetDir(""); + +#ifdef LOAD_INI_SETTINGS + LoadINIControllerSettings(); +#endif } SetErrorMode(SEM_FAILCRITICALERRORS); From deaaf3d22f69cef5298ba5f18e5a96903d20f15a Mon Sep 17 00:00:00 2001 From: erorcun Date: Fri, 15 Jan 2021 12:36:58 +0300 Subject: [PATCH 112/152] Migrate from old .ini to new .ini --- src/core/re3.cpp | 9 ++++++++- src/extras/ini_parser.hpp | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/core/re3.cpp b/src/core/re3.cpp index d7bf88ea..09eafe74 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -429,6 +429,7 @@ void LoadINISettings() #endif #ifdef CUSTOM_FRONTEND_OPTIONS + bool migrate = cfg.category_size("FrontendOptions") != 0; for (int i = 0; i < MENUPAGES; i++) { for (int j = 0; j < NUM_MENUROWS; j++) { CMenuScreenCustom::CMenuEntry &option = aScreens[i].m_aEntries[j]; @@ -438,7 +439,13 @@ void LoadINISettings() // CFO check if (option.m_Action < MENUACTION_NOTHING && option.m_CFO->save) { // CFO only supports saving uint8 right now - ReadIniIfExists(option.m_CFO->saveCat, option.m_CFO->save, option.m_CFO->value); + + // Migrate from old .ini to new .ini + if (migrate && ReadIniIfExists("FrontendOptions", option.m_CFO->save, option.m_CFO->value)) + cfg.remove("FrontendOptions", option.m_CFO->save); + else + ReadIniIfExists(option.m_CFO->saveCat, option.m_CFO->save, option.m_CFO->value); + if (option.m_Action == MENUACTION_CFO_SELECT) { option.m_CFOSelect->lastSavedValue = option.m_CFOSelect->displayedValue = *option.m_CFO->value; } diff --git a/src/extras/ini_parser.hpp b/src/extras/ini_parser.hpp index 8e88bc29..7bea024c 100644 --- a/src/extras/ini_parser.hpp +++ b/src/extras/ini_parser.hpp @@ -158,6 +158,25 @@ namespace linb /* Too lazy to continue this container... If you need more methods, just add it */ + // re3 + void remove(const string_type& sect, const key_type& key) + { + auto it = this->find(sect); + if(it != this->end()) + { + it->second.erase(key); + } + } + + int category_size(const string_type& sect) + { + auto it = this->find(sect); + if(it != this->end()) + { + return it->second.size(); + } + return 0; + } #if 1 bool read_file(const char_type* filename) From a6faa0384b591e8b9093b52b4955011126e942a3 Mon Sep 17 00:00:00 2001 From: withmorten Date: Sun, 17 Jan 2021 22:10:04 +0100 Subject: [PATCH 113/152] fix common.h d3d includes --- src/core/common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/common.h b/src/core/common.h index 8b5f6b3c..d7facfd1 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -29,9 +29,9 @@ #define WITH_D3D // librw includes d3d9 itself via this right now #else #ifndef USE_D3D9 - #include + #include #else - #include + #include #endif #endif #endif From da292032199a9169896439b9171a0c5081fc5c4c Mon Sep 17 00:00:00 2001 From: withmorten Date: Sun, 17 Jan 2021 22:15:49 +0100 Subject: [PATCH 114/152] sync milessdk with re3mss --- vendor/milessdk/include/mss.h | 139 ++++++++++++++++++++-------------- vendor/milessdk/lib/mss32.lib | Bin 15316 -> 15570 bytes 2 files changed, 82 insertions(+), 57 deletions(-) diff --git a/vendor/milessdk/include/mss.h b/vendor/milessdk/include/mss.h index 38371eb9..b5b20bea 100644 --- a/vendor/milessdk/include/mss.h +++ b/vendor/milessdk/include/mss.h @@ -56,61 +56,86 @@ typedef struct _AILSOUNDINFO void const *initial_ptr; } AILSOUNDINFO; -#define DLLEXPORT extern "C" __declspec(dllexport) +typedef U32 (WINAPI *AIL_file_open_callback)(char const * Filename, U32 * FileHandle); -DLLEXPORT S32 WINAPI AIL_enumerate_3D_providers(HPROENUM *next, HPROVIDER *dest, C8 **name); -DLLEXPORT void WINAPI AIL_release_3D_sample_handle(H3DSAMPLE S); -DLLEXPORT void WINAPI AIL_close_3D_provider(HPROVIDER lib); -DLLEXPORT void WINAPI AIL_set_3D_provider_preference(HPROVIDER lib, C8 const *name, void const *val); -DLLEXPORT M3DRESULT WINAPI AIL_open_3D_provider(HPROVIDER lib); -DLLEXPORT C8 *WINAPI AIL_last_error(void); -DLLEXPORT S32 WINAPI AIL_3D_room_type(HPROVIDER lib); -DLLEXPORT void WINAPI AIL_set_3D_room_type(HPROVIDER lib, S32 room_type); -DLLEXPORT void WINAPI AIL_3D_provider_attribute(HPROVIDER lib, C8 const *name, void *val); -DLLEXPORT H3DSAMPLE WINAPI AIL_allocate_3D_sample_handle(HPROVIDER lib); -DLLEXPORT void WINAPI AIL_set_3D_sample_effects_level(H3DSAMPLE S, F32 effects_level); -DLLEXPORT void WINAPI AIL_set_3D_speaker_type(HPROVIDER lib, S32 speaker_type); -DLLEXPORT HSTREAM WINAPI AIL_open_stream(HDIGDRIVER dig, C8 const *filename, S32 stream_mem); -DLLEXPORT void WINAPI AIL_stream_ms_position(HSTREAM S, S32 *total_milliseconds, S32 *current_milliseconds); -DLLEXPORT void WINAPI AIL_close_stream(HSTREAM stream); -DLLEXPORT S32 WINAPI AIL_digital_handle_release(HDIGDRIVER drvr); -DLLEXPORT S32 WINAPI AIL_digital_handle_reacquire(HDIGDRIVER drvr); -DLLEXPORT C8 *WINAPI AIL_set_redist_directory(C8 const *dir); -DLLEXPORT S32 WINAPI AIL_startup(void); -DLLEXPORT S32 WINAPI AIL_set_preference(U32 number, S32 value); -DLLEXPORT HDIGDRIVER WINAPI AIL_open_digital_driver(U32 frequency, S32 bits, S32 channel, U32 flags); -DLLEXPORT void *WINAPI AIL_mem_alloc_lock(U32 size); -DLLEXPORT HSAMPLE WINAPI AIL_allocate_sample_handle(HDIGDRIVER dig); -DLLEXPORT void WINAPI AIL_init_sample(HSAMPLE S); -DLLEXPORT void WINAPI AIL_set_sample_type(HSAMPLE S, S32 format, U32 flags); -DLLEXPORT void WINAPI AIL_pause_stream(HSTREAM stream, S32 onoff); -DLLEXPORT void WINAPI AIL_release_sample_handle(HSAMPLE S); -DLLEXPORT void WINAPI AIL_mem_free_lock(void *ptr); -DLLEXPORT void WINAPI AIL_close_digital_driver(HDIGDRIVER dig); -DLLEXPORT void WINAPI AIL_shutdown(void); -DLLEXPORT void WINAPI AIL_set_3D_sample_volume(H3DSAMPLE S, S32 volume); -DLLEXPORT void WINAPI AIL_set_sample_volume(HSAMPLE S, S32 volume); -DLLEXPORT void WINAPI AIL_set_sample_address(HSAMPLE S, void const *start, U32 len); -DLLEXPORT S32 WINAPI AIL_set_3D_sample_info(H3DSAMPLE S, AILSOUNDINFO const *info); -DLLEXPORT void WINAPI AIL_set_3D_position(H3DPOBJECT obj, F32 X, F32 Y, F32 Z); -DLLEXPORT void WINAPI AIL_set_3D_sample_distances(H3DSAMPLE S, F32 max_dist, F32 min_dist); -DLLEXPORT void WINAPI AIL_set_sample_pan(HSAMPLE S, S32 pan); -DLLEXPORT void WINAPI AIL_set_sample_playback_rate(HSAMPLE S, S32 playback_rate); -DLLEXPORT void WINAPI AIL_set_3D_sample_playback_rate(H3DSAMPLE S, S32 playback_rate); -DLLEXPORT void WINAPI AIL_set_sample_loop_block(HSAMPLE S, S32 loop_start_offset, S32 loop_end_offset); -DLLEXPORT void WINAPI AIL_set_3D_sample_loop_block(H3DSAMPLE S, S32 loop_start_offset, S32 loop_end_offset); -DLLEXPORT void WINAPI AIL_set_sample_loop_count(HSAMPLE S, S32 loop_count); -DLLEXPORT void WINAPI AIL_set_3D_sample_loop_count(H3DSAMPLE S, S32 loops); -DLLEXPORT U32 WINAPI AIL_sample_status(HSAMPLE S); -DLLEXPORT U32 WINAPI AIL_3D_sample_status(H3DSAMPLE S); -DLLEXPORT void WINAPI AIL_start_sample(HSAMPLE S); -DLLEXPORT void WINAPI AIL_start_3D_sample(H3DSAMPLE S); -DLLEXPORT void WINAPI AIL_end_sample(HSAMPLE S); -DLLEXPORT void WINAPI AIL_end_3D_sample(H3DSAMPLE S); -DLLEXPORT void WINAPI AIL_set_stream_loop_count(HSTREAM stream, S32 count); -DLLEXPORT S32 WINAPI AIL_service_stream(HSTREAM stream, S32 fillup); -DLLEXPORT void WINAPI AIL_start_stream(HSTREAM stream); -DLLEXPORT void WINAPI AIL_set_stream_ms_position(HSTREAM S, S32 milliseconds); -DLLEXPORT void WINAPI AIL_set_stream_volume(HSTREAM stream, S32 volume); -DLLEXPORT void WINAPI AIL_set_stream_pan(HSTREAM stream, S32 pan); -DLLEXPORT S32 WINAPI AIL_stream_status(HSTREAM stream); +typedef void (WINAPI *AIL_file_close_callback)(U32 FileHandle); + +#define AIL_FILE_SEEK_BEGIN 0 +#define AIL_FILE_SEEK_CURRENT 1 +#define AIL_FILE_SEEK_END 2 + +typedef S32(WINAPI *AIL_file_seek_callback)(U32 FileHandle, S32 Offset, U32 Type); + +typedef U32(WINAPI *AIL_file_read_callback)(U32 FileHandle, void* Buffer, U32 Bytes); + +#ifdef RE3MSS_EXPORTS +#define RE3MSS_EXPORT __declspec(dllexport) +#else +#define RE3MSS_EXPORT __declspec(dllimport) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +RE3MSS_EXPORT S32 WINAPI AIL_enumerate_3D_providers(HPROENUM *next, HPROVIDER *dest, C8 **name); +RE3MSS_EXPORT void WINAPI AIL_release_3D_sample_handle(H3DSAMPLE S); +RE3MSS_EXPORT void WINAPI AIL_close_3D_provider(HPROVIDER lib); +RE3MSS_EXPORT void WINAPI AIL_set_3D_provider_preference(HPROVIDER lib, C8 const *name, void const *val); +RE3MSS_EXPORT M3DRESULT WINAPI AIL_open_3D_provider(HPROVIDER lib); +RE3MSS_EXPORT C8 *WINAPI AIL_last_error(void); +RE3MSS_EXPORT S32 WINAPI AIL_3D_room_type(HPROVIDER lib); +RE3MSS_EXPORT void WINAPI AIL_set_3D_room_type(HPROVIDER lib, S32 room_type); +RE3MSS_EXPORT void WINAPI AIL_3D_provider_attribute(HPROVIDER lib, C8 const *name, void *val); +RE3MSS_EXPORT H3DSAMPLE WINAPI AIL_allocate_3D_sample_handle(HPROVIDER lib); +RE3MSS_EXPORT void WINAPI AIL_set_3D_sample_effects_level(H3DSAMPLE S, F32 effects_level); +RE3MSS_EXPORT void WINAPI AIL_set_3D_speaker_type(HPROVIDER lib, S32 speaker_type); +RE3MSS_EXPORT HSTREAM WINAPI AIL_open_stream(HDIGDRIVER dig, C8 const *filename, S32 stream_mem); +RE3MSS_EXPORT void WINAPI AIL_stream_ms_position(HSTREAM S, S32 *total_milliseconds, S32 *current_milliseconds); +RE3MSS_EXPORT void WINAPI AIL_close_stream(HSTREAM stream); +RE3MSS_EXPORT S32 WINAPI AIL_digital_handle_release(HDIGDRIVER drvr); +RE3MSS_EXPORT S32 WINAPI AIL_digital_handle_reacquire(HDIGDRIVER drvr); +RE3MSS_EXPORT C8 *WINAPI AIL_set_redist_directory(C8 const *dir); +RE3MSS_EXPORT S32 WINAPI AIL_startup(void); +RE3MSS_EXPORT S32 WINAPI AIL_set_preference(U32 number, S32 value); +RE3MSS_EXPORT HDIGDRIVER WINAPI AIL_open_digital_driver(U32 frequency, S32 bits, S32 channel, U32 flags); +RE3MSS_EXPORT void *WINAPI AIL_mem_alloc_lock(U32 size); +RE3MSS_EXPORT HSAMPLE WINAPI AIL_allocate_sample_handle(HDIGDRIVER dig); +RE3MSS_EXPORT void WINAPI AIL_init_sample(HSAMPLE S); +RE3MSS_EXPORT void WINAPI AIL_set_sample_type(HSAMPLE S, S32 format, U32 flags); +RE3MSS_EXPORT void WINAPI AIL_pause_stream(HSTREAM stream, S32 onoff); +RE3MSS_EXPORT void WINAPI AIL_release_sample_handle(HSAMPLE S); +RE3MSS_EXPORT void WINAPI AIL_mem_free_lock(void *ptr); +RE3MSS_EXPORT void WINAPI AIL_close_digital_driver(HDIGDRIVER dig); +RE3MSS_EXPORT void WINAPI AIL_shutdown(void); +RE3MSS_EXPORT void WINAPI AIL_set_3D_sample_volume(H3DSAMPLE S, S32 volume); +RE3MSS_EXPORT void WINAPI AIL_set_sample_volume(HSAMPLE S, S32 volume); +RE3MSS_EXPORT void WINAPI AIL_set_sample_address(HSAMPLE S, void const *start, U32 len); +RE3MSS_EXPORT S32 WINAPI AIL_set_3D_sample_info(H3DSAMPLE S, AILSOUNDINFO const *info); +RE3MSS_EXPORT void WINAPI AIL_set_3D_position(H3DPOBJECT obj, F32 X, F32 Y, F32 Z); +RE3MSS_EXPORT void WINAPI AIL_set_3D_sample_distances(H3DSAMPLE S, F32 max_dist, F32 min_dist); +RE3MSS_EXPORT void WINAPI AIL_set_sample_pan(HSAMPLE S, S32 pan); +RE3MSS_EXPORT void WINAPI AIL_set_sample_playback_rate(HSAMPLE S, S32 playback_rate); +RE3MSS_EXPORT void WINAPI AIL_set_3D_sample_playback_rate(H3DSAMPLE S, S32 playback_rate); +RE3MSS_EXPORT void WINAPI AIL_set_sample_loop_block(HSAMPLE S, S32 loop_start_offset, S32 loop_end_offset); +RE3MSS_EXPORT void WINAPI AIL_set_3D_sample_loop_block(H3DSAMPLE S, S32 loop_start_offset, S32 loop_end_offset); +RE3MSS_EXPORT void WINAPI AIL_set_sample_loop_count(HSAMPLE S, S32 loop_count); +RE3MSS_EXPORT void WINAPI AIL_set_3D_sample_loop_count(H3DSAMPLE S, S32 loops); +RE3MSS_EXPORT U32 WINAPI AIL_sample_status(HSAMPLE S); +RE3MSS_EXPORT U32 WINAPI AIL_3D_sample_status(H3DSAMPLE S); +RE3MSS_EXPORT void WINAPI AIL_start_sample(HSAMPLE S); +RE3MSS_EXPORT void WINAPI AIL_start_3D_sample(H3DSAMPLE S); +RE3MSS_EXPORT void WINAPI AIL_end_sample(HSAMPLE S); +RE3MSS_EXPORT void WINAPI AIL_end_3D_sample(H3DSAMPLE S); +RE3MSS_EXPORT void WINAPI AIL_set_stream_loop_count(HSTREAM stream, S32 count); +RE3MSS_EXPORT S32 WINAPI AIL_service_stream(HSTREAM stream, S32 fillup); +RE3MSS_EXPORT void WINAPI AIL_start_stream(HSTREAM stream); +RE3MSS_EXPORT void WINAPI AIL_set_stream_ms_position(HSTREAM S, S32 milliseconds); +RE3MSS_EXPORT void WINAPI AIL_set_stream_volume(HSTREAM stream, S32 volume); +RE3MSS_EXPORT void WINAPI AIL_set_stream_pan(HSTREAM stream, S32 pan); +RE3MSS_EXPORT S32 WINAPI AIL_stream_status(HSTREAM stream); +RE3MSS_EXPORT void WINAPI AIL_set_file_callbacks(AIL_file_open_callback opencb, AIL_file_close_callback closecb, AIL_file_seek_callback seekcb, AIL_file_read_callback readcb); + +#ifdef __cplusplus +} +#endif diff --git a/vendor/milessdk/lib/mss32.lib b/vendor/milessdk/lib/mss32.lib index f97091c75ff9988cd906e5e43e56b538c951a428..e63a1a05f4daa88f97baf81655ef07cc9a7b8124 100644 GIT binary patch delta 3203 zcmchZe{56N6~_mMP~=*S9Ps;*^OA%%c;?q_F-tvek{$p5X>6Va1IRSyt3Hxjw} zh#J~unpYDE(i1Wn*a*_=WtuERg78t9#w$bu{|=b|Tnn;^9DDHuo-^Iz7Z$;pAl4(3 z>?ab$B$;Fi|AW|+OzI_~8GLwx$S#?B*a)H!79@sb8n+@K5XZ&@nGqRp_aKoM1fw#c z(?o*0D>98HEChiGnVJ(sf?7Bh)RoFKj3HB?2_k~TJu<%CL;}BE#s?ii(-$%i*KLCX z5WgT3g+oEjG8y+2ksu;=2|SO<)V3l35bTwy--n$8?_!w{j!qEh6!0!<1D~w6@rnX% za_tjs4|jB~ZCkUdvvc*THNSj(VJt;$Z5``2w6*>4?t9xFzm>tEpBKDh%&(pJ|7)k2 zh#sgS+UO+ea}l*S5Us}GL>l86qV;%Mnuv~uiLNvf?eJqk06EGM?FDB%u)|zWjHo|J zB;lFDa|+LwaG*Z0D}u3ltVRBYP)Xfe;b>!=XaoX-UgRxEbUFlqIwBM1CLnO42FA5S zr5GDSP+JkiJy^UOxwIpQD4t(nY#Zh;z*i}pFT`d;|n2l2(wX@^E< zfV#zXp#-JKL=EJlEIFy3LKG$=6;m^LsgeBTqBJ%dB@Z=`o92_ADkwuqDyKL($U>!L zr7DV%M72~$3#g3DWG5TdP$e0th_p19s%ajTkdA^BAq~x;f*IAW?^m{vM~%)yj`@2E z=g%siLj#t>TKlZwTvhQwi;b<0dHkNF0A*(E|K=-dVxP>c8f#bvjL&7k_{I#9{7mRdcJe{pPxeyk<$BeXGkP zJ!jZ=l^=2S-86OR7q01Ax1qkH9WuAM7b%wT%9@}QKC|p&9&|5Mjz_aW>BZRb_c`uK zDaSX2Y&;$|OMP>XOmeR$tDIX|W8?i%v+>hf=`)lY72?qOpwY$mhV*J*T+EpH|H6EV1(S zfJMrT-#^Vm{)A!*S+#Llz$|?*{op$s3MiGuvh4wjVM}r1!%B!3Lwsqeg^k(#9NiT7 zYV5{GY^hZVh`73N42566`xox1RmR0PV_tvY<*Ph7drll*Xa9-+@XDa-_;TqrtT=t- z7`g^-uEZt!O1=_Qr9@=fdUEwUd{>=1(-^PQ4vz9$dE>sIvErEaV>B3CepJNLawjT6 z<#R(QDA_mPd5L$2W>teo|J&|2C)gUEwN0eJurVI|#0lSag!^N&jo%38xt=LlW6RR< z%jkLNO9)}K+|Jf|m7O@UKSj*O;#dE135^^WZsA74BSwks=+RPwBZoY*L!{#37OV^L6fztL`VpeYQPc9>MDctzV+= zeiQRhV1d$OuG9_B7CJ|qSnWjs18BInIA_GEJ8L`jcM+$LUunoF{U8F(@A`%>d3j61 z#(fS0hZCyope5-3^?Y(zw1fbUrp#>kWlRt6{}h0`0bdVA5Gd|7*I;( zLe?xFUOw#Pvq?K2&}w*lGQUD}Yg@LCi3+Kkk&7-caZyTTl&dz4YkJ9;n~$e#++9}0 zn`RrKXX=jq?DLQCI;SwaHLBwY8uq^#Ix0R&>XE)ZWmR06%-_6bV&|)02RN3t@!uM6 zxu5-yEdRHYUx&f&0xjR4o)s#hFnsv*qEjLYyz+Untb#v}DTQX5TH2!9d$|2b1+3y+ zo(U^sZOH_U1NU7X#zz*uIz+pWY`o5|^ucIBhSy&B<0wAJ@TDMe)LMrAsfq?By3$P- zW=xX2CL2>|h#3Bmwdmfm_fMC@MT$qWsu)lz#$U8uyC90SQN*yN(!oD%QpF%n2CYf= PEI&0|4ZAcSZ1VgMN$ln9 delta 2953 zcmchZOK6-`7>3`b(=?gpGELH%m}D|DnankFzh@F+Eww6S5jV98CMl$aB5l*O+6W~< zs4j{~^xG7x@w&*O)l0+?aUS{ zEWb(Btx1jniqb<(qzSN?=SYT2HC8y1Amb}`r72YSO|o;E;#t5V z%8{g9n&brvAekmj{u-btoz`U6=}#&*G@%@zSd3APBC%I9bOcb8IyBKqKry&S6QdYK z{EQ~I1}Lgbq{xqJ!t9L25=RnZ4n_5WW{AxuQ^*};0Fq`vMew?2fE6oJ%bJ1v{3cOW zpon*CQhu(J!ONNciU9MZGz_eeeL?yrxRwDf7JyS6D;(#tz}X_@5?30yK>sGLUCRTf zOIXA@4Q?<&F2q1FU@wClVOKhsWHJiu8Dt>NpNRu&+^y3TF-~W97+4}J^n1WL)yacg zKf@%~DQ0c}SWW@=Io@ELZuk zKgx(8jR8~6g6jVyZ5iS5_{FEWTCj$U-310J{$L?4{kiY;hFKU&d-Cd80} z1DnwBZ_dU4Dd}cRJ@L%=RDSo=?A*~;4$T~xo7#Wk#M~j7Xl-46Y5Td&a?aVdn%?n2 zZ+o@x{JGk3ii*Hj}c#61x4!PazlhII*-DEmc3;R}R z)SUOoZ=p`horjf&!66?tc_kb+-0N!R!-m?6rFe_V%(Kh$LC*CyDB_oG@e?;US~Ll!#x@^iG;X7*037C99& z6dRG>iy4vcBy}JCjM~nq0jEd8aifsB;Q6>AxV~-o;#HdpnGRX~)rGt;G-h9`H}%^g zLt=e?EMd&E**ebo#4aOFMa$-c!HeyX_U3+Wzf&GXw%g6>(wCElbXKjywxx{udPxf@ zqa@Y;pi|kcwEpC*xV;o=}AqK%G`U1N6$mmL^%xZV15g>XHIhrWbQV_BxGi zy^=GwRjv8*`h4>3=S%C5U%L9_`Mgn){jd$v@D;gv5onlYiJ zSS1WgYjN1Fmbb6|K13L!wb3V^7L8P{O5Az_BeGcRtF^@`hbzVjvP+Jssv14=X32=d z7F%)Rab=?I@JesVXe_I>Bt+%$3ZrjsleLPW(OyQHWqjA*k?~=}gd(gMK}ipLWWn1kUk@8e zX8S$z*Rbw+55;7~Q%%~Hs=Yf<)du{jf}FfoE!quu%dJxSxtLd_T=90vxvEo^!$z}c zXZ1tb6=eTN)*eL3SRK(>9-~1~ZjEe^VLyx|)_c?4C(n(VJ|7MK4e49V AmjD0& From 7687ce84ed49e71c1fe3dcfba69ca182e72cc090 Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 18 Jan 2021 20:03:24 +0100 Subject: [PATCH 115/152] wrong ifdef --- src/extras/custompipes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extras/custompipes.h b/src/extras/custompipes.h index 183b85da..7ad239f0 100644 --- a/src/extras/custompipes.h +++ b/src/extras/custompipes.h @@ -1,7 +1,7 @@ #pragma once -#ifdef EXTENDED_PIPELINES #ifdef LIBRW +#ifdef EXTENDED_PIPELINES namespace CustomPipes { From 91093305d65305722e380c0087c71469363a8396 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 18 Jan 2021 21:06:59 +0200 Subject: [PATCH 116/152] Get rid of RwMatrix in CMatrix --- src/control/Replay.cpp | 2 +- src/core/Camera.cpp | 45 +++- src/core/Camera.h | 6 +- src/entities/Entity.cpp | 6 +- src/math/Matrix.cpp | 452 +++++++++++++++++++-------------------- src/math/Matrix.h | 66 +++--- src/math/Vector.cpp | 18 +- src/render/SpecialFX.cpp | 2 +- 8 files changed, 319 insertions(+), 278 deletions(-) diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index 2e87d1a7..2dd66333 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -305,7 +305,7 @@ void CReplay::RecordThisFrame(void) #endif tGeneralPacket* general = (tGeneralPacket*)&Record.m_pBase[Record.m_nOffset]; general->type = REPLAYPACKET_GENERAL; - general->camera_pos.CopyOnlyMatrix(&TheCamera.GetMatrix()); + general->camera_pos.CopyOnlyMatrix(TheCamera.GetMatrix()); general->player_pos = FindPlayerCoors(); general->in_rcvehicle = CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle ? true : false; Record.m_nOffset += sizeof(*general); diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 7a831068..9d169716 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -3629,9 +3629,17 @@ CCamera::CalculateDerivedValues(void) bool CCamera::IsPointVisible(const CVector ¢er, const CMatrix *mat) { - RwV3d c; - c = center; - RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix); +#ifdef GTA_PS2 + CVuVector c; + TransformPoint(c, *mat, center); +#else + CVector c = center; + #ifdef FIX_BUGS + c = *mat * center; + #else + RwV3dTransformPoints(&c, &c, 1, (RwMatrix*)mat); + #endif +#endif if(c.y < CDraw::GetNearClipZ()) return false; if(c.y > CDraw::GetFarClipZ()) return false; if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > 0.0f) return false; @@ -3644,9 +3652,17 @@ CCamera::IsPointVisible(const CVector ¢er, const CMatrix *mat) bool CCamera::IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat) { - RwV3d c; - c = center; - RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix); +#ifdef GTA_PS2 + CVuVector c; + TransformPoint(c, *mat, center); +#else + CVector c = center; + #ifdef FIX_BUGS + c = *mat * center; + #else + RwV3dTransformPoints(&c, &c, 1, (RwMatrix*)mat); + #endif +#endif if(c.y + radius < CDraw::GetNearClipZ()) return false; if(c.y - radius > CDraw::GetFarClipZ()) return false; if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > radius) return false; @@ -3664,11 +3680,24 @@ CCamera::IsSphereVisible(const CVector ¢er, float radius) } bool -CCamera::IsBoxVisible(RwV3d *box, const CMatrix *mat) +#ifdef GTA_PS2 +CCamera::IsBoxVisible(CVuVector *box, const CMatrix *mat) +#else +CCamera::IsBoxVisible(CVector *box, const CMatrix *mat) +#endif { int i; int frustumTests[6] = { 0 }; - RwV3dTransformPoints(box, box, 8, &mat->m_matrix); +#ifdef GTA_PS2 + TransformPoints(box, 8, *mat, box); +#else + #ifdef FIX_BUGS + for (i = 0; i < 8; i++) + box[i] = *mat * box[i]; + #else + RwV3dTransformPoints(box, box, 8, (RwMatrix*)mat); + #endif +#endif for(i = 0; i < 8; i++){ if(box[i].y < CDraw::GetNearClipZ()) frustumTests[0]++; diff --git a/src/core/Camera.h b/src/core/Camera.h index ca1bd135..d7293e20 100644 --- a/src/core/Camera.h +++ b/src/core/Camera.h @@ -641,7 +641,11 @@ public: bool IsPointVisible(const CVector ¢er, const CMatrix *mat); bool IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat); bool IsSphereVisible(const CVector ¢er, float radius); - bool IsBoxVisible(RwV3d *box, const CMatrix *mat); +#ifdef GTA_PS2 + bool IsBoxVisible(CVuVector *box, const CMatrix *mat); +#else + bool IsBoxVisible(CVector *box, const CMatrix *mat); +#endif }; VALIDATE_SIZE(CCamera, 0xE9D8); diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index 709f91c1..4885d631 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -407,7 +407,11 @@ CEntity::GetIsOnScreen(void) bool CEntity::GetIsOnScreenComplex(void) { - RwV3d boundBox[8]; +#ifdef GTA_PS2 + CVuVector boundBox[8]; +#else + CVector boundBox[8]; +#endif if(TheCamera.IsPointVisible(GetBoundCentre(), &TheCamera.GetCameraMatrix())) return true; diff --git a/src/math/Matrix.cpp b/src/math/Matrix.cpp index a8b1b182..bee3ffba 100644 --- a/src/math/Matrix.cpp +++ b/src/math/Matrix.cpp @@ -60,14 +60,20 @@ CMatrix::Detach(void) void CMatrix::Update(void) { - m_matrix = *m_attachment; + right = m_attachment->right; + forward = m_attachment->up; + up = m_attachment->at; + pos = m_attachment->pos; } void CMatrix::UpdateRW(void) { if (m_attachment) { - *m_attachment = m_matrix; + m_attachment->right = right; + m_attachment->up = forward; + m_attachment->at = up; + m_attachment->pos = pos; RwMatrixUpdate(m_attachment); } } @@ -75,104 +81,96 @@ CMatrix::UpdateRW(void) void CMatrix::operator=(CMatrix const &rhs) { - m_matrix = rhs.m_matrix; + memcpy(this, &rhs, sizeof(f)); if (m_attachment) UpdateRW(); } void -CMatrix::CopyOnlyMatrix(CMatrix *other) +CMatrix::CopyOnlyMatrix(const CMatrix &other) { - m_matrix = other->m_matrix; + memcpy(this, &other, sizeof(f)); } CMatrix & CMatrix::operator+=(CMatrix const &rhs) { - m_matrix.right.x += rhs.m_matrix.right.x; - m_matrix.up.x += rhs.m_matrix.up.x; - m_matrix.at.x += rhs.m_matrix.at.x; - m_matrix.right.y += rhs.m_matrix.right.y; - m_matrix.up.y += rhs.m_matrix.up.y; - m_matrix.at.y += rhs.m_matrix.at.y; - m_matrix.right.z += rhs.m_matrix.right.z; - m_matrix.up.z += rhs.m_matrix.up.z; - m_matrix.at.z += rhs.m_matrix.at.z; - m_matrix.pos.x += rhs.m_matrix.pos.x; - m_matrix.pos.y += rhs.m_matrix.pos.y; - m_matrix.pos.z += rhs.m_matrix.pos.z; + right += rhs.right; + forward += rhs.forward; + up += rhs.up; + pos += rhs.pos; return *this; } void CMatrix::SetUnity(void) { - m_matrix.right.x = 1.0f; - m_matrix.right.y = 0.0f; - m_matrix.right.z = 0.0f; - m_matrix.up.x = 0.0f; - m_matrix.up.y = 1.0f; - m_matrix.up.z = 0.0f; - m_matrix.at.x = 0.0f; - m_matrix.at.y = 0.0f; - m_matrix.at.z = 1.0f; - m_matrix.pos.x = 0.0f; - m_matrix.pos.y = 0.0f; - m_matrix.pos.z = 0.0f; + right.x = 1.0f; + right.y = 0.0f; + right.z = 0.0f; + forward.x = 0.0f; + forward.y = 1.0f; + forward.z = 0.0f; + up.x = 0.0f; + up.y = 0.0f; + up.z = 1.0f; + pos.x = 0.0f; + pos.y = 0.0f; + pos.z = 0.0f; } void CMatrix::ResetOrientation(void) { - m_matrix.right.x = 1.0f; - m_matrix.right.y = 0.0f; - m_matrix.right.z = 0.0f; - m_matrix.up.x = 0.0f; - m_matrix.up.y = 1.0f; - m_matrix.up.z = 0.0f; - m_matrix.at.x = 0.0f; - m_matrix.at.y = 0.0f; - m_matrix.at.z = 1.0f; + right.x = 1.0f; + right.y = 0.0f; + right.z = 0.0f; + forward.x = 0.0f; + forward.y = 1.0f; + forward.z = 0.0f; + up.x = 0.0f; + up.y = 0.0f; + up.z = 1.0f; } void CMatrix::SetScale(float s) { - m_matrix.right.x = s; - m_matrix.right.y = 0.0f; - m_matrix.right.z = 0.0f; + right.x = s; + right.y = 0.0f; + right.z = 0.0f; - m_matrix.up.x = 0.0f; - m_matrix.up.y = s; - m_matrix.up.z = 0.0f; + forward.x = 0.0f; + forward.y = s; + forward.z = 0.0f; - m_matrix.at.x = 0.0f; - m_matrix.at.y = 0.0f; - m_matrix.at.z = s; + up.x = 0.0f; + up.y = 0.0f; + up.z = s; - m_matrix.pos.x = 0.0f; - m_matrix.pos.y = 0.0f; - m_matrix.pos.z = 0.0f; + pos.x = 0.0f; + pos.y = 0.0f; + pos.z = 0.0f; } void CMatrix::SetTranslate(float x, float y, float z) { - m_matrix.right.x = 1.0f; - m_matrix.right.y = 0.0f; - m_matrix.right.z = 0.0f; + right.x = 1.0f; + right.y = 0.0f; + right.z = 0.0f; - m_matrix.up.x = 0.0f; - m_matrix.up.y = 1.0f; - m_matrix.up.z = 0.0f; + forward.x = 0.0f; + forward.y = 1.0f; + forward.z = 0.0f; - m_matrix.at.x = 0.0f; - m_matrix.at.y = 0.0f; - m_matrix.at.z = 1.0f; + up.x = 0.0f; + up.y = 0.0f; + up.z = 1.0f; - m_matrix.pos.x = x; - m_matrix.pos.y = y; - m_matrix.pos.z = z; + pos.x = x; + pos.y = y; + pos.z = z; } void @@ -181,17 +179,17 @@ CMatrix::SetRotateXOnly(float angle) float c = Cos(angle); float s = Sin(angle); - m_matrix.right.x = 1.0f; - m_matrix.right.y = 0.0f; - m_matrix.right.z = 0.0f; + right.x = 1.0f; + right.y = 0.0f; + right.z = 0.0f; - m_matrix.up.x = 0.0f; - m_matrix.up.y = c; - m_matrix.up.z = s; + forward.x = 0.0f; + forward.y = c; + forward.z = s; - m_matrix.at.x = 0.0f; - m_matrix.at.y = -s; - m_matrix.at.z = c; + up.x = 0.0f; + up.y = -s; + up.z = c; } void @@ -200,17 +198,17 @@ CMatrix::SetRotateYOnly(float angle) float c = Cos(angle); float s = Sin(angle); - m_matrix.right.x = c; - m_matrix.right.y = 0.0f; - m_matrix.right.z = -s; + right.x = c; + right.y = 0.0f; + right.z = -s; - m_matrix.up.x = 0.0f; - m_matrix.up.y = 1.0f; - m_matrix.up.z = 0.0f; + forward.x = 0.0f; + forward.y = 1.0f; + forward.z = 0.0f; - m_matrix.at.x = s; - m_matrix.at.y = 0.0f; - m_matrix.at.z = c; + up.x = s; + up.y = 0.0f; + up.z = c; } void @@ -219,26 +217,26 @@ CMatrix::SetRotateZOnly(float angle) float c = Cos(angle); float s = Sin(angle); - m_matrix.right.x = c; - m_matrix.right.y = s; - m_matrix.right.z = 0.0f; + right.x = c; + right.y = s; + right.z = 0.0f; - m_matrix.up.x = -s; - m_matrix.up.y = c; - m_matrix.up.z = 0.0f; + forward.x = -s; + forward.y = c; + forward.z = 0.0f; - m_matrix.at.x = 0.0f; - m_matrix.at.y = 0.0f; - m_matrix.at.z = 1.0f; + up.x = 0.0f; + up.y = 0.0f; + up.z = 1.0f; } void CMatrix::SetRotateX(float angle) { SetRotateXOnly(angle); - m_matrix.pos.x = 0.0f; - m_matrix.pos.y = 0.0f; - m_matrix.pos.z = 0.0f; + pos.x = 0.0f; + pos.y = 0.0f; + pos.z = 0.0f; } @@ -246,18 +244,18 @@ void CMatrix::SetRotateY(float angle) { SetRotateYOnly(angle); - m_matrix.pos.x = 0.0f; - m_matrix.pos.y = 0.0f; - m_matrix.pos.z = 0.0f; + pos.x = 0.0f; + pos.y = 0.0f; + pos.z = 0.0f; } void CMatrix::SetRotateZ(float angle) { SetRotateZOnly(angle); - m_matrix.pos.x = 0.0f; - m_matrix.pos.y = 0.0f; - m_matrix.pos.z = 0.0f; + pos.x = 0.0f; + pos.y = 0.0f; + pos.z = 0.0f; } void @@ -270,21 +268,21 @@ CMatrix::SetRotate(float xAngle, float yAngle, float zAngle) float cZ = Cos(zAngle); float sZ = Sin(zAngle); - m_matrix.right.x = cZ * cY - (sZ * sX) * sY; - m_matrix.right.y = (cZ * sX) * sY + sZ * cY; - m_matrix.right.z = -cX * sY; + right.x = cZ * cY - (sZ * sX) * sY; + right.y = (cZ * sX) * sY + sZ * cY; + right.z = -cX * sY; - m_matrix.up.x = -sZ * cX; - m_matrix.up.y = cZ * cX; - m_matrix.up.z = sX; + forward.x = -sZ * cX; + forward.y = cZ * cX; + forward.z = sX; - m_matrix.at.x = (sZ * sX) * cY + cZ * sY; - m_matrix.at.y = sZ * sY - (cZ * sX) * cY; - m_matrix.at.z = cX * cY; + up.x = (sZ * sX) * cY + cZ * sY; + up.y = sZ * sY - (cZ * sX) * cY; + up.z = cX * cY; - m_matrix.pos.x = 0.0f; - m_matrix.pos.y = 0.0f; - m_matrix.pos.z = 0.0f; + pos.x = 0.0f; + pos.y = 0.0f; + pos.z = 0.0f; } void @@ -293,23 +291,23 @@ CMatrix::RotateX(float x) float c = Cos(x); float s = Sin(x); - float ry = m_matrix.right.y; - float rz = m_matrix.right.z; - float uy = m_matrix.up.y; - float uz = m_matrix.up.z; - float ay = m_matrix.at.y; - float az = m_matrix.at.z; - float py = m_matrix.pos.y; - float pz = m_matrix.pos.z; + float ry = right.y; + float rz = right.z; + float uy = forward.y; + float uz = forward.z; + float ay = up.y; + float az = up.z; + float py = pos.y; + float pz = pos.z; - m_matrix.right.y = c * ry - s * rz; - m_matrix.right.z = c * rz + s * ry; - m_matrix.up.y = c * uy - s * uz; - m_matrix.up.z = c * uz + s * uy; - m_matrix.at.y = c * ay - s * az; - m_matrix.at.z = c * az + s * ay; - m_matrix.pos.y = c * py - s * pz; - m_matrix.pos.z = c * pz + s * py; + right.y = c * ry - s * rz; + right.z = c * rz + s * ry; + forward.y = c * uy - s * uz; + forward.z = c * uz + s * uy; + up.y = c * ay - s * az; + up.z = c * az + s * ay; + pos.y = c * py - s * pz; + pos.z = c * pz + s * py; } void @@ -318,23 +316,23 @@ CMatrix::RotateY(float y) float c = Cos(y); float s = Sin(y); - float rx = m_matrix.right.x; - float rz = m_matrix.right.z; - float ux = m_matrix.up.x; - float uz = m_matrix.up.z; - float ax = m_matrix.at.x; - float az = m_matrix.at.z; - float px = m_matrix.pos.x; - float pz = m_matrix.pos.z; + float rx = right.x; + float rz = right.z; + float ux = forward.x; + float uz = forward.z; + float ax = up.x; + float az = up.z; + float px = pos.x; + float pz = pos.z; - m_matrix.right.x = c * rx + s * rz; - m_matrix.right.z = c * rz - s * rx; - m_matrix.up.x = c * ux + s * uz; - m_matrix.up.z = c * uz - s * ux; - m_matrix.at.x = c * ax + s * az; - m_matrix.at.z = c * az - s * ax; - m_matrix.pos.x = c * px + s * pz; - m_matrix.pos.z = c * pz - s * px; + right.x = c * rx + s * rz; + right.z = c * rz - s * rx; + forward.x = c * ux + s * uz; + forward.z = c * uz - s * ux; + up.x = c * ax + s * az; + up.z = c * az - s * ax; + pos.x = c * px + s * pz; + pos.z = c * pz - s * px; } void @@ -343,23 +341,23 @@ CMatrix::RotateZ(float z) float c = Cos(z); float s = Sin(z); - float ry = m_matrix.right.y; - float rx = m_matrix.right.x; - float uy = m_matrix.up.y; - float ux = m_matrix.up.x; - float ay = m_matrix.at.y; - float ax = m_matrix.at.x; - float py = m_matrix.pos.y; - float px = m_matrix.pos.x; + float ry = right.y; + float rx = right.x; + float uy = forward.y; + float ux = forward.x; + float ay = up.y; + float ax = up.x; + float py = pos.y; + float px = pos.x; - m_matrix.right.x = c * rx - s * ry; - m_matrix.right.y = c * ry + s * rx; - m_matrix.up.x = c * ux - s * uy; - m_matrix.up.y = c * uy + s * ux; - m_matrix.at.x = c * ax - s * ay; - m_matrix.at.y = c * ay + s * ax; - m_matrix.pos.x = c * px - s * py; - m_matrix.pos.y = c * py + s * px; + right.x = c * rx - s * ry; + right.y = c * ry + s * rx; + forward.x = c * ux - s * uy; + forward.y = c * uy + s * ux; + up.x = c * ax - s * ay; + up.y = c * ay + s * ax; + pos.x = c * px - s * py; + pos.y = c * py + s * px; } @@ -373,18 +371,18 @@ CMatrix::Rotate(float x, float y, float z) float cZ = Cos(z); float sZ = Sin(z); - float rx = m_matrix.right.x; - float ry = m_matrix.right.y; - float rz = m_matrix.right.z; - float ux = m_matrix.up.x; - float uy = m_matrix.up.y; - float uz = m_matrix.up.z; - float ax = m_matrix.at.x; - float ay = m_matrix.at.y; - float az = m_matrix.at.z; - float px = m_matrix.pos.x; - float py = m_matrix.pos.y; - float pz = m_matrix.pos.z; + float rx = right.x; + float ry = right.y; + float rz = right.z; + float ux = forward.x; + float uy = forward.y; + float uz = forward.z; + float ax = up.x; + float ay = up.y; + float az = up.z; + float px = pos.x; + float py = pos.y; + float pz = pos.z; float x1 = cZ * cY - (sZ * sX) * sY; float x2 = (cZ * sX) * sY + sZ * cY; @@ -396,18 +394,18 @@ CMatrix::Rotate(float x, float y, float z) float z2 = sZ * sY - (cZ * sX) * cY; float z3 = cX * cY; - m_matrix.right.x = x1 * rx + y1 * ry + z1 * rz; - m_matrix.right.y = x2 * rx + y2 * ry + z2 * rz; - m_matrix.right.z = x3 * rx + y3 * ry + z3 * rz; - m_matrix.up.x = x1 * ux + y1 * uy + z1 * uz; - m_matrix.up.y = x2 * ux + y2 * uy + z2 * uz; - m_matrix.up.z = x3 * ux + y3 * uy + z3 * uz; - m_matrix.at.x = x1 * ax + y1 * ay + z1 * az; - m_matrix.at.y = x2 * ax + y2 * ay + z2 * az; - m_matrix.at.z = x3 * ax + y3 * ay + z3 * az; - m_matrix.pos.x = x1 * px + y1 * py + z1 * pz; - m_matrix.pos.y = x2 * px + y2 * py + z2 * pz; - m_matrix.pos.z = x3 * px + y3 * py + z3 * pz; + right.x = x1 * rx + y1 * ry + z1 * rz; + right.y = x2 * rx + y2 * ry + z2 * rz; + right.z = x3 * rx + y3 * ry + z3 * rz; + forward.x = x1 * ux + y1 * uy + z1 * uz; + forward.y = x2 * ux + y2 * uy + z2 * uz; + forward.z = x3 * ux + y3 * uy + z3 * uz; + up.x = x1 * ax + y1 * ay + z1 * az; + up.y = x2 * ax + y2 * ay + z2 * az; + up.z = x3 * ax + y3 * ay + z3 * az; + pos.x = x1 * px + y1 * py + z1 * pz; + pos.y = x2 * px + y2 * py + z2 * pz; + pos.z = x3 * px + y3 * py + z3 * pz; } CMatrix & @@ -436,21 +434,18 @@ operator*(const CMatrix &m1, const CMatrix &m2) { // TODO: VU0 code CMatrix out; - RwMatrix *dst = &out.m_matrix; - const RwMatrix *src1 = &m1.m_matrix; - const RwMatrix *src2 = &m2.m_matrix; - dst->right.x = src1->right.x * src2->right.x + src1->up.x * src2->right.y + src1->at.x * src2->right.z; - dst->right.y = src1->right.y * src2->right.x + src1->up.y * src2->right.y + src1->at.y * src2->right.z; - dst->right.z = src1->right.z * src2->right.x + src1->up.z * src2->right.y + src1->at.z * src2->right.z; - dst->up.x = src1->right.x * src2->up.x + src1->up.x * src2->up.y + src1->at.x * src2->up.z; - dst->up.y = src1->right.y * src2->up.x + src1->up.y * src2->up.y + src1->at.y * src2->up.z; - dst->up.z = src1->right.z * src2->up.x + src1->up.z * src2->up.y + src1->at.z * src2->up.z; - dst->at.x = src1->right.x * src2->at.x + src1->up.x * src2->at.y + src1->at.x * src2->at.z; - dst->at.y = src1->right.y * src2->at.x + src1->up.y * src2->at.y + src1->at.y * src2->at.z; - dst->at.z = src1->right.z * src2->at.x + src1->up.z * src2->at.y + src1->at.z * src2->at.z; - dst->pos.x = src1->right.x * src2->pos.x + src1->up.x * src2->pos.y + src1->at.x * src2->pos.z + src1->pos.x; - dst->pos.y = src1->right.y * src2->pos.x + src1->up.y * src2->pos.y + src1->at.y * src2->pos.z + src1->pos.y; - dst->pos.z = src1->right.z * src2->pos.x + src1->up.z * src2->pos.y + src1->at.z * src2->pos.z + src1->pos.z; + out.right.x = m1.right.x * m2.right.x + m1.forward.x * m2.right.y + m1.up.x * m2.right.z; + out.right.y = m1.right.y * m2.right.x + m1.forward.y * m2.right.y + m1.up.y * m2.right.z; + out.right.z = m1.right.z * m2.right.x + m1.forward.z * m2.right.y + m1.up.z * m2.right.z; + out.forward.x = m1.right.x * m2.forward.x + m1.forward.x * m2.forward.y + m1.up.x * m2.forward.z; + out.forward.y = m1.right.y * m2.forward.x + m1.forward.y * m2.forward.y + m1.up.y * m2.forward.z; + out.forward.z = m1.right.z * m2.forward.x + m1.forward.z * m2.forward.y + m1.up.z * m2.forward.z; + out.up.x = m1.right.x * m2.up.x + m1.forward.x * m2.up.y + m1.up.x * m2.up.z; + out.up.y = m1.right.y * m2.up.x + m1.forward.y * m2.up.y + m1.up.y * m2.up.z; + out.up.z = m1.right.z * m2.up.x + m1.forward.z * m2.up.y + m1.up.z * m2.up.z; + out.pos.x = m1.right.x * m2.pos.x + m1.forward.x * m2.pos.y + m1.up.x * m2.pos.z + m1.pos.x; + out.pos.y = m1.right.y * m2.pos.x + m1.forward.y * m2.pos.y + m1.up.y * m2.pos.z + m1.pos.y; + out.pos.z = m1.right.z * m2.pos.x + m1.forward.z * m2.pos.y + m1.up.z * m2.pos.z + m1.pos.z; return out; } @@ -460,59 +455,56 @@ Invert(const CMatrix &src, CMatrix &dst) // TODO: VU0 code // GTA handles this as a raw 4x4 orthonormal matrix // and trashes the RW flags, let's not do that - float (*scr_fm)[4] = (float (*)[4])&src.m_matrix; - float (*dst_fm)[4] = (float (*)[4])&dst.m_matrix; - - dst_fm[3][0] = dst_fm[3][1] = dst_fm[3][2] = 0.0f; + dst.f[3][0] = dst.f[3][1] = dst.f[3][2] = 0.0f; #ifndef FIX_BUGS - dst_fm[3][3] = scr_fm[3][3]; + dst.f[3][3] = src.f[3][3]; #endif - dst_fm[0][0] = scr_fm[0][0]; - dst_fm[0][1] = scr_fm[1][0]; - dst_fm[0][2] = scr_fm[2][0]; + dst.f[0][0] = src.f[0][0]; + dst.f[0][1] = src.f[1][0]; + dst.f[0][2] = src.f[2][0]; #ifndef FIX_BUGS - dst_fm[0][3] = scr_fm[3][0]; + dst.f[0][3] = src.f[3][0]; #endif - dst_fm[1][0] = scr_fm[0][1]; - dst_fm[1][1] = scr_fm[1][1]; - dst_fm[1][2] = scr_fm[2][1]; + dst.f[1][0] = src.f[0][1]; + dst.f[1][1] = src.f[1][1]; + dst.f[1][2] = src.f[2][1]; #ifndef FIX_BUGS - dst_fm[1][3] = scr_fm[3][1]; + dst.f[1][3] = src.f[3][1]; #endif - dst_fm[2][0] = scr_fm[0][2]; - dst_fm[2][1] = scr_fm[1][2]; - dst_fm[2][2] = scr_fm[2][2]; + dst.f[2][0] = src.f[0][2]; + dst.f[2][1] = src.f[1][2]; + dst.f[2][2] = src.f[2][2]; #ifndef FIX_BUGS - dst_fm[2][3] = scr_fm[3][2]; + dst.f[2][3] = src.f[3][2]; #endif - dst_fm[3][0] += dst_fm[0][0] * scr_fm[3][0]; - dst_fm[3][1] += dst_fm[0][1] * scr_fm[3][0]; - dst_fm[3][2] += dst_fm[0][2] * scr_fm[3][0]; + dst.f[3][0] += dst.f[0][0] * src.f[3][0]; + dst.f[3][1] += dst.f[0][1] * src.f[3][0]; + dst.f[3][2] += dst.f[0][2] * src.f[3][0]; #ifndef FIX_BUGS - dst_fm[3][3] += dst_fm[0][3] * scr_fm[3][0]; + dst.f[3][3] += dst.f[0][3] * src.f[3][0]; #endif - dst_fm[3][0] += dst_fm[1][0] * scr_fm[3][1]; - dst_fm[3][1] += dst_fm[1][1] * scr_fm[3][1]; - dst_fm[3][2] += dst_fm[1][2] * scr_fm[3][1]; + dst.f[3][0] += dst.f[1][0] * src.f[3][1]; + dst.f[3][1] += dst.f[1][1] * src.f[3][1]; + dst.f[3][2] += dst.f[1][2] * src.f[3][1]; #ifndef FIX_BUGS - dst_fm[3][3] += dst_fm[1][3] * scr_fm[3][1]; + dst.f[3][3] += dst.f[1][3] * src.f[3][1]; #endif - dst_fm[3][0] += dst_fm[2][0] * scr_fm[3][2]; - dst_fm[3][1] += dst_fm[2][1] * scr_fm[3][2]; - dst_fm[3][2] += dst_fm[2][2] * scr_fm[3][2]; + dst.f[3][0] += dst.f[2][0] * src.f[3][2]; + dst.f[3][1] += dst.f[2][1] * src.f[3][2]; + dst.f[3][2] += dst.f[2][2] * src.f[3][2]; #ifndef FIX_BUGS - dst_fm[3][3] += dst_fm[2][3] * scr_fm[3][2]; + dst.f[3][3] += dst.f[2][3] * src.f[3][2]; #endif - dst_fm[3][0] = -dst_fm[3][0]; - dst_fm[3][1] = -dst_fm[3][1]; - dst_fm[3][2] = -dst_fm[3][2]; + dst.f[3][0] = -dst.f[3][0]; + dst.f[3][1] = -dst.f[3][1]; + dst.f[3][2] = -dst.f[3][2]; #ifndef FIX_BUGS - dst_fm[3][3] = scr_fm[3][3] - dst_fm[3][3]; + dst.f[3][3] = src.f[3][3] - dst.f[3][3]; #endif return dst; diff --git a/src/math/Matrix.h b/src/math/Matrix.h index d8f6388d..fdbd0b60 100644 --- a/src/math/Matrix.h +++ b/src/math/Matrix.h @@ -1,9 +1,22 @@ #pragma once +#include "VuVector.h" + class CMatrix { public: - RwMatrix m_matrix; + union + { + float f[4][4]; + struct + { + CVuVector right; + CVuVector forward; + CVuVector up; + CVuVector pos; + }; + }; + RwMatrix *m_attachment; bool m_hasRwMatrix; // are we the owner? @@ -25,31 +38,30 @@ public: CMatrix &operator+=(CMatrix const &rhs); CMatrix &operator*=(CMatrix const &rhs); - CVector &GetPosition(void){ return *(CVector*)&m_matrix.pos; } - CVector &GetRight(void) { return *(CVector*)&m_matrix.right; } - CVector &GetForward(void) { return *(CVector*)&m_matrix.up; } - CVector &GetUp(void) { return *(CVector*)&m_matrix.at; } + CVector &GetPosition(void){ return pos; } + CVector &GetRight(void) { return right; } + CVector &GetForward(void) { return forward; } + CVector &GetUp(void) { return up; } void SetTranslate(float x, float y, float z); void SetTranslate(const CVector &trans){ SetTranslate(trans.x, trans.y, trans.z); } void Translate(float x, float y, float z){ - m_matrix.pos.x += x; - m_matrix.pos.y += y; - m_matrix.pos.z += z; + pos.x += x; + pos.y += y; + pos.z += z; } void Translate(const CVector &trans){ Translate(trans.x, trans.y, trans.z); } void SetScale(float s); void Scale(float scale) { - float *pFloatMatrix = (float*)&m_matrix; for (int i = 0; i < 3; i++) #ifdef FIX_BUGS // BUGFIX from VC for (int j = 0; j < 3; j++) #else for (int j = 0; j < 4; j++) #endif - pFloatMatrix[i * 4 + j] *= scale; + f[i][j] *= scale; } @@ -60,17 +72,17 @@ public: float c = Cos(angle); float s = Sin(angle); - m_matrix.right.x = c * scale; - m_matrix.right.y = s * scale; - m_matrix.right.z = 0.0f; + right.x = c * scale; + right.y = s * scale; + right.z = 0.0f; - m_matrix.up.x = -s * scale; - m_matrix.up.y = c * scale; - m_matrix.up.z = 0.0f; + forward.x = -s * scale; + forward.y = c * scale; + forward.z = 0.0f; - m_matrix.at.x = 0.0f; - m_matrix.at.y = 0.0f; - m_matrix.at.z = scale; + up.x = 0.0f; + up.y = 0.0f; + up.z = scale; } void SetRotateX(float angle); void SetRotateY(float angle); @@ -82,13 +94,13 @@ public: void RotateZ(float z); void Reorthogonalise(void); - void CopyOnlyMatrix(CMatrix *other); + void CopyOnlyMatrix(const CMatrix &other); void SetUnity(void); void ResetOrientation(void); void SetTranslateOnly(float x, float y, float z) { - m_matrix.pos.x = x; - m_matrix.pos.y = y; - m_matrix.pos.z = z; + pos.x = x; + pos.y = y; + pos.z = z; } void SetTranslateOnly(const CVector& pos) { SetTranslateOnly(pos.x, pos.y, pos.z); @@ -102,11 +114,11 @@ CMatrix Invert(const CMatrix &matrix); CMatrix operator*(const CMatrix &m1, const CMatrix &m2); inline CVector MultiplyInverse(const CMatrix &mat, const CVector &vec) { - CVector v(vec.x - mat.m_matrix.pos.x, vec.y - mat.m_matrix.pos.y, vec.z - mat.m_matrix.pos.z); + CVector v(vec.x - mat.pos.x, vec.y - mat.pos.y, vec.z - mat.pos.z); return CVector( - mat.m_matrix.right.x * v.x + mat.m_matrix.right.y * v.y + mat.m_matrix.right.z * v.z, - mat.m_matrix.up.x * v.x + mat.m_matrix.up.y * v.y + mat.m_matrix.up.z * v.z, - mat.m_matrix.at.x * v.x + mat.m_matrix.at.y * v.y + mat.m_matrix.at.z * v.z); + mat.right.x * v.x + mat.right.y * v.y + mat.right.z * v.z, + mat.forward.x * v.x + mat.forward.y * v.y + mat.forward.z * v.z, + mat.up.x * v.x + mat.up.y * v.y + mat.up.z * v.z); } diff --git a/src/math/Vector.cpp b/src/math/Vector.cpp index 42e1828e..3bc395d8 100644 --- a/src/math/Vector.cpp +++ b/src/math/Vector.cpp @@ -23,24 +23,24 @@ CVector Multiply3x3(const CMatrix &mat, const CVector &vec) { // TODO: VU0 code - return CVector(mat.m_matrix.right.x * vec.x + mat.m_matrix.up.x * vec.y + mat.m_matrix.at.x * vec.z, - mat.m_matrix.right.y * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.at.y * vec.z, - mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z); + return CVector(mat.right.x * vec.x + mat.forward.x * vec.y + mat.up.x * vec.z, + mat.right.y * vec.x + mat.forward.y * vec.y + mat.up.y * vec.z, + mat.right.z * vec.x + mat.forward.z * vec.y + mat.up.z * vec.z); } CVector Multiply3x3(const CVector &vec, const CMatrix &mat) { - return CVector(mat.m_matrix.right.x * vec.x + mat.m_matrix.right.y * vec.y + mat.m_matrix.right.z * vec.z, - mat.m_matrix.up.x * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.up.z * vec.z, - mat.m_matrix.at.x * vec.x + mat.m_matrix.at.y * vec.y + mat.m_matrix.at.z * vec.z); + return CVector(mat.right.x * vec.x + mat.right.y * vec.y + mat.right.z * vec.z, + mat.forward.x * vec.x + mat.forward.y * vec.y + mat.forward.z * vec.z, + mat.up.x * vec.x + mat.up.y * vec.y + mat.up.z * vec.z); } CVector operator*(const CMatrix &mat, const CVector &vec) { // TODO: VU0 code - return CVector(mat.m_matrix.right.x * vec.x + mat.m_matrix.up.x * vec.y + mat.m_matrix.at.x * vec.z + mat.m_matrix.pos.x, - mat.m_matrix.right.y * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.at.y * vec.z + mat.m_matrix.pos.y, - mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z + mat.m_matrix.pos.z); + return CVector(mat.right.x * vec.x + mat.forward.x * vec.y + mat.up.x * vec.z + mat.pos.x, + mat.right.y * vec.x + mat.forward.y * vec.y + mat.up.y * vec.z + mat.pos.y, + mat.right.z * vec.x + mat.forward.z * vec.y + mat.up.z * vec.z + mat.pos.z); } diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp index e3d2ffa6..13afadb6 100644 --- a/src/render/SpecialFX.cpp +++ b/src/render/SpecialFX.cpp @@ -587,7 +587,7 @@ C3dMarkers::PlaceMarker(uint32 identifier, uint16 type, CVector &pos, float size pMarker->m_Color.alpha = (float)a * 0.4f * someSin + a; } if (pMarker->m_nRotateRate) { - RwV3d pos = pMarker->m_Matrix.m_matrix.pos; + CVector pos = pMarker->m_Matrix.GetPosition(); pMarker->m_Matrix.RotateZ(DEGTORAD(pMarker->m_nRotateRate * CTimer::GetTimeStep())); pMarker->m_Matrix.GetPosition() = pos; } From 8c1f4ba65d1a037fa442f489f5d542eed42edcab Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Mon, 18 Jan 2021 23:59:07 +0300 Subject: [PATCH 117/152] fix --- src/control/Script4.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/Script4.cpp b/src/control/Script4.cpp index d17334a9..ecbb337a 100644 --- a/src/control/Script4.cpp +++ b/src/control/Script4.cpp @@ -1417,7 +1417,7 @@ int8 CRunningScript::ProcessCommands900To999(int32 command) CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); script_assert(pVehicle); const CVector& pos = pVehicle->GetPosition(); - float heading = CGeneral::GetATanOfXY(pos.y - *(float*)&ScriptParams[2], pos.x - *(float*)&ScriptParams[1]) + HALFPI; + float heading = CGeneral::GetATanOfXY(pos.x - *(float*)&ScriptParams[1], pos.y - *(float*)&ScriptParams[2]) + HALFPI; if (heading > TWOPI) heading -= TWOPI; pVehicle->SetHeading(heading); From 25d3066eae00ea0af66c0ea908f7bbddac806078 Mon Sep 17 00:00:00 2001 From: withmorten Date: Tue, 19 Jan 2021 12:05:38 +0100 Subject: [PATCH 118/152] fix RWLIBS build without GTA_PS2_STUFF --- src/core/Radar.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp index 816da6b9..ba939fa3 100644 --- a/src/core/Radar.cpp +++ b/src/core/Radar.cpp @@ -1,3 +1,6 @@ +#if !defined(GTA_PS2_STUFF) && defined(RWLIBS) +#define WITHD3D +#endif #include "config.h" #include "common.h" From e6ef1644418401e5ace5a12537d6bd500db7f0e2 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 19 Jan 2021 17:09:06 +0200 Subject: [PATCH 119/152] Get rid of VuVector --- src/math/Matrix.cpp | 378 ++++++++++++++++++++++---------------------- src/math/Matrix.h | 62 ++++---- src/math/Vector.cpp | 18 +-- 3 files changed, 231 insertions(+), 227 deletions(-) diff --git a/src/math/Matrix.cpp b/src/math/Matrix.cpp index bee3ffba..b11e8a1c 100644 --- a/src/math/Matrix.cpp +++ b/src/math/Matrix.cpp @@ -60,20 +60,20 @@ CMatrix::Detach(void) void CMatrix::Update(void) { - right = m_attachment->right; - forward = m_attachment->up; - up = m_attachment->at; - pos = m_attachment->pos; + GetRight() = m_attachment->right; + GetForward() = m_attachment->up; + GetUp() = m_attachment->at; + GetPosition() = m_attachment->pos; } void CMatrix::UpdateRW(void) { if (m_attachment) { - m_attachment->right = right; - m_attachment->up = forward; - m_attachment->at = up; - m_attachment->pos = pos; + m_attachment->right = GetRight(); + m_attachment->up = GetForward(); + m_attachment->at = GetUp(); + m_attachment->pos = GetPosition(); RwMatrixUpdate(m_attachment); } } @@ -95,82 +95,82 @@ CMatrix::CopyOnlyMatrix(const CMatrix &other) CMatrix & CMatrix::operator+=(CMatrix const &rhs) { - right += rhs.right; - forward += rhs.forward; - up += rhs.up; - pos += rhs.pos; + GetRight() += rhs.GetRight(); + GetForward() += rhs.GetForward(); + GetUp() += rhs.GetUp(); + GetPosition() += rhs.GetPosition(); return *this; } void CMatrix::SetUnity(void) { - right.x = 1.0f; - right.y = 0.0f; - right.z = 0.0f; - forward.x = 0.0f; - forward.y = 1.0f; - forward.z = 0.0f; - up.x = 0.0f; - up.y = 0.0f; - up.z = 1.0f; - pos.x = 0.0f; - pos.y = 0.0f; - pos.z = 0.0f; + rx = 1.0f; + ry = 0.0f; + rz = 0.0f; + fx = 0.0f; + fy = 1.0f; + fz = 0.0f; + ux = 0.0f; + uy = 0.0f; + uz = 1.0f; + px = 0.0f; + py = 0.0f; + pz = 0.0f; } void CMatrix::ResetOrientation(void) { - right.x = 1.0f; - right.y = 0.0f; - right.z = 0.0f; - forward.x = 0.0f; - forward.y = 1.0f; - forward.z = 0.0f; - up.x = 0.0f; - up.y = 0.0f; - up.z = 1.0f; + rx = 1.0f; + ry = 0.0f; + rz = 0.0f; + fx = 0.0f; + fy = 1.0f; + fz = 0.0f; + ux = 0.0f; + uy = 0.0f; + uz = 1.0f; } void CMatrix::SetScale(float s) { - right.x = s; - right.y = 0.0f; - right.z = 0.0f; + rx = s; + ry = 0.0f; + rz = 0.0f; - forward.x = 0.0f; - forward.y = s; - forward.z = 0.0f; + fx = 0.0f; + fy = s; + fz = 0.0f; - up.x = 0.0f; - up.y = 0.0f; - up.z = s; + ux = 0.0f; + uy = 0.0f; + uz = s; - pos.x = 0.0f; - pos.y = 0.0f; - pos.z = 0.0f; + px = 0.0f; + py = 0.0f; + pz = 0.0f; } void CMatrix::SetTranslate(float x, float y, float z) { - right.x = 1.0f; - right.y = 0.0f; - right.z = 0.0f; + rx = 1.0f; + ry = 0.0f; + rz = 0.0f; - forward.x = 0.0f; - forward.y = 1.0f; - forward.z = 0.0f; + fx = 0.0f; + fy = 1.0f; + fz = 0.0f; - up.x = 0.0f; - up.y = 0.0f; - up.z = 1.0f; + ux = 0.0f; + uy = 0.0f; + uz = 1.0f; - pos.x = x; - pos.y = y; - pos.z = z; + px = x; + py = y; + pz = z; } void @@ -179,17 +179,17 @@ CMatrix::SetRotateXOnly(float angle) float c = Cos(angle); float s = Sin(angle); - right.x = 1.0f; - right.y = 0.0f; - right.z = 0.0f; + rx = 1.0f; + ry = 0.0f; + rz = 0.0f; - forward.x = 0.0f; - forward.y = c; - forward.z = s; + fx = 0.0f; + fy = c; + fz = s; - up.x = 0.0f; - up.y = -s; - up.z = c; + ux = 0.0f; + uy = -s; + uz = c; } void @@ -198,17 +198,17 @@ CMatrix::SetRotateYOnly(float angle) float c = Cos(angle); float s = Sin(angle); - right.x = c; - right.y = 0.0f; - right.z = -s; + rx = c; + ry = 0.0f; + rz = -s; - forward.x = 0.0f; - forward.y = 1.0f; - forward.z = 0.0f; + fx = 0.0f; + fy = 1.0f; + fz = 0.0f; - up.x = s; - up.y = 0.0f; - up.z = c; + ux = s; + uy = 0.0f; + uz = c; } void @@ -217,26 +217,26 @@ CMatrix::SetRotateZOnly(float angle) float c = Cos(angle); float s = Sin(angle); - right.x = c; - right.y = s; - right.z = 0.0f; + rx = c; + ry = s; + rz = 0.0f; - forward.x = -s; - forward.y = c; - forward.z = 0.0f; + fx = -s; + fy = c; + fz = 0.0f; - up.x = 0.0f; - up.y = 0.0f; - up.z = 1.0f; + ux = 0.0f; + uy = 0.0f; + uz = 1.0f; } void CMatrix::SetRotateX(float angle) { SetRotateXOnly(angle); - pos.x = 0.0f; - pos.y = 0.0f; - pos.z = 0.0f; + px = 0.0f; + py = 0.0f; + pz = 0.0f; } @@ -244,18 +244,18 @@ void CMatrix::SetRotateY(float angle) { SetRotateYOnly(angle); - pos.x = 0.0f; - pos.y = 0.0f; - pos.z = 0.0f; + px = 0.0f; + py = 0.0f; + pz = 0.0f; } void CMatrix::SetRotateZ(float angle) { SetRotateZOnly(angle); - pos.x = 0.0f; - pos.y = 0.0f; - pos.z = 0.0f; + px = 0.0f; + py = 0.0f; + pz = 0.0f; } void @@ -268,21 +268,21 @@ CMatrix::SetRotate(float xAngle, float yAngle, float zAngle) float cZ = Cos(zAngle); float sZ = Sin(zAngle); - right.x = cZ * cY - (sZ * sX) * sY; - right.y = (cZ * sX) * sY + sZ * cY; - right.z = -cX * sY; + rx = cZ * cY - (sZ * sX) * sY; + ry = (cZ * sX) * sY + sZ * cY; + rz = -cX * sY; - forward.x = -sZ * cX; - forward.y = cZ * cX; - forward.z = sX; + fx = -sZ * cX; + fy = cZ * cX; + fz = sX; - up.x = (sZ * sX) * cY + cZ * sY; - up.y = sZ * sY - (cZ * sX) * cY; - up.z = cX * cY; + ux = (sZ * sX) * cY + cZ * sY; + uy = sZ * sY - (cZ * sX) * cY; + uz = cX * cY; - pos.x = 0.0f; - pos.y = 0.0f; - pos.z = 0.0f; + px = 0.0f; + py = 0.0f; + pz = 0.0f; } void @@ -291,23 +291,23 @@ CMatrix::RotateX(float x) float c = Cos(x); float s = Sin(x); - float ry = right.y; - float rz = right.z; - float uy = forward.y; - float uz = forward.z; - float ay = up.y; - float az = up.z; - float py = pos.y; - float pz = pos.z; + float ry = this->ry; + float rz = this->rz; + float uy = this->fy; + float uz = this->fz; + float ay = this->uy; + float az = this->uz; + float py = this->py; + float pz = this->pz; - right.y = c * ry - s * rz; - right.z = c * rz + s * ry; - forward.y = c * uy - s * uz; - forward.z = c * uz + s * uy; - up.y = c * ay - s * az; - up.z = c * az + s * ay; - pos.y = c * py - s * pz; - pos.z = c * pz + s * py; + this->ry = c * ry - s * rz; + this->rz = c * rz + s * ry; + this->fy = c * uy - s * uz; + this->fz = c * uz + s * uy; + this->uy = c * ay - s * az; + this->uz = c * az + s * ay; + this->py = c * py - s * pz; + this->pz = c * pz + s * py; } void @@ -316,23 +316,23 @@ CMatrix::RotateY(float y) float c = Cos(y); float s = Sin(y); - float rx = right.x; - float rz = right.z; - float ux = forward.x; - float uz = forward.z; - float ax = up.x; - float az = up.z; - float px = pos.x; - float pz = pos.z; + float rx = this->rx; + float rz = this->rz; + float ux = this->fx; + float uz = this->fz; + float ax = this->ux; + float az = this->uz; + float px = this->px; + float pz = this->pz; - right.x = c * rx + s * rz; - right.z = c * rz - s * rx; - forward.x = c * ux + s * uz; - forward.z = c * uz - s * ux; - up.x = c * ax + s * az; - up.z = c * az - s * ax; - pos.x = c * px + s * pz; - pos.z = c * pz - s * px; + this->rx = c * rx + s * rz; + this->rz = c * rz - s * rx; + this->fx = c * ux + s * uz; + this->fz = c * uz - s * ux; + this->ux = c * ax + s * az; + this->uz = c * az - s * ax; + this->px = c * px + s * pz; + this->pz = c * pz - s * px; } void @@ -341,23 +341,23 @@ CMatrix::RotateZ(float z) float c = Cos(z); float s = Sin(z); - float ry = right.y; - float rx = right.x; - float uy = forward.y; - float ux = forward.x; - float ay = up.y; - float ax = up.x; - float py = pos.y; - float px = pos.x; + float ry = this->ry; + float rx = this->rx; + float uy = this->fy; + float ux = this->fx; + float ay = this->uy; + float ax = this->ux; + float py = this->py; + float px = this->px; - right.x = c * rx - s * ry; - right.y = c * ry + s * rx; - forward.x = c * ux - s * uy; - forward.y = c * uy + s * ux; - up.x = c * ax - s * ay; - up.y = c * ay + s * ax; - pos.x = c * px - s * py; - pos.y = c * py + s * px; + this->rx = c * rx - s * ry; + this->ry = c * ry + s * rx; + this->fx = c * ux - s * uy; + this->fy = c * uy + s * ux; + this->ux = c * ax - s * ay; + this->uy = c * ay + s * ax; + this->px = c * px - s * py; + this->py = c * py + s * px; } @@ -371,18 +371,18 @@ CMatrix::Rotate(float x, float y, float z) float cZ = Cos(z); float sZ = Sin(z); - float rx = right.x; - float ry = right.y; - float rz = right.z; - float ux = forward.x; - float uy = forward.y; - float uz = forward.z; - float ax = up.x; - float ay = up.y; - float az = up.z; - float px = pos.x; - float py = pos.y; - float pz = pos.z; + float rx = this->rx; + float ry = this->ry; + float rz = this->rz; + float ux = this->fx; + float uy = this->fy; + float uz = this->fz; + float ax = this->ux; + float ay = this->uy; + float az = this->uz; + float px = this->px; + float py = this->py; + float pz = this->pz; float x1 = cZ * cY - (sZ * sX) * sY; float x2 = (cZ * sX) * sY + sZ * cY; @@ -394,18 +394,18 @@ CMatrix::Rotate(float x, float y, float z) float z2 = sZ * sY - (cZ * sX) * cY; float z3 = cX * cY; - right.x = x1 * rx + y1 * ry + z1 * rz; - right.y = x2 * rx + y2 * ry + z2 * rz; - right.z = x3 * rx + y3 * ry + z3 * rz; - forward.x = x1 * ux + y1 * uy + z1 * uz; - forward.y = x2 * ux + y2 * uy + z2 * uz; - forward.z = x3 * ux + y3 * uy + z3 * uz; - up.x = x1 * ax + y1 * ay + z1 * az; - up.y = x2 * ax + y2 * ay + z2 * az; - up.z = x3 * ax + y3 * ay + z3 * az; - pos.x = x1 * px + y1 * py + z1 * pz; - pos.y = x2 * px + y2 * py + z2 * pz; - pos.z = x3 * px + y3 * py + z3 * pz; + this->rx = x1 * rx + y1 * ry + z1 * rz; + this->ry = x2 * rx + y2 * ry + z2 * rz; + this->rz = x3 * rx + y3 * ry + z3 * rz; + this->fx = x1 * ux + y1 * uy + z1 * uz; + this->fy = x2 * ux + y2 * uy + z2 * uz; + this->fz = x3 * ux + y3 * uy + z3 * uz; + this->ux = x1 * ax + y1 * ay + z1 * az; + this->uy = x2 * ax + y2 * ay + z2 * az; + this->uz = x3 * ax + y3 * ay + z3 * az; + this->px = x1 * px + y1 * py + z1 * pz; + this->py = x2 * px + y2 * py + z2 * pz; + this->pz = x3 * px + y3 * py + z3 * pz; } CMatrix & @@ -434,18 +434,18 @@ operator*(const CMatrix &m1, const CMatrix &m2) { // TODO: VU0 code CMatrix out; - out.right.x = m1.right.x * m2.right.x + m1.forward.x * m2.right.y + m1.up.x * m2.right.z; - out.right.y = m1.right.y * m2.right.x + m1.forward.y * m2.right.y + m1.up.y * m2.right.z; - out.right.z = m1.right.z * m2.right.x + m1.forward.z * m2.right.y + m1.up.z * m2.right.z; - out.forward.x = m1.right.x * m2.forward.x + m1.forward.x * m2.forward.y + m1.up.x * m2.forward.z; - out.forward.y = m1.right.y * m2.forward.x + m1.forward.y * m2.forward.y + m1.up.y * m2.forward.z; - out.forward.z = m1.right.z * m2.forward.x + m1.forward.z * m2.forward.y + m1.up.z * m2.forward.z; - out.up.x = m1.right.x * m2.up.x + m1.forward.x * m2.up.y + m1.up.x * m2.up.z; - out.up.y = m1.right.y * m2.up.x + m1.forward.y * m2.up.y + m1.up.y * m2.up.z; - out.up.z = m1.right.z * m2.up.x + m1.forward.z * m2.up.y + m1.up.z * m2.up.z; - out.pos.x = m1.right.x * m2.pos.x + m1.forward.x * m2.pos.y + m1.up.x * m2.pos.z + m1.pos.x; - out.pos.y = m1.right.y * m2.pos.x + m1.forward.y * m2.pos.y + m1.up.y * m2.pos.z + m1.pos.y; - out.pos.z = m1.right.z * m2.pos.x + m1.forward.z * m2.pos.y + m1.up.z * m2.pos.z + m1.pos.z; + out.rx = m1.rx * m2.rx + m1.fx * m2.ry + m1.ux * m2.rz; + out.ry = m1.ry * m2.rx + m1.fy * m2.ry + m1.uy * m2.rz; + out.rz = m1.rz * m2.rx + m1.fz * m2.ry + m1.uz * m2.rz; + out.fx = m1.rx * m2.fx + m1.fx * m2.fy + m1.ux * m2.fz; + out.fy = m1.ry * m2.fx + m1.fy * m2.fy + m1.uy * m2.fz; + out.fz = m1.rz * m2.fx + m1.fz * m2.fy + m1.uz * m2.fz; + out.ux = m1.rx * m2.ux + m1.fx * m2.uy + m1.ux * m2.uz; + out.uy = m1.ry * m2.ux + m1.fy * m2.uy + m1.uy * m2.uz; + out.uz = m1.rz * m2.ux + m1.fz * m2.uy + m1.uz * m2.uz; + out.px = m1.rx * m2.px + m1.fx * m2.py + m1.ux * m2.pz + m1.px; + out.py = m1.ry * m2.px + m1.fy * m2.py + m1.uy * m2.pz + m1.py; + out.pz = m1.rz * m2.px + m1.fz * m2.py + m1.uz * m2.pz + m1.pz; return out; } diff --git a/src/math/Matrix.h b/src/math/Matrix.h index fdbd0b60..9d50a4f6 100644 --- a/src/math/Matrix.h +++ b/src/math/Matrix.h @@ -1,7 +1,5 @@ #pragma once -#include "VuVector.h" - class CMatrix { public: @@ -10,10 +8,10 @@ public: float f[4][4]; struct { - CVuVector right; - CVuVector forward; - CVuVector up; - CVuVector pos; + float rx, ry, rz, rw; + float fx, fy, fz, fw; + float ux, uy, uz, uw; + float px, py, pz, pw; }; }; @@ -38,17 +36,23 @@ public: CMatrix &operator+=(CMatrix const &rhs); CMatrix &operator*=(CMatrix const &rhs); - CVector &GetPosition(void){ return pos; } - CVector &GetRight(void) { return right; } - CVector &GetForward(void) { return forward; } - CVector &GetUp(void) { return up; } + CVector &GetPosition(void) { return *(CVector*)&px; } + CVector &GetRight(void) { return *(CVector*)℞ } + CVector &GetForward(void) { return *(CVector*)&fx; } + CVector &GetUp(void) { return *(CVector*)&ux; } + + const CVector &GetPosition(void) const { return *(CVector*)&px; } + const CVector &GetRight(void) const { return *(CVector*)℞ } + const CVector &GetForward(void) const { return *(CVector*)&fx; } + const CVector &GetUp(void) const { return *(CVector*)&ux; } + void SetTranslate(float x, float y, float z); void SetTranslate(const CVector &trans){ SetTranslate(trans.x, trans.y, trans.z); } void Translate(float x, float y, float z){ - pos.x += x; - pos.y += y; - pos.z += z; + px += x; + py += y; + pz += z; } void Translate(const CVector &trans){ Translate(trans.x, trans.y, trans.z); } @@ -72,17 +76,17 @@ public: float c = Cos(angle); float s = Sin(angle); - right.x = c * scale; - right.y = s * scale; - right.z = 0.0f; + rx = c * scale; + ry = s * scale; + rz = 0.0f; - forward.x = -s * scale; - forward.y = c * scale; - forward.z = 0.0f; + fx = -s * scale; + fy = c * scale; + fz = 0.0f; - up.x = 0.0f; - up.y = 0.0f; - up.z = scale; + ux = 0.0f; + uy = 0.0f; + uz = scale; } void SetRotateX(float angle); void SetRotateY(float angle); @@ -98,9 +102,9 @@ public: void SetUnity(void); void ResetOrientation(void); void SetTranslateOnly(float x, float y, float z) { - pos.x = x; - pos.y = y; - pos.z = z; + px = x; + py = y; + pz = z; } void SetTranslateOnly(const CVector& pos) { SetTranslateOnly(pos.x, pos.y, pos.z); @@ -114,11 +118,11 @@ CMatrix Invert(const CMatrix &matrix); CMatrix operator*(const CMatrix &m1, const CMatrix &m2); inline CVector MultiplyInverse(const CMatrix &mat, const CVector &vec) { - CVector v(vec.x - mat.pos.x, vec.y - mat.pos.y, vec.z - mat.pos.z); + CVector v(vec.x - mat.px, vec.y - mat.py, vec.z - mat.pz); return CVector( - mat.right.x * v.x + mat.right.y * v.y + mat.right.z * v.z, - mat.forward.x * v.x + mat.forward.y * v.y + mat.forward.z * v.z, - mat.up.x * v.x + mat.up.y * v.y + mat.up.z * v.z); + mat.rx * v.x + mat.ry * v.y + mat.rz * v.z, + mat.fx * v.x + mat.fy * v.y + mat.fz * v.z, + mat.ux * v.x + mat.uy * v.y + mat.uz * v.z); } diff --git a/src/math/Vector.cpp b/src/math/Vector.cpp index 3bc395d8..ee76e555 100644 --- a/src/math/Vector.cpp +++ b/src/math/Vector.cpp @@ -23,24 +23,24 @@ CVector Multiply3x3(const CMatrix &mat, const CVector &vec) { // TODO: VU0 code - return CVector(mat.right.x * vec.x + mat.forward.x * vec.y + mat.up.x * vec.z, - mat.right.y * vec.x + mat.forward.y * vec.y + mat.up.y * vec.z, - mat.right.z * vec.x + mat.forward.z * vec.y + mat.up.z * vec.z); + return CVector(mat.rx * vec.x + mat.fx * vec.y + mat.ux * vec.z, + mat.ry * vec.x + mat.fy * vec.y + mat.uy * vec.z, + mat.rz * vec.x + mat.fz * vec.y + mat.uz * vec.z); } CVector Multiply3x3(const CVector &vec, const CMatrix &mat) { - return CVector(mat.right.x * vec.x + mat.right.y * vec.y + mat.right.z * vec.z, - mat.forward.x * vec.x + mat.forward.y * vec.y + mat.forward.z * vec.z, - mat.up.x * vec.x + mat.up.y * vec.y + mat.up.z * vec.z); + return CVector(mat.rx * vec.x + mat.ry * vec.y + mat.rz * vec.z, + mat.fx * vec.x + mat.fy * vec.y + mat.fz * vec.z, + mat.ux * vec.x + mat.uy * vec.y + mat.uz * vec.z); } CVector operator*(const CMatrix &mat, const CVector &vec) { // TODO: VU0 code - return CVector(mat.right.x * vec.x + mat.forward.x * vec.y + mat.up.x * vec.z + mat.pos.x, - mat.right.y * vec.x + mat.forward.y * vec.y + mat.up.y * vec.z + mat.pos.y, - mat.right.z * vec.x + mat.forward.z * vec.y + mat.up.z * vec.z + mat.pos.z); + return CVector(mat.rx * vec.x + mat.fx * vec.y + mat.ux * vec.z + mat.px, + mat.ry * vec.x + mat.fy * vec.y + mat.uy * vec.z + mat.py, + mat.rz * vec.x + mat.fz * vec.y + mat.uz * vec.z + mat.pz); } From a9b8d30ce0e4e40dc5b5410c85bd0987548c6772 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 19 Jan 2021 21:32:55 +0200 Subject: [PATCH 120/152] Get rid of bitfields in CPool --- src/control/Garages.cpp | 8 ++--- src/core/Pools.cpp | 2 +- src/core/templates.h | 71 ++++++++++++++++++++++++++--------------- 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index 2b79b338..79c44dfd 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -1539,7 +1539,7 @@ void CGarage::RefreshDoorPointers(bool bCreate) m_bRecreateDoorOnNextRefresh = false; if (m_pDoor1) { if (m_bDoor1IsDummy) { - if (CPools::GetDummyPool()->IsFreeSlot(CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)m_pDoor1))) + if (CPools::GetDummyPool()->GetIsFree(CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)m_pDoor1))) bNeedToFindDoorEntities = true; else { if (m_bDoor1PoolIndex != (CPools::GetDummyPool()->GetIndex((CDummy*)m_pDoor1) & 0x7F)) @@ -1549,7 +1549,7 @@ void CGarage::RefreshDoorPointers(bool bCreate) } } else { - if (CPools::GetObjectPool()->IsFreeSlot(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)m_pDoor1))) + if (CPools::GetObjectPool()->GetIsFree(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)m_pDoor1))) bNeedToFindDoorEntities = true; else { if (m_bDoor1PoolIndex != (CPools::GetObjectPool()->GetIndex((CObject*)m_pDoor1) & 0x7F)) @@ -1561,7 +1561,7 @@ void CGarage::RefreshDoorPointers(bool bCreate) } if (m_pDoor2) { if (m_bDoor2IsDummy) { - if (CPools::GetDummyPool()->IsFreeSlot(CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)m_pDoor2))) + if (CPools::GetDummyPool()->GetIsFree(CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)m_pDoor2))) bNeedToFindDoorEntities = true; else { if (m_bDoor2PoolIndex != (CPools::GetDummyPool()->GetIndex((CDummy*)m_pDoor2) & 0x7F)) @@ -1571,7 +1571,7 @@ void CGarage::RefreshDoorPointers(bool bCreate) } } else { - if (CPools::GetObjectPool()->IsFreeSlot(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)m_pDoor2))) + if (CPools::GetObjectPool()->GetIsFree(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)m_pDoor2))) bNeedToFindDoorEntities = true; else { if (m_bDoor2PoolIndex != (CPools::GetObjectPool()->GetIndex((CObject*)m_pDoor2) & 0x7F)) diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp index d3801a2a..39cfb1d4 100644 --- a/src/core/Pools.cpp +++ b/src/core/Pools.cpp @@ -102,7 +102,7 @@ CPools::CheckPoolsEmpty() void CPools::MakeSureSlotInObjectPoolIsEmpty(int32 slot) { - if (ms_pObjectPool->IsFreeSlot(slot)) return; + if (ms_pObjectPool->GetIsFree(slot)) return; CObject *object = ms_pObjectPool->GetSlot(slot); if (object->ObjectCreatedBy == TEMP_OBJECT) { diff --git a/src/core/templates.h b/src/core/templates.h index 3a5b314f..545dac39 100644 --- a/src/core/templates.h +++ b/src/core/templates.h @@ -29,39 +29,59 @@ public: } }; +#define POOLFLAG_ID 0x7f +#define POOLFLAG_ISFREE 0x80 + template class CPool { U *m_entries; - union Flags { - struct { - uint8 id : 7; - uint8 free : 1; - }; - uint8 u; - } *m_flags; + uint8 *m_flags; int32 m_size; int32 m_allocPtr; public: CPool(int32 size){ m_entries = (U*)new uint8[sizeof(U)*size]; - m_flags = (Flags*)new uint8[sizeof(Flags)*size]; + m_flags = new uint8[size]; m_size = size; m_allocPtr = 0; for(int i = 0; i < size; i++){ - m_flags[i].id = 0; - m_flags[i].free = 1; + SetId(i, 0); + SetIsFree(i, true); } } + int GetId(int i) const + { + return m_flags[i] & POOLFLAG_ID; + } + + bool GetIsFree(int i) const + { + return !!(m_flags[i] & POOLFLAG_ISFREE); + } + + void SetId(int i, int id) + { + m_flags[i] = (m_flags[i] & POOLFLAG_ISFREE) | (id & POOLFLAG_ID); + } + + void SetIsFree(int i, bool isFree) + { + if (isFree) + m_flags[i] |= POOLFLAG_ISFREE; + else + m_flags[i] &= ~POOLFLAG_ISFREE; + } + ~CPool() { Flush(); } void Flush() { if (m_size > 0) { delete[] (uint8*)m_entries; - delete[] (uint8*)m_flags; + delete[] m_flags; m_entries = nil; m_flags = nil; m_size = 0; @@ -87,9 +107,9 @@ public: m_allocPtr = 0; } #endif - while(!m_flags[m_allocPtr].free); - m_flags[m_allocPtr].free = 0; - m_flags[m_allocPtr].id++; + while(!GetIsFree(m_allocPtr)); + SetIsFree(m_allocPtr, false); + SetId(m_allocPtr, GetId(m_allocPtr)+1); return (T*)&m_entries[m_allocPtr]; } T *New(int32 handle){ @@ -99,36 +119,36 @@ public: } void SetNotFreeAt(int32 handle){ int idx = handle>>8; - m_flags[idx].free = 0; - m_flags[idx].id = handle & 0x7F; + SetIsFree(idx, false); + SetId(idx, handle & POOLFLAG_ID); for(m_allocPtr = 0; m_allocPtr < m_size; m_allocPtr++) - if(m_flags[m_allocPtr].free) + if(GetIsFree(m_allocPtr)) return; } void Delete(T *entry){ int i = GetJustIndex(entry); - m_flags[i].free = 1; + SetIsFree(i, true); if(i < m_allocPtr) m_allocPtr = i; } T *GetSlot(int i){ - return m_flags[i].free ? nil : (T*)&m_entries[i]; + return GetIsFree(i) ? nil : (T*)&m_entries[i]; } T *GetAt(int handle){ #ifdef FIX_BUGS if (handle == -1) return nil; #endif - return m_flags[handle>>8].u == (handle & 0xFF) ? + return m_flags[handle>>8] == (handle & 0xFF) ? (T*)&m_entries[handle >> 8] : nil; } int32 GetIndex(T *entry){ int i = GetJustIndex_NoFreeAssert(entry); - return m_flags[i].u + (i<<8); + return m_flags[i] + (i<<8); } int32 GetJustIndex(T *entry){ int index = GetJustIndex_NoFreeAssert(entry); - assert(!IsFreeSlot(index)); + assert(!GetIsFree(index)); return index; } int32 GetJustIndex_NoFreeAssert(T* entry){ @@ -140,13 +160,12 @@ public: int i; int n = 0; for(i = 0; i < m_size; i++) - if(!m_flags[i].free) + if(!GetIsFree(i)) n++; return n; } - bool IsFreeSlot(int i) { return !!m_flags[i].free; } void ClearStorage(uint8 *&flags, U *&entries){ - delete[] (uint8*)flags; + delete[] flags; delete[] (uint8*)entries; flags = nil; entries = nil; @@ -155,7 +174,7 @@ public: void CopyBack(uint8 *&flags, U *&entries){ memcpy(m_flags, flags, sizeof(uint8)*m_size); memcpy(m_entries, entries, sizeof(U)*m_size); - debug("Size copied:%d (%d)\n", sizeof(U)*m_size, sizeof(Flags)*m_size); + debug("Size copied:%d (%d)\n", sizeof(U)*m_size, m_size); m_allocPtr = 0; ClearStorage(flags, entries); debug("CopyBack:%d (/%d)\n", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */ From bb66028e74d5a8d9e75f2448caa876ac35d4f700 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 19 Jan 2021 21:33:09 +0100 Subject: [PATCH 121/152] pc radar fix --- src/core/Radar.cpp | 2 +- src/render/Sprite2d.cpp | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp index 816da6b9..a5acdfad 100644 --- a/src/core/Radar.cpp +++ b/src/core/Radar.cpp @@ -778,7 +778,7 @@ void CRadar::DrawRadarMask() CVector2D(-1.0, -1.0f) }; - RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)nil); RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT); diff --git a/src/render/Sprite2d.cpp b/src/render/Sprite2d.cpp index 98bb6eb2..59622516 100644 --- a/src/render/Sprite2d.cpp +++ b/src/render/Sprite2d.cpp @@ -358,7 +358,11 @@ CSprite2d::SetMaskVertices(int n, float *positions) RwIm2DVertexSetScreenZ(&maVertices[i], screenz); RwIm2DVertexSetCameraZ(&maVertices[i], z); RwIm2DVertexSetRecipCameraZ(&maVertices[i], recipz); - RwIm2DVertexSetIntRGBA(&maVertices[i], 255, 255, 255, 255); // 0, 0, 0, 0 on PC +#if !defined(GTA_PS2_STUFF) && defined(RWLIBS) + RwIm2DVertexSetIntRGBA(&maVertices[i], 0, 0, 0, 0); +#else + RwIm2DVertexSetIntRGBA(&maVertices[i], 255, 255, 255, 255); +#endif } } From 8e825fa629dc3a0d82d1bc3ea8807ac10c986c82 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Wed, 20 Jan 2021 22:16:11 +0300 Subject: [PATCH 122/152] fixed saving --- src/core/Zones.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Zones.cpp b/src/core/Zones.cpp index 2e3e0f6e..cdae85e1 100644 --- a/src/core/Zones.cpp +++ b/src/core/Zones.cpp @@ -649,7 +649,7 @@ CTheZones::SaveAllZones(uint8 *buffer, uint32 *size) WriteSaveHeader(buffer, 'Z', 'N', 'S', '\0', *size - SAVE_HEADER_SIZE); - WriteSaveBuf(buffer, GetIndexForZonePointer(m_pPlayersZone)); + WriteSaveBuf(buffer, (int32)GetIndexForZonePointer(m_pPlayersZone)); WriteSaveBuf(buffer, m_CurrLevel); WriteSaveBuf(buffer, FindIndex); WriteSaveBuf(buffer, (int16)0); // padding From ac0f759b274368b9424222a392d9f28b73980eb0 Mon Sep 17 00:00:00 2001 From: withmorten Date: Tue, 19 Jan 2021 13:35:48 +0100 Subject: [PATCH 123/152] make building with Codewarrior 7 possible --- .gitignore | 6 +- codewarrior/re3.mcp | Bin 0 -> 228825 bytes src/animation/AnimBlendAssocGroup.cpp | 18 +- src/audio/AudioLogic.cpp | 4 +- src/audio/AudioManager.cpp | 4 +- src/audio/AudioManager.h | 2 +- src/audio/PoliceRadio.cpp | 2 +- src/audio/sampman_miles.cpp | 2 +- src/control/Pickups.h | 2 +- src/control/RoadBlocks.cpp | 4 +- src/control/SceneEdit.cpp | 6 +- src/control/Script.cpp | 2 +- src/control/Script.h | 300 +++++++++++++------------- src/control/Script5.cpp | 14 +- src/core/Cam.cpp | 2 +- src/core/CdStream.cpp | 11 +- src/core/Frontend.cpp | 2 + src/core/General.h | 2 +- src/core/Placeable.cpp | 4 +- src/core/Placeable.h | 2 +- src/core/Radar.cpp | 12 +- src/core/Stats.h | 2 +- src/core/common.h | 61 +++++- src/core/config.h | 97 ++++++++- src/core/main.cpp | 21 +- src/core/re3.cpp | 12 ++ src/entities/Physical.cpp | 10 +- src/peds/PlayerPed.cpp | 2 +- src/peds/Population.cpp | 44 ++-- src/peds/Population.h | 10 +- src/render/Font.h | 2 + src/render/Glass.cpp | 2 +- src/render/Hud.cpp | 8 +- src/render/Instance.h | 2 +- src/render/SpecialFX.cpp | 2 +- src/rw/MemoryHeap.h | 2 +- src/save/GenericGameStorage.h | 1 + src/skel/crossplatform.h | 7 +- src/skel/win/win.cpp | 6 +- src/vehicles/Automobile.cpp | 2 +- src/weapons/WeaponInfo.cpp | 50 ++--- src/weapons/WeaponInfo.h | 1 - 42 files changed, 471 insertions(+), 274 deletions(-) create mode 100644 codewarrior/re3.mcp diff --git a/.gitignore b/.gitignore index 971fb957..44d3eb0b 100644 --- a/.gitignore +++ b/.gitignore @@ -353,4 +353,8 @@ vendor/glew-2.1.0/ vendor/glfw-3.3.2.bin.WIN32/ vendor/glfw-3.3.2.bin.WIN64/ -sdk/ \ No newline at end of file +sdk/ + +codewarrior/re3_Data/ +codewarrior/Release/ +codewarrior/Debug/ diff --git a/codewarrior/re3.mcp b/codewarrior/re3.mcp new file mode 100644 index 0000000000000000000000000000000000000000..93c280f1f999c176522e8bb56d480403cc46b5dd GIT binary patch literal 228825 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 Vf_ZhJUmpTESk7U1UDo^c{{wrSqbL9X literal 0 HcmV?d00001 diff --git a/src/animation/AnimBlendAssocGroup.cpp b/src/animation/AnimBlendAssocGroup.cpp index 1d234bb8..295d6be3 100644 --- a/src/animation/AnimBlendAssocGroup.cpp +++ b/src/animation/AnimBlendAssocGroup.cpp @@ -1,7 +1,11 @@ #include "common.h" #if defined _WIN32 && !defined __MINGW32__ +#if defined __MWERKS__ +#include +#else #include "ctype.h" +#endif #else #include #endif @@ -83,18 +87,18 @@ strcmpIgnoringDigits(const char *s1, const char *s2) if(c1) s1++; if(c2) s2++; if(c1 == '\0' && c2 == '\0') return true; -#if defined _WIN32 && !defined __MINGW32__ - if(__ascii_iswdigit(c1) && __ascii_iswdigit(c2)) -#else +#ifndef ASCII_STRCMP if(iswdigit(c1) && iswdigit(c2)) +#else + if(__ascii_iswdigit(c1) && __ascii_iswdigit(c2)) #endif continue; -#if defined _WIN32 && !defined __MINGW32__ - c1 = __ascii_toupper(c1); - c2 = __ascii_toupper(c2); -#else +#ifndef ASCII_STRCMP c1 = toupper(c1); c2 = toupper(c2); +#else + c1 = __ascii_toupper(c1); + c2 = __ascii_toupper(c2); #endif if(c1 != c2) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 777fdfe4..eab14ce6 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -1,4 +1,4 @@ -#include "common.h" +#include "common.h" #include "AudioManager.h" #include "audio_enums.h" @@ -38,7 +38,7 @@ #include "ZoneCull.h" #include "sampman.h" -const int channels = ARRAY_SIZE(cAudioManager::m_asActiveSamples); +const int channels = ARRAY_SIZE(AudioManager.m_asActiveSamples); const int policeChannel = channels + 1; const int allChannels = channels + 2; diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index e1b5be1d..f61350fb 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -13,7 +13,7 @@ cAudioManager AudioManager; -const int channels = ARRAY_SIZE(cAudioManager::m_asActiveSamples); +const int channels = ARRAY_SIZE(AudioManager.m_asActiveSamples); const int policeChannel = channels + 1; const int allChannels = channels + 2; @@ -948,7 +948,7 @@ cAudioManager::ClearActiveSamples() m_asActiveSamples[i].m_nCalculatedVolume = 0; m_asActiveSamples[i].m_nReleasingVolumeDivider = 0; m_asActiveSamples[i].m_nVolumeChange = -1; - m_asActiveSamples[i].m_vecPos = {0.0f, 0.0f, 0.0f}; + m_asActiveSamples[i].m_vecPos = CVector(0.0f, 0.0f, 0.0f); m_asActiveSamples[i].m_bReverbFlag = false; m_asActiveSamples[i].m_nLoopsRemaining = 0; m_asActiveSamples[i].m_bRequireReflection = false; diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h index 2f86ee98..57ed0fb7 100644 --- a/src/audio/AudioManager.h +++ b/src/audio/AudioManager.h @@ -499,7 +499,7 @@ public: }; #ifdef AUDIO_MSS -static_assert(sizeof(cAudioManager) == 19220, "cAudioManager: error"); +re3_static_assert(sizeof(cAudioManager) == 19220, "cAudioManager: error"); #endif extern cAudioManager AudioManager; diff --git a/src/audio/PoliceRadio.cpp b/src/audio/PoliceRadio.cpp index 94143746..7021b5be 100644 --- a/src/audio/PoliceRadio.cpp +++ b/src/audio/PoliceRadio.cpp @@ -15,7 +15,7 @@ #include "sampman.h" #include "Wanted.h" -const int channels = ARRAY_SIZE(cAudioManager::m_asActiveSamples); +const int channels = ARRAY_SIZE(AudioManager.m_asActiveSamples); const int policeChannel = channels + 1; struct tPoliceRadioZone { diff --git a/src/audio/sampman_miles.cpp b/src/audio/sampman_miles.cpp index 82886c66..eccc9114 100644 --- a/src/audio/sampman_miles.cpp +++ b/src/audio/sampman_miles.cpp @@ -1,4 +1,4 @@ -#ifdef AUDIO_MSS +#if defined(AUDIO_MSS) || defined (__MWERKS__) #include #include diff --git a/src/control/Pickups.h b/src/control/Pickups.h index 72a37d99..4e1c7643 100644 --- a/src/control/Pickups.h +++ b/src/control/Pickups.h @@ -120,7 +120,7 @@ public: class CPacManPickups { - friend CPacManPickup; + friend class CPacManPickup; static CPacManPickup aPMPickUps[NUMPACMANPICKUPS]; static CVector LastPickUpCoors; diff --git a/src/control/RoadBlocks.cpp b/src/control/RoadBlocks.cpp index 170c5ff8..3ec34a57 100644 --- a/src/control/RoadBlocks.cpp +++ b/src/control/RoadBlocks.cpp @@ -46,8 +46,8 @@ CRoadBlocks::Init(void) void CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType, int16 roadBlockNode) { - static const CVector vecRoadBlockOffets[6] = { {-1.5, 1.8f, 0.0f}, {-1.5f, -1.8f, 0.0f}, {1.5f, 1.8f, 0.0f}, - {1.5f, -1.8f, 0.0f}, {-1.5f, 0.0f, 0.0f}, {1.5, 0.0, 0.0} }; + static const CVector vecRoadBlockOffets[6] = { CVector(-1.5, 1.8f, 0.0f), CVector(-1.5f, -1.8f, 0.0f), CVector(1.5f, 1.8f, 0.0f), + CVector(1.5f, -1.8f, 0.0f), CVector(-1.5f, 0.0f, 0.0f), CVector(1.5, 0.0, 0.0) }; CEntity* pEntityToAttack = (CEntity*)FindPlayerVehicle(); if (!pEntityToAttack) pEntityToAttack = (CEntity*)FindPlayerPed(); diff --git a/src/control/SceneEdit.cpp b/src/control/SceneEdit.cpp index b7623133..0a679ab5 100644 --- a/src/control/SceneEdit.cpp +++ b/src/control/SceneEdit.cpp @@ -69,7 +69,7 @@ static const char* pCommandStrings[] = { }; #ifdef CHECK_STRUCT_SIZES -static_assert(ARRAY_SIZE(pCommandStrings) == CSceneEdit::MOVIE_TOTAL_COMMANDS, "Scene edit: not all commands have names"); +re3_static_assert(ARRAY_SIZE(pCommandStrings) == CSceneEdit::MOVIE_TOTAL_COMMANDS, "Scene edit: not all commands have names"); #endif static int32 NextValidModelId(int32 mi, int32 step) @@ -329,7 +329,7 @@ void CSceneEdit::Draw(void) #ifdef FIX_BUGS CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(COMMAND_NAME_X_RIGHT - SHADOW_OFFSET), SCREEN_SCALE_Y(COMMAND_NAME_Y + SHADOW_OFFSET + i * COMMAND_NAME_HEIGHT), wstr); #else - CFont::PrintString(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH-COMMAND_NAME_X_RIGHT) + SHADOW_OFFSET, SCREEN_SCALE_FROM_BOTTOM(DEFAULT_SCREEN_HEIGHT-COMMAND_NAME_Y) + SHADOW_OFFSET + i * COMMAND_NAME_HEIGHT), wstr); + CFont::PrintString(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH-COMMAND_NAME_X_RIGHT) + SHADOW_OFFSET, SCREEN_SCALE_FROM_BOTTOM(DEFAULT_SCREEN_HEIGHT-COMMAND_NAME_Y) + SHADOW_OFFSET + i * COMMAND_NAME_HEIGHT, wstr); #endif if (nCommandDrawn == m_nCurrentCommand) CFont::SetColor(CRGBA(156, 91, 40, 255)); @@ -338,7 +338,7 @@ void CSceneEdit::Draw(void) #ifdef FIX_BUGS CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(COMMAND_NAME_X_RIGHT), SCREEN_SCALE_Y(COMMAND_NAME_Y + i * COMMAND_NAME_HEIGHT), wstr); #else - CFont::PrintString(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH-COMMAND_NAME_X_RIGHT), SCREEN_SCALE_FROM_BOTTOM(DEFAULT_SCREEN_HEIGHT-COMMAND_NAME_Y) + i * COMMAND_NAME_HEIGHT), wstr); + CFont::PrintString(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH-COMMAND_NAME_X_RIGHT), SCREEN_SCALE_FROM_BOTTOM(DEFAULT_SCREEN_HEIGHT-COMMAND_NAME_Y) + i * COMMAND_NAME_HEIGHT, wstr); #endif } } diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 09a696cf..fe8bbdfe 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -1282,7 +1282,7 @@ const tScriptCommandData commands[] = { #undef INPUT_ARGUMENTS #undef OUTPUT_ARGUMENTS -static_assert(ARRAY_SIZE(commands) == LAST_SCRIPT_COMMAND, "commands array not filled"); +re3_static_assert(ARRAY_SIZE(commands) == LAST_SCRIPT_COMMAND, "commands array not filled"); #if SCRIPT_LOG_FILE_LEVEL == 1 || SCRIPT_LOG_FILE_LEVEL == 2 static FILE* dbg_log; diff --git a/src/control/Script.h b/src/control/Script.h index ff1a9706..5682024b 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -247,6 +247,156 @@ struct tBuildingSwap }; +enum { +#if GTA_VERSION > GTA3_PS2_160 + MAX_STACK_DEPTH = 6, +#else + MAX_STACK_DEPTH = 4, +#endif + NUM_LOCAL_VARS = 16, + NUM_TIMERS = 2 +}; + +class CRunningScript +{ + enum { + ANDOR_NONE = 0, + ANDS_1 = 1, + ANDS_2, + ANDS_3, + ANDS_4, + ANDS_5, + ANDS_6, + ANDS_7, + ANDS_8, + ORS_1 = 21, + ORS_2, + ORS_3, + ORS_4, + ORS_5, + ORS_6, + ORS_7, + ORS_8 + }; + +public: + CRunningScript* next; + CRunningScript* prev; + char m_abScriptName[8]; + uint32 m_nIp; + uint32 m_anStack[MAX_STACK_DEPTH]; + uint16 m_nStackPointer; + int32 m_anLocalVariables[NUM_LOCAL_VARS + NUM_TIMERS]; + bool m_bCondResult; + bool m_bIsMissionScript; + bool m_bSkipWakeTime; + uint32 m_nWakeTime; + uint16 m_nAndOrState; + bool m_bNotFlag; + bool m_bDeatharrestEnabled; + bool m_bDeatharrestExecuted; + bool m_bMissionFlag; + +public: + void SetIP(uint32 ip) { m_nIp = ip; } + CRunningScript* GetNext() const { return next; } + + void Save(uint8*& buf); + void Load(uint8*& buf); + + void UpdateTimers(float timeStep) { + m_anLocalVariables[NUM_LOCAL_VARS] += timeStep; + m_anLocalVariables[NUM_LOCAL_VARS + 1] += timeStep; + } + + void Init(); + void Process(); + + void RemoveScriptFromList(CRunningScript**); + void AddScriptToList(CRunningScript**); + + static const uint32 nSaveStructSize; + + void CollectParameters(uint32*, int16); + int32 CollectNextParameterWithoutIncreasingPC(uint32); + int32* GetPointerToScriptVariable(uint32*, int16); + void StoreParameters(uint32*, int16); + + int8 ProcessOneCommand(); + void DoDeatharrestCheck(); + void UpdateCompareFlag(bool); + int16 GetPadState(uint16, uint16); + + int8 ProcessCommands0To99(int32); + int8 ProcessCommands100To199(int32); + int8 ProcessCommands200To299(int32); + int8 ProcessCommands300To399(int32); + int8 ProcessCommands400To499(int32); + int8 ProcessCommands500To599(int32); + int8 ProcessCommands600To699(int32); + int8 ProcessCommands700To799(int32); + int8 ProcessCommands800To899(int32); + int8 ProcessCommands900To999(int32); + int8 ProcessCommands1000To1099(int32); +#if GTA_VERSION > GTA3_PS2_160 + int8 ProcessCommands1100To1199(int32); +#endif + void LocatePlayerCommand(int32, uint32*); + void LocatePlayerCharCommand(int32, uint32*); + void LocatePlayerCarCommand(int32, uint32*); + void LocateCharCommand(int32, uint32*); + void LocateCharCharCommand(int32, uint32*); + void LocateCharCarCommand(int32, uint32*); + void LocateCharObjectCommand(int32, uint32*); + void LocateCarCommand(int32, uint32*); + void LocateSniperBulletCommand(int32, uint32*); + void PlayerInAreaCheckCommand(int32, uint32*); + void PlayerInAngledAreaCheckCommand(int32, uint32*); + void CharInAreaCheckCommand(int32, uint32*); + void CarInAreaCheckCommand(int32, uint32*); + +#ifdef GTA_SCRIPT_COLLECTIVE + void LocateCollectiveCommand(int32, uint32*); + void LocateCollectiveCharCommand(int32, uint32*); + void LocateCollectiveCarCommand(int32, uint32*); + void LocateCollectivePlayerCommand(int32, uint32*); + void CollectiveInAreaCheckCommand(int32, uint32*); +#endif + +#ifdef MISSION_REPLAY + bool CanAllowMissionReplay(); +#endif + +#ifdef USE_ADVANCED_SCRIPT_DEBUG_OUTPUT + int CollectParameterForDebug(char* buf, bool& var); + void GetStoredParameterForDebug(char* buf); +#endif + + float LimitAngleOnCircle(float angle) { return angle < 0.0f ? angle + 360.0f : angle; } + + bool ThisIsAValidRandomPed(uint32 pedtype) { + switch (pedtype) { + case PEDTYPE_CIVMALE: + case PEDTYPE_CIVFEMALE: + case PEDTYPE_GANG1: + case PEDTYPE_GANG2: + case PEDTYPE_GANG3: + case PEDTYPE_GANG4: + case PEDTYPE_GANG5: + case PEDTYPE_GANG6: + case PEDTYPE_GANG7: + case PEDTYPE_GANG8: + case PEDTYPE_GANG9: + case PEDTYPE_CRIMINAL: + case PEDTYPE_PROSTITUTE: + return true; + default: + return false; + } + } +}; + + enum { VAR_LOCAL = 1, VAR_GLOBAL = 2, @@ -428,156 +578,6 @@ public: #endif }; - -enum { -#if GTA_VERSION > GTA3_PS2_160 - MAX_STACK_DEPTH = 6, -#else - MAX_STACK_DEPTH = 4, -#endif - NUM_LOCAL_VARS = 16, - NUM_TIMERS = 2 -}; - -class CRunningScript -{ - enum { - ANDOR_NONE = 0, - ANDS_1 = 1, - ANDS_2, - ANDS_3, - ANDS_4, - ANDS_5, - ANDS_6, - ANDS_7, - ANDS_8, - ORS_1 = 21, - ORS_2, - ORS_3, - ORS_4, - ORS_5, - ORS_6, - ORS_7, - ORS_8 - }; - -public: - CRunningScript* next; - CRunningScript* prev; - char m_abScriptName[8]; - uint32 m_nIp; - uint32 m_anStack[MAX_STACK_DEPTH]; - uint16 m_nStackPointer; - int32 m_anLocalVariables[NUM_LOCAL_VARS + NUM_TIMERS]; - bool m_bCondResult; - bool m_bIsMissionScript; - bool m_bSkipWakeTime; - uint32 m_nWakeTime; - uint16 m_nAndOrState; - bool m_bNotFlag; - bool m_bDeatharrestEnabled; - bool m_bDeatharrestExecuted; - bool m_bMissionFlag; - -public: - void SetIP(uint32 ip) { m_nIp = ip; } - CRunningScript* GetNext() const { return next; } - - void Save(uint8*& buf); - void Load(uint8*& buf); - - void UpdateTimers(float timeStep) { - m_anLocalVariables[NUM_LOCAL_VARS] += timeStep; - m_anLocalVariables[NUM_LOCAL_VARS + 1] += timeStep; - } - - void Init(); - void Process(); - - void RemoveScriptFromList(CRunningScript**); - void AddScriptToList(CRunningScript**); - - static const uint32 nSaveStructSize; - - void CollectParameters(uint32*, int16); - int32 CollectNextParameterWithoutIncreasingPC(uint32); - int32* GetPointerToScriptVariable(uint32*, int16); - void StoreParameters(uint32*, int16); - - int8 ProcessOneCommand(); - void DoDeatharrestCheck(); - void UpdateCompareFlag(bool); - int16 GetPadState(uint16, uint16); - - int8 ProcessCommands0To99(int32); - int8 ProcessCommands100To199(int32); - int8 ProcessCommands200To299(int32); - int8 ProcessCommands300To399(int32); - int8 ProcessCommands400To499(int32); - int8 ProcessCommands500To599(int32); - int8 ProcessCommands600To699(int32); - int8 ProcessCommands700To799(int32); - int8 ProcessCommands800To899(int32); - int8 ProcessCommands900To999(int32); - int8 ProcessCommands1000To1099(int32); -#if GTA_VERSION > GTA3_PS2_160 - int8 ProcessCommands1100To1199(int32); -#endif - void LocatePlayerCommand(int32, uint32*); - void LocatePlayerCharCommand(int32, uint32*); - void LocatePlayerCarCommand(int32, uint32*); - void LocateCharCommand(int32, uint32*); - void LocateCharCharCommand(int32, uint32*); - void LocateCharCarCommand(int32, uint32*); - void LocateCharObjectCommand(int32, uint32*); - void LocateCarCommand(int32, uint32*); - void LocateSniperBulletCommand(int32, uint32*); - void PlayerInAreaCheckCommand(int32, uint32*); - void PlayerInAngledAreaCheckCommand(int32, uint32*); - void CharInAreaCheckCommand(int32, uint32*); - void CarInAreaCheckCommand(int32, uint32*); - -#ifdef GTA_SCRIPT_COLLECTIVE - void LocateCollectiveCommand(int32, uint32*); - void LocateCollectiveCharCommand(int32, uint32*); - void LocateCollectiveCarCommand(int32, uint32*); - void LocateCollectivePlayerCommand(int32, uint32*); - void CollectiveInAreaCheckCommand(int32, uint32*); -#endif - -#ifdef MISSION_REPLAY - bool CanAllowMissionReplay(); -#endif - -#ifdef USE_ADVANCED_SCRIPT_DEBUG_OUTPUT - int CollectParameterForDebug(char* buf, bool& var); - void GetStoredParameterForDebug(char* buf); -#endif - - float LimitAngleOnCircle(float angle) { return angle < 0.0f ? angle + 360.0f : angle; } - - bool ThisIsAValidRandomPed(uint32 pedtype) { - switch (pedtype) { - case PEDTYPE_CIVMALE: - case PEDTYPE_CIVFEMALE: - case PEDTYPE_GANG1: - case PEDTYPE_GANG2: - case PEDTYPE_GANG3: - case PEDTYPE_GANG4: - case PEDTYPE_GANG5: - case PEDTYPE_GANG6: - case PEDTYPE_GANG7: - case PEDTYPE_GANG8: - case PEDTYPE_GANG9: - case PEDTYPE_CRIMINAL: - case PEDTYPE_PROSTITUTE: - return true; - default: - return false; - } - } -}; - #ifdef MISSION_REPLAY extern int AllowMissionReplay; extern uint32 WaitForMissionActivate; diff --git a/src/control/Script5.cpp b/src/control/Script5.cpp index e74a1081..56164075 100644 --- a/src/control/Script5.cpp +++ b/src/control/Script5.cpp @@ -1924,7 +1924,7 @@ INITSAVEBUF for (uint32 i = 0; i < varSpace; i++) WriteSaveBuf(buf, ScriptSpace[i]); #ifdef CHECK_STRUCT_SIZES - static_assert(SCRIPT_DATA_SIZE == 968, "CTheScripts::SaveAllScripts"); + re3_static_assert(SCRIPT_DATA_SIZE == 968, "CTheScripts::SaveAllScripts"); #endif uint32 script_data_size = SCRIPT_DATA_SIZE; WriteSaveBuf(buf, script_data_size); @@ -2083,14 +2083,14 @@ void CRunningScript::Save(uint8*& buf) WriteSaveBuf(buf, m_abScriptName[i]); WriteSaveBuf(buf, m_nIp); #ifdef CHECK_STRUCT_SIZES - static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6"); + re3_static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6"); #endif for (int i = 0; i < MAX_STACK_DEPTH; i++) WriteSaveBuf(buf, m_anStack[i]); WriteSaveBuf(buf, m_nStackPointer); SkipSaveBuf(buf, 2); #ifdef CHECK_STRUCT_SIZES - static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18"); + re3_static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18"); #endif for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++) WriteSaveBuf(buf, m_anLocalVariables[i]); @@ -2118,14 +2118,14 @@ void CRunningScript::Load(uint8*& buf) m_abScriptName[i] = ReadSaveBuf(buf); m_nIp = ReadSaveBuf(buf); #ifdef CHECK_STRUCT_SIZES - static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6"); + re3_static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6"); #endif for (int i = 0; i < MAX_STACK_DEPTH; i++) m_anStack[i] = ReadSaveBuf(buf); m_nStackPointer = ReadSaveBuf(buf); SkipSaveBuf(buf, 2); #ifdef CHECK_STRUCT_SIZES - static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18"); + re3_static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18"); #endif for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++) m_anLocalVariables[i] = ReadSaveBuf(buf); @@ -2442,7 +2442,7 @@ bool CTheScripts::IsPedStopped(CPed* pPed) { if (pPed->bInVehicle) return IsVehicleStopped(pPed->m_pMyVehicle); - return pPed->m_nMoveState == eMoveState::PEDMOVE_NONE || pPed->m_nMoveState == eMoveState::PEDMOVE_STILL; + return pPed->m_nMoveState == PEDMOVE_NONE || pPed->m_nMoveState == PEDMOVE_STILL; } bool CTheScripts::IsPlayerStopped(CPlayerInfo* pPlayer) @@ -2455,7 +2455,7 @@ bool CTheScripts::IsPlayerStopped(CPlayerInfo* pPlayer) RpAnimBlendClumpGetAssociation(pPed->GetClump(), ANIM_JUMP_LAUNCH) || RpAnimBlendClumpGetAssociation(pPed->GetClump(), ANIM_JUMP_GLIDE)) return false; - return pPed->m_nMoveState == eMoveState::PEDMOVE_NONE || pPed->m_nMoveState == eMoveState::PEDMOVE_STILL; + return pPed->m_nMoveState == PEDMOVE_NONE || pPed->m_nMoveState == PEDMOVE_STILL; } bool CTheScripts::IsVehicleStopped(CVehicle* pVehicle) diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp index a11cd6a4..74de0ab7 100644 --- a/src/core/Cam.cpp +++ b/src/core/Cam.cpp @@ -946,7 +946,7 @@ CVector CCam::DoAverageOnVector(const CVector &vec) { int i; - CVector Average = { 0.0f, 0.0f, 0.0f }; + CVector Average(0.0f, 0.0f, 0.0f); if(ResetStatics){ m_iRunningVectorArrayPos = 0; diff --git a/src/core/CdStream.cpp b/src/core/CdStream.cpp index 4bb31ea4..a1843473 100644 --- a/src/core/CdStream.cpp +++ b/src/core/CdStream.cpp @@ -7,9 +7,6 @@ #include "RwHelper.h" #include "MemoryMgr.h" -#define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) -#define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) - struct CdReadInfo { uint32 nSectorOffset; @@ -60,7 +57,7 @@ CdStreamInitThread(void) if ( gpReadInfo[i].hSemaphore == nil ) { - CDTRACE("failed to create sync semaphore"); + printf("%s: failed to create sync semaphore\n", "cdvd_stream"); ASSERT(0); return; } @@ -81,7 +78,7 @@ CdStreamInitThread(void) if ( gCdStreamSema == nil ) { - CDTRACE("failed to create stream semaphore"); + printf("%s: failed to create stream semaphore\n", "cdvd_stream"); ASSERT(0); return; } @@ -90,7 +87,7 @@ CdStreamInitThread(void) if ( _gCdStreamThread == nil ) { - CDTRACE("failed to create streaming thread"); + printf("%s: failed to create streaming thread\n", "cdvd_stream"); ASSERT(0); return; } @@ -138,7 +135,7 @@ CdStreamInit(int32 numChannels) gpReadInfo = (CdReadInfo *)LocalAlloc(LMEM_ZEROINIT, sizeof(CdReadInfo) * numChannels); ASSERT( gpReadInfo != nil ); - CDDEBUG("read info %p", gpReadInfo); + debug("%s: read info %p\n", gpReadInfo, "cdvd_stream"); CdStreamAddImage("MODELS\\GTA3.IMG"); diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 65eab125..707184d5 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -1281,7 +1281,9 @@ CMenuManager::Draw() float smallestSliderBar = lineHeight * 0.1f; bool foundTheHoveringItem = false; wchar unicodeTemp[64]; +#ifdef ASPECT_RATIO_SCALE char asciiTemp[32]; +#endif #ifdef MENU_MAP if (m_nCurrScreen == MENUPAGE_MAP) { diff --git a/src/core/General.h b/src/core/General.h index de803558..478ef027 100644 --- a/src/core/General.h +++ b/src/core/General.h @@ -133,7 +133,7 @@ public: static bool faststricmp(const char *str1, const char *str2) { for (; *str1; str1++, str2++) { -#if MUCH_SLOWER || !defined _WIN32 || defined __MINGW32__ +#ifndef ASCII_STRCMP if (toupper(*str1) != toupper(*str2)) #else if (__ascii_toupper(*str1) != __ascii_toupper(*str2)) diff --git a/src/core/Placeable.cpp b/src/core/Placeable.cpp index 69b3d3ea..162148f7 100644 --- a/src/core/Placeable.cpp +++ b/src/core/Placeable.cpp @@ -7,7 +7,9 @@ CPlaceable::CPlaceable(void) m_matrix.SetScale(1.0f); } -CPlaceable::~CPlaceable(void) = default; +CPlaceable::~CPlaceable(void) +{ +} void CPlaceable::SetHeading(float angle) diff --git a/src/core/Placeable.h b/src/core/Placeable.h index 970c0d48..1d51f306 100644 --- a/src/core/Placeable.h +++ b/src/core/Placeable.h @@ -4,7 +4,7 @@ class CPlaceable { public: // disable allocation - static void *operator new(size_t) = delete; + static void *operator new(size_t); CMatrix m_matrix; diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp index ba939fa3..4672e024 100644 --- a/src/core/Radar.cpp +++ b/src/core/Radar.cpp @@ -1,4 +1,4 @@ -#if !defined(GTA_PS2_STUFF) && defined(RWLIBS) +#if (!defined(GTA_PS2_STUFF) && defined(RWLIBS)) || defined(__MWERKS__) #define WITHD3D #endif #include "config.h" @@ -79,7 +79,7 @@ CSprite2d *CRadar::RadarSprites[RADAR_SPRITE_COUNT] = { #define RADAR_NUM_TILES (8) #define RADAR_TILE_SIZE (RADAR_SIZE_X / RADAR_NUM_TILES) -static_assert(RADAR_TILE_SIZE == (RADAR_SIZE_Y / RADAR_NUM_TILES), "CRadar: not a square"); +re3_static_assert(RADAR_TILE_SIZE == (RADAR_SIZE_Y / RADAR_NUM_TILES), "CRadar: not a square"); #define RADAR_MIN_RANGE (120.0f) #define RADAR_MAX_RANGE (350.0f) @@ -298,10 +298,10 @@ void CRadar::ClearBlipForEntity(eBlipType type, int32 id) int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *rect) { CVector2D corners[4] = { - { 1.0f, -1.0f }, // top right - { 1.0f, 1.0f }, // bottom right - { -1.0f, 1.0f }, // bottom left - { -1.0f, -1.0f }, // top left + CVector2D( 1.0f, -1.0f ), // top right + CVector2D( 1.0f, 1.0f ), // bottom right + CVector2D( -1.0f, 1.0f ), // bottom left + CVector2D( -1.0f, -1.0f ), // top left }; CVector2D tmp; int i, j, n; diff --git a/src/core/Stats.h b/src/core/Stats.h index 5dfcf803..6abcfb61 100644 --- a/src/core/Stats.h +++ b/src/core/Stats.h @@ -17,7 +17,7 @@ public: static int32 NumberKillFrenziesPassed; static int32 PeopleKilledByOthers; static int32 HelisDestroyed; - static int32 PedsKilledOfThisType[ePedType::NUM_PEDTYPES]; + static int32 PedsKilledOfThisType[NUM_PEDTYPES]; static int32 TimesDied; static int32 TimesArrested; static int32 KillsSinceLastCheckpoint; diff --git a/src/core/common.h b/src/core/common.h index d7facfd1..d3b0daa9 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -7,10 +7,18 @@ #pragma warning(disable: 4838) // narrowing conversion #pragma warning(disable: 4996) // POSIX names +#ifdef __MWERKS__ +#define __STDC_LIMIT_MACROS // so we get UINT32_MAX etc +#endif + #include #include #include +#ifdef __MWERKS__ +#define RWLIBS // codewarrior doesn't support project level defines - so not even this is enough, but still catches most ifdefs +#endif + #if !defined RW_D3D9 && defined LIBRW #undef WITHD3D #undef WITHDINPUT @@ -79,8 +87,13 @@ typedef uint8_t uint8; typedef int8_t int8; typedef uint16_t uint16; typedef int16_t int16; +#ifndef __MWERKS__ typedef uint32_t uint32; typedef int32_t int32; +#else +typedef unsigned int uint32; +typedef int int32; +#endif typedef uintptr_t uintptr; typedef intptr_t intptr; typedef uint64_t uint64; @@ -92,7 +105,7 @@ typedef uint8 bool8; typedef uint16 bool16; typedef uint32 bool32; -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined (__MWERKS__) typedef ptrdiff_t ssize_t; #endif @@ -275,6 +288,22 @@ extern wchar *AllocUnicode(const char*src); inline float sq(float x) { return x*x; } #define SQR(x) ((x) * (x)) +#ifdef __MWERKS__ +#define M_E 2.71828182845904523536 // e +#define M_LOG2E 1.44269504088896340736 // log2(e) +#define M_LOG10E 0.434294481903251827651 // log10(e) +#define M_LN2 0.693147180559945309417 // ln(2) +#define M_LN10 2.30258509299404568402 // ln(10) +#define M_PI 3.14159265358979323846 // pi +#define M_PI_2 1.57079632679489661923 // pi/2 +#define M_PI_4 0.785398163397448309616 // pi/4 +#define M_1_PI 0.318309886183790671538 // 1/pi +#define M_2_PI 0.636619772367581343076 // 2/pi +#define M_2_SQRTPI 1.12837916709551257390 // 2/sqrt(pi) +#define M_SQRT2 1.41421356237309504880 // sqrt(2) +#define M_SQRT1_2 0.707106781186547524401 // 1/sqrt(2) +#endif + #define PI (float)M_PI #define TWOPI (PI*2) #define HALFPI (PI/2) @@ -304,23 +333,45 @@ void re3_usererror(const char *format, ...); #define DEV(f, ...) re3_debug("[DEV]: " f, ## __VA_ARGS__) #endif +#ifdef __MWERKS__ +void debug(char *f, ...); +void Error(char *f, ...); +__inline__ void TRACE(char *f, ...) { } // this is re3 only, and so the function needs to be inline - this way no call actually gets placed +// USERERROR only gets used in oal builds ... once +#else #define debug(f, ...) re3_debug("[DBG]: " f, ## __VA_ARGS__) -#define TRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, f, ## __VA_ARGS__) #define Error(f, ...) re3_debug("[ERROR]: " f, ## __VA_ARGS__) +#ifndef MASTER +#define TRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, f, ## __VA_ARGS__) #define USERERROR(f, ...) re3_usererror(f, ## __VA_ARGS__) +#else +#define TRACE(f, ...) +#define USERERROR(f, ...) +#endif +#endif +#ifndef MASTER #define assert(_Expression) (void)( (!!(_Expression)) || (re3_assert(#_Expression, __FILE__, __LINE__, __FUNCTION__), 0) ) +#else +#define assert(_Expression) +#endif #define ASSERT assert +#if defined DEBUG && !defined __MWERKS__ +#define re3_static_assert(bool_constexpr, message) static_assert(bool_constexpr, message) +#else +#define re3_static_assert(bool_constexpr, message) +#endif + #define _TODO(x) #define _TODOCONST(x) (x) #ifdef CHECK_STRUCT_SIZES -#define VALIDATE_SIZE(struc, size) static_assert(sizeof(struc) == size, "Invalid structure size of " #struc) +#define VALIDATE_SIZE(struc, size) re3_static_assert(sizeof(struc) == size, "Invalid structure size of " #struc) #else #define VALIDATE_SIZE(struc, size) #endif -#define VALIDATE_OFFSET(struc, member, offset) static_assert(offsetof(struc, member) == offset, "The offset of " #member " in " #struc " is not " #offset "...") +#define VALIDATE_OFFSET(struc, member, offset) re3_static_assert(offsetof(struc, member) == offset, "The offset of " #member " in " #struc " is not " #offset "...") #define PERCENT(x, p) ((float(x) * (float(p) / 100.0f))) #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) @@ -335,6 +386,7 @@ void re3_usererror(const char *format, ...); #define CONCAT_(x,y) x##y #define CONCAT(x,y) CONCAT_(x,y) +#ifdef DEBUGMENU // Tweaking stuff for debugmenu #define TWEAKPATH ___tw___TWEAKPATH #define SETTWEAKPATH(path) static const char *___tw___TWEAKPATH = path; @@ -448,6 +500,7 @@ _TWEEKCLASS(CTweakUInt32, uint32); _TWEEKCLASS(CTweakFloat, float); #undef _TWEEKCLASS +#endif #ifdef VALIDATE_SAVE_SIZE extern int32 _saveBufCount; diff --git a/src/core/config.h b/src/core/config.h index ce7ee1e3..e71c34a8 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -1,5 +1,8 @@ #pragma once +// disable (most) stuff that wasn't in original gta3.exe - check section at the bottom of this file +#define VANILLA_DEFINES + enum Config { NUMPLAYERS = 1, // 4 on PS2 @@ -8,8 +11,11 @@ enum Config { MAX_CDCHANNELS = 5, MODELINFOSIZE = 5500, // 3150 on PS2 -// TXDSTORESIZE = 850, +#if defined __MWERKS__ || defined VANILLA_DEFINES + TXDSTORESIZE = 850, +#else TXDSTORESIZE = 1024, // for Xbox map +#endif EXTRADIRSIZE = 128, CUTSCENEDIRSIZE = 512, @@ -235,6 +241,12 @@ enum Config { #define FIX_BUGS_64 // Must have fixes to be able to run 64 bit build #endif +#define ASCII_STRCMP // use faster ascii str comparisons + +#if !defined _WIN32 || defined __MWERKS__ || defined __MINGW32__ +#undef ASCII_STRCMP +#endif + // Just debug menu entries #ifdef DEBUGMENU #define MISSION_SWITCHER // from debug menu @@ -394,3 +406,86 @@ enum Config { #ifdef LIBRW // these are not supported with librw yet #endif + +#if defined __MWERKS__ || defined VANILLA_DEFINES +#define FINAL +#undef CHATTYSPLASH +#undef TIMEBARS +//#define USE_MY_DOCUMENTS + +#define MASTER +#undef VALIDATE_SAVE_SIZE +#undef NO_MOVIES +#undef DEBUGMENU + +#undef DRAW_GAME_VERSION_TEXT +#undef DRAW_MENU_VERSION_TEXT + +#undef GTA_PS2_STUFF +#undef USE_PS2_RAND +#undef RANDOMSPLASH +#undef PS2_MATFX + +#undef FIX_BUGS +#undef THIS_IS_STUPID +#undef MORE_LANGUAGES +#undef MORE_LANGUAGES +#undef COMPATIBLE_SAVES +#undef LOAD_INI_SETTINGS + +#undef ASPECT_RATIO_SCALE +#undef PROPER_SCALING +#undef DEFAULT_NATIVE_RESOLUTION +#undef PS2_ALPHA_TEST +#undef IMPROVED_VIDEOMODE +#undef DISABLE_LOADING_SCREEN +#undef DISABLE_VSYNC_ON_TEXTURE_CONVERSION +//#define USE_TEXTURE_POOL // not possible because R* used custom RW33 + +#undef FIX_SPRITES + +#define PC_PARTICLE + +#undef XINPUT +#undef DETECT_PAD_INPUT_SWITCH +#undef KANGAROO_CHEAT +#undef ALLCARSHELI_CHEAT +#undef ALT_DODO_CHEAT +#undef REGISTER_START_BUTTON +#undef BIND_VEHICLE_FIREWEAPON +#undef BUTTON_ICONS + +#undef HUD_ENHANCEMENTS +#undef TRIANGULAR_BLIPS +#undef FIX_RADAR +#undef RADIO_OFF_TEXT + +#undef MENU_MAP +#undef SCROLLABLE_STATS_PAGE +#undef CUSTOM_FRONTEND_OPTIONS + +#undef GRAPHICS_MENU_OPTIONS +#undef NO_ISLAND_LOADING +#undef CUTSCENE_BORDERS_SWITCH +#undef MULTISAMPLING +#undef INVERT_LOOK_FOR_PAD + +#undef USE_DEBUG_SCRIPT_LOADER +#undef USE_MEASUREMENTS_IN_METERS // TODO +#undef USE_PRECISE_MEASUREMENT_CONVERTION +#undef MISSION_REPLAY +#undef USE_ADVANCED_SCRIPT_DEBUG_OUTPUT +#undef USE_BASIC_SCRIPT_DEBUG_OUTPUT + +#define DONT_FIX_REPLAY_BUGS + +#undef EXPLODING_AIRTRAIN +#undef CAMERA_PICKUP +#undef PED_SKIN +#undef ANIMATE_PED_COL_MODEL +#undef CANCELLABLE_CAR_ENTER +#undef IMPROVED_CAMERA +#undef FREE_CAM +#undef RADIO_SCROLL_TO_PREV_STATION +#undef BIG_IMG +#endif diff --git a/src/core/main.cpp b/src/core/main.cpp index d43f4a74..9d8a8e52 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -128,6 +128,24 @@ bool gbNewRenderer; #define CLEARMODE (rwCAMERACLEARZ) #endif +#ifdef __MWERKS__ +void +debug(char *fmt, ...) +{ +#ifndef MASTER + // TODO put something here +#endif +} + +void +Error(char *fmt, ...) +{ +#ifndef MASTER + // TODO put something here +#endif +} +#endif + void ValidateVersion() { @@ -857,6 +875,7 @@ ProcessSlowMode(void) float FramesPerSecondCounter; int32 FrameSamples; +#ifndef MASTER struct tZonePrint { char name[12]; @@ -877,8 +896,6 @@ tZonePrint ZonePrint[] = { "no zone", CRect( 0.0f, 0.0f, 0.0f, 0.0f) } }; -#ifndef MASTER - void PrintMemoryUsage(void) { diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 09eafe74..48e8a6bc 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -983,9 +983,13 @@ extern bool gbRenderWorld2; } #endif +#ifndef __MWERKS__ +#ifndef MASTER const int re3_buffsize = 1024; static char re3_buff[re3_buffsize]; +#endif +#ifndef MASTER void re3_assert(const char *expr, const char *filename, unsigned int lineno, const char *func) { #ifdef _WIN32 @@ -1039,9 +1043,11 @@ void re3_assert(const char *expr, const char *filename, unsigned int lineno, con assert(false); #endif } +#endif void re3_debug(const char *format, ...) { +#ifndef MASTER va_list va; va_start(va, format); #ifdef _WIN32 @@ -1053,8 +1059,10 @@ void re3_debug(const char *format, ...) printf("%s", re3_buff); CDebug::DebugAddText(re3_buff); +#endif } +#ifndef MASTER void re3_trace(const char *filename, unsigned int lineno, const char *func, const char *format, ...) { char buff[re3_buffsize *2]; @@ -1074,7 +1082,9 @@ void re3_trace(const char *filename, unsigned int lineno, const char *func, cons OutputDebugString(buff); } +#endif +#ifndef MASTER void re3_usererror(const char *format, ...) { va_list va; @@ -1094,6 +1104,8 @@ void re3_usererror(const char *format, ...) assert(false); #endif } +#endif +#endif #ifdef VALIDATE_SAVE_SIZE int32 _saveBufCount; diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index 24017e19..ed01297e 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -1092,7 +1092,7 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists) int numCollisions; int mostColliding; CColPoint colpoints[MAX_COLLISION_POINTS]; - CVector shift = { 0.0f, 0.0f, 0.0f }; + CVector shift = CVector(0.0f, 0.0f, 0.0f); bool doShift = false; CEntity *boat = nil; @@ -1539,8 +1539,8 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) if(numCollisions <= 0) continue; - CVector moveSpeed = { 0.0f, 0.0f, 0.0f }; - CVector turnSpeed = { 0.0f, 0.0f, 0.0f }; + CVector moveSpeed = CVector(0.0f, 0.0f, 0.0f); + CVector turnSpeed = CVector(0.0f, 0.0f, 0.0f); numResponses = 0; if(A->bHasContacted){ for(i = 0; i < numCollisions; i++){ @@ -1899,8 +1899,8 @@ CPhysical::ProcessCollision(void) }else if(IsObject()){ int responsecase = ((CObject*)this)->m_nSpecialCollisionResponseCases; if(responsecase == COLLRESPONSE_LAMPOST){ - CVector speedUp = { 0.0f, 0.0f, 0.0f }; - CVector speedDown = { 0.0f, 0.0f, 0.0f }; + CVector speedUp = CVector(0.0f, 0.0f, 0.0f); + CVector speedDown = CVector(0.0f, 0.0f, 0.0f); speedUp.z = GetBoundRadius(); speedDown.z = -speedUp.z; speedUp = Multiply3x3(GetMatrix(), speedUp); diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp index a8e2e972..ae981d1d 100644 --- a/src/peds/PlayerPed.cpp +++ b/src/peds/PlayerPed.cpp @@ -229,7 +229,7 @@ CPlayerPed::SetInitialState(void) m_nAdrenalineTime = 0; CTimer::SetTimeScale(1.0f); m_pSeekTarget = nil; - m_vecSeekPos = { 0.0f, 0.0f, 0.0f }; + m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); m_fleeFromPosX = 0.0f; m_fleeFromPosY = 0.0f; m_fleeFrom = nil; diff --git a/src/peds/Population.cpp b/src/peds/Population.cpp index 35443cb8..53db7263 100644 --- a/src/peds/Population.cpp +++ b/src/peds/Population.cpp @@ -32,22 +32,22 @@ // Transition areas between zones const RegenerationPoint aSafeZones[] = { - { LEVEL_INDUSTRIAL, LEVEL_COMMERCIAL, 400.0f, 814.0f, -954.0f, -903.0f, 30.0f, 100.0f, - CVector(790.0f, -917.0f, 39.0f), CVector(775.0f, -921.0f, 39.0f), CVector(424.0f, -942.0f, 38.0f), CVector(439.0f, -938.0f, 38.0f) }, - { LEVEL_INDUSTRIAL, LEVEL_COMMERCIAL, 555.0f, 711.0f, 118.0f, 186.0f, -30.0f, -10.0f, - CVector(698.0f, 182.0f, -20.0f), CVector(681.0f, 178.0f, -20.0f), CVector(586.0f, 144.0f, -20.0f), CVector(577.0f, 135.0f, -20.0f) }, - { LEVEL_INDUSTRIAL, LEVEL_COMMERCIAL, 626.0f, 744.0f, -124.0f, -87.0f, -20.0f, -6.0f, - CVector(736.0f, -117.0f, -13.0f), CVector(730.0f, -115.0f, -13.0f), CVector(635.0f, -93.0f, -12.5f), CVector(650.0f, -89.0f, -12.5f) }, - { LEVEL_INDUSTRIAL, LEVEL_COMMERCIAL, 645.0f, 734.0f, -780.0f, -750.0f, -25.0f, -6.0f, - CVector(729.0f, -764.0f, -18.0f), CVector(720.0f, -769.0f, -17.0f), CVector(652.0f, -774.0f, -10.5f), CVector(659.0f, -770.0f, -10.5f) }, - { LEVEL_COMMERCIAL, LEVEL_SUBURBAN, -532.0f, -136.0f, -668.0f, -599.0f, 34.0f, 60.0f, - CVector(-172.0f, -619.0f, 44.0f), CVector(-183.0f, -623.0f, 44.0f), CVector(-511.0f, -645.0f, 41.0f), CVector(-493.0f, -639.0f, 41.5f) }, - { LEVEL_COMMERCIAL, LEVEL_SUBURBAN, -325.0f, -175.0f, 27.0f, 75.0f, -30.0f, -10.0f, - CVector(-185.0f, 40.8f, -20.5f), CVector(-202.0f, 37.0f, -20.5f), CVector(-315.0f, 65.5f, -20.5f), CVector(-306.0f, 62.4f, -20.5f) }, - { LEVEL_COMMERCIAL, LEVEL_SUBURBAN, -410.0f, -310.0f, -1055.0f, -1030.0f, -20.0f, -6.0f, - CVector(-321.0f, -1043.0f, -13.2f), CVector(-328.0f, -1045.0f, -13.2f), CVector(-398.0f, -1044.0f, -13.5f), CVector(-390.0f, -1040.5f, -13.5f) }, - { LEVEL_COMMERCIAL, LEVEL_SUBURBAN, -425.0f, -280.0f, -471.0f, -447.0f, -20.0f, -5.0f, - CVector(-292.0f, -457.0f, -11.6f), CVector(-310.0f, -461.0f, -11.6f), CVector(-413.0f, -461.0f, -11.5f), CVector(-399.0f, -457.0f, -11.3f) } + LEVEL_INDUSTRIAL, LEVEL_COMMERCIAL, 400.0f, 814.0f, -954.0f, -903.0f, 30.0f, 100.0f, + 790.0f, -917.0f, 39.0f, 775.0f, -921.0f, 39.0f, 424.0f, -942.0f, 38.0f, 439.0f, -938.0f, 38.0f, + LEVEL_INDUSTRIAL, LEVEL_COMMERCIAL, 555.0f, 711.0f, 118.0f, 186.0f, -30.0f, -10.0f, + CVector(698.0f, 182.0f, -20.0f), CVector(681.0f, 178.0f, -20.0f), CVector(586.0f, 144.0f, -20.0f), CVector(577.0f, 135.0f, -20.0f), + LEVEL_INDUSTRIAL, LEVEL_COMMERCIAL, 626.0f, 744.0f, -124.0f, -87.0f, -20.0f, -6.0f, + CVector(736.0f, -117.0f, -13.0f), CVector(730.0f, -115.0f, -13.0f), CVector(635.0f, -93.0f, -12.5f), CVector(650.0f, -89.0f, -12.5f), + LEVEL_INDUSTRIAL, LEVEL_COMMERCIAL, 645.0f, 734.0f, -780.0f, -750.0f, -25.0f, -6.0f, + CVector(729.0f, -764.0f, -18.0f), CVector(720.0f, -769.0f, -17.0f), CVector(652.0f, -774.0f, -10.5f), CVector(659.0f, -770.0f, -10.5f), + LEVEL_COMMERCIAL, LEVEL_SUBURBAN, -532.0f, -136.0f, -668.0f, -599.0f, 34.0f, 60.0f, + CVector(-172.0f, -619.0f, 44.0f), CVector(-183.0f, -623.0f, 44.0f), CVector(-511.0f, -645.0f, 41.0f), CVector(-493.0f, -639.0f, 41.5f), + LEVEL_COMMERCIAL, LEVEL_SUBURBAN, -325.0f, -175.0f, 27.0f, 75.0f, -30.0f, -10.0f, + CVector(-185.0f, 40.8f, -20.5f), CVector(-202.0f, 37.0f, -20.5f), CVector(-315.0f, 65.5f, -20.5f), CVector(-306.0f, 62.4f, -20.5f), + LEVEL_COMMERCIAL, LEVEL_SUBURBAN, -410.0f, -310.0f, -1055.0f, -1030.0f, -20.0f, -6.0f, + CVector(-321.0f, -1043.0f, -13.2f), CVector(-328.0f, -1045.0f, -13.2f), CVector(-398.0f, -1044.0f, -13.5f), CVector(-390.0f, -1040.5f, -13.5f), + LEVEL_COMMERCIAL, LEVEL_SUBURBAN, -425.0f, -280.0f, -471.0f, -447.0f, -20.0f, -5.0f, + CVector(-292.0f, -457.0f, -11.6f), CVector(-310.0f, -461.0f, -11.6f), CVector(-413.0f, -461.0f, -11.5f), CVector(-399.0f, -457.0f, -11.3f) }; PedGroup CPopulation::ms_pPedGroups[NUMPEDGROUPS]; @@ -77,7 +77,7 @@ uint32 CPopulation::ms_nNumGang7; uint32 CPopulation::ms_nNumGang8; CVector CPopulation::RegenerationPoint_a; CVector CPopulation::RegenerationPoint_b; -CVector CPopulation::RegenerationForward; +CVector CPopulation::RegenerationFront; void CPopulation::Initialise() @@ -370,13 +370,13 @@ CPopulation::DealWithZoneChange(eLevelName oldLevel, eLevelName newLevel, bool f if (aSafeZones[safeZone].srcLevel == newLevel) { CPopulation::RegenerationPoint_a = aSafeZones[safeZone].srcPosA; CPopulation::RegenerationPoint_b = aSafeZones[safeZone].srcPosB; - CPopulation::RegenerationForward = aSafeZones[safeZone].destPosA - aSafeZones[safeZone].srcPosA; - RegenerationForward.Normalise(); + CPopulation::RegenerationFront = aSafeZones[safeZone].destPosA - aSafeZones[safeZone].srcPosA; + RegenerationFront.Normalise(); } else if (aSafeZones[safeZone].destLevel == newLevel) { CPopulation::RegenerationPoint_a = aSafeZones[safeZone].destPosA; CPopulation::RegenerationPoint_b = aSafeZones[safeZone].destPosB; - CPopulation::RegenerationForward = aSafeZones[safeZone].srcPosA - aSafeZones[safeZone].destPosA; - RegenerationForward.Normalise(); + CPopulation::RegenerationFront = aSafeZones[safeZone].srcPosA - aSafeZones[safeZone].destPosA; + RegenerationFront.Normalise(); } } @@ -895,7 +895,7 @@ CPopulation::MoveCarsAndPedsOutOfAbandonedZones() break; } veh->GetMatrix().GetPosition().z += (movedVehicleCount / 4) * 7.0f; - veh->GetMatrix().GetForward() = RegenerationForward; + veh->GetMatrix().GetForward() = RegenerationFront; ((CAutomobile*)veh)->PlaceOnRoadProperly(); CCarCtrl::JoinCarWithRoadSystem(veh); CTheScripts::ClearSpaceForMissionEntity(veh->GetPosition(), veh); diff --git a/src/peds/Population.h b/src/peds/Population.h index aa8129c0..61f0bdb7 100644 --- a/src/peds/Population.h +++ b/src/peds/Population.h @@ -24,10 +24,10 @@ struct RegenerationPoint float y2; float z1; float z2; - CVector destPosA; - CVector destPosB; - CVector srcPosA; - CVector srcPosB; + RwV3d destPosA; + RwV3d destPosB; + RwV3d srcPosA; + RwV3d srcPosB; }; class CPopulation @@ -60,7 +60,7 @@ public: static uint32 ms_nNumGang8; static CVector RegenerationPoint_a; static CVector RegenerationPoint_b; - static CVector RegenerationForward; + static CVector RegenerationFront; static void Initialise(); static void Update(void); diff --git a/src/render/Font.h b/src/render/Font.h index a7a4b487..621375d6 100644 --- a/src/render/Font.h +++ b/src/render/Font.h @@ -1,5 +1,7 @@ #pragma once +#include "Sprite2d.h" + void AsciiToUnicode(const char *src, wchar *dst); void UnicodeStrcpy(wchar *dst, const wchar *src); void UnicodeStrcat(wchar *dst, wchar *append); diff --git a/src/render/Glass.cpp b/src/render/Glass.cpp index 0b25525e..3b6fbd46 100644 --- a/src/render/Glass.cpp +++ b/src/render/Glass.cpp @@ -1,4 +1,4 @@ -#include "common.h" +#include "common.h" #include "Glass.h" #include "Timer.h" diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index b718c163..f20397a3 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -1148,20 +1148,20 @@ void CHud::Draw() // Yeah, top and bottom changed place. R* vision if (IntroRect.m_bIsUsed && IntroRect.m_bBeforeFade) { if (IntroRect.m_nTextureId >= 0) { - CRect rect = { + CRect rect ( IntroRect.m_sRect.left, IntroRect.m_sRect.top, IntroRect.m_sRect.right, - IntroRect.m_sRect.bottom }; + IntroRect.m_sRect.bottom ); CTheScripts::ScriptSprites[IntroRect.m_nTextureId].Draw(rect, IntroRect.m_sColor); } else { - CRect rect = { + CRect rect ( IntroRect.m_sRect.left, IntroRect.m_sRect.top, IntroRect.m_sRect.right, - IntroRect.m_sRect.bottom }; + IntroRect.m_sRect.bottom ); CSprite2d::DrawRect(rect, IntroRect.m_sColor); } diff --git a/src/render/Instance.h b/src/render/Instance.h index 01dfb6a2..693cfdf1 100644 --- a/src/render/Instance.h +++ b/src/render/Instance.h @@ -9,6 +9,6 @@ class CInstance : public CPlaceable public: int m_modelIndex; public: - ~CInstance() = default; + ~CInstance() { } void Shutdown(); }; diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp index e3d2ffa6..6f0f24f1 100644 --- a/src/render/SpecialFX.cpp +++ b/src/render/SpecialFX.cpp @@ -1119,7 +1119,7 @@ CMoneyMessages::RegisterOne(CVector vecPos, const char *pText, uint8 bRed, uint8 } CRGBA FoamColour(255, 255, 255, 255); -unsigned int CSpecialParticleStuff::BoatFromStart; +uint32 CSpecialParticleStuff::BoatFromStart; void CSpecialParticleStuff::CreateFoamAroundObject(CMatrix* pMatrix, float innerFw, float innerRg, float innerUp, int32 particles) diff --git a/src/rw/MemoryHeap.h b/src/rw/MemoryHeap.h index cd8cf22c..ed2e83b6 100644 --- a/src/rw/MemoryHeap.h +++ b/src/rw/MemoryHeap.h @@ -95,7 +95,7 @@ struct HeapBlockDesc #ifdef USE_CUSTOM_ALLOCATOR // TODO: figure something out for 64 bit pointers -static_assert(sizeof(HeapBlockDesc) == 0x10, "HeapBlockDesc must have 0x10 size otherwise most of assumptions don't make sense"); +re3_static_assert(sizeof(HeapBlockDesc) == 0x10, "HeapBlockDesc must have 0x10 size otherwise most of assumptions don't make sense"); #endif struct HeapBlockList diff --git a/src/save/GenericGameStorage.h b/src/save/GenericGameStorage.h index ee8a52a1..069ba7cd 100644 --- a/src/save/GenericGameStorage.h +++ b/src/save/GenericGameStorage.h @@ -1,5 +1,6 @@ #pragma once +#include "Game.h" #include "PCSave.h" #define SLOT_COUNT (8) diff --git a/src/skel/crossplatform.h b/src/skel/crossplatform.h index d8807f2b..b4e6a751 100644 --- a/src/skel/crossplatform.h +++ b/src/skel/crossplatform.h @@ -17,7 +17,11 @@ enum eWinVersion // As long as WITHWINDOWS isn't defined / isn't included, we only need type definitions so let's include . // NOTE: It's perfectly fine to include here, but it can increase build size and time in *some* conditions, and maybe substantially in future if we'll use crossplatform.h more. #ifndef _INC_WINDOWS - #include + #ifndef __MWERKS__ + #include + #else + #include + #endif #endif #if defined RW_D3D9 || defined RWLIBS #include "win.h" @@ -114,6 +118,7 @@ struct SYSTEMTIME { void GetLocalTime_CP(SYSTEMTIME* out); #define GetLocalTime GetLocalTime_CP + #define OutputDebugString(s) re3_debug("[DBG-2]: %s\n",s) #endif diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index 5a0c7db2..2fdf078e 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -1,4 +1,4 @@ -#if defined RW_D3D9 || defined RWLIBS +#if defined RW_D3D9 || defined RWLIBS || defined __MWERKS__ #define _WIN32_WINDOWS 0x0500 #define WINVER 0x0500 @@ -19,6 +19,10 @@ #pragma warning( push ) #pragma warning( disable : 4005) +#ifdef __MWERKS__ +#define MAPVK_VK_TO_CHAR (2) // this is missing from codewarrior win32 headers - but it gets used ... how? +#endif + #include #include #pragma warning( pop ) diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 966042e2..77173538 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -1,4 +1,4 @@ -#include "common.h" +#include "common.h" #include "main.h" #include "General.h" diff --git a/src/weapons/WeaponInfo.cpp b/src/weapons/WeaponInfo.cpp index b40329c8..10737acb 100644 --- a/src/weapons/WeaponInfo.cpp +++ b/src/weapons/WeaponInfo.cpp @@ -7,7 +7,7 @@ #include "AnimBlendAssociation.h" #include "Weapon.h" -CWeaponInfo CWeaponInfo::ms_apWeaponInfos[WEAPONTYPE_TOTALWEAPONS]; +static CWeaponInfo aWeaponInfo[WEAPONTYPE_TOTALWEAPONS]; static char ms_aWeaponNames[][32] = { "Unarmed", @@ -28,7 +28,7 @@ static char ms_aWeaponNames[][32] = { CWeaponInfo* CWeaponInfo::GetWeaponInfo(eWeaponType weaponType) { - return &CWeaponInfo::ms_apWeaponInfos[weaponType]; + return &aWeaponInfo[weaponType]; } void @@ -36,10 +36,10 @@ CWeaponInfo::Initialise(void) { debug("Initialising CWeaponInfo...\n"); for (int i = 0; i < WEAPONTYPE_TOTALWEAPONS; i++) { - ms_apWeaponInfos[i].m_eWeaponFire = WEAPON_FIRE_INSTANT_HIT; - ms_apWeaponInfos[i].m_AnimToPlay = ANIM_PUNCH_R; - ms_apWeaponInfos[i].m_Anim2ToPlay = NUM_ANIMS; - ms_apWeaponInfos[i].m_Flags = WEAPONFLAG_USE_GRAVITY | WEAPONFLAG_SLOWS_DOWN | WEAPONFLAG_RAND_SPEED | WEAPONFLAG_EXPANDS | WEAPONFLAG_EXPLODES; + aWeaponInfo[i].m_eWeaponFire = WEAPON_FIRE_INSTANT_HIT; + aWeaponInfo[i].m_AnimToPlay = ANIM_PUNCH_R; + aWeaponInfo[i].m_Anim2ToPlay = NUM_ANIMS; + aWeaponInfo[i].m_Flags = WEAPONFLAG_USE_GRAVITY | WEAPONFLAG_SLOWS_DOWN | WEAPONFLAG_RAND_SPEED | WEAPONFLAG_EXPANDS | WEAPONFLAG_EXPLODES; } debug("Loading weapon data...\n"); LoadWeaponData(); @@ -133,29 +133,29 @@ CWeaponInfo::LoadWeaponData(void) if (strcmp(anim2ToPlay, "null") != 0) { animAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, anim2ToPlay); - ms_apWeaponInfos[weaponType].m_Anim2ToPlay = (AnimationId) animAssoc->animId; + aWeaponInfo[weaponType].m_Anim2ToPlay = (AnimationId) animAssoc->animId; } CVector vecFireOffset(fireOffsetX, fireOffsetY, fireOffsetZ); - ms_apWeaponInfos[weaponType].m_eWeaponFire = FindWeaponFireType(fireType); - ms_apWeaponInfos[weaponType].m_fRange = range; - ms_apWeaponInfos[weaponType].m_nFiringRate = firingRate; - ms_apWeaponInfos[weaponType].m_nReload = reload; - ms_apWeaponInfos[weaponType].m_nAmountofAmmunition = ammoAmount; - ms_apWeaponInfos[weaponType].m_nDamage = damage; - ms_apWeaponInfos[weaponType].m_fSpeed = speed; - ms_apWeaponInfos[weaponType].m_fRadius = radius; - ms_apWeaponInfos[weaponType].m_fLifespan = lifeSpan; - ms_apWeaponInfos[weaponType].m_fSpread = spread; - ms_apWeaponInfos[weaponType].m_vecFireOffset = vecFireOffset; - ms_apWeaponInfos[weaponType].m_AnimToPlay = animId; - ms_apWeaponInfos[weaponType].m_fAnimLoopStart = animLoopStart / 30.0f; - ms_apWeaponInfos[weaponType].m_fAnimLoopEnd = animLoopEnd / 30.0f; - ms_apWeaponInfos[weaponType].m_fAnimFrameFire = delayBetweenAnimAndFire / 30.0f; - ms_apWeaponInfos[weaponType].m_fAnim2FrameFire = delayBetweenAnim2AndFire / 30.0f; - ms_apWeaponInfos[weaponType].m_nModelId = modelId; - ms_apWeaponInfos[weaponType].m_Flags = flags; + aWeaponInfo[weaponType].m_eWeaponFire = FindWeaponFireType(fireType); + aWeaponInfo[weaponType].m_fRange = range; + aWeaponInfo[weaponType].m_nFiringRate = firingRate; + aWeaponInfo[weaponType].m_nReload = reload; + aWeaponInfo[weaponType].m_nAmountofAmmunition = ammoAmount; + aWeaponInfo[weaponType].m_nDamage = damage; + aWeaponInfo[weaponType].m_fSpeed = speed; + aWeaponInfo[weaponType].m_fRadius = radius; + aWeaponInfo[weaponType].m_fLifespan = lifeSpan; + aWeaponInfo[weaponType].m_fSpread = spread; + aWeaponInfo[weaponType].m_vecFireOffset = vecFireOffset; + aWeaponInfo[weaponType].m_AnimToPlay = animId; + aWeaponInfo[weaponType].m_fAnimLoopStart = animLoopStart / 30.0f; + aWeaponInfo[weaponType].m_fAnimLoopEnd = animLoopEnd / 30.0f; + aWeaponInfo[weaponType].m_fAnimFrameFire = delayBetweenAnimAndFire / 30.0f; + aWeaponInfo[weaponType].m_fAnim2FrameFire = delayBetweenAnim2AndFire / 30.0f; + aWeaponInfo[weaponType].m_nModelId = modelId; + aWeaponInfo[weaponType].m_Flags = flags; } } diff --git a/src/weapons/WeaponInfo.h b/src/weapons/WeaponInfo.h index 69ad1f39..96e2ecf4 100644 --- a/src/weapons/WeaponInfo.h +++ b/src/weapons/WeaponInfo.h @@ -19,7 +19,6 @@ enum }; class CWeaponInfo { - static CWeaponInfo ms_apWeaponInfos[WEAPONTYPE_LAST_WEAPONTYPE]; public: eWeaponFire m_eWeaponFire; float m_fRange; From 6df52f06b658ebe0267fe5de9cd414d9e46aefb4 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 21 Jan 2021 10:19:01 +0100 Subject: [PATCH 124/152] enable screenshots for librw --- src/skel/glfw/glfw.cpp | 4 ++++ src/skel/win/win.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 5f87d600..786ada5e 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -202,6 +202,10 @@ psGrabScreen(RwCamera *pCamera) RwImageSetFromRaster(pImage, pRaster); return pImage; } +#else + rw::Image *image = RwCameraGetRaster(pCamera)->toImage(); + if(image) + return image; #endif return nil; } diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index 5a0c7db2..cea6c3c0 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -249,6 +249,10 @@ psGrabScreen(RwCamera *pCamera) RwImageSetFromRaster(pImage, pRaster); return pImage; } +#else + rw::Image *image = RwCameraGetRaster(pCamera)->toImage(); + if(image) + return image; #endif return nil; } From 3c221d94664f2526645aba1773f1931e0024f833 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 21 Jan 2021 10:19:43 +0100 Subject: [PATCH 125/152] update librw --- vendor/librw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/librw b/vendor/librw index 61b288a9..9260bddc 160000 --- a/vendor/librw +++ b/vendor/librw @@ -1 +1 @@ -Subproject commit 61b288a9fe72ae4073c0ac5fd2a5815ed510c8c8 +Subproject commit 9260bddc66f70eb51adf0749fa835fed1562c178 From 034df61f3c2757b28c082101fd0f38054263c0ed Mon Sep 17 00:00:00 2001 From: withmorten Date: Thu, 21 Jan 2021 03:40:56 +0100 Subject: [PATCH 126/152] codewarrior: finishing touches --- codewarrior/Debug/gta3.txt | 0 codewarrior/Release/gta3.txt | 0 codewarrior/re3.mcp | Bin 228825 -> 228825 bytes src/audio/AudioManager.h | 2 +- src/control/SceneEdit.cpp | 2 +- src/control/Script.cpp | 2 +- src/control/Script5.cpp | 10 +++++----- src/core/Radar.cpp | 2 +- src/core/common.h | 10 ++++------ src/core/config.h | 9 ++++----- src/rw/MemoryHeap.h | 2 +- src/skel/crossplatform.h | 1 - 12 files changed, 18 insertions(+), 22 deletions(-) create mode 100644 codewarrior/Debug/gta3.txt create mode 100644 codewarrior/Release/gta3.txt diff --git a/codewarrior/Debug/gta3.txt b/codewarrior/Debug/gta3.txt new file mode 100644 index 00000000..e69de29b diff --git a/codewarrior/Release/gta3.txt b/codewarrior/Release/gta3.txt new file mode 100644 index 00000000..e69de29b diff --git a/codewarrior/re3.mcp b/codewarrior/re3.mcp index 93c280f1f999c176522e8bb56d480403cc46b5dd..9b9cee791327a00ac6ef7ecfac956f45099e107a 100644 GIT binary patch delta 64 zcmccloA>5#-VM{(SreD)-8nP;U<|YH<|qLk#>oPTKc?FYF>-9)#o5O-IYUHavWJL5 U^8}Ih2_lR@%(Q)i2(xD<09CUWb^rhX delta 64 zcmccloA>5#-VM{(Srr%Q-FYoPTKc?FYF>-9)#o5O-xj;l=vWJL9 U^8}Ih2_lR@%(Q)i2(xD<08D@vQ2+n{ diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h index 57ed0fb7..2f86ee98 100644 --- a/src/audio/AudioManager.h +++ b/src/audio/AudioManager.h @@ -499,7 +499,7 @@ public: }; #ifdef AUDIO_MSS -re3_static_assert(sizeof(cAudioManager) == 19220, "cAudioManager: error"); +static_assert(sizeof(cAudioManager) == 19220, "cAudioManager: error"); #endif extern cAudioManager AudioManager; diff --git a/src/control/SceneEdit.cpp b/src/control/SceneEdit.cpp index 0a679ab5..42dadee0 100644 --- a/src/control/SceneEdit.cpp +++ b/src/control/SceneEdit.cpp @@ -69,7 +69,7 @@ static const char* pCommandStrings[] = { }; #ifdef CHECK_STRUCT_SIZES -re3_static_assert(ARRAY_SIZE(pCommandStrings) == CSceneEdit::MOVIE_TOTAL_COMMANDS, "Scene edit: not all commands have names"); +static_assert(ARRAY_SIZE(pCommandStrings) == CSceneEdit::MOVIE_TOTAL_COMMANDS, "Scene edit: not all commands have names"); #endif static int32 NextValidModelId(int32 mi, int32 step) diff --git a/src/control/Script.cpp b/src/control/Script.cpp index fe8bbdfe..09a696cf 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -1282,7 +1282,7 @@ const tScriptCommandData commands[] = { #undef INPUT_ARGUMENTS #undef OUTPUT_ARGUMENTS -re3_static_assert(ARRAY_SIZE(commands) == LAST_SCRIPT_COMMAND, "commands array not filled"); +static_assert(ARRAY_SIZE(commands) == LAST_SCRIPT_COMMAND, "commands array not filled"); #if SCRIPT_LOG_FILE_LEVEL == 1 || SCRIPT_LOG_FILE_LEVEL == 2 static FILE* dbg_log; diff --git a/src/control/Script5.cpp b/src/control/Script5.cpp index 56164075..b54d425c 100644 --- a/src/control/Script5.cpp +++ b/src/control/Script5.cpp @@ -1924,7 +1924,7 @@ INITSAVEBUF for (uint32 i = 0; i < varSpace; i++) WriteSaveBuf(buf, ScriptSpace[i]); #ifdef CHECK_STRUCT_SIZES - re3_static_assert(SCRIPT_DATA_SIZE == 968, "CTheScripts::SaveAllScripts"); + static_assert(SCRIPT_DATA_SIZE == 968, "CTheScripts::SaveAllScripts"); #endif uint32 script_data_size = SCRIPT_DATA_SIZE; WriteSaveBuf(buf, script_data_size); @@ -2083,14 +2083,14 @@ void CRunningScript::Save(uint8*& buf) WriteSaveBuf(buf, m_abScriptName[i]); WriteSaveBuf(buf, m_nIp); #ifdef CHECK_STRUCT_SIZES - re3_static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6"); + static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6"); #endif for (int i = 0; i < MAX_STACK_DEPTH; i++) WriteSaveBuf(buf, m_anStack[i]); WriteSaveBuf(buf, m_nStackPointer); SkipSaveBuf(buf, 2); #ifdef CHECK_STRUCT_SIZES - re3_static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18"); + static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18"); #endif for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++) WriteSaveBuf(buf, m_anLocalVariables[i]); @@ -2118,14 +2118,14 @@ void CRunningScript::Load(uint8*& buf) m_abScriptName[i] = ReadSaveBuf(buf); m_nIp = ReadSaveBuf(buf); #ifdef CHECK_STRUCT_SIZES - re3_static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6"); + static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6"); #endif for (int i = 0; i < MAX_STACK_DEPTH; i++) m_anStack[i] = ReadSaveBuf(buf); m_nStackPointer = ReadSaveBuf(buf); SkipSaveBuf(buf, 2); #ifdef CHECK_STRUCT_SIZES - re3_static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18"); + static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18"); #endif for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++) m_anLocalVariables[i] = ReadSaveBuf(buf); diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp index 99ad7d0b..116e9e94 100644 --- a/src/core/Radar.cpp +++ b/src/core/Radar.cpp @@ -79,7 +79,7 @@ CSprite2d *CRadar::RadarSprites[RADAR_SPRITE_COUNT] = { #define RADAR_NUM_TILES (8) #define RADAR_TILE_SIZE (RADAR_SIZE_X / RADAR_NUM_TILES) -re3_static_assert(RADAR_TILE_SIZE == (RADAR_SIZE_Y / RADAR_NUM_TILES), "CRadar: not a square"); +static_assert(RADAR_TILE_SIZE == (RADAR_SIZE_Y / RADAR_NUM_TILES), "CRadar: not a square"); #define RADAR_MIN_RANGE (120.0f) #define RADAR_MAX_RANGE (350.0f) diff --git a/src/core/common.h b/src/core/common.h index d3b0daa9..84440968 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -357,21 +357,19 @@ __inline__ void TRACE(char *f, ...) { } // this is re3 only, and so the function #endif #define ASSERT assert -#if defined DEBUG && !defined __MWERKS__ -#define re3_static_assert(bool_constexpr, message) static_assert(bool_constexpr, message) -#else -#define re3_static_assert(bool_constexpr, message) +#ifdef __MWERKS__ +#define static_assert(bool_constexpr, message) #endif #define _TODO(x) #define _TODOCONST(x) (x) #ifdef CHECK_STRUCT_SIZES -#define VALIDATE_SIZE(struc, size) re3_static_assert(sizeof(struc) == size, "Invalid structure size of " #struc) +#define VALIDATE_SIZE(struc, size) static_assert(sizeof(struc) == size, "Invalid structure size of " #struc) #else #define VALIDATE_SIZE(struc, size) #endif -#define VALIDATE_OFFSET(struc, member, offset) re3_static_assert(offsetof(struc, member) == offset, "The offset of " #member " in " #struc " is not " #offset "...") +#define VALIDATE_OFFSET(struc, member, offset) static_assert(offsetof(struc, member) == offset, "The offset of " #member " in " #struc " is not " #offset "...") #define PERCENT(x, p) ((float(x) * (float(p) / 100.0f))) #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) diff --git a/src/core/config.h b/src/core/config.h index e71c34a8..35130024 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -1,7 +1,7 @@ #pragma once -// disable (most) stuff that wasn't in original gta3.exe - check section at the bottom of this file -#define VANILLA_DEFINES +// disables (most) stuff that wasn't in original gta3.exe - check section at the bottom of this file +//#define VANILLA_DEFINES enum Config { NUMPLAYERS = 1, // 4 on PS2 @@ -243,7 +243,7 @@ enum Config { #define ASCII_STRCMP // use faster ascii str comparisons -#if !defined _WIN32 || defined __MWERKS__ || defined __MINGW32__ +#if !defined _WIN32 || defined __MWERKS__ || defined __MINGW32__ || defined VANILLA_DEFINES #undef ASCII_STRCMP #endif @@ -429,7 +429,6 @@ enum Config { #undef FIX_BUGS #undef THIS_IS_STUPID #undef MORE_LANGUAGES -#undef MORE_LANGUAGES #undef COMPATIBLE_SAVES #undef LOAD_INI_SETTINGS @@ -471,7 +470,7 @@ enum Config { #undef INVERT_LOOK_FOR_PAD #undef USE_DEBUG_SCRIPT_LOADER -#undef USE_MEASUREMENTS_IN_METERS // TODO +#undef USE_MEASUREMENTS_IN_METERS #undef USE_PRECISE_MEASUREMENT_CONVERTION #undef MISSION_REPLAY #undef USE_ADVANCED_SCRIPT_DEBUG_OUTPUT diff --git a/src/rw/MemoryHeap.h b/src/rw/MemoryHeap.h index ed2e83b6..cd8cf22c 100644 --- a/src/rw/MemoryHeap.h +++ b/src/rw/MemoryHeap.h @@ -95,7 +95,7 @@ struct HeapBlockDesc #ifdef USE_CUSTOM_ALLOCATOR // TODO: figure something out for 64 bit pointers -re3_static_assert(sizeof(HeapBlockDesc) == 0x10, "HeapBlockDesc must have 0x10 size otherwise most of assumptions don't make sense"); +static_assert(sizeof(HeapBlockDesc) == 0x10, "HeapBlockDesc must have 0x10 size otherwise most of assumptions don't make sense"); #endif struct HeapBlockList diff --git a/src/skel/crossplatform.h b/src/skel/crossplatform.h index b4e6a751..e9a94cf4 100644 --- a/src/skel/crossplatform.h +++ b/src/skel/crossplatform.h @@ -118,7 +118,6 @@ struct SYSTEMTIME { void GetLocalTime_CP(SYSTEMTIME* out); #define GetLocalTime GetLocalTime_CP - #define OutputDebugString(s) re3_debug("[DBG-2]: %s\n",s) #endif From c67273e92a60e50d67d8146f6a150a5b39a2a641 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 21 Jan 2021 22:30:20 +0100 Subject: [PATCH 127/152] fixed anisotropic filtering; updated librw --- src/core/config.h | 1 + src/core/main.cpp | 8 +++++++- src/fakerw/fake.cpp | 9 +++++++++ src/fakerw/rpanisot.h | 6 ++++++ src/rw/TexRead.cpp | 9 +++++++++ vendor/librw | 2 +- 6 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 src/fakerw/rpanisot.h diff --git a/src/core/config.h b/src/core/config.h index 35130024..e4568306 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -264,6 +264,7 @@ enum Config { #define IMPROVED_VIDEOMODE // save and load videomode parameters instead of a magic number #define DISABLE_LOADING_SCREEN // disable the loading screen which vastly improves the loading time #define DISABLE_VSYNC_ON_TEXTURE_CONVERSION // make texture conversion work faster by disabling vsync +#define ANISOTROPIC_FILTERING // set all textures to max anisotropic filtering //#define USE_TEXTURE_POOL #ifdef LIBRW #define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur) diff --git a/src/core/main.cpp b/src/core/main.cpp index 9d8a8e52..239fae7b 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -3,6 +3,9 @@ #include "rphanim.h" #include "rpskin.h" #include "rtbmp.h" +#ifdef ANISOTROPIC_FILTERING +#include "rpanisot.h" +#endif #include "main.h" #include "CdStream.h" @@ -432,6 +435,9 @@ PluginAttach(void) return FALSE; } +#ifdef ANISOTROPIC_FILTERING + RpAnisotPluginAttach(); +#endif #ifdef EXTENDED_PIPELINES CustomPipes::CustomPipeRegister(); #endif @@ -440,7 +446,7 @@ PluginAttach(void) } #ifdef GTA_PS2 -#define NUM_PREALLOC_ATOMICS 3245 +#define NUM_PREALLOC_ATOMICS 32455 #define NUM_PREALLOC_CLUMPS 101 #define NUM_PREALLOC_FRAMES 2821 #define NUM_PREALLOC_GEOMETRIES 1404 diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp index c1150931..366dcf3e 100644 --- a/src/fakerw/fake.cpp +++ b/src/fakerw/fake.cpp @@ -962,3 +962,12 @@ RtCharset *RtCharsetSetColors(RtCharset * charSet, const RwRGBA * foreGround, RtCharset *RtCharsetGetDesc(RtCharset * charset, RtCharsetDesc * desc) { *desc = charset->desc; return charset; } RtCharset *RtCharsetCreate(const RwRGBA * foreGround, const RwRGBA * backGround) { return Charset::create(foreGround, backGround); } RwBool RtCharsetDestroy(RtCharset * charSet) { charSet->destroy(); return true; } + + + +#include + +RwInt8 RpAnisotGetMaxSupportedMaxAnisotropy(void) { return rw::getMaxSupportedMaxAnisotropy(); } +RwTexture *RpAnisotTextureSetMaxAnisotropy(RwTexture *tex, RwInt8 val) { tex->setMaxAnisotropy(val); return tex; } +RwInt8 RpAnisotTextureGetMaxAnisotropy(RwTexture *tex) { return tex->getMaxAnisotropy(); } +RwBool RpAnisotPluginAttach(void) { rw::registerAnisotropyPlugin(); return true; } diff --git a/src/fakerw/rpanisot.h b/src/fakerw/rpanisot.h new file mode 100644 index 00000000..a886512f --- /dev/null +++ b/src/fakerw/rpanisot.h @@ -0,0 +1,6 @@ +#pragma once + +RwInt8 RpAnisotGetMaxSupportedMaxAnisotropy(void); +RwTexture *RpAnisotTextureSetMaxAnisotropy(RwTexture *tex, RwInt8 val); +RwInt8 RpAnisotTextureGetMaxAnisotropy(RwTexture *tex); +RwBool RpAnisotPluginAttach(void); diff --git a/src/rw/TexRead.cpp b/src/rw/TexRead.cpp index d0addcca..c009af96 100644 --- a/src/rw/TexRead.cpp +++ b/src/rw/TexRead.cpp @@ -2,6 +2,9 @@ #pragma warning( disable : 4005) #pragma warning( pop ) #include "common.h" +#ifdef ANISOTROPIC_FILTERING +#include "rpanisot.h" +#endif #include "crossplatform.h" #include "platform.h" @@ -48,6 +51,12 @@ RwTextureGtaStreamRead(RwStream *stream) texLoadTime = (texNumLoaded * texLoadTime + (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond() - preloadTime) / (float)(texNumLoaded+1); texNumLoaded++; } + +#ifdef ANISOTROPIC_FILTERING + if(tex && RpAnisotGetMaxSupportedMaxAnisotropy() > 1) // BUG? this was RpAnisotTextureGetMaxAnisotropy, but that doesn't make much sense + RpAnisotTextureSetMaxAnisotropy(tex, RpAnisotGetMaxSupportedMaxAnisotropy()); +#endif + return tex; } diff --git a/vendor/librw b/vendor/librw index 9260bddc..60a5ace1 160000 --- a/vendor/librw +++ b/vendor/librw @@ -1 +1 @@ -Subproject commit 9260bddc66f70eb51adf0749fa835fed1562c178 +Subproject commit 60a5ace16309ccd3d174a3ec14a1062540934066 From 69500eed5672a0b7abb2ddbf5133fbc61b9794a0 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 21 Jan 2021 22:35:11 +0100 Subject: [PATCH 128/152] how the hell did that happen? --- src/core/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/main.cpp b/src/core/main.cpp index 239fae7b..f1346fc0 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -446,7 +446,7 @@ PluginAttach(void) } #ifdef GTA_PS2 -#define NUM_PREALLOC_ATOMICS 32455 +#define NUM_PREALLOC_ATOMICS 3245 #define NUM_PREALLOC_CLUMPS 101 #define NUM_PREALLOC_FRAMES 2821 #define NUM_PREALLOC_GEOMETRIES 1404 From a511d79bf056a8ff65d4687822dcba6185d9c7ef Mon Sep 17 00:00:00 2001 From: withmorten Date: Thu, 21 Jan 2021 23:21:03 +0100 Subject: [PATCH 129/152] free cam fixes --- src/core/Cam.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp index 74de0ab7..f43ff57a 100644 --- a/src/core/Cam.cpp +++ b/src/core/Cam.cpp @@ -193,7 +193,7 @@ CCam::Process(void) break; case MODE_CAM_ON_A_STRING: #ifdef FREE_CAM - if(CCamera::bFreeCam) + if(CCamera::bFreeCam && !CVehicle::bCheat5) Process_FollowCar_SA(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); else #endif @@ -5039,11 +5039,15 @@ CCam::Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation, // Using GetCarGun(LR/UD) will give us same unprocessed RightStick value as SA float stickX = -(pad->GetCarGunLeftRight()); - float stickY = pad->GetCarGunUpDown(); + float stickY = -pad->GetCarGunUpDown(); // In SA this is for not let num2/num8 move camera when Keyboard & Mouse controls are used. // if (CCamera::m_bUseMouse3rdPerson) // stickY = 0.0f; +#ifdef INVERT_LOOK_FOR_PAD + if (CPad::bInvertLook4Pad) + stickY = -stickY; +#endif float xMovement = Abs(stickX) * (FOV / 80.0f * 5.f / 70.f) * stickX * 0.007f * 0.007f; float yMovement = Abs(stickY) * (FOV / 80.0f * 3.f / 70.f) * stickY * 0.007f * 0.007f; From 497e0b801ff30cf836887b625752c1643b533a7e Mon Sep 17 00:00:00 2001 From: withmorten Date: Fri, 22 Jan 2021 00:19:44 +0100 Subject: [PATCH 130/152] m_nWantedLevel -> GetWantedLevel() --- src/audio/PoliceRadio.cpp | 4 ++-- src/control/CarAI.cpp | 28 ++++++++++++++-------------- src/control/CarCtrl.cpp | 18 +++++++++--------- src/control/GameLogic.cpp | 2 +- src/control/Garages.cpp | 2 +- src/control/Pickups.cpp | 4 ++-- src/control/Script.cpp | 2 +- src/control/Script2.cpp | 2 +- src/core/Camera.cpp | 4 ++-- src/core/Pad.cpp | 2 +- src/core/Wanted.h | 1 + src/peds/CopPed.cpp | 6 +++--- src/peds/PedAI.cpp | 2 +- src/peds/Population.cpp | 2 +- src/render/Hud.cpp | 2 +- src/vehicles/Automobile.cpp | 2 +- src/vehicles/Heli.cpp | 2 +- 17 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/audio/PoliceRadio.cpp b/src/audio/PoliceRadio.cpp index 7021b5be..785dbf8f 100644 --- a/src/audio/PoliceRadio.cpp +++ b/src/audio/PoliceRadio.cpp @@ -161,7 +161,7 @@ cAudioManager::ServicePoliceRadio() if(CReplay::IsPlayingBack() || !FindPlayerPed() || !FindPlayerPed()->m_pWanted) return; #endif - wantedLevel = FindPlayerPed()->m_pWanted->m_nWantedLevel; + wantedLevel = FindPlayerPed()->m_pWanted->GetWantedLevel(); if(!crimeReport) { if(wantedLevel != 0) { if(nLastSeen != 0) { @@ -679,7 +679,7 @@ void cAudioManager::ReportCrime(eCrimeType type, const CVector &pos) { int32 lastCrime = ARRAY_SIZE(m_sPoliceRadioQueue.crimes); - if (m_bIsInitialised && MusicManager.m_nMusicMode != MUSICMODE_CUTSCENE && FindPlayerPed()->m_pWanted->m_nWantedLevel > 0 && + if (m_bIsInitialised && MusicManager.m_nMusicMode != MUSICMODE_CUTSCENE && FindPlayerPed()->m_pWanted->GetWantedLevel() > 0 && (type > CRIME_NONE || type < NUM_CRIME_TYPES) && m_FrameCounter >= gMinTimeToNextReport[type]) { for (int32 i = 0; i < ARRAY_SIZE(m_sPoliceRadioQueue.crimes); i++) { if (m_sPoliceRadioQueue.crimes[i].type) { diff --git a/src/control/CarAI.cpp b/src/control/CarAI.cpp index 8c0c5966..d2a82121 100644 --- a/src/control/CarAI.cpp +++ b/src/control/CarAI.cpp @@ -68,7 +68,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) pVehicle->m_bSirenOrAlarm = true; } if (FindPlayerPed()->m_pWanted->m_bIgnoredByEveryone || pVehicle->bIsLawEnforcer && - (FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) { + (FindPlayerPed()->m_pWanted->GetWantedLevel() == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) { CCarCtrl::JoinCarWithRoadSystem(pVehicle); pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; @@ -110,7 +110,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) TellOccupantsToLeaveCar(pVehicle); pVehicle->AutoPilot.m_nCruiseSpeed = 0; pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; - if (FindPlayerPed()->m_pWanted->m_nWantedLevel <= 1) + if (FindPlayerPed()->m_pWanted->GetWantedLevel() <= 1) pVehicle->m_bSirenOrAlarm = false; } } @@ -121,7 +121,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) pVehicle->m_nCarHornTimer = 0; } if (FindPlayerPed()->m_pWanted->m_bIgnoredByEveryone || pVehicle->bIsLawEnforcer && - (FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())){ + (FindPlayerPed()->m_pWanted->GetWantedLevel() == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())){ CCarCtrl::JoinCarWithRoadSystem(pVehicle); pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; @@ -141,7 +141,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) pVehicle->m_bSirenOrAlarm = true; } if (FindPlayerPed()->m_pWanted->m_bIgnoredByEveryone || pVehicle->bIsLawEnforcer && - (FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) { + (FindPlayerPed()->m_pWanted->GetWantedLevel() == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) { CCarCtrl::JoinCarWithRoadSystem(pVehicle); pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; @@ -169,7 +169,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) TellOccupantsToLeaveCar(pVehicle); pVehicle->AutoPilot.m_nCruiseSpeed = 0; pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; - if (FindPlayerPed()->m_pWanted->m_nWantedLevel <= 1) + if (FindPlayerPed()->m_pWanted->GetWantedLevel() <= 1) pVehicle->m_bSirenOrAlarm = false; } } @@ -179,7 +179,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) pVehicle->m_nCarHornTimer = 0; } if (FindPlayerPed()->m_pWanted->m_bIgnoredByEveryone || pVehicle->bIsLawEnforcer && - (FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) { + (FindPlayerPed()->m_pWanted->GetWantedLevel() == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) { CCarCtrl::JoinCarWithRoadSystem(pVehicle); pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; @@ -283,7 +283,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) (FindPlayerVehicle() == pVehicle->AutoPilot.m_pTargetCar && #endif (FindPlayerPed()->m_pWanted->m_bIgnoredByEveryone || pVehicle->bIsLawEnforcer && - (FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) + (FindPlayerPed()->m_pWanted->GetWantedLevel() == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) #ifdef FIX_BUGS ) #endif @@ -337,7 +337,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) } break; default: - if (pVehicle->bIsLawEnforcer && FindPlayerPed()->m_pWanted->m_nWantedLevel > 0 && !CCullZones::NoPolice()){ + if (pVehicle->bIsLawEnforcer && FindPlayerPed()->m_pWanted->GetWantedLevel() > 0 && !CCullZones::NoPolice()){ if (ABS(FindPlayerCoors().x - pVehicle->GetPosition().x) > 10.0f || ABS(FindPlayerCoors().y - pVehicle->GetPosition().y) > 10.0f){ pVehicle->AutoPilot.m_nCruiseSpeed = FindPoliceCarSpeedForWantedLevel(pVehicle); @@ -351,7 +351,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) TellOccupantsToLeaveCar(pVehicle); pVehicle->AutoPilot.m_nCruiseSpeed = 0; pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; - if (FindPlayerPed()->m_pWanted->m_nWantedLevel <= 1) + if (FindPlayerPed()->m_pWanted->GetWantedLevel() <= 1) pVehicle->m_bSirenOrAlarm = false; } } @@ -486,7 +486,7 @@ void CCarAI::AddPoliceCarOccupants(CVehicle* pVehicle) case MI_RHINO: case MI_BARRACKS: pVehicle->SetUpDriver(); - if (FindPlayerPed()->m_pWanted->m_nWantedLevel > 1) + if (FindPlayerPed()->m_pWanted->GetWantedLevel() > 1) pVehicle->SetupPassenger(0); return; default: @@ -541,7 +541,7 @@ void CCarAI::TellCarToBlockOtherCar(CVehicle* pVehicle, CVehicle* pTarget) uint8 CCarAI::FindPoliceCarMissionForWantedLevel() { - switch (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel){ + switch (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->GetWantedLevel()){ case 0: case 1: return MISSION_BLOCKPLAYER_FARAWAY; case 2: return (CGeneral::GetRandomNumber() & 3) >= 3 ? MISSION_RAMPLAYER_FARAWAY : MISSION_BLOCKPLAYER_FARAWAY; @@ -555,7 +555,7 @@ uint8 CCarAI::FindPoliceCarMissionForWantedLevel() int32 CCarAI::FindPoliceCarSpeedForWantedLevel(CVehicle* pVehicle) { - switch (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel) { + switch (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->GetWantedLevel()) { case 0: return CGeneral::GetRandomNumberInRange(12, 16); case 1: return 25; case 2: return 34; @@ -569,7 +569,7 @@ int32 CCarAI::FindPoliceCarSpeedForWantedLevel(CVehicle* pVehicle) void CCarAI::MellowOutChaseSpeed(CVehicle* pVehicle) { - if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel == 1){ + if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->GetWantedLevel() == 1){ float distanceToPlayer = (pVehicle->GetPosition() - FindPlayerCoors()).Magnitude(); if (FindPlayerVehicle()){ if (distanceToPlayer < 10.0f) @@ -586,7 +586,7 @@ void CCarAI::MellowOutChaseSpeed(CVehicle* pVehicle) else pVehicle->AutoPilot.m_nCruiseSpeed = 25; } - }else if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel == 2){ + }else if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->GetWantedLevel() == 2){ float distanceToPlayer = (pVehicle->GetPosition() - FindPlayerCoors()).Magnitude(); if (FindPlayerVehicle()) { if (distanceToPlayer < 10.0f) diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp index edf367b8..25ced498 100644 --- a/src/control/CarCtrl.cpp +++ b/src/control/CarCtrl.cpp @@ -124,18 +124,18 @@ CCarCtrl::GenerateOneRandomCar() CWanted* pWanted = pPlayer->m_pPed->m_pWanted; int carClass; int carModel; - if (pWanted->m_nWantedLevel > 1 && NumLawEnforcerCars < pWanted->m_MaximumLawEnforcerVehicles && + if (pWanted->GetWantedLevel() > 1 && NumLawEnforcerCars < pWanted->m_MaximumLawEnforcerVehicles && pWanted->m_CurrentCops < pWanted->m_MaxCops && ( - pWanted->m_nWantedLevel > 3 || - pWanted->m_nWantedLevel > 2 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 5000 || - pWanted->m_nWantedLevel > 1 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 8000)) { - /* Last pWanted->m_nWantedLevel > 1 is unnecessary but I added it for better readability. */ + pWanted->GetWantedLevel() > 3 || + pWanted->GetWantedLevel() > 2 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 5000 || + pWanted->GetWantedLevel() > 1 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 8000)) { + /* Last pWanted->GetWantedLevel() > 1 is unnecessary but I added it for better readability. */ /* Wouldn't be surprised it was there originally but was optimized out. */ carClass = COPS; carModel = ChoosePoliceCarModel(); }else{ carModel = ChooseModel(&zone, &vecTargetPos, &carClass); - if (carClass == COPS && pWanted->m_nWantedLevel >= 1) + if (carClass == COPS && pWanted->GetWantedLevel() >= 1) /* All cop spawns with wanted level are handled by condition above. */ /* In particular it means that cop cars never spawn if player has wanted level of 1. */ return; @@ -267,7 +267,7 @@ CCarCtrl::GenerateOneRandomCar() } if (!ThePaths.NewGenerateCarCreationCoors(vecTargetPos.x, vecTargetPos.y, frontX, frontY, preferredDistance, angleLimit, invertAngleLimitTest, &spawnPosition, &curNodeId, &nextNodeId, - &positionBetweenNodes, carClass == COPS && pWanted->m_nWantedLevel >= 1)) + &positionBetweenNodes, carClass == COPS && pWanted->GetWantedLevel() >= 1)) return; int16 colliding; CWorld::FindObjectsKindaColliding(spawnPosition, 10.0f, true, &colliding, 2, nil, false, true, true, false, false); @@ -331,7 +331,7 @@ CCarCtrl::GenerateOneRandomCar() } case COPS: pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; - if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel != 0){ + if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->GetWantedLevel() != 0){ pVehicle->AutoPilot.m_nCruiseSpeed = CCarAI::FindPoliceCarSpeedForWantedLevel(pVehicle); pVehicle->AutoPilot.m_fMaxTrafficSpeed = pVehicle->AutoPilot.m_nCruiseSpeed / 2; pVehicle->AutoPilot.m_nCarMission = CCarAI::FindPoliceCarMissionForWantedLevel(); @@ -2654,7 +2654,7 @@ void CCarCtrl::FindLinksToGoWithTheseNodes(CVehicle* pVehicle) void CCarCtrl::GenerateEmergencyServicesCar(void) { - if (FindPlayerPed()->m_pWanted->m_nWantedLevel > 3) + if (FindPlayerPed()->m_pWanted->GetWantedLevel() > 3) return; if (NumFiretrucksOnDuty + NumAmbulancesOnDuty + NumParkedCars + NumMissionCars + NumLawEnforcerCars + NumRandomCars > MaxNumberOfCarsInUse) diff --git a/src/control/GameLogic.cpp b/src/control/GameLogic.cpp index 59c75dd4..19e0f83d 100644 --- a/src/control/GameLogic.cpp +++ b/src/control/GameLogic.cpp @@ -159,7 +159,7 @@ CGameLogic::Update() pPlayerInfo.m_WBState = WBSTATE_PLAYING; int takeMoney; - switch (pPlayerInfo.m_pPed->m_pWanted->m_nWantedLevel) { + switch (pPlayerInfo.m_pPed->m_pWanted->GetWantedLevel()) { case 0: case 1: takeMoney = 100; diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index 79c44dfd..a8e1f1cb 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -387,7 +387,7 @@ void CGarage::Update() m_eGarageState = GS_OPENING; DMAudio.PlayFrontEndSound(SOUND_GARAGE_OPENING, 1); bool bTakeMoney = false; - if (FindPlayerPed()->m_pWanted->m_nWantedLevel != 0) + if (FindPlayerPed()->m_pWanted->GetWantedLevel() != 0) bTakeMoney = true; FindPlayerPed()->m_pWanted->Reset(); CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_GARAGE); diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp index 857f74ec..96a8a670 100644 --- a/src/control/Pickups.cpp +++ b/src/control/Pickups.cpp @@ -129,7 +129,7 @@ CPickup::CanBePickedUp(CPlayerPed *player) bool cannotBePickedUp = (m_pObject->GetModelIndex() == MI_PICKUP_BODYARMOUR && player->m_fArmour > 99.5f) || (m_pObject->GetModelIndex() == MI_PICKUP_HEALTH && player->m_fHealth > 99.5f) - || (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE && player->m_pWanted->m_nWantedLevel == 0) + || (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE && player->m_pWanted->GetWantedLevel() == 0) || (m_pObject->GetModelIndex() == MI_PICKUP_KILLFRENZY && (CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame)); return !cannotBePickedUp; } @@ -456,7 +456,7 @@ CPickups::GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex) DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0); return true; } else if (modelIndex == MI_PICKUP_BRIBE) { - int32 level = FindPlayerPed()->m_pWanted->m_nWantedLevel - 1; + int32 level = FindPlayerPed()->m_pWanted->GetWantedLevel() - 1; if (level < 0) level = 0; player->SetWantedLevel(level); DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0); diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 09a696cf..e435f615 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -4083,7 +4083,7 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) return 0; case COMMAND_IS_WANTED_LEVEL_GREATER: CollectParameters(&m_nIp, 2); - UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_pPed->m_pWanted->m_nWantedLevel > ScriptParams[1]); + UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_pPed->m_pWanted->GetWantedLevel() > ScriptParams[1]); return 0; case COMMAND_CLEAR_WANTED_LEVEL: CollectParameters(&m_nIp, 1); diff --git a/src/control/Script2.cpp b/src/control/Script2.cpp index 6cb078bb..9329b3bc 100644 --- a/src/control/Script2.cpp +++ b/src/control/Script2.cpp @@ -1033,7 +1033,7 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) CollectParameters(&m_nIp, 1); CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; script_assert(pPed); - ScriptParams[0] = pPed->m_pWanted->m_nWantedLevel; + ScriptParams[0] = pPed->m_pWanted->GetWantedLevel(); StoreParameters(&m_nIp, 1); return 0; } diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 9d169716..2ce4e754 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -2783,7 +2783,7 @@ CCamera::TryToStartNewCamMode(int obbeMode) if (CReplay::IsPlayingBack()) return false; #endif - if(FindPlayerPed()->m_pWanted->m_nWantedLevel < 1) + if(FindPlayerPed()->m_pWanted->GetWantedLevel() < 1) return false; if(FindPlayerVehicle() == nil) return false; @@ -2811,7 +2811,7 @@ CCamera::TryToStartNewCamMode(int obbeMode) if (CReplay::IsPlayingBack()) return false; #endif - if(FindPlayerPed()->m_pWanted->m_nWantedLevel < 1) + if(FindPlayerPed()->m_pWanted->GetWantedLevel() < 1) return false; if(FindPlayerVehicle() == nil) return false; diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index 5e5f1326..95a107ee 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -226,7 +226,7 @@ void ArmourCheat() void WantedLevelUpCheat() { CHud::SetHelpMessage(TheText.Get("CHEAT5"), true); - FindPlayerPed()->SetWantedLevel(Min(FindPlayerPed()->m_pWanted->m_nWantedLevel + 2, 6)); + FindPlayerPed()->SetWantedLevel(Min(FindPlayerPed()->m_pWanted->GetWantedLevel() + 2, 6)); } void WantedLevelDownCheat() diff --git a/src/core/Wanted.h b/src/core/Wanted.h index de36c442..9f08e752 100644 --- a/src/core/Wanted.h +++ b/src/core/Wanted.h @@ -37,6 +37,7 @@ public: int32 NumOfHelisRequired(); void SetWantedLevel(int32); void SetWantedLevelNoDrop(int32 level); + int32 GetWantedLevel() { return m_nWantedLevel; } void RegisterCrime(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare); void RegisterCrime_Immediately(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare); void ClearQdCrimes(); diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp index e518fae4..29612ccf 100644 --- a/src/peds/CopPed.cpp +++ b/src/peds/CopPed.cpp @@ -179,7 +179,7 @@ CCopPed::ClearPursuit(void) m_bZoneDisabled = false; ClearObjective(); if (IsPedInControl()) { - if (!m_pMyVehicle || wanted->m_nWantedLevel != 0) { + if (!m_pMyVehicle || wanted->GetWantedLevel() != 0) { if (m_pMyVehicle && (m_pMyVehicle->GetPosition() - GetPosition()).MagnitudeSqr() < sq(5.0f)) { m_nLastPedState = PED_IDLE; SetSeek((CEntity*)m_pMyVehicle, 2.5f); @@ -275,7 +275,7 @@ CCopPed::ScanForCrimes(void) if (!m_bIsInPursuit) { CPlayerPed *player = FindPlayerPed(); if ((m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) - && player->m_pWanted->m_nWantedLevel == 0) { + && player->m_pWanted->GetWantedLevel() == 0) { if (player->m_pMyVehicle #ifdef FIX_BUGS @@ -291,7 +291,7 @@ void CCopPed::CopAI(void) { CWanted *wanted = FindPlayerPed()->m_pWanted; - int wantedLevel = wanted->m_nWantedLevel; + int wantedLevel = wanted->GetWantedLevel(); CPhysical *playerOrHisVeh = FindPlayerVehicle() ? (CPhysical*)FindPlayerVehicle() : (CPhysical*)FindPlayerPed(); if (wanted->m_bIgnoredByEveryone || wanted->m_bIgnoredByCops) { diff --git a/src/peds/PedAI.cpp b/src/peds/PedAI.cpp index 46476e55..f77a64b4 100644 --- a/src/peds/PedAI.cpp +++ b/src/peds/PedAI.cpp @@ -832,7 +832,7 @@ CPed::ProcessObjective(void) m_pMyVehicle->SetStatus(STATUS_PHYSICS); m_pMyVehicle->AutoPilot.m_nPrevRouteNode = 0; if (m_nPedType == PEDTYPE_COP) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = (FindPlayerPed()->m_pWanted->m_nWantedLevel * 0.1f + 0.6f) * (GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fMaxCruiseVelocity); + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = (FindPlayerPed()->m_pWanted->GetWantedLevel() * 0.1f + 0.6f) * (GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fMaxCruiseVelocity); m_pMyVehicle->AutoPilot.m_nCarMission = CCarAI::FindPoliceCarMissionForWantedLevel(); } else { m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fMaxCruiseVelocity * 0.8f; diff --git a/src/peds/Population.cpp b/src/peds/Population.cpp index 53db7263..053cf5e4 100644 --- a/src/peds/Population.cpp +++ b/src/peds/Population.cpp @@ -582,7 +582,7 @@ CPopulation::AddToPopulation(float minDist, float maxDist, float minDistOffScree CVector playerCentreOfWorld = FindPlayerCentreOfWorld(CWorld::PlayerInFocus); CTheZones::GetZoneInfoForTimeOfDay(&playerCentreOfWorld, &zoneInfo); CWanted *wantedInfo = playerInfo->m_pPed->m_pWanted; - if (wantedInfo->m_nWantedLevel > 2) { + if (wantedInfo->GetWantedLevel() > 2) { if (ms_nNumCop < wantedInfo->m_MaxCops && !playerInfo->m_pPed->bInVehicle && (CCarCtrl::NumLawEnforcerCars >= wantedInfo->m_MaximumLawEnforcerVehicles || CCarCtrl::NumRandomCars >= playerInfo->m_nTrafficMultiplier * CCarCtrl::CarDensityMultiplier diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index f20397a3..2f7b9001 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -655,7 +655,7 @@ void CHud::Draw() CFont::SetColor(CRGBA(0, 0, 0, 255)); CFont::PrintString(fStarsX + SCREEN_SCALE_X_FIX(2.0f), SCREEN_SCALE_Y(87.0f) + SCREEN_SCALE_Y_FIX(2.0f), sPrintIcon); - if (FindPlayerPed()->m_pWanted->m_nWantedLevel > i + if (FindPlayerPed()->m_pWanted->GetWantedLevel() > i && (CTimer::GetTimeInMilliseconds() > FindPlayerPed()->m_pWanted->m_nLastWantedLevelChange + 2000 || CTimer::GetFrameCounter() & 4)) { diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 77173538..7e8c4702 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -240,7 +240,7 @@ CAutomobile::ProcessControl(void) // Improve grip of vehicles in certain cases bool strongGrip1 = false; bool strongGrip2 = false; - if(FindPlayerVehicle() && this != FindPlayerVehicle() && FindPlayerPed()->m_pWanted->m_nWantedLevel > 3 && + if(FindPlayerVehicle() && this != FindPlayerVehicle() && FindPlayerPed()->m_pWanted->GetWantedLevel() > 3 && (AutoPilot.m_nCarMission == MISSION_RAMPLAYER_FARAWAY || AutoPilot.m_nCarMission == MISSION_RAMPLAYER_CLOSE || AutoPilot.m_nCarMission == MISSION_BLOCKPLAYER_FARAWAY || AutoPilot.m_nCarMission == MISSION_BLOCKPLAYER_CLOSE) && FindPlayerSpeed().Magnitude() > 0.3f){ diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp index 44e9a73f..98e1f5fa 100644 --- a/src/vehicles/Heli.cpp +++ b/src/vehicles/Heli.cpp @@ -474,7 +474,7 @@ CHeli::ProcessControl(void) // Shoot int shootTimeout; if (m_heliType == HELI_TYPE_RANDOM) { - switch (FindPlayerPed()->m_pWanted->m_nWantedLevel) { + switch (FindPlayerPed()->m_pWanted->GetWantedLevel()) { case 0: case 1: case 2: shootTimeout = 999999; break; From 950a3e82c1955745e3319efc824a272d8b296977 Mon Sep 17 00:00:00 2001 From: withmorten Date: Fri, 22 Jan 2021 19:35:24 +0100 Subject: [PATCH 131/152] cw: fix linking order --- codewarrior/re3.mcp | Bin 228825 -> 228825 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/codewarrior/re3.mcp b/codewarrior/re3.mcp index 9b9cee791327a00ac6ef7ecfac956f45099e107a..e86c37b9c021c2d1630f3182b7981ce15416529c 100644 GIT binary patch delta 4527 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 From 609cad506ff43f3333b61f5ff39d1ec494eba42e Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Fri, 22 Jan 2021 19:54:43 +0100 Subject: [PATCH 132/152] Better output for validating size assert --- src/core/common.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/core/common.h b/src/core/common.h index 84440968..13218983 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -364,8 +364,11 @@ __inline__ void TRACE(char *f, ...) { } // this is re3 only, and so the function #define _TODO(x) #define _TODOCONST(x) (x) -#ifdef CHECK_STRUCT_SIZES -#define VALIDATE_SIZE(struc, size) static_assert(sizeof(struc) == size, "Invalid structure size of " #struc) +#if CHECK_STRUCT_SIZES +template struct check_size { + static_assert(s == t, "Invalid structure size"); +}; +#define VALIDATE_SIZE(struc, size) check_size struc ## Check #else #define VALIDATE_SIZE(struc, size) #endif From e9adf8162bd4bca98c27aa3e81dfaa90a4b9efe4 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Fri, 22 Jan 2021 19:59:27 +0100 Subject: [PATCH 133/152] fix --- src/core/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/common.h b/src/core/common.h index 13218983..596c47ee 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -364,7 +364,7 @@ __inline__ void TRACE(char *f, ...) { } // this is re3 only, and so the function #define _TODO(x) #define _TODOCONST(x) (x) -#if CHECK_STRUCT_SIZES +#ifdef CHECK_STRUCT_SIZES template struct check_size { static_assert(s == t, "Invalid structure size"); }; From d58f090198912c1d640a0ec29d6a3f5d31abfc38 Mon Sep 17 00:00:00 2001 From: withmorten Date: Fri, 22 Jan 2021 20:33:29 +0100 Subject: [PATCH 134/152] fix RW33 build, undef ANISOTROPIC_FILTERING for vanilla build --- premake5.lua | 2 +- src/core/config.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/premake5.lua b/premake5.lua index d4ef5198..e6c8ea5a 100644 --- a/premake5.lua +++ b/premake5.lua @@ -359,7 +359,7 @@ project "re3" filter "platforms:*RW33*" includedirs { "sdk/rwsdk/include/d3d8" } libdirs { "sdk/rwsdk/lib/d3d8/release" } - links { "rwcore", "rpworld", "rpmatfx", "rpskin", "rphanim", "rtbmp", "rtquat", "rtcharse" } + links { "rwcore", "rpworld", "rpmatfx", "rpskin", "rphanim", "rtbmp", "rtquat", "rtcharse", "rpanisot" } defines { "RWLIBS" } linkoptions "/SECTION:_rwcseg,ER!W /MERGE:_rwcseg=.text" diff --git a/src/core/config.h b/src/core/config.h index e4568306..569134f1 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -440,6 +440,7 @@ enum Config { #undef IMPROVED_VIDEOMODE #undef DISABLE_LOADING_SCREEN #undef DISABLE_VSYNC_ON_TEXTURE_CONVERSION +#undef ANISOTROPIC_FILTERING //#define USE_TEXTURE_POOL // not possible because R* used custom RW33 #undef FIX_SPRITES From 2e5898490c9c41d3f97d5dbac1ebc461f12cf9c7 Mon Sep 17 00:00:00 2001 From: withmorten Date: Fri, 22 Jan 2021 20:44:11 +0100 Subject: [PATCH 135/152] cw: remove extras folder --- codewarrior/re3.mcp | Bin 228825 -> 228825 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/codewarrior/re3.mcp b/codewarrior/re3.mcp index e86c37b9c021c2d1630f3182b7981ce15416529c..fc1f2104801b67071a082ccf49a25b143be9f6ff 100644 GIT binary patch delta 3980 zcmXxn30O^O9LMo{(;}qOEn00M6xl^2%T+B(&i()2^W4%ZyV5GV>{J`86*zIlD$f0*(WSi>wu0}2c1xZ&gg=5 zu^zgj8@i(hdZL#}Nn4+w0XD=&*ciRBi7-4eqOVH)StjX5T%VvDN`K@rC?9uY0q(&< zEJ6eB#eKNnq@+DSa1amSVLXCIu^5lxaXf(~coI+HX*`2xjf&@gj^I3Az>9bZFXI&~ z#jAJ?%kVnhz?)c(w-lAi;5EL% zxA-5v!%BRQAFv8P;wSu!Ur?ns?J8=uN-}OQ76jGM60Oi0ZLm7pVhyZ`wa^Z0qdhvH zquN4jL-x6zzI8~PP=n6sf^~&*RIa~NkH8h(&>cO{6TPrLHo%712pbE{P3S0k&vvvv zRu>;PW`y2}PV`nrDs|I@k2J+*=!4C%1-3+A^ut!z8vU^iw#9bXUTCbF4g?*A<~2Kr zRodudM(TzqCDvxeofy{{1F#Er#X#(a-7yGzV6a-{YOI@{1ii4gQ1;4mmHH59u`h;T zDE7nt7={CIAP&NC9E=h86@G0pQX5I|4StJJ_#FD!}YiUGjSts!p*n^rL7!n!z|3k?LzaS>x#u% zCPt6fRcF;Z7?guMF&B4X9_Hh2q3NRH{%abqI!YI>94N1^0!Hn@LM%c9?!|q$9}nO` zJR~&VLJeiIB;CX$Ytv+Y+QW=Gf=96!kKu8lT(ZYgIzdo^C-D@X#xr;p&*6EzfEV!+ zUdAg}idRiWYOfKL;dQ)$H?bUV;cdKwck!N3E-Lhp?h`z~hggA+@G(BYr}zw?;|qL= zukba#5t_dkckvS_sz?*~iF2Rv3#!DMT`3Ob4X@N+|#U delta 3938 zcmXxn2Urtl9LMn_LQpA+5Jgr*Ma6;Q-XbUw6ctcfTU%R%*rF&_aMapfTifD9@f5+m zw}K*q2yrVaDsI8J_udn&eJ}YY&y(kK&+p#cy?6KjzxSl9!l|snDLdUk>r)zF4v)+U zb=IrpYx;Nd16|aWa|)`YR+UHV{NzxbUrvT@Ql?ZxrP73ihZ$VZ6?Iq>YoQy~MtAf; zPxL}>)MFj=u__tr64b-`=!*@oAvO|5L`U^fiI2VVjTsvkpD3oOQZB=fQH`+)HpOP> zk5Y3sT3`US#8%iE+hAL4hwZTgcEnED8M_E=)7Pq0a$1(FZ&&tp!$9ngK|;AWOD_cz z^uV4Nf(8^f$MR4^F${ZS9}LI7*bn<-1V&n|X^0{ifCGi{#B47qgdaRDyGMYtH3;8I+M%W(y+#8tQ&*I1Oo3~LG2;d23iPFy_$QRlwOefmHE;ezDaWMU{lR*Wz3k$IbO}HEP z;9lH^`>jfb0|W>05FW;2Jc38@7?$91Jb@>%6i?x4JY!MZ|FZ<=@H}3?i&%!`cnQsT z8L!|~yoT5D2HsRu?*A=<+js}>;yt{N5AY#A!pHaopW-uojxX?~P*T>uR|K!|4Zg*9 z_#QuC1%AX&_#b{omD;+hs8NHJ)GEoc+}IJ=qZS>oGFHK==!jpS6IR3O=!`Yc1zpt| zu?$tu^=_sksfo4F4Qr#jP#%;UAbAjYq8ECj9_yeF*2Q{QAAPZb(AI=CMDJA@nHXnG zh#xg9(UneYsEkzVrV&5!!^YSIn_@Hc$L81q1F$8w!q(UZ+hRMRrEc02bP(F+>?~&K zkT`U>F*Z4=8Z++5xK7v^yI@!BhJn}}gD@C-s8#Nky6H&}f(D_i&vTc05rkqG_QpOK zj(xEo_Qwc}#3&qq12G!Ev>I*rieM0ajo;v4{1(5%A^1K1fH6YZG2c@fN)U^2XvAUo zBmRW(I2=b{0*=H{n24kCXRDH73_%hm<5(Pr<8cE1f)nvqoP@vO?9DL56U;dGpVGcgrs;cQG(RQhfXfsAu;9;V}b%)m@sfD3UEF2*IeRA_4} zC(%lpG2?X-Ewzj>%W(y+#8tQ&*Wg-QhwE_zZp2Nv8MmO6#YQ%6#ch})v`yMgOx7+b zW}LAyv)<02T-0X|>_e#B2g+etk{ w5!m;QPcSB_slB&iudFo Date: Fri, 22 Jan 2021 21:10:49 +0100 Subject: [PATCH 136/152] small fix regarding codewarrior and AUDIO_MSS --- src/audio/sampman_miles.cpp | 5 +++-- src/core/common.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/audio/sampman_miles.cpp b/src/audio/sampman_miles.cpp index eccc9114..11e2b0ff 100644 --- a/src/audio/sampman_miles.cpp +++ b/src/audio/sampman_miles.cpp @@ -1,4 +1,6 @@ -#if defined(AUDIO_MSS) || defined (__MWERKS__) +#include "common.h" + +#ifdef AUDIO_MSS #include #include @@ -8,7 +10,6 @@ #include "eax-util.h" #include "mss.h" -#include "common.h" #include "sampman.h" #include "AudioManager.h" #include "MusicManager.h" diff --git a/src/core/common.h b/src/core/common.h index 596c47ee..33d8910d 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -16,6 +16,7 @@ #include #ifdef __MWERKS__ +#define AUDIO_MSS #define RWLIBS // codewarrior doesn't support project level defines - so not even this is enough, but still catches most ifdefs #endif From f6c846d27a419735e641881f9970d01cbd832f77 Mon Sep 17 00:00:00 2001 From: withmorten Date: Fri, 22 Jan 2021 21:27:18 +0100 Subject: [PATCH 137/152] fix --- src/core/CdStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/CdStream.cpp b/src/core/CdStream.cpp index a1843473..da85a238 100644 --- a/src/core/CdStream.cpp +++ b/src/core/CdStream.cpp @@ -135,7 +135,7 @@ CdStreamInit(int32 numChannels) gpReadInfo = (CdReadInfo *)LocalAlloc(LMEM_ZEROINIT, sizeof(CdReadInfo) * numChannels); ASSERT( gpReadInfo != nil ); - debug("%s: read info %p\n", gpReadInfo, "cdvd_stream"); + debug("%s: read info %p\n", "cdvd_stream", gpReadInfo); CdStreamAddImage("MODELS\\GTA3.IMG"); From 226e3b83dafbff6e59b8d351441026c5a6a4bf25 Mon Sep 17 00:00:00 2001 From: erorcun Date: Fri, 22 Jan 2021 23:40:28 +0300 Subject: [PATCH 138/152] No more resetting bindings for joypad, create .ini at the first start, joystick hotplug for Linux --- src/core/ControllerConfig.cpp | 87 +++++++++++++++++++++------------- src/core/ControllerConfig.h | 4 ++ src/core/Frontend.cpp | 18 +++---- src/core/MenuScreensCustom.cpp | 17 ++++++- src/core/main.h | 2 +- src/core/re3.cpp | 57 +++++++--------------- src/skel/glfw/glfw.cpp | 18 ++++++- src/skel/win/win.cpp | 14 +++++- 8 files changed, 132 insertions(+), 85 deletions(-) diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp index ee3cb959..6e9db6e3 100644 --- a/src/core/ControllerConfig.cpp +++ b/src/core/ControllerConfig.cpp @@ -31,6 +31,9 @@ CControllerConfigManager::CControllerConfigManager() void CControllerConfigManager::MakeControllerActionsBlank() { +#ifdef LOAD_INI_SETTINGS + ms_padButtonsInited = 0; +#endif for (int32 i = 0; i < MAX_CONTROLLERTYPES; i++) { for (int32 j = 0; j < MAX_CONTROLLERACTIONS; j++) @@ -345,6 +348,10 @@ void CControllerConfigManager::InitDefaultControlConfigMouse(CMouseControllerSta } } +#ifdef LOAD_INI_SETTINGS +uint32 CControllerConfigManager::ms_padButtonsInited = 0; +#endif + void CControllerConfigManager::InitDefaultControlConfigJoyPad(uint32 buttons) { m_bFirstCapture = true; @@ -353,6 +360,22 @@ void CControllerConfigManager::InitDefaultControlConfigJoyPad(uint32 buttons) if (buttons > 16) btn = 16; +#ifdef LOAD_INI_SETTINGS + uint32 buttonMin = ms_padButtonsInited; + if (buttonMin >= btn) + return; + + ms_padButtonsInited = btn; + + #define IF_BTN_IN_RANGE(n) \ + case n: \ + if (n <= buttonMin) \ + return; +#else + #define IF_BTN_IN_RANGE(n) \ + case n: +#endif + // Now we use SDL Game Controller DB #if defined RW_D3D9 || defined RWLIBS if ( AllValidWinJoys.m_aJoys[JOYSTICK1].m_nVendorID == 0x3427 @@ -365,49 +388,49 @@ void CControllerConfigManager::InitDefaultControlConfigJoyPad(uint32 buttons) switch (btn) { - case 16: + IF_BTN_IN_RANGE(16) SetControllerKeyAssociatedWithAction(GO_LEFT, 16, JOYSTICK); - case 15: + IF_BTN_IN_RANGE(15) SetControllerKeyAssociatedWithAction(GO_BACK, 15, JOYSTICK); - case 14: + IF_BTN_IN_RANGE(14) SetControllerKeyAssociatedWithAction(GO_RIGHT, 14, JOYSTICK); - case 13: + IF_BTN_IN_RANGE(13) SetControllerKeyAssociatedWithAction(GO_FORWARD, 13, JOYSTICK); - case 12: - case 11: + IF_BTN_IN_RANGE(12) + IF_BTN_IN_RANGE(11) SetControllerKeyAssociatedWithAction(PED_LOOKBEHIND, 11, JOYSTICK); SetControllerKeyAssociatedWithAction(TOGGLE_SUBMISSIONS, 11, JOYSTICK); - case 10: + IF_BTN_IN_RANGE(10) SetControllerKeyAssociatedWithAction(VEHICLE_HORN, 10, JOYSTICK); - case 9: + IF_BTN_IN_RANGE(9) SetControllerKeyAssociatedWithAction(CAMERA_CHANGE_VIEW_ALL_SITUATIONS, 9, JOYSTICK); - case 8: + IF_BTN_IN_RANGE(8) SetControllerKeyAssociatedWithAction(VEHICLE_HANDBRAKE, 8, JOYSTICK); SetControllerKeyAssociatedWithAction(PED_LOCK_TARGET, 8, JOYSTICK); - case 7: + IF_BTN_IN_RANGE(7) SetControllerKeyAssociatedWithAction(PED_CENTER_CAMERA_BEHIND_PLAYER, 7, JOYSTICK); SetControllerKeyAssociatedWithAction(VEHICLE_CHANGE_RADIO_STATION, 7, JOYSTICK); - case 6: + IF_BTN_IN_RANGE(6) SetControllerKeyAssociatedWithAction(PED_CYCLE_WEAPON_RIGHT, 6, JOYSTICK); SetControllerKeyAssociatedWithAction(VEHICLE_LOOKRIGHT, 6, JOYSTICK); - case 5: + IF_BTN_IN_RANGE(5) SetControllerKeyAssociatedWithAction(PED_CYCLE_WEAPON_LEFT, 5, JOYSTICK); SetControllerKeyAssociatedWithAction(VEHICLE_LOOKLEFT, 5, JOYSTICK); /*******************************************************************************************/ - case 4: + IF_BTN_IN_RANGE(4) SetControllerKeyAssociatedWithAction(VEHICLE_BRAKE, 4, JOYSTICK); SetControllerKeyAssociatedWithAction(PED_JUMPING, 4, JOYSTICK); SetControllerKeyAssociatedWithAction(PED_SNIPER_ZOOM_IN, 4, JOYSTICK); - case 3: + IF_BTN_IN_RANGE(3) SetControllerKeyAssociatedWithAction(VEHICLE_ACCELERATE, 3, JOYSTICK); SetControllerKeyAssociatedWithAction(PED_SPRINT, 3, JOYSTICK); SetControllerKeyAssociatedWithAction(PED_SNIPER_ZOOM_OUT, 3, JOYSTICK); - case 2: + IF_BTN_IN_RANGE(2) SetControllerKeyAssociatedWithAction(PED_FIREWEAPON, 2, JOYSTICK); #ifdef BIND_VEHICLE_FIREWEAPON SetControllerKeyAssociatedWithAction(VEHICLE_FIREWEAPON, 2, JOYSTICK); #endif - case 1: + IF_BTN_IN_RANGE(1) SetControllerKeyAssociatedWithAction(VEHICLE_ENTER_EXIT, 1, JOYSTICK); /*******************************************************************************************/ } @@ -416,46 +439,46 @@ void CControllerConfigManager::InitDefaultControlConfigJoyPad(uint32 buttons) { switch (btn) { - case 16: + IF_BTN_IN_RANGE(16) SetControllerKeyAssociatedWithAction(GO_LEFT, 16, JOYSTICK); - case 15: + IF_BTN_IN_RANGE(15) SetControllerKeyAssociatedWithAction(GO_BACK, 15, JOYSTICK); - case 14: + IF_BTN_IN_RANGE(14) SetControllerKeyAssociatedWithAction(GO_RIGHT, 14, JOYSTICK); - case 13: + IF_BTN_IN_RANGE(13) SetControllerKeyAssociatedWithAction(GO_FORWARD, 13, JOYSTICK); - case 12: - case 11: + IF_BTN_IN_RANGE(12) + IF_BTN_IN_RANGE(11) SetControllerKeyAssociatedWithAction(PED_LOOKBEHIND, 11, JOYSTICK); SetControllerKeyAssociatedWithAction(TOGGLE_SUBMISSIONS, 11, JOYSTICK); - case 10: + IF_BTN_IN_RANGE(10) SetControllerKeyAssociatedWithAction(VEHICLE_HORN, 10, JOYSTICK); - case 9: + IF_BTN_IN_RANGE(9) SetControllerKeyAssociatedWithAction(CAMERA_CHANGE_VIEW_ALL_SITUATIONS, 9, JOYSTICK); - case 8: + IF_BTN_IN_RANGE(8) SetControllerKeyAssociatedWithAction(VEHICLE_HANDBRAKE, 8, JOYSTICK); SetControllerKeyAssociatedWithAction(PED_LOCK_TARGET, 8, JOYSTICK); - case 7: + IF_BTN_IN_RANGE(7) SetControllerKeyAssociatedWithAction(PED_CENTER_CAMERA_BEHIND_PLAYER, 7, JOYSTICK); SetControllerKeyAssociatedWithAction(VEHICLE_CHANGE_RADIO_STATION, 7, JOYSTICK); - case 6: + IF_BTN_IN_RANGE(6) SetControllerKeyAssociatedWithAction(PED_CYCLE_WEAPON_RIGHT, 6, JOYSTICK); SetControllerKeyAssociatedWithAction(VEHICLE_LOOKRIGHT, 6, JOYSTICK); - case 5: + IF_BTN_IN_RANGE(5) SetControllerKeyAssociatedWithAction(PED_CYCLE_WEAPON_LEFT, 5, JOYSTICK); SetControllerKeyAssociatedWithAction(VEHICLE_LOOKLEFT, 5, JOYSTICK); /*******************************************************************************************/ - case 4: + IF_BTN_IN_RANGE(4) SetControllerKeyAssociatedWithAction(VEHICLE_ENTER_EXIT, 4, JOYSTICK); - case 3: + IF_BTN_IN_RANGE(3) SetControllerKeyAssociatedWithAction(VEHICLE_BRAKE, 3, JOYSTICK); SetControllerKeyAssociatedWithAction(PED_JUMPING, 3, JOYSTICK); SetControllerKeyAssociatedWithAction(PED_SNIPER_ZOOM_IN, 3, JOYSTICK); - case 2: + IF_BTN_IN_RANGE(2) SetControllerKeyAssociatedWithAction(VEHICLE_ACCELERATE, 2, JOYSTICK); SetControllerKeyAssociatedWithAction(PED_SPRINT, 2, JOYSTICK); SetControllerKeyAssociatedWithAction(PED_SNIPER_ZOOM_OUT, 2, JOYSTICK); - case 1: + IF_BTN_IN_RANGE(1) SetControllerKeyAssociatedWithAction(PED_FIREWEAPON, 1, JOYSTICK); #ifdef BIND_VEHICLE_FIREWEAPON SetControllerKeyAssociatedWithAction(VEHICLE_FIREWEAPON, 1, JOYSTICK); diff --git a/src/core/ControllerConfig.h b/src/core/ControllerConfig.h index d3c2293d..295f03b9 100644 --- a/src/core/ControllerConfig.h +++ b/src/core/ControllerConfig.h @@ -141,6 +141,10 @@ public: tControllerConfigBind m_aSettings[MAX_CONTROLLERACTIONS][MAX_CONTROLLERTYPES]; bool m_aSimCheckers[MAX_SIMS][MAX_CONTROLLERTYPES]; bool m_bMouseAssociated; + +#ifdef LOAD_INI_SETTINGS + static uint32 ms_padButtonsInited; +#endif CControllerConfigManager(); diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 707184d5..bd72a15f 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -3730,8 +3730,13 @@ CMenuManager::LoadSettings() CFileMgr::SetDir(""); #ifdef LOAD_INI_SETTINGS - LoadINISettings(); - LoadINIControllerSettings(); // Calling that after LoadINISettings is important because of gSelectedJoystickName loading + if (LoadINISettings()) { + LoadINIControllerSettings(); + } else { + // no re3.ini, create it + SaveINISettings(); + SaveINIControllerSettings(); + } #endif m_PrefsVsync = m_PrefsVsyncDisp; @@ -3828,12 +3833,6 @@ CMenuManager::SaveSettings() CFileMgr::SetDir(""); #else - static bool firstTime = true; - // In other conditions we already call SaveINIControllerSettings explicitly. - if (firstTime) { - SaveINIControllerSettings(); - firstTime = false; - } SaveINISettings(); #endif } @@ -5605,6 +5604,9 @@ CMenuManager::SwitchMenuOnAndOff() #endif ShutdownJustMenu(); SaveSettings(); +#ifdef LOAD_INI_SETTINGS + SaveINIControllerSettings(); +#endif m_bStartUpFrontEndRequested = false; pControlEdit = nil; m_bShutDownFrontEndRequested = false; diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp index 07223608..3eee8dd2 100644 --- a/src/core/MenuScreensCustom.cpp +++ b/src/core/MenuScreensCustom.cpp @@ -16,6 +16,7 @@ #include "Collision.h" #include "ModelInfo.h" #include "Pad.h" +#include "ControllerConfig.h" // Menu screens array is at the bottom of the file. @@ -292,6 +293,7 @@ void ScreenModeAfterChange(int8 before, int8 after) #ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS wchar selectedJoystickUnicode[128]; +int cachedButtonNum = -1; wchar* DetectJoystickDraw(bool* disabled, bool userHovering) { int numButtons; @@ -320,6 +322,7 @@ wchar* DetectJoystickDraw(bool* disabled, bool userHovering) { strcpy(gSelectedJoystickName, joyname); PSGLOBAL(joy1id) = found; + cachedButtonNum = numButtons; } } if (PSGLOBAL(joy1id) == -1) @@ -329,6 +332,18 @@ wchar* DetectJoystickDraw(bool* disabled, bool userHovering) { return selectedJoystickUnicode; } + +void DetectJoystickGoBack() { + if (cachedButtonNum != -1) { +#ifdef LOAD_INI_SETTINGS + ControlsManager.InitDefaultControlConfigJoyPad(cachedButtonNum); + SaveINIControllerSettings(); +#else + // Otherwise no way to save gSelectedJoystickName or ms_padButtonsInited anyway :shrug: Why do you even use this config.?? +#endif + cachedButtonNum = -1; + } +} #endif CMenuScreenCustom aScreens[MENUPAGES] = { @@ -836,7 +851,7 @@ CMenuScreenCustom aScreens[MENUPAGES] = { #ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS // MENUPAGE_DETECT_JOYSTICK { "FEC_JOD", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, - new CCustomScreenLayout({MENUSPRITE_MAINMENU, 40, 60, 20, FONT_BANK, FESCREEN_LEFT_ALIGN, false, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE}), nil, + new CCustomScreenLayout({MENUSPRITE_MAINMENU, 40, 60, 20, FONT_BANK, FESCREEN_LEFT_ALIGN, false, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE}), DetectJoystickGoBack, MENUACTION_LABEL, "FEC_JPR", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, MENUACTION_CFO_DYNAMIC, "FEC_JDE", { new CCFODynamic(nil, nil, nil, DetectJoystickDraw, nil) }, diff --git a/src/core/main.h b/src/core/main.h index eacfd8e1..9f181101 100644 --- a/src/core/main.h +++ b/src/core/main.h @@ -45,7 +45,7 @@ void TheModelViewer(void); #endif #ifdef LOAD_INI_SETTINGS -void LoadINISettings(); +bool LoadINISettings(); void SaveINISettings(); void LoadINIControllerSettings(); void SaveINIControllerSettings(); diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 48e8a6bc..42e59e6e 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -244,6 +244,14 @@ const char *iniKeyboardButtons[] = {"ESC","F1","F2","F3","F4","F5","F6","F7","F8 void LoadINIControllerSettings() { +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS + ReadIniIfExists("Controller", "JoystickName", gSelectedJoystickName, 128); +#endif + // force to default GTA behaviour (never overwrite bindings on joy change/initialization) if user init'ed/set bindings before we introduced that + if (!ReadIniIfExists("Controller", "PadButtonsInited", &ControlsManager.ms_padButtonsInited)) { + ControlsManager.ms_padButtonsInited = cfg.category_size("Bindings") != 0 ? 16 : 0; + } + for (int32 i = 0; i < MAX_CONTROLLERACTIONS; i++) { char value[128]; if (ReadIniIfExists("Bindings", iniControllerActions[i], value, 128)) { @@ -335,12 +343,17 @@ void SaveINIControllerSettings() StoreIni("Bindings", iniControllerActions[i], value, 128); } +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS + StoreIni("Controller", "JoystickName", gSelectedJoystickName, 128); +#endif + StoreIni("Controller", "PadButtonsInited", ControlsManager.ms_padButtonsInited); cfg.write_file("re3.ini"); } -void LoadINISettings() +bool LoadINISettings() { - cfg.load_file("re3.ini"); + if (!cfg.load_file("re3.ini")) + return false; #ifdef IMPROVED_VIDEOMODE ReadIniIfExists("VideoMode", "Width", &FrontEndMenuManager.m_nPrefsWidth); @@ -394,40 +407,6 @@ void LoadINISettings() ReadIniIfExists("Draw", "FixSprites", &CDraw::ms_bFixSprites); #endif -#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS - // Written by assuming the codes below will run after _InputInitialiseJoys(). - std::string strval = cfg.get("Controller", "JoystickName", ""); - const char *value = strval.c_str(); - strcpy(gSelectedJoystickName, value); - - if(gSelectedJoystickName[0] != '\0') { - for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) { - if (glfwJoystickPresent(i) && strncmp(gSelectedJoystickName, glfwGetJoystickName(i), strlen(gSelectedJoystickName)) == 0) { - if (PSGLOBAL(joy1id) != -1) { - PSGLOBAL(joy2id) = PSGLOBAL(joy1id); - } - PSGLOBAL(joy1id) = i; - int count; - glfwGetJoystickButtons(PSGLOBAL(joy1id), &count); - - // We need to init and reload bindings, because; - // 1-joypad button number may differ with saved/prvly connected one - // 2-bindings are not init'ed if there is no joypad at the start - ControlsManager.InitDefaultControlConfigJoyPad(count); - CFileMgr::SetDirMyDocuments(); - int32 gta3set = CFileMgr::OpenFile("gta3.set", "r"); - if (gta3set) { - ControlsManager.LoadSettings(gta3set); - CFileMgr::CloseFile(gta3set); - } - CFileMgr::SetDir(""); - // We call LoadINIControllerSettings after this func., so calling here isn't needed - break; - } - } - } -#endif - #ifdef CUSTOM_FRONTEND_OPTIONS bool migrate = cfg.category_size("FrontendOptions") != 0; for (int i = 0; i < MENUPAGES; i++) { @@ -453,6 +432,8 @@ void LoadINISettings() } } #endif + + return true; } void SaveINISettings() @@ -508,10 +489,6 @@ void SaveINISettings() #ifdef FIX_SPRITES StoreIni("Draw", "FixSprites", CDraw::ms_bFixSprites); #endif - -#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS - StoreIni("Controller", "JoystickName", gSelectedJoystickName, 128); -#endif #ifdef CUSTOM_FRONTEND_OPTIONS for (int i = 0; i < MENUPAGES; i++) { for (int j = 0; j < NUM_MENUROWS; j++) { diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 786ada5e..332f59f0 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -1602,10 +1602,16 @@ main(int argc, char *argv[]) SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &NewStickyKeys, SPIF_SENDCHANGE); #endif - // This part is needed because controller initialisation overwrites loaded settings. { CFileMgr::SetDirMyDocuments(); +#ifdef LOAD_INI_SETTINGS + // At this point InitDefaultControlConfigJoyPad must have set all bindings to default and ms_padButtonsInited to number of detected buttons. + // We will load stored bindings below, but let's cache ms_padButtonsInited before LoadINIControllerSettings and LoadSettings clears it, + // so we can add new joy bindings **on top of** stored bindings. + int connectedPadButtons = ControlsManager.ms_padButtonsInited; +#endif + int32 gta3set = CFileMgr::OpenFile("gta3.set", "r"); if ( gta3set ) @@ -1618,6 +1624,10 @@ main(int argc, char *argv[]) #ifdef LOAD_INI_SETTINGS LoadINIControllerSettings(); + if (connectedPadButtons != 0) { + ControlsManager.InitDefaultControlConfigJoyPad(connectedPadButtons); + SaveINIControllerSettings(); + } #endif } @@ -2131,6 +2141,12 @@ void joysChangeCB(int jid, int event) PSGLOBAL(joy1id) = jid; #ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS strcpy(gSelectedJoystickName, glfwGetJoystickName(jid)); +#endif + // This is behind LOAD_INI_SETTINGS, because otherwise the Init call below will destroy/overwrite your bindings. +#ifdef LOAD_INI_SETTINGS + int count; + glfwGetJoystickButtons(PSGLOBAL(joy1id), &count); + ControlsManager.InitDefaultControlConfigJoyPad(count); #endif } else if (PSGLOBAL(joy2id) == -1) PSGLOBAL(joy2id) = jid; diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index 16c37490..3bda4e9d 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -2150,12 +2150,18 @@ WinMain(HINSTANCE instance, ShowWindow(PSGLOBAL(window), cmdShow); UpdateWindow(PSGLOBAL(window)); - // This part is needed because controller initialisation overwrites loaded settings. { CFileMgr::SetDirMyDocuments(); +#ifdef LOAD_INI_SETTINGS + // At this point InitDefaultControlConfigJoyPad must have set all bindings to default and ms_padButtonsInited to number of detected buttons. + // We will load stored bindings below, but let's cache ms_padButtonsInited before LoadINIControllerSettings and LoadSettings clears it, + // so we can add new joy bindings **on top of** stored bindings. + int connectedPadButtons = ControlsManager.ms_padButtonsInited; +#endif + int32 gta3set = CFileMgr::OpenFile("gta3.set", "r"); - + if ( gta3set ) { ControlsManager.LoadSettings(gta3set); @@ -2166,6 +2172,10 @@ WinMain(HINSTANCE instance, #ifdef LOAD_INI_SETTINGS LoadINIControllerSettings(); + if (connectedPadButtons != 0) { + ControlsManager.InitDefaultControlConfigJoyPad(connectedPadButtons); + SaveINIControllerSettings(); + } #endif } From 0ea72af60c3b24e6ef256bff739fadf4c93b9078 Mon Sep 17 00:00:00 2001 From: erorcun Date: Fri, 22 Jan 2021 23:58:57 +0300 Subject: [PATCH 139/152] Peds reporting to phone changes for GTA3D --- src/control/Phones.cpp | 1 - src/peds/CivilianPed.cpp | 11 +++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/control/Phones.cpp b/src/control/Phones.cpp index 4769559c..f649d435 100644 --- a/src/control/Phones.cpp +++ b/src/control/Phones.cpp @@ -40,7 +40,6 @@ bool isPhoneAvailable(int m_phoneId) { return crimeReporters[m_phoneId] == nil || !crimeReporters[m_phoneId]->IsPointerValid() || crimeReporters[m_phoneId]->m_objective > OBJECTIVE_WAIT_ON_FOOT || - crimeReporters[m_phoneId]->m_nLastPedState != PED_SEEK_POS && (crimeReporters[m_phoneId]->m_nPedState != PED_MAKE_CALL && crimeReporters[m_phoneId]->m_nPedState != PED_FACE_PHONE && crimeReporters[m_phoneId]->m_nPedState != PED_SEEK_POS); } #endif diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp index a2f44357..1c4f10f5 100644 --- a/src/peds/CivilianPed.cpp +++ b/src/peds/CivilianPed.cpp @@ -264,15 +264,11 @@ CCivilianPed::ProcessControl(void) m_pNextPathNode = nil; #ifdef PEDS_REPORT_CRIMES_ON_PHONE } else if (bRunningToPhone && m_objective < OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE) { - if (!isPhoneAvailable(m_phoneId)) { + if (crimeReporters[m_phoneId] != this) { RestorePreviousState(); - if (crimeReporters[m_phoneId] == this) - crimeReporters[m_phoneId] = nil; - m_phoneId = -1; bRunningToPhone = false; } else { - crimeReporters[m_phoneId] = this; m_facePhoneStart = true; SetPedState(PED_FACE_PHONE); } @@ -431,7 +427,8 @@ CPed::RunToReportCrime(eCrimeType crimeToReport) { #ifdef PEDS_REPORT_CRIMES_ON_PHONE if (bRunningToPhone) { - if (!isPhoneAvailable(m_phoneId)) { + if (!isPhoneAvailable(m_phoneId) && crimeReporters[m_phoneId] != this) { + crimeReporters[m_phoneId] = nil; m_phoneId = -1; bIsRunning = false; ClearSeek(); // clears bRunningToPhone @@ -456,6 +453,8 @@ CPed::RunToReportCrime(eCrimeType crimeToReport) #ifndef PEDS_REPORT_CRIMES_ON_PHONE if (phone->m_nState != PHONE_STATE_FREE) return false; +#else + crimeReporters[phoneId] = this; #endif bRunningToPhone = true; From 5988c0e95aacfb393c2535999aaceed0ff572b64 Mon Sep 17 00:00:00 2001 From: withmorten Date: Fri, 22 Jan 2021 22:01:00 +0100 Subject: [PATCH 140/152] fix tabs in crossplatform --- src/skel/crossplatform.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/skel/crossplatform.h b/src/skel/crossplatform.h index e9a94cf4..8c4fb14c 100644 --- a/src/skel/crossplatform.h +++ b/src/skel/crossplatform.h @@ -17,11 +17,11 @@ enum eWinVersion // As long as WITHWINDOWS isn't defined / isn't included, we only need type definitions so let's include . // NOTE: It's perfectly fine to include here, but it can increase build size and time in *some* conditions, and maybe substantially in future if we'll use crossplatform.h more. #ifndef _INC_WINDOWS - #ifndef __MWERKS__ - #include - #else - #include - #endif + #ifndef __MWERKS__ + #include + #else + #include + #endif #endif #if defined RW_D3D9 || defined RWLIBS #include "win.h" From 6f4e2ab49147e14dbfa8eb2c71d4a8b0b1c19007 Mon Sep 17 00:00:00 2001 From: withmorten Date: Fri, 22 Jan 2021 22:47:29 +0100 Subject: [PATCH 141/152] get rid of unsupported LIBRW in config.h --- src/core/config.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/core/config.h b/src/core/config.h index 569134f1..025c8cb2 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -404,10 +404,6 @@ enum Config { #define VC_RAIN_NERF // Reduces number of rain particles #endif -#ifdef LIBRW -// these are not supported with librw yet -#endif - #if defined __MWERKS__ || defined VANILLA_DEFINES #define FINAL #undef CHATTYSPLASH From 2650fa9a9212f064f4191aee54ac0b65df3f8dc9 Mon Sep 17 00:00:00 2001 From: withmorten Date: Sat, 23 Jan 2021 02:17:28 +0100 Subject: [PATCH 142/152] VANILLA_BUILD fixes --- src/core/config.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/config.h b/src/core/config.h index 025c8cb2..588c99c0 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -415,6 +415,9 @@ enum Config { #undef NO_MOVIES #undef DEBUGMENU +//#undef NASTY_GAME +//#undef NO_CDCHECK + #undef DRAW_GAME_VERSION_TEXT #undef DRAW_MENU_VERSION_TEXT @@ -424,7 +427,7 @@ enum Config { #undef PS2_MATFX #undef FIX_BUGS -#undef THIS_IS_STUPID +#define THIS_IS_STUPID #undef MORE_LANGUAGES #undef COMPATIBLE_SAVES #undef LOAD_INI_SETTINGS From 35258b9b9c731e782e68c63c4969dbc9759f447d Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sat, 23 Jan 2021 15:29:00 +0300 Subject: [PATCH 143/152] added some missing functions --- src/control/Garages.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/control/Garages.h | 5 +++++ 2 files changed, 45 insertions(+) diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index a8e1f1cb..afbae005 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -111,6 +111,8 @@ const int32 gaCarsToCollectInCraigsGarages[TOTAL_COLLECTCARS_GARAGES][TOTAL_COLL { MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_CHEETAH, MI_TAXI, MI_ESPERANT, MI_SENTINEL, MI_IDAHO } }; +const int32 gaCarsToCollectIn60Seconds[] = { MI_CHEETAH, MI_TAXI, MI_ESPERANT, MI_SENTINEL, MI_IDAHO }; + int32 CGarages::BankVansCollected; bool CGarages::BombsAreFree; bool CGarages::RespraysAreFree; @@ -2424,3 +2426,41 @@ CGarages::IsModelIndexADoor(uint32 id) id == MI_CRUSHERBODY || id == MI_CRUSHERLID; } + +void CGarages::StopCarFromBlowingUp(CAutomobile* pCar) +{ + pCar->m_fFireBlowUpTimer = 0.0f; + pCar->m_fHealth = Max(pCar->m_fHealth, 300.0f); + pCar->Damage.SetEngineStatus(Max(pCar->Damage.GetEngineStatus(), 275)); +} + +bool CGarage::Does60SecondsNeedThisCarAtAll(int mi) +{ + for (int i = 0; i < ARRAY_SIZE(gaCarsToCollectIn60Seconds); i++) { + if (gaCarsToCollectIn60Seconds[i] == mi) + return true; + } + return false; +} + +bool CGarage::Does60SecondsNeedThisCar(int mi) +{ + for (int i = 0; i < ARRAY_SIZE(gaCarsToCollectIn60Seconds); i++) { + if (gaCarsToCollectIn60Seconds[i] == mi) + return m_bCollectedCarsState & BIT(i); + } + return false; +} + +void CGarage::MarkThisCarAsCollectedFor60Seconds(int mi) +{ + for (int i = 0; i < ARRAY_SIZE(gaCarsToCollectIn60Seconds); i++) { + if (gaCarsToCollectIn60Seconds[i] == mi) + m_bCollectedCarsState |= BIT(i); + } +} + +bool CGarage::IsPlayerEntirelyInsideGarage() +{ + return IsEntityEntirelyInside3D(FindPlayerVehicle() ? (CEntity*)FindPlayerVehicle() : (CEntity*)FindPlayerPed(), 0.0f); +} diff --git a/src/control/Garages.h b/src/control/Garages.h index 3a8bc08d..a7dfa462 100644 --- a/src/control/Garages.h +++ b/src/control/Garages.h @@ -166,6 +166,10 @@ public: void FindDoorsEntities(); void FindDoorsEntitiesSectorList(CPtrList&, bool); void PlayerArrestedOrDied(); + bool Does60SecondsNeedThisCarAtAll(int mi); + bool Does60SecondsNeedThisCar(int mi); + void MarkThisCarAsCollectedFor60Seconds(int mi); + bool IsPlayerEntirelyInsideGarage(); }; @@ -236,6 +240,7 @@ public: static bool IsModelIndexADoor(uint32 id); static void SetFreeBombs(bool bValue) { BombsAreFree = bValue; } static void SetFreeResprays(bool bValue) { RespraysAreFree = bValue; } + static void StopCarFromBlowingUp(CAutomobile*); static bool IsCarSprayable(CVehicle*); static float FindDoorHeightForMI(int32); From 921ca7712e9377359422d756163563337825e018 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sat, 23 Jan 2021 23:10:59 +0300 Subject: [PATCH 144/152] use ARRAY_SIZE --- src/core/re3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 42e59e6e..7c780516 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -936,7 +936,7 @@ extern bool gbRenderWorld2; "Uzi Money", "Toyminator", "Rigged To Blow", "Bullion Run", "Rumble", "The Exchange" }; - missionEntry = DebugMenuAddVar("Debug", "Select mission", &nextMissionToSwitch, nil, 1, 0, 79, missions); + missionEntry = DebugMenuAddVar("Debug", "Select mission", &nextMissionToSwitch, nil, 1, 0, ARRAY_SIZE(missions) - 1, missions); DebugMenuEntrySetWrap(missionEntry, true); DebugMenuAddCmd("Debug", "Start selected mission ", SwitchToMission); #endif From 6bdc0365eee4c8a587d04ad7693e28bc5a388a35 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sat, 23 Jan 2021 23:15:50 +0300 Subject: [PATCH 145/152] another backport --- src/control/Script.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/control/Script.cpp b/src/control/Script.cpp index e435f615..e70bd508 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -2059,7 +2059,9 @@ int8 CRunningScript::ProcessOneCommand() uint32 ip = m_nIp; if (command < ARRAY_SIZE(commands)) { script_assert(commands[command].id == command); + m_nIp -= 2; sprintf(commandInfo, m_nIp >= SIZE_MAIN_SCRIPT ? "M<%5d> " : "<%6d> ", m_nIp >= SIZE_MAIN_SCRIPT ? m_nIp - SIZE_MAIN_SCRIPT : m_nIp); + m_nIp += 2; if (m_bNotFlag) strcat(commandInfo, "NOT "); if (commands[command].position == -1) From db6b7b473df5a187fee14458601500fd8cfe6c85 Mon Sep 17 00:00:00 2001 From: withmorten Date: Sat, 23 Jan 2021 23:02:22 +0100 Subject: [PATCH 146/152] whitespace fix --- src/skel/skeleton.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/skel/skeleton.cpp b/src/skel/skeleton.cpp index 98fc9843..7889056b 100644 --- a/src/skel/skeleton.cpp +++ b/src/skel/skeleton.cpp @@ -13,8 +13,6 @@ #include "main.h" #include "MemoryHeap.h" - - static RwBool DefaultVideoMode = TRUE; RsGlobalType RsGlobal; From 5183d7cf0ffa470464f81ddbab161bf2ecd00fad Mon Sep 17 00:00:00 2001 From: withmorten Date: Sat, 23 Jan 2021 23:18:05 +0100 Subject: [PATCH 147/152] enable default resolution for vanilla defines --- src/core/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/config.h b/src/core/config.h index 588c99c0..b2c7135a 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -434,7 +434,7 @@ enum Config { #undef ASPECT_RATIO_SCALE #undef PROPER_SCALING -#undef DEFAULT_NATIVE_RESOLUTION +//#undef DEFAULT_NATIVE_RESOLUTION #undef PS2_ALPHA_TEST #undef IMPROVED_VIDEOMODE #undef DISABLE_LOADING_SCREEN From 3e6bb267f3d9834a1f341449945cac43563cffc2 Mon Sep 17 00:00:00 2001 From: shfil Date: Sun, 24 Jan 2021 12:34:40 +0100 Subject: [PATCH 148/152] Fix CCollision::DistToLine --- src/collision/Collision.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/collision/Collision.cpp b/src/collision/Collision.cpp index 7fb5c30b..396e3b85 100644 --- a/src/collision/Collision.cpp +++ b/src/collision/Collision.cpp @@ -2245,12 +2245,12 @@ CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *poin float dot = DotProduct(*point - *l0, *l1 - *l0); // Between 0 and len we're above the line. // if not, calculate distance to endpoint - if(dot <= 0.0f) - return (*point - *l0).Magnitude(); - if(dot >= lensq) - return (*point - *l1).Magnitude(); + if(dot <= 0.0f) return (*point - *l0).Magnitude(); + if(dot >= lensq) return (*point - *l1).Magnitude(); // distance to line - return Sqrt((*point - *l0).MagnitudeSqr() - dot*dot/lensq); + float distSqr = (*point - *l0).MagnitudeSqr() - dot * dot / lensq; + if(distSqr <= 0.f) return 0.f; + return Sqrt(distSqr); } // same as above but also return the point on the line @@ -2733,4 +2733,4 @@ CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); -} \ No newline at end of file +} From a0bf47cfd2e510dc9d3ce55fc3020bde6b8a668b Mon Sep 17 00:00:00 2001 From: erorcun Date: Sun, 24 Jan 2021 19:08:07 +0300 Subject: [PATCH 149/152] Fix out of bound binding orders --- src/core/ControllerConfig.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp index 6e9db6e3..4115cd38 100644 --- a/src/core/ControllerConfig.cpp +++ b/src/core/ControllerConfig.cpp @@ -2784,9 +2784,10 @@ wchar *CControllerConfigManager::GetButtonComboText(e_ControllerAction action) void CControllerConfigManager::SetControllerKeyAssociatedWithAction(e_ControllerAction action, int32 key, eControllerType type) { ResetSettingOrder(action); + int numOfSettings = GetNumOfSettingsForAction(action); m_aSettings[action][type].m_Key = key; - m_aSettings[action][type].m_ContSetOrder = GetNumOfSettingsForAction(action) + 1; + m_aSettings[action][type].m_ContSetOrder = numOfSettings + 1; } int32 CControllerConfigManager::GetMouseButtonAssociatedWithAction(e_ControllerAction action) @@ -2796,8 +2797,10 @@ int32 CControllerConfigManager::GetMouseButtonAssociatedWithAction(e_ControllerA void CControllerConfigManager::SetMouseButtonAssociatedWithAction(e_ControllerAction action, int32 button) { + int numOfSettings = GetNumOfSettingsForAction(action); + m_aSettings[action][MOUSE].m_Key = button; - m_aSettings[action][MOUSE].m_ContSetOrder = GetNumOfSettingsForAction(action) + 1; + m_aSettings[action][MOUSE].m_ContSetOrder = numOfSettings + 1; } void CControllerConfigManager::ResetSettingOrder(e_ControllerAction action) From 5336620f5c70db0c637ed6a585dc2ac823470ccf Mon Sep 17 00:00:00 2001 From: erorcun Date: Sun, 24 Jan 2021 20:05:43 +0300 Subject: [PATCH 150/152] Ped: car enter anim. fix --- src/peds/PedAI.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/peds/PedAI.cpp b/src/peds/PedAI.cpp index f77a64b4..089c8d9d 100644 --- a/src/peds/PedAI.cpp +++ b/src/peds/PedAI.cpp @@ -3016,6 +3016,7 @@ void CPed::LineUpPedWithCar(PedLineUpPhase phase) { bool vehIsUpsideDown = false; + bool stillGettingInOut = false; int vehAnim; float seatPosMult = 0.0f; float currentZ; @@ -3205,8 +3206,8 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) if (m_pVehicleAnim && vehAnim != ANIM_VAN_GETIN_L && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE && vehAnim != ANIM_VAN_GETIN) { neededPos.z = autoZPos.z; m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - } else if (neededPos.z <= currentZ && m_pVehicleAnim && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE) { - adjustedTimeStep = Min(m_pVehicleAnim->timeStep, 0.1f); + } else if (neededPos.z < currentZ && m_pVehicleAnim && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE) { + adjustedTimeStep = Max(m_pVehicleAnim->timeStep, 0.1f); // Smoothly change ped position neededPos.z = currentZ - (currentZ - neededPos.z) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep); @@ -3228,7 +3229,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) if (m_pVehicleAnim && (vehAnim == ANIM_CAR_GETIN_RHS || vehAnim == ANIM_CAR_GETIN_LOW_RHS || vehAnim == ANIM_CAR_GETIN_LHS || vehAnim == ANIM_CAR_GETIN_LOW_LHS || vehAnim == ANIM_CAR_QJACK || vehAnim == ANIM_VAN_GETIN_L || vehAnim == ANIM_VAN_GETIN)) { - adjustedTimeStep = Min(m_pVehicleAnim->timeStep, 0.1f); + adjustedTimeStep = Max(m_pVehicleAnim->timeStep, 0.1f); // Smoothly change ped position neededPos.z = (neededPos.z - currentZ) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep) + currentZ; @@ -3242,7 +3243,6 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) } } - bool stillGettingInOut = false; if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer) stillGettingInOut = veh->m_vehType != VEHICLE_TYPE_BOAT || bOnBoat; From 1d3b4d1e9a16c5eddd5f71e50b1e8a082f58676b Mon Sep 17 00:00:00 2001 From: shfil Date: Sun, 24 Jan 2021 21:34:53 +0100 Subject: [PATCH 151/152] Add cmake option for sanitizers --- src/CMakeLists.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dc204d17..df39c7c9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -79,6 +79,21 @@ endif() target_compile_definitions(${EXECUTABLE} PRIVATE ) +option(${PROJECT}_WITH_SANITIZERS "Use UB sanitizers (better crash log)" OFF) +option(${PROJECT}_WITH_ASAN "Use Address sanitizer (better crash log)" OFF) + +if(${PROJECT}_WITH_SANITIZERS) + target_compile_options(${EXECUTABLE} PUBLIC + -fsanitize=undefined,float-divide-by-zero,integer,implicit-conversion,implicit-integer-truncation,implicit-integer-arithmetic-value-change,local-bounds,nullability + -g3 -fno-omit-frame-pointer) + target_link_options(${EXECUTABLE} PUBLIC -fsanitize=undefined,float-divide-by-zero,integer,implicit-conversion,implicit-integer-truncation,implicit-integer-arithmetic-value-change,local-bounds,nullability) +endif() + +if(${PROJECT}_WITH_ASAN) + target_compile_options(${EXECUTABLE} PUBLIC -fsanitize=address -g3 -fno-omit-frame-pointer) + target_link_options(${EXECUTABLE} PUBLIC -fsanitize=address) +endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") target_compile_options(${EXECUTABLE} PRIVATE From 4564f7aeea447226137ad72e0f0d1ea26cf159ba Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 24 Jan 2021 23:24:41 +0100 Subject: [PATCH 152/152] modelinfo fixes --- src/modelinfo/BaseModelInfo.cpp | 2 +- src/modelinfo/SimpleModelInfo.cpp | 3 +-- src/modelinfo/VehicleModelInfo.cpp | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/modelinfo/BaseModelInfo.cpp b/src/modelinfo/BaseModelInfo.cpp index f1c7d050..7137c604 100644 --- a/src/modelinfo/BaseModelInfo.cpp +++ b/src/modelinfo/BaseModelInfo.cpp @@ -56,7 +56,7 @@ void CBaseModelInfo::SetTexDictionary(const char *name) { int slot = CTxdStore::FindTxdSlot(name); - if(slot < 0) + if(slot == -1) slot = CTxdStore::AddTxdSlot(name); m_txdSlot = slot; } diff --git a/src/modelinfo/SimpleModelInfo.cpp b/src/modelinfo/SimpleModelInfo.cpp index 55828b31..9fc0dd6e 100644 --- a/src/modelinfo/SimpleModelInfo.cpp +++ b/src/modelinfo/SimpleModelInfo.cpp @@ -2,11 +2,10 @@ #include "General.h" #include "Camera.h" +#include "Renderer.h" #include "ModelInfo.h" #include "custompipes.h" -#define LOD_DISTANCE (300.0f) - void CSimpleModelInfo::DeleteRwObject(void) { diff --git a/src/modelinfo/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp index c0daaead..685b6ef6 100644 --- a/src/modelinfo/VehicleModelInfo.cpp +++ b/src/modelinfo/VehicleModelInfo.cpp @@ -553,9 +553,9 @@ CVehicleModelInfo::SetVehicleComponentFlags(RwFrame *frame, uint32 flags) SETFLAGS(ATOMIC_FLAG_FRONT); else if(flags & VEHICLE_FLAG_REAR && (handling->Flags & HANDLING_IS_VAN || (flags & (VEHICLE_FLAG_LEFT|VEHICLE_FLAG_RIGHT)) == 0)) SETFLAGS(ATOMIC_FLAG_REAR); - if(flags & VEHICLE_FLAG_LEFT) + else if(flags & VEHICLE_FLAG_LEFT) SETFLAGS(ATOMIC_FLAG_LEFT); - if(flags & VEHICLE_FLAG_RIGHT) + else if(flags & VEHICLE_FLAG_RIGHT) SETFLAGS(ATOMIC_FLAG_RIGHT); if(flags & VEHICLE_FLAG_REARDOOR) @@ -709,7 +709,7 @@ struct editableMatCBData RpMaterial* CVehicleModelInfo::GetEditableMaterialListCB(RpMaterial *material, void *data) { - static RwRGBA white = { 255, 255, 255, 255 }; + RwRGBA white = { 255, 255, 255, 255 }; const RwRGBA *col; editableMatCBData *cbdata;