summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/control/PathFind.cpp17
-rw-r--r--src/control/PathFind.h9
-rw-r--r--src/control/RoadBlocks.cpp34
-rw-r--r--src/control/RoadBlocks.h4
-rw-r--r--src/core/ControllerConfig.cpp10
-rw-r--r--src/core/EventList.cpp23
-rw-r--r--src/core/EventList.h2
-rw-r--r--src/core/Frontend.cpp268
-rw-r--r--src/core/Frontend.h12
-rw-r--r--src/core/Timer.h13
-rw-r--r--src/core/config.h7
-rw-r--r--src/peds/CopPed.cpp287
-rw-r--r--src/peds/CopPed.h5
-rw-r--r--src/peds/Ped.cpp8
-rw-r--r--src/peds/Population.cpp2
-rw-r--r--src/save/GenericGameStorage.cpp45
-rw-r--r--src/save/PCSave.cpp14
17 files changed, 575 insertions, 185 deletions
diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp
index daa27e57..608a209a 100644
--- a/src/control/PathFind.cpp
+++ b/src/control/PathFind.cpp
@@ -11,19 +11,10 @@ CPathFind &ThePaths = *(CPathFind*)0x8F6754;
WRAPPER bool CPedPath::CalcPedRoute(uint8, CVector, CVector, CVector*, int16*, int16) { EAXJMP(0x42E680); }
-enum
-{
- NodeTypeExtern = 1,
- NodeTypeIntern = 2,
-
- ObjectFlag1 = 1,
- ObjectEastWest = 2,
-
- MAX_DIST = INT16_MAX-1
-};
+#define MAX_DIST INT16_MAX-1
// object flags:
-// 1
+// 1 UseInRoadBlock
// 2 east/west road(?)
CPathInfoForObject *&InfoForTileCars = *(CPathInfoForObject**)0x8F1A8C;
@@ -218,14 +209,14 @@ CPathFind::PreparePathData(void)
if(numIntern == 1 && numExtern == 2){
if(numLanes < 4){
if((i & 7) == 4){ // WHAT?
- m_objectFlags[i] |= ObjectFlag1;
+ m_objectFlags[i] |= UseInRoadBlock;
if(maxX > maxY)
m_objectFlags[i] |= ObjectEastWest;
else
m_objectFlags[i] &= ~ObjectEastWest;
}
}else{
- m_objectFlags[i] |= ObjectFlag1;
+ m_objectFlags[i] |= UseInRoadBlock;
if(maxX > maxY)
m_objectFlags[i] |= ObjectEastWest;
else
diff --git a/src/control/PathFind.h b/src/control/PathFind.h
index d42b8bb3..c51cb7c7 100644
--- a/src/control/PathFind.h
+++ b/src/control/PathFind.h
@@ -11,6 +11,15 @@ public:
enum
{
+ NodeTypeExtern = 1,
+ NodeTypeIntern = 2,
+
+ UseInRoadBlock = 1,
+ ObjectEastWest = 2,
+};
+
+enum
+{
PATH_CAR = 0,
PATH_PED = 1,
};
diff --git a/src/control/RoadBlocks.cpp b/src/control/RoadBlocks.cpp
index ed092391..e39fe481 100644
--- a/src/control/RoadBlocks.cpp
+++ b/src/control/RoadBlocks.cpp
@@ -1,7 +1,37 @@
#include "common.h"
#include "patcher.h"
#include "RoadBlocks.h"
+#include "PathFind.h"
+
+int16 &CRoadBlocks::NumRoadBlocks = *(int16*)0x95CC34;
+int16 (&CRoadBlocks::RoadBlockObjects)[NUMROADBLOCKS] = *(int16(*)[NUMROADBLOCKS]) * (uintptr*)0x72B3A8;
+bool (&CRoadBlocks::InOrOut)[NUMROADBLOCKS] = *(bool(*)[NUMROADBLOCKS]) * (uintptr*)0x733810;
-WRAPPER void CRoadBlocks::Init(void) { EAXJMP(0x436F50); }
WRAPPER void CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle*, int32, int16) { EAXJMP(0x4376A0); }
-WRAPPER void CRoadBlocks::GenerateRoadBlocks(void) { EAXJMP(0x436FA0); } \ No newline at end of file
+WRAPPER void CRoadBlocks::GenerateRoadBlocks(void) { EAXJMP(0x436FA0); }
+
+void
+CRoadBlocks::Init(void)
+{
+ NumRoadBlocks = 0;
+ for (int objId = 0; objId < ThePaths.m_numMapObjects; objId++) {
+ if (ThePaths.m_objectFlags[objId] & UseInRoadBlock) {
+ if (NumRoadBlocks < 600) {
+ InOrOut[NumRoadBlocks] = true;
+ RoadBlockObjects[NumRoadBlocks] = objId;
+ NumRoadBlocks++;
+ } else {
+#ifndef MASTER
+ printf("Not enough room for the potential roadblocks\n");
+#endif
+ // FIX: Don't iterate loop after NUMROADBLOCKS
+ return;
+ }
+ }
+ }
+
+}
+
+STARTPATCHES
+ InjectHook(0x436F50, &CRoadBlocks::Init, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/control/RoadBlocks.h b/src/control/RoadBlocks.h
index b1bb3589..3f5868e7 100644
--- a/src/control/RoadBlocks.h
+++ b/src/control/RoadBlocks.h
@@ -6,6 +6,10 @@ class CVehicle;
class CRoadBlocks
{
public:
+ static int16 (&NumRoadBlocks);
+ static int16 (&RoadBlockObjects)[NUMROADBLOCKS];
+ static bool (&InOrOut)[NUMROADBLOCKS];
+
static void Init(void);
static void GenerateRoadBlockCopsForCar(CVehicle*, int32, int16);
static void GenerateRoadBlocks(void);
diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp
index 92c51182..541257c6 100644
--- a/src/core/ControllerConfig.cpp
+++ b/src/core/ControllerConfig.cpp
@@ -417,6 +417,11 @@ void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonDown(int32 button, i
case 13:
pad->PCTempJoyState.DPadUp = 255;
break;
+#ifdef REGISTER_START_BUTTON
+ case 12:
+ pad->PCTempJoyState.Start = 255;
+ break;
+#endif
case 11:
pad->PCTempJoyState.RightShock = 255;
break;
@@ -839,6 +844,11 @@ void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonUp(int32 button, int
case 13:
pad->PCTempJoyState.DPadUp = 0;
break;
+#ifdef REGISTER_START_BUTTON
+ case 12:
+ pad->PCTempJoyState.Start = 0;
+ break;
+#endif
case 11:
pad->PCTempJoyState.RightShock = 0;
break;
diff --git a/src/core/EventList.cpp b/src/core/EventList.cpp
index caf0cb3f..4364359a 100644
--- a/src/core/EventList.cpp
+++ b/src/core/EventList.cpp
@@ -5,10 +5,13 @@
#include "World.h"
#include "Wanted.h"
#include "EventList.h"
+#include "Messages.h"
+#include "Text.h"
+#include "main.h"
int32 CEventList::ms_nFirstFreeSlotIndex;
-//CEvent gaEvent[NUMEVENTS];
-CEvent *gaEvent = (CEvent*)0x6EF830;
+CEvent gaEvent[NUMEVENTS];
+//CEvent *gaEvent = (CEvent*)0x6EF830;
enum
{
@@ -207,8 +210,20 @@ CEventList::ReportCrimeForEvent(eEventType type, int32 crimeId, bool copsDontCar
default: crime = CRIME_NONE; break;
}
- if(crime == CRIME_NONE)
- return;
+#ifdef VC_PED_PORTS
+ if (crime == CRIME_HIT_PED && ((CPed*)crimeId)->IsPointerValid() &&
+ FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 && ((CPed*)crimeId)->m_ped_flagE2) {
+
+ if(!((CPed*)crimeId)->DyingOrDead()) {
+ sprintf(gString, "$50 Good Citizen Bonus!");
+ AsciiToUnicode(gString, gUString);
+ CMessages::AddBigMessage(gUString, 5000, 0);
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 50;
+ }
+ } else
+#endif
+ if(crime == CRIME_NONE)
+ return;
CVector playerPedCoors = FindPlayerPed()->GetPosition();
CVector playerCoors = FindPlayerCoors();
diff --git a/src/core/EventList.h b/src/core/EventList.h
index 2799fca4..1c03c9d6 100644
--- a/src/core/EventList.h
+++ b/src/core/EventList.h
@@ -63,4 +63,4 @@ public:
static void ReportCrimeForEvent(eEventType type, int32, bool);
};
-extern CEvent *gaEvent; \ No newline at end of file
+extern CEvent gaEvent[NUMEVENTS]; \ No newline at end of file
diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp
index 4c2f3afa..aff8a3ec 100644
--- a/src/core/Frontend.cpp
+++ b/src/core/Frontend.cpp
@@ -181,6 +181,7 @@ ScaleAndCenterX(float x)
#endif
#define isPlainTextScreen(screen) (screen == MENUPAGE_BRIEFS || screen == MENUPAGE_STATS)
+
#ifdef PS2_LIKE_MENU
#define ChangeScreen(screen, option, updateDelay, withReverseAlpha) \
do { \
@@ -235,67 +236,100 @@ ScaleAndCenterX(float x)
m_nHoverOption = HOVEROPTION_NOT_HOVERING; \
} while(0)
-#define ScrollUpListByOne() \
- do { \
- if (m_nSelectedListRow == m_nFirstVisibleRowOnList) { \
- if (m_nFirstVisibleRowOnList > 0) { \
- m_nSelectedListRow--; \
- m_nFirstVisibleRowOnList--; \
- m_nCurListItemY -= LIST_HEIGHT / m_nTotalListRow; \
- } \
- } else { \
- m_nSelectedListRow--; \
- } \
- } while(0)
+// --- Functions not in the game/inlined starts
-#define ScrollDownListByOne() \
- do { \
- if (m_nSelectedListRow == m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1) { \
- if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { \
- m_nSelectedListRow++; \
- m_nFirstVisibleRowOnList++; \
- m_nCurListItemY += LIST_HEIGHT / m_nTotalListRow; \
- } \
- } else { \
- if (m_nSelectedListRow < m_nTotalListRow - 1) { \
- m_nSelectedListRow++; \
- } \
- } \
- } while(0)
+inline void
+CMenuManager::ScrollUpListByOne()
+{
+ if (m_nSelectedListRow == m_nFirstVisibleRowOnList) {
+ if (m_nFirstVisibleRowOnList > 0) {
+ m_nSelectedListRow--;
+ m_nFirstVisibleRowOnList--;
+ m_nCurListItemY -= LIST_HEIGHT / m_nTotalListRow;
+ }
+ } else {
+ m_nSelectedListRow--;
+ }
+}
-#define PageUpList(playSoundOnSuccess) \
- do { \
- if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { \
- if (m_nFirstVisibleRowOnList > 0) { \
- if(playSoundOnSuccess) \
- DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); \
- \
- m_nFirstVisibleRowOnList = max(0, m_nFirstVisibleRowOnList - MAX_VISIBLE_LIST_ROW); \
- m_nSelectedListRow = min(m_nSelectedListRow, m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1); \
- } else { \
- m_nFirstVisibleRowOnList = 0; \
- m_nSelectedListRow = 0; \
- } \
- m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; \
- } \
- } while(0)
+inline void
+CMenuManager::ScrollDownListByOne()
+{
+ if (m_nSelectedListRow == m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1) {
+ if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) {
+ m_nSelectedListRow++;
+ m_nFirstVisibleRowOnList++;
+ m_nCurListItemY += LIST_HEIGHT / m_nTotalListRow;
+ }
+ } else {
+ if (m_nSelectedListRow < m_nTotalListRow - 1) {
+ m_nSelectedListRow++;
+ }
+ }
+}
-#define PageDownList(playSoundOnSuccess) \
- do { \
- if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { \
- if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { \
- if(playSoundOnSuccess) \
- DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); \
- \
- m_nFirstVisibleRowOnList = min(m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW, m_nTotalListRow - MAX_VISIBLE_LIST_ROW); \
- m_nSelectedListRow = max(m_nSelectedListRow, m_nFirstVisibleRowOnList); \
- } else { \
- m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW; \
- m_nSelectedListRow = m_nTotalListRow - 1; \
- } \
- m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; \
- } \
- } while(0)
+inline void
+CMenuManager::PageUpList(bool playSoundOnSuccess)
+{
+ if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) {
+ if (m_nFirstVisibleRowOnList > 0) {
+ if(playSoundOnSuccess)
+ DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+
+ m_nFirstVisibleRowOnList = max(0, m_nFirstVisibleRowOnList - MAX_VISIBLE_LIST_ROW);
+ m_nSelectedListRow = min(m_nSelectedListRow, m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1);
+ } else {
+ m_nFirstVisibleRowOnList = 0;
+ m_nSelectedListRow = 0;
+ }
+ m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
+ }
+}
+
+inline void
+CMenuManager::PageDownList(bool playSoundOnSuccess)
+{
+ if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) {
+ if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) {
+ if(playSoundOnSuccess)
+ DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+
+ m_nFirstVisibleRowOnList = min(m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW, m_nTotalListRow - MAX_VISIBLE_LIST_ROW);
+ m_nSelectedListRow = max(m_nSelectedListRow, m_nFirstVisibleRowOnList);
+ } else {
+ m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW;
+ m_nSelectedListRow = m_nTotalListRow - 1;
+ }
+ m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
+ }
+}
+
+inline void
+CMenuManager::ThingsToDoBeforeLeavingPage()
+{
+ if ((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && strcmp(m_aSkinName, m_PrefsSkinFile) != 0) {
+ CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile);
+ } else if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) {
+ if (m_nPrefsAudio3DProviderIndex != -1)
+ m_nPrefsAudio3DProviderIndex = DMAudio.GetCurrent3DProviderIndex();
+#ifdef TIDY_UP_PBP
+ DMAudio.StopFrontEndTrack();
+ OutputDebugString("FRONTEND AUDIO TRACK STOPPED");
+#endif
+ } else if (m_nCurrScreen == MENUPAGE_GRAPHICS_SETTINGS) {
+ m_nDisplayVideoMode = m_nPrefsVideoMode;
+ }
+
+ if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) {
+ CPlayerSkin::EndFrontendSkinEdit();
+ }
+
+ if ((m_nCurrScreen == MENUPAGE_SKIN_SELECT) || (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS)) {
+ m_nTotalListRow = 0;
+ }
+}
+
+// ------ Functions not in the game/inlined ends
void
CMenuManager::BuildStatLine(char *text, void *stat, uint8 aFloat, void *stat2)
@@ -1173,7 +1207,6 @@ void CMenuManager::DrawFrontEnd()
bbNames[5] = { "FESZ_QU",MENUPAGE_EXIT };
bbTabCount = 6;
}
- m_nCurrScreen = MENUPAGE_NEW_GAME;
} else {
if (bbTabCount != 8) {
bbNames[0] = { "FEB_STA",MENUPAGE_STATS };
@@ -1186,8 +1219,8 @@ void CMenuManager::DrawFrontEnd()
bbNames[7] = { "FESZ_QU",MENUPAGE_EXIT };
bbTabCount = 8;
}
- m_nCurrScreen = MENUPAGE_STATS;
}
+ m_nCurrScreen = bbNames[0].screenId;
bottomBarActive = true;
curBottomBarOption = 0;
}
@@ -1285,7 +1318,6 @@ void CMenuManager::DrawFrontEndNormal()
eFrontendSprites currentSprite;
switch (m_nCurrScreen) {
case MENUPAGE_STATS:
- case MENUPAGE_NEW_GAME:
case MENUPAGE_START_MENU:
case MENUPAGE_PAUSE_MENU:
case MENUPAGE_EXIT:
@@ -1315,7 +1347,7 @@ void CMenuManager::DrawFrontEndNormal()
currentSprite = FE_ICONCONTROLS;
break;
default:
- /* actually MENUPAGE_NEW_GAME too*/
+ /*case MENUPAGE_NEW_GAME: */
/*case MENUPAGE_BRIEFS: */
currentSprite = FE_ICONBRIEF;
break;
@@ -1324,16 +1356,16 @@ void CMenuManager::DrawFrontEndNormal()
m_aFrontEndSprites[currentSprite].Draw(CRect(MENU_X_LEFT_ALIGNED(50.0f), MENU_Y(50.0f), MENU_X_RIGHT_ALIGNED(50.0f), SCREEN_SCALE_FROM_BOTTOM(95.0f)), CRGBA(255, 255, 255, m_nMenuFadeAlpha > 255 ? 255 : m_nMenuFadeAlpha));
if (m_nMenuFadeAlpha < 255) {
- static int LastFade = 0;
+ static uint32 LastFade = 0;
if (m_nMenuFadeAlpha <= 0 && reverseAlpha) {
reverseAlpha = false;
ChangeScreen(pendingScreen, pendingOption, true, false);
- } else if(CTimer::GetTimeInMillisecondsPauseMode() - LastFade > 10){
+ } else {
if (!reverseAlpha)
- m_nMenuFadeAlpha += 20;
+ m_nMenuFadeAlpha += min((CTimer::GetTimeInMillisecondsPauseMode() - LastFade) / 33.0f, 1.0f) * 20.0f;
else
- m_nMenuFadeAlpha = max(m_nMenuFadeAlpha - 30, 0);
+ m_nMenuFadeAlpha = max(0, m_nMenuFadeAlpha - min((CTimer::GetTimeInMillisecondsPauseMode() - LastFade) / 33.0f, 1.0f) * 30.0f);
LastFade = CTimer::GetTimeInMillisecondsPauseMode();
}
@@ -1537,12 +1569,18 @@ void CMenuManager::DrawFrontEndNormal()
}
if (m_nMenuFadeAlpha < 255) {
- static int LastFade = 0;
+ static uint32 LastFade = 0;
+ // Famous transparent menu bug. 33.0f = 1000.f/30.f (original frame limiter fps)
+#ifdef FIX_BUGS
+ m_nMenuFadeAlpha += min((CTimer::GetTimeInMillisecondsPauseMode() - LastFade) / 33.0f, 1.0f) * 20.0f;
+ LastFade = CTimer::GetTimeInMillisecondsPauseMode();
+#else
if(CTimer::GetTimeInMillisecondsPauseMode() - LastFade > 10){
m_nMenuFadeAlpha += 20;
LastFade = CTimer::GetTimeInMillisecondsPauseMode();
}
+#endif
if (m_nMenuFadeAlpha > 255){
m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
@@ -1950,7 +1988,7 @@ WRAPPER void CMenuManager::Process(void) { EAXJMP(0x485100); }
#else
void CMenuManager::Process(void)
{
- m_bMenuNotProcessed = false;
+ m_bMenuStateChanged = false;
if (!m_bSaveMenuActive && TheCamera.GetScreenFadeStatus() != FADE_0)
return;
@@ -2701,6 +2739,8 @@ CMenuManager::ProcessButtonPresses(void)
if (CPad::GetPad(0)->GetEnterJustDown() || CPad::GetPad(0)->GetCrossJustDown()) {
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
bottomBarActive = false;
+
+ // If there's a menu change with fade ongoing, finish it now
if (reverseAlpha)
m_nMenuFadeAlpha = 0;
return;
@@ -3116,51 +3156,43 @@ CMenuManager::ProcessButtonPresses(void)
if (goBack) {
CMenuManager::ResetHelperText();
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_EXIT, 0);
- if (m_nCurrScreen == MENUPAGE_PAUSE_MENU && !m_bGameNotLoaded && !m_bMenuNotProcessed){
- if (CMenuManager::m_PrefsVsyncDisp != CMenuManager::m_PrefsVsync) {
- CMenuManager::m_PrefsVsync = CMenuManager::m_PrefsVsyncDisp;
- }
- CMenuManager::RequestFrontEndShutDown();
- } else if (m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT
-#ifdef PS2_SAVE_DIALOG
- || m_nCurrScreen == MENUPAGE_SAVE
-#endif
- ) {
- CMenuManager::RequestFrontEndShutDown();
- } else if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) {
- DMAudio.StopFrontEndTrack();
- OutputDebugString("FRONTEND AUDIO TRACK STOPPED");
- }
-
- int oldScreen = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_PreviousPage[1] : aScreens[m_nCurrScreen].m_PreviousPage[0];
- int oldOption = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_ParentEntry[1] : aScreens[m_nCurrScreen].m_ParentEntry[0];
-
#ifdef PS2_LIKE_MENU
- if (bottomBarActive){
- bottomBarActive = false;
- if (!m_bGameNotLoaded) {
+ if (m_nCurrScreen == MENUPAGE_PAUSE_MENU || bottomBarActive) {
+#else
+ if (m_nCurrScreen == MENUPAGE_PAUSE_MENU) {
+#endif
+ if (!m_bGameNotLoaded && !m_bMenuStateChanged) {
if (CMenuManager::m_PrefsVsyncDisp != CMenuManager::m_PrefsVsync) {
CMenuManager::m_PrefsVsync = CMenuManager::m_PrefsVsyncDisp;
}
CMenuManager::RequestFrontEndShutDown();
}
+
+ // We're already resuming, we don't need further processing.
+#if defined(FIX_BUGS) || defined(PS2_LIKE_MENU)
return;
+#endif
+ }
+#ifdef PS2_LIKE_MENU
+ else if (m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT || m_nCurrScreen == MENUPAGE_SAVE) {
+#else
+ else if (m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT) {
+#endif
+ CMenuManager::RequestFrontEndShutDown();
+ }
+ // It's now in ThingsToDoBeforeLeavingPage()
+#ifndef TIDY_UP_PBP
+ else if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) {
+ DMAudio.StopFrontEndTrack();
+ OutputDebugString("FRONTEND AUDIO TRACK STOPPED");
}
#endif
+ int oldScreen = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_PreviousPage[1] : aScreens[m_nCurrScreen].m_PreviousPage[0];
+ int oldOption = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_ParentEntry[1] : aScreens[m_nCurrScreen].m_ParentEntry[0];
+
if (oldScreen != -1) {
- if ((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && strcmp(m_aSkinName, m_PrefsSkinFile) != 0) {
- CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile);
- }
- if ((m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) && (m_nPrefsAudio3DProviderIndex != -1)) {
- m_nPrefsAudio3DProviderIndex = DMAudio.GetCurrent3DProviderIndex();
- }
- if (m_nCurrScreen == MENUPAGE_GRAPHICS_SETTINGS) {
- m_nDisplayVideoMode = m_nPrefsVideoMode;
- }
- if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) {
- CPlayerSkin::EndFrontendSkinEdit();
- }
+ ThingsToDoBeforeLeavingPage();
#ifdef PS2_LIKE_MENU
if (!bottomBarActive &&
@@ -3168,10 +3200,8 @@ CMenuManager::ProcessButtonPresses(void)
bottomBarActive = true;
} else
#endif
+ {
ChangeScreen(oldScreen, oldOption, true, true);
-
- if ((m_nPrevScreen == MENUPAGE_SKIN_SELECT) || (m_nPrevScreen == MENUPAGE_KEYBOARD_CONTROLS)) {
- m_nTotalListRow = 0;
}
// We will go back for sure at this point, why process other things?!
@@ -3512,11 +3542,16 @@ WRAPPER void CMenuManager::SwitchMenuOnAndOff() { EAXJMP(0x488790); }
#else
void CMenuManager::SwitchMenuOnAndOff()
{
- if (!!(CPad::GetPad(0)->NewState.Start && !CPad::GetPad(0)->OldState.Start)
- || m_bShutDownFrontEndRequested || m_bStartUpFrontEndRequested) {
+ bool menuWasActive = !!m_bMenuActive;
- if (!m_bMenuActive)
- m_bMenuActive = true;
+ // Reminder: You need REGISTER_START_BUTTON defined to make it work.
+ if (CPad::GetPad(0)->GetStartJustDown()
+#ifdef FIX_BUGS
+ && !m_bGameNotLoaded
+#endif
+ || m_bShutDownFrontEndRequested || m_bStartUpFrontEndRequested) {
+
+ m_bMenuActive = !m_bMenuActive;
if (m_bShutDownFrontEndRequested)
m_bMenuActive = false;
@@ -3525,8 +3560,13 @@ void CMenuManager::SwitchMenuOnAndOff()
if (m_bMenuActive) {
CTimer::StartUserPause();
- }
- else {
+ } else {
+#ifdef PS2_LIKE_MENU
+ bottomBarActive = false;
+#endif
+#ifdef FIX_BUGS
+ ThingsToDoBeforeLeavingPage();
+#endif
ShutdownJustMenu();
SaveSettings();
m_bStartUpFrontEndRequested = false;
@@ -3553,7 +3593,7 @@ void CMenuManager::SwitchMenuOnAndOff()
PcSaveHelper.PopulateSlotInfo();
m_nCurrOption = 0;
}
-/* // Unused?
+/* // PS2 leftover?
if (m_nCurrScreen != MENUPAGE_SOUND_SETTINGS && gMusicPlaying)
{
DMAudio.StopFrontEndTrack();
@@ -3561,8 +3601,8 @@ void CMenuManager::SwitchMenuOnAndOff()
gMusicPlaying = 0;
}
*/
- if (!m_bMenuActive)
- m_bMenuNotProcessed = true;
+ if (m_bMenuActive != menuWasActive)
+ m_bMenuStateChanged = true;
m_bStartUpFrontEndRequested = false;
m_bShutDownFrontEndRequested = false;
diff --git a/src/core/Frontend.h b/src/core/Frontend.h
index 6d7327d3..3dbed164 100644
--- a/src/core/Frontend.h
+++ b/src/core/Frontend.h
@@ -403,7 +403,7 @@ public:
int32 m_nHelperTextMsgId;
bool m_bLanguageLoaded;
bool m_bMenuActive;
- bool m_bMenuNotProcessed;
+ bool m_bMenuStateChanged;
bool m_bWaitingForNewKeyBind;
bool m_bStartGameLoading;
bool m_bFirstTime;
@@ -540,8 +540,14 @@ public:
void WaitForUserCD();
void PrintController();
- // New content:
- uint8 GetNumberOfMenuOptions();
+ // New (not in function or inlined in the game)
+ void ThingsToDoBeforeLeavingPage();
+ void ScrollUpListByOne();
+ void ScrollDownListByOne();
+ void PageUpList(bool);
+ void PageDownList(bool);
+
+ // uint8 GetNumberOfMenuOptions();
};
static_assert(sizeof(CMenuManager) == 0x564, "CMenuManager: error");
diff --git a/src/core/Timer.h b/src/core/Timer.h
index 89c4a430..ef525be7 100644
--- a/src/core/Timer.h
+++ b/src/core/Timer.h
@@ -2,7 +2,7 @@
class CTimer
{
-public:
+
static uint32 &m_snTimeInMilliseconds;
static uint32 &m_snTimeInMillisecondsPauseMode;
static uint32 &m_snTimeInMillisecondsNonClipped;
@@ -11,19 +11,20 @@ public:
static float &ms_fTimeScale;
static float &ms_fTimeStep;
static float &ms_fTimeStepNonClipped;
+public:
static bool &m_UserPause;
static bool &m_CodePause;
- static float GetTimeStep(void) { return ms_fTimeStep; }
+ static const float &GetTimeStep(void) { return ms_fTimeStep; }
static void SetTimeStep(float ts) { ms_fTimeStep = ts; }
static float GetTimeStepInSeconds() { return ms_fTimeStep / 50.0f; }
static float GetTimeStepInMilliseconds() { return ms_fTimeStep / 50.0f * 1000.0f; }
- static float GetTimeStepNonClipped(void) { return ms_fTimeStepNonClipped; }
+ static const float &GetTimeStepNonClipped(void) { return ms_fTimeStepNonClipped; }
static float GetTimeStepNonClippedInSeconds(void) { return ms_fTimeStepNonClipped / 50.0f; }
static void SetTimeStepNonClipped(float ts) { ms_fTimeStepNonClipped = ts; }
- static uint32 GetFrameCounter(void) { return m_FrameCounter; }
+ static const uint32 &GetFrameCounter(void) { return m_FrameCounter; }
static void SetFrameCounter(uint32 fc) { m_FrameCounter = fc; }
- static uint32 GetTimeInMilliseconds(void) { return m_snTimeInMilliseconds; }
+ static const uint32 &GetTimeInMilliseconds(void) { return m_snTimeInMilliseconds; }
static void SetTimeInMilliseconds(uint32 t) { m_snTimeInMilliseconds = t; }
static uint32 GetTimeInMillisecondsNonClipped(void) { return m_snTimeInMillisecondsNonClipped; }
static void SetTimeInMillisecondsNonClipped(uint32 t) { m_snTimeInMillisecondsNonClipped = t; }
@@ -31,7 +32,7 @@ public:
static void SetTimeInMillisecondsPauseMode(uint32 t) { m_snTimeInMillisecondsPauseMode = t; }
static uint32 GetPreviousTimeInMilliseconds(void) { return m_snPreviousTimeInMilliseconds; }
static void SetPreviousTimeInMilliseconds(uint32 t) { m_snPreviousTimeInMilliseconds = t; }
- static float GetTimeScale(void) { return ms_fTimeScale; }
+ static const float &GetTimeScale(void) { return ms_fTimeScale; }
static void SetTimeScale(float ts) { ms_fTimeScale = ts; }
static bool GetIsPaused() { return m_UserPause || m_CodePause; }
diff --git a/src/core/config.h b/src/core/config.h
index 9235e744..ff779946 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -101,6 +101,8 @@ enum Config {
NUMPEDGROUPS = 31,
NUMMODELSPERPEDGROUP = 8,
+ NUMROADBLOCKS = 600,
+
NUMVISIBLEENTITIES = 2000,
NUMINVISIBLEENTITIES = 150,
@@ -169,10 +171,11 @@ enum Config {
#endif
#define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more
-#define TOGGLEABLE_BETA_FEATURES // toggleable from debug menu. doesn't have too many things
+#define TOGGLEABLE_BETA_FEATURES // toggleable from debug menu. not too many things
// Pad
#define KANGAROO_CHEAT
+#define REGISTER_START_BUTTON // currently only in menu sadly. resumes the game
// Hud, frontend and radar
#define ASPECT_RATIO_SCALE // Not just makes everything scale with aspect ratio, also adds support for all aspect ratios
@@ -199,5 +202,5 @@ enum Config {
// Peds
#define ANIMATE_PED_COL_MODEL
#define VC_PED_PORTS // various ports from VC's CPed, mostly subtle
-#define NEW_WALK_AROUND_ALGORITHM // to make walking around vehicles/objects less awkward
+// #define NEW_WALK_AROUND_ALGORITHM // to make walking around vehicles/objects less awkward
#define CANCELLABLE_CAR_ENTER
diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp
index 53ae1747..dae866a4 100644
--- a/src/peds/CopPed.cpp
+++ b/src/peds/CopPed.cpp
@@ -7,8 +7,11 @@
#include "Vehicle.h"
#include "RpAnimBlend.h"
#include "General.h"
+#include "ZoneCull.h"
+#include "PathFind.h"
+#include "RoadBlocks.h"
-WRAPPER void CCopPed::ProcessControl() { EAXJMP(0x4C1400); }
+WRAPPER void CCopPed::ProcessControl() { EAXJMP(0x4C1400); }
CCopPed::CCopPed(eCopType copType) : CPed(PEDTYPE_COP)
{
@@ -58,11 +61,16 @@ CCopPed::CCopPed(eCopType copType) : CPed(PEDTYPE_COP)
m_bIsDisabledCop = false;
field_1356 = 0;
m_attackTimer = 0;
- field_1351 = 0;
+ m_bBeatingSuspect = false;
m_bZoneDisabledButClose = false;
m_bZoneDisabled = false;
field_1364 = -1;
m_pPointGunAt = nil;
+
+ // VC also initializes in here, but it keeps object
+#ifdef FIX_BUGS
+ m_wRoadblockNode = -1;
+#endif
}
CCopPed::~CCopPed()
@@ -181,15 +189,15 @@ CCopPed::ClearPursuit(void)
}
}
-// TO-DO: m_MaxCops in for loop may be a bug, check it out after CopAI
+// TODO: I don't know why they needed that parameter.
void
-CCopPed::SetPursuit(bool iMayAlreadyBeInPursuit)
+CCopPed::SetPursuit(bool ignoreCopLimit)
{
CWanted *wanted = FindPlayerPed()->m_pWanted;
if (m_bIsInPursuit || !IsPedInControl())
return;
- if (wanted->m_CurrentCops < wanted->m_MaxCops || iMayAlreadyBeInPursuit) {
+ if (wanted->m_CurrentCops < wanted->m_MaxCops || ignoreCopLimit) {
for (int i = 0; i < wanted->m_MaxCops; ++i) {
if (!wanted->m_pCops[i]) {
m_bIsInPursuit = true;
@@ -275,6 +283,274 @@ CCopPed::ScanForCrimes(void)
}
}
+void
+CCopPed::CopAI(void)
+{
+ CWanted *wanted = FindPlayerPed()->m_pWanted;
+ int wantedLevel = wanted->m_nWantedLevel;
+ CPhysical *playerOrHisVeh = FindPlayerVehicle() ? (CPhysical*)FindPlayerVehicle() : (CPhysical*)FindPlayerPed();
+
+ if (wanted->m_bIgnoredByEveryone || wanted->m_bIgnoredByCops) {
+ if (m_nPedState != PED_ARREST_PLAYER)
+ ClearPursuit();
+
+ return;
+ }
+ if (CCullZones::NoPolice() && m_bIsInPursuit && !m_bIsDisabledCop) {
+ if (bHitSomethingLastFrame) {
+ m_bZoneDisabled = true;
+ m_bIsDisabledCop = true;
+#ifdef FIX_BUGS
+ m_wRoadblockNode = -1;
+#else
+ m_wRoadblockNode = 0;
+#endif
+ bKindaStayInSamePlace = true;
+ bIsRunning = false;
+ bNotAllowedToDuck = false;
+ bCrouchWhenShooting = false;
+ SetIdle();
+ ClearObjective();
+ ClearPursuit();
+ m_prevObjective = OBJECTIVE_NONE;
+ m_nLastPedState = PED_NONE;
+ SetAttackTimer(0);
+ if (m_fDistanceToTarget > 15.0f)
+ m_bZoneDisabledButClose = true;
+ }
+ } else if (m_bZoneDisabled && !CCullZones::NoPolice()) {
+ m_bZoneDisabled = false;
+ m_bIsDisabledCop = false;
+ m_bZoneDisabledButClose = false;
+ bKindaStayInSamePlace = false;
+ bCrouchWhenShooting = false;
+ bDuckAndCover = false;
+ ClearPursuit();
+ }
+ if (wantedLevel > 0) {
+ if (!m_bIsDisabledCop) {
+ if (!m_bIsInPursuit || wanted->m_CurrentCops > wanted->m_MaxCops) {
+ CCopPed *copFarthestToTarget = nil;
+ float copFarthestToTargetDist = m_fDistanceToTarget;
+
+ int oldCopNum = wanted->m_CurrentCops;
+ int maxCops = wanted->m_MaxCops;
+
+ for (int i = 0; i < max(maxCops, oldCopNum); i++) {
+ CCopPed *cop = wanted->m_pCops[i];
+ if (cop && cop->m_fDistanceToTarget > copFarthestToTargetDist) {
+ copFarthestToTargetDist = cop->m_fDistanceToTarget;
+ copFarthestToTarget = wanted->m_pCops[i];
+ }
+ }
+
+ if (m_bIsInPursuit) {
+ if (copFarthestToTarget && oldCopNum > maxCops) {
+ if (copFarthestToTarget == this && m_fDistanceToTarget > 10.0f) {
+ ClearPursuit();
+ } else if(copFarthestToTargetDist > 10.0f)
+ copFarthestToTarget->ClearPursuit();
+ }
+ } else {
+ if (oldCopNum < maxCops) {
+ SetPursuit(true);
+ } else {
+ if (m_fDistanceToTarget <= 10.0f || copFarthestToTarget && m_fDistanceToTarget < copFarthestToTargetDist) {
+ if (copFarthestToTarget && copFarthestToTargetDist > 10.0f)
+ copFarthestToTarget->ClearPursuit();
+
+ SetPursuit(true);
+ }
+ }
+ }
+ } else
+ SetPursuit(false);
+
+ if (!m_bIsInPursuit)
+ return;
+
+ if (wantedLevel > 1 && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED)
+ SetCurrentWeapon(WEAPONTYPE_COLT45);
+ else if (wantedLevel == 1 && GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && !FindPlayerPed()->m_pCurrentPhysSurface) {
+ // i.e. if player is on top of car, cop will still use colt45.
+ SetCurrentWeapon(WEAPONTYPE_UNARMED);
+ }
+
+ if (FindPlayerVehicle()) {
+ if (m_bBeatingSuspect) {
+ --wanted->m_CopsBeatingSuspect;
+ m_bBeatingSuspect = false;
+ }
+ if (m_fDistanceToTarget * FindPlayerSpeed().Magnitude() > 4.0f)
+ ClearPursuit();
+ }
+ return;
+ }
+ float weaponRange = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_fRange;
+ SetLookFlag(playerOrHisVeh, true);
+ TurnBody();
+ SetCurrentWeapon(WEAPONTYPE_COLT45);
+ if (!bIsDucking) {
+ if (m_attackTimer >= CTimer::GetTimeInMilliseconds()) {
+ if (m_nPedState != PED_ATTACK && m_nPedState != PED_FIGHT && !m_bZoneDisabled) {
+ CVector targetDist = playerOrHisVeh->GetPosition() - GetPosition();
+ if (m_fDistanceToTarget > 30.0f) {
+ CAnimBlendAssociation* crouchShootAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RBLOCK_CSHOOT);
+ if (crouchShootAssoc)
+ crouchShootAssoc->blendDelta = -1000.0f;
+
+ // Target is coming onto us
+ if (DotProduct(playerOrHisVeh->m_vecMoveSpeed, targetDist) > 0.0f) {
+ m_bIsDisabledCop = false;
+ bKindaStayInSamePlace = false;
+ bNotAllowedToDuck = false;
+ bDuckAndCover = false;
+ SetPursuit(false);
+ SetObjective(OBJECTIVE_KILL_CHAR_ANY_MEANS, FindPlayerPed());
+ }
+ } else if (m_fDistanceToTarget < 5.0f
+ && (!FindPlayerVehicle() || FindPlayerVehicle()->m_vecMoveSpeed.MagnitudeSqr() < sq(1.f/200.f))) {
+ m_bIsDisabledCop = false;
+ bKindaStayInSamePlace = false;
+ bNotAllowedToDuck = false;
+ bDuckAndCover = false;
+ } else {
+ // VC checks for != nil compared to buggy behaviour of III. I check for != -1 here.
+#ifdef VC_PED_PORTS
+ float dotProd;
+ if (m_wRoadblockNode != -1) {
+ CTreadable *roadBlockRoad = ThePaths.m_mapObjects[CRoadBlocks::RoadBlockObjects[m_wRoadblockNode]];
+ dotProd = DotProduct2D(playerOrHisVeh->GetPosition() - roadBlockRoad->GetPosition(), GetPosition() - roadBlockRoad->GetPosition());
+ } else
+ dotProd = -1.0f;
+
+ if(dotProd >= 0.0f) {
+#else
+
+#ifndef FIX_BUGS
+ float copRoadDotProd, targetRoadDotProd;
+#else
+ float copRoadDotProd = 1.0f, targetRoadDotProd = 1.0f;
+ if (m_wRoadblockNode != -1)
+#endif
+ {
+ CTreadable* roadBlockRoad = ThePaths.m_mapObjects[CRoadBlocks::RoadBlockObjects[m_wRoadblockNode]];
+ CVector2D roadFwd = roadBlockRoad->GetForward();
+ copRoadDotProd = DotProduct2D(GetPosition() - roadBlockRoad->GetPosition(), roadFwd);
+ targetRoadDotProd = DotProduct2D(playerOrHisVeh->GetPosition() - roadBlockRoad->GetPosition(), roadFwd);
+ }
+ // Roadblock may be towards road's fwd or opposite, so check both
+ if ((copRoadDotProd >= 0.0f || targetRoadDotProd >= 0.0f)
+ && (copRoadDotProd <= 0.0f || targetRoadDotProd <= 0.0f)) {
+#endif
+ bIsPointingGunAt = true;
+ } else {
+ m_bIsDisabledCop = false;
+ bKindaStayInSamePlace = false;
+ bNotAllowedToDuck = false;
+ bCrouchWhenShooting = false;
+ bIsDucking = false;
+ bDuckAndCover = false;
+ SetPursuit(false);
+ }
+ }
+ }
+ } else {
+ if (m_fDistanceToTarget < weaponRange) {
+ CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
+ CVector gunPos = weaponInfo->m_vecFireOffset;
+ for (RwFrame *i = GetNodeFrame(PED_HANDR); i; i = RwFrameGetParent(i))
+ RwV3dTransformPoints((RwV3d*)&gunPos, (RwV3d*)&gunPos, 1, RwFrameGetMatrix(i));
+
+ CColPoint foundCol;
+ CEntity *foundEnt;
+ if (!CWorld::ProcessLineOfSight(gunPos, playerOrHisVeh->GetPosition(), foundCol, foundEnt,
+ false, true, false, false, true, false, false)
+ || foundEnt && foundEnt == playerOrHisVeh) {
+ m_pPointGunAt = playerOrHisVeh;
+ if (playerOrHisVeh)
+ playerOrHisVeh->RegisterReference((CEntity**) &m_pPointGunAt);
+
+ SetAttack(playerOrHisVeh);
+ SetShootTimer(CGeneral::GetRandomNumberInRange(500, 1000));
+ }
+ SetAttackTimer(CGeneral::GetRandomNumberInRange(100, 300));
+ }
+ SetMoveState(PEDMOVE_STILL);
+ }
+ }
+ } else {
+ if (!m_bIsDisabledCop || m_bZoneDisabled) {
+ if (m_nPedState != PED_AIM_GUN) {
+ if (m_bIsInPursuit)
+ ClearPursuit();
+
+ if (IsPedInControl()) {
+ // Entering the vehicle
+ if (m_pMyVehicle && !bInVehicle) {
+ if (m_pMyVehicle->IsLawEnforcementVehicle()) {
+ if (m_pMyVehicle->pDriver) {
+ if (m_pMyVehicle->pDriver->m_nPedType == PEDTYPE_COP) {
+ if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER)
+ SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_pMyVehicle);
+ } else if (m_pMyVehicle->pDriver->IsPlayer()) {
+ FindPlayerPed()->SetWantedLevelNoDrop(1);
+ }
+ } else if (m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) {
+ SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle);
+ }
+ } else {
+ m_pMyVehicle = nil;
+ ClearObjective();
+ SetWanderPath(CGeneral::GetRandomNumber() & 7);
+ }
+ }
+#ifdef VC_PED_PORTS
+ else {
+ if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && CharCreatedBy == RANDOM_CHAR) {
+ for (int i = 0; i < m_numNearPeds; i++) {
+ CPed *nearPed = m_nearPeds[i];
+ if (nearPed->CharCreatedBy == RANDOM_CHAR) {
+ if ((nearPed->m_nPedType == PEDTYPE_CRIMINAL || nearPed->IsGangMember())
+ && nearPed->IsPedInControl()) {
+
+ bool anotherCopChasesHim = false;
+ if (nearPed->m_nPedState == PED_FLEE_ENTITY) {
+ if (nearPed->m_fleeFrom && nearPed->m_fleeFrom->IsPed() &&
+ ((CPed*)nearPed->m_fleeFrom)->m_nPedType == PEDTYPE_COP) {
+ anotherCopChasesHim = true;
+ }
+ }
+ if (!anotherCopChasesHim) {
+ SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, nearPed);
+ nearPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, this);
+ nearPed->m_ped_flagE2 = true;
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
+ }
+ }
+ } else {
+ if (m_bIsInPursuit && m_nPedState != PED_AIM_GUN)
+ ClearPursuit();
+
+ m_bIsDisabledCop = false;
+ bKindaStayInSamePlace = false;
+ bNotAllowedToDuck = false;
+ bCrouchWhenShooting = false;
+ bIsDucking = false;
+ bDuckAndCover = false;
+ if (m_pMyVehicle)
+ SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle);
+ }
+ }
+}
+
class CCopPed_ : public CCopPed
{
public:
@@ -290,4 +566,5 @@ STARTPATCHES
InjectHook(0x4C27D0, &CCopPed::SetPursuit, PATCH_JUMP);
InjectHook(0x4C2C90, &CCopPed::ArrestPlayer, PATCH_JUMP);
InjectHook(0x4C26A0, &CCopPed::ScanForCrimes, PATCH_JUMP);
+ InjectHook(0x4C1B50, &CCopPed::CopAI, PATCH_JUMP);
ENDPATCHES
diff --git a/src/peds/CopPed.h b/src/peds/CopPed.h
index 7705eb12..142be56a 100644
--- a/src/peds/CopPed.h
+++ b/src/peds/CopPed.h
@@ -17,9 +17,9 @@ public:
int8 field_1343;
float m_fDistanceToTarget;
int8 m_bIsInPursuit;
- int8 m_bIsDisabledCop;
+ int8 m_bIsDisabledCop; // What disabled cop actually is?
int8 field_1350;
- int8 field_1351;
+ bool m_bBeatingSuspect;
int8 m_bZoneDisabledButClose;
int8 m_bZoneDisabled;
int8 field_1354;
@@ -40,6 +40,7 @@ public:
void SetPursuit(bool);
void ArrestPlayer(void);
void ScanForCrimes(void);
+ void CopAI(void);
};
static_assert(sizeof(CCopPed) == 0x558, "CCopPed: error");
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index db6b7ee2..ae24faa3 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -2720,6 +2720,10 @@ CPed::SetObjective(eObjective newObj, void *entity)
return;
}
+#ifdef VC_PED_PORTS
+ SetObjectiveTimer(0);
+ ClearPointGunAt();
+#endif
bObjectiveCompleted = false;
if (!IsTemporaryObjective(m_objective) || IsTemporaryObjective(newObj)) {
if (m_objective != newObj) {
@@ -3444,8 +3448,12 @@ CPed::ClearAll(void)
m_fleeFrom = nil;
m_fleeTimer = 0;
bUsesCollision = true;
+#ifdef VC_PED_PORTS
+ ClearPointGunAt();
+#else
ClearAimFlag();
ClearLookFlag();
+#endif
bIsPointingGunAt = false;
bRenderPedInCar = true;
bKnockedUpIntoAir = false;
diff --git a/src/peds/Population.cpp b/src/peds/Population.cpp
index d87764ff..6b674dd3 100644
--- a/src/peds/Population.cpp
+++ b/src/peds/Population.cpp
@@ -576,7 +576,7 @@ CPopulation::AddToPopulation(float minDist, float maxDist, float minDistOffScree
}
// Yeah, float
float maxPossiblePedsForArea = (zoneInfo.pedDensity + zoneInfo.carDensity) * playerInfo->m_fRoadDensity * PedDensityMultiplier * CIniFile::PedNumberMultiplier;
- // maxPossiblePedsForArea = min(maxPossiblePedsForArea, MaxNumberOfPedsInUse);
+ maxPossiblePedsForArea = min(maxPossiblePedsForArea, MaxNumberOfPedsInUse);
if (ms_nTotalPeds < maxPossiblePedsForArea || addCop) {
int decisionThreshold = CGeneral::GetRandomNumberInRange(0, 1000);
diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp
index 8c851686..5288e67e 100644
--- a/src/save/GenericGameStorage.cpp
+++ b/src/save/GenericGameStorage.cpp
@@ -61,9 +61,9 @@ do {\
MakeSpaceForSizeInBufferPointer(presize, buf, postsize);\
save_func(buf, &size);\
CopySizeAndPreparePointer(presize, buf, postsize, reserved, size);\
- if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size + 4))\
+ if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff))\
return false;\
- totalSize += size;\
+ totalSize += buf - work_buff;\
} while (0)
bool
@@ -74,7 +74,6 @@ GenericSave(int file)
uint32 reserved;
uint32 totalSize;
- uint32 i;
wchar *lastMissionPassed;
wchar suffix[6];
@@ -85,13 +84,11 @@ GenericSave(int file)
CheckSum = 0;
buf = work_buff;
reserved = 0;
- totalSize = 0;
// Save simple vars
-INITSAVEBUF
lastMissionPassed = TheText.Get(CStats::LastMissionPassedName);
if (*lastMissionPassed) {
- AsciiToUnicode("'...", suffix);
+ AsciiToUnicode("...'", suffix);
TextCopy(saveName, lastMissionPassed);
int len = UnicodeStrlen(saveName);
saveName[len] = '\0';
@@ -104,20 +101,20 @@ INITSAVEBUF
WriteDataToBufferPointer(buf, saveTime);
WriteDataToBufferPointer(buf, SIZE_OF_ONE_GAME_IN_BYTES);
WriteDataToBufferPointer(buf, CGame::currLevel);
- WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.x);
- WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.y);
- WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.z);
+ WriteDataToBufferPointer(buf, TheCamera.GetPosition().x);
+ WriteDataToBufferPointer(buf, TheCamera.GetPosition().y);
+ WriteDataToBufferPointer(buf, TheCamera.GetPosition().z);
WriteDataToBufferPointer(buf, CClock::ms_nMillisecondsPerGameMinute);
WriteDataToBufferPointer(buf, CClock::ms_nLastClockTick);
WriteDataToBufferPointer(buf, CClock::ms_nGameClockHours);
WriteDataToBufferPointer(buf, CClock::ms_nGameClockMinutes);
currPad = CPad::GetPad(0);
WriteDataToBufferPointer(buf, currPad->Mode);
- WriteDataToBufferPointer(buf, CTimer::m_snTimeInMilliseconds);
- WriteDataToBufferPointer(buf, CTimer::ms_fTimeScale);
- WriteDataToBufferPointer(buf, CTimer::ms_fTimeStep);
- WriteDataToBufferPointer(buf, CTimer::ms_fTimeStepNonClipped);
- WriteDataToBufferPointer(buf, CTimer::m_FrameCounter);
+ WriteDataToBufferPointer(buf, CTimer::GetTimeInMilliseconds());
+ WriteDataToBufferPointer(buf, CTimer::GetTimeScale());
+ WriteDataToBufferPointer(buf, CTimer::GetTimeStep());
+ WriteDataToBufferPointer(buf, CTimer::GetTimeStepNonClipped());
+ WriteDataToBufferPointer(buf, CTimer::GetFrameCounter());
WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeStep);
WriteDataToBufferPointer(buf, CTimeStep::ms_fFramesPerUpdate);
WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeScale);
@@ -134,10 +131,8 @@ INITSAVEBUF
WriteDataToBufferPointer(buf, CWeather::WeatherTypeInList);
WriteDataToBufferPointer(buf, TheCamera.CarZoomIndicator);
WriteDataToBufferPointer(buf, TheCamera.PedZoomIndicator);
-#ifdef VALIDATE_SAVE_SIZE
- _saveBufCount = buf - work_buff;
-#endif
-VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
+
+ assert(buf - work_buff == SIZE_OF_SIMPLEVARS);
// Save scripts, block is nested within the same block as simple vars for some reason
presize = buf;
@@ -145,9 +140,10 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
postsize = buf;
CTheScripts::SaveAllScripts(buf, &size);
CopySizeAndPreparePointer(presize, buf, postsize, reserved, size);
- if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size + SIZE_OF_SIMPLEVARS + 4))
+ if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff))
return false;
- totalSize += size + SIZE_OF_SIMPLEVARS;
+
+ totalSize = buf - work_buff;
// Save the rest
WRITE_BLOCK(CPools::SavePedPool);
@@ -171,8 +167,7 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
WRITE_BLOCK(CPedType::Save);
// Write padding
- i = 0;
- do {
+ for (int i = 0; i < 4; i++) {
size = align4bytes(SIZE_OF_ONE_GAME_IN_BYTES - totalSize - 4);
if (size > sizeof(work_buff))
size = sizeof(work_buff);
@@ -181,15 +176,15 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
return false;
totalSize += size;
}
- i++;
- } while (i < 4);
+ }
// Write checksum and close
CFileMgr::Write(file, (const char *) &CheckSum, sizeof(CheckSum));
if (CFileMgr::GetErrorReadWrite(file)) {
PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE;
- if (CloseFile(file))
+ if (!CloseFile(file))
PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE;
+
return false;
}
diff --git a/src/save/PCSave.cpp b/src/save/PCSave.cpp
index 2702bd6e..e94db6db 100644
--- a/src/save/PCSave.cpp
+++ b/src/save/PCSave.cpp
@@ -38,7 +38,7 @@ C_PcSave::SaveSlot(int32 slot)
if (file != 0) {
DoGameSpecificStuffBeforeSave();
if (GenericSave(file)) {
- if (CFileMgr::CloseFile(file) != 0)
+ if (!!CFileMgr::CloseFile(file))
nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE;
return true;
}
@@ -55,21 +55,21 @@ C_PcSave::PcClassSaveRoutine(int32 file, uint8 *data, uint32 size)
CFileMgr::Write(file, (const char*)&size, sizeof(size));
if (CFileMgr::GetErrorReadWrite(file)) {
nErrorCode = SAVESTATUS_ERR_SAVE_WRITE;
- strncpy(SaveFileNameJustSaved, ValidSaveName, 259);
+ strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1);
return false;
}
CFileMgr::Write(file, (const char*)data, align4bytes(size));
- CheckSum += ((uint8*)&size)[0];
- CheckSum += ((uint8*)&size)[1];
- CheckSum += ((uint8*)&size)[2];
- CheckSum += ((uint8*)&size)[3];
+ CheckSum += (uint8) size;
+ CheckSum += (uint8) (size >> 8);
+ CheckSum += (uint8) (size >> 16);
+ CheckSum += (uint8) (size >> 24);
for (int i = 0; i < align4bytes(size); i++) {
CheckSum += *data++;
}
if (CFileMgr::GetErrorReadWrite(file)) {
nErrorCode = SAVESTATUS_ERR_SAVE_WRITE;
- strncpy(SaveFileNameJustSaved, ValidSaveName, 259);
+ strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1);
return false;
}