Merge pull request #355 from erorcun/erorcun

CCopPed 2 and fixes
This commit is contained in:
erorcun 2020-03-26 18:55:12 +03:00 committed by GitHub
commit 29ef6e29f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 575 additions and 185 deletions

View File

@ -11,19 +11,10 @@ CPathFind &ThePaths = *(CPathFind*)0x8F6754;
WRAPPER bool CPedPath::CalcPedRoute(uint8, CVector, CVector, CVector*, int16*, int16) { EAXJMP(0x42E680); } WRAPPER bool CPedPath::CalcPedRoute(uint8, CVector, CVector, CVector*, int16*, int16) { EAXJMP(0x42E680); }
enum #define MAX_DIST INT16_MAX-1
{
NodeTypeExtern = 1,
NodeTypeIntern = 2,
ObjectFlag1 = 1,
ObjectEastWest = 2,
MAX_DIST = INT16_MAX-1
};
// object flags: // object flags:
// 1 // 1 UseInRoadBlock
// 2 east/west road(?) // 2 east/west road(?)
CPathInfoForObject *&InfoForTileCars = *(CPathInfoForObject**)0x8F1A8C; CPathInfoForObject *&InfoForTileCars = *(CPathInfoForObject**)0x8F1A8C;
@ -218,14 +209,14 @@ CPathFind::PreparePathData(void)
if(numIntern == 1 && numExtern == 2){ if(numIntern == 1 && numExtern == 2){
if(numLanes < 4){ if(numLanes < 4){
if((i & 7) == 4){ // WHAT? if((i & 7) == 4){ // WHAT?
m_objectFlags[i] |= ObjectFlag1; m_objectFlags[i] |= UseInRoadBlock;
if(maxX > maxY) if(maxX > maxY)
m_objectFlags[i] |= ObjectEastWest; m_objectFlags[i] |= ObjectEastWest;
else else
m_objectFlags[i] &= ~ObjectEastWest; m_objectFlags[i] &= ~ObjectEastWest;
} }
}else{ }else{
m_objectFlags[i] |= ObjectFlag1; m_objectFlags[i] |= UseInRoadBlock;
if(maxX > maxY) if(maxX > maxY)
m_objectFlags[i] |= ObjectEastWest; m_objectFlags[i] |= ObjectEastWest;
else else

View File

@ -9,6 +9,15 @@ public:
static bool CalcPedRoute(uint8, CVector, CVector, CVector*, int16*, int16); static bool CalcPedRoute(uint8, CVector, CVector, CVector*, int16*, int16);
}; };
enum
{
NodeTypeExtern = 1,
NodeTypeIntern = 2,
UseInRoadBlock = 1,
ObjectEastWest = 2,
};
enum enum
{ {
PATH_CAR = 0, PATH_CAR = 0,

View File

@ -1,7 +1,37 @@
#include "common.h" #include "common.h"
#include "patcher.h" #include "patcher.h"
#include "RoadBlocks.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::GenerateRoadBlockCopsForCar(CVehicle*, int32, int16) { EAXJMP(0x4376A0); }
WRAPPER void CRoadBlocks::GenerateRoadBlocks(void) { EAXJMP(0x436FA0); } 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

View File

@ -6,6 +6,10 @@ class CVehicle;
class CRoadBlocks class CRoadBlocks
{ {
public: public:
static int16 (&NumRoadBlocks);
static int16 (&RoadBlockObjects)[NUMROADBLOCKS];
static bool (&InOrOut)[NUMROADBLOCKS];
static void Init(void); static void Init(void);
static void GenerateRoadBlockCopsForCar(CVehicle*, int32, int16); static void GenerateRoadBlockCopsForCar(CVehicle*, int32, int16);
static void GenerateRoadBlocks(void); static void GenerateRoadBlocks(void);

View File

@ -417,6 +417,11 @@ void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonDown(int32 button, i
case 13: case 13:
pad->PCTempJoyState.DPadUp = 255; pad->PCTempJoyState.DPadUp = 255;
break; break;
#ifdef REGISTER_START_BUTTON
case 12:
pad->PCTempJoyState.Start = 255;
break;
#endif
case 11: case 11:
pad->PCTempJoyState.RightShock = 255; pad->PCTempJoyState.RightShock = 255;
break; break;
@ -839,6 +844,11 @@ void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonUp(int32 button, int
case 13: case 13:
pad->PCTempJoyState.DPadUp = 0; pad->PCTempJoyState.DPadUp = 0;
break; break;
#ifdef REGISTER_START_BUTTON
case 12:
pad->PCTempJoyState.Start = 0;
break;
#endif
case 11: case 11:
pad->PCTempJoyState.RightShock = 0; pad->PCTempJoyState.RightShock = 0;
break; break;

View File

@ -5,10 +5,13 @@
#include "World.h" #include "World.h"
#include "Wanted.h" #include "Wanted.h"
#include "EventList.h" #include "EventList.h"
#include "Messages.h"
#include "Text.h"
#include "main.h"
int32 CEventList::ms_nFirstFreeSlotIndex; int32 CEventList::ms_nFirstFreeSlotIndex;
//CEvent gaEvent[NUMEVENTS]; CEvent gaEvent[NUMEVENTS];
CEvent *gaEvent = (CEvent*)0x6EF830; //CEvent *gaEvent = (CEvent*)0x6EF830;
enum enum
{ {
@ -207,8 +210,20 @@ CEventList::ReportCrimeForEvent(eEventType type, int32 crimeId, bool copsDontCar
default: crime = CRIME_NONE; break; default: crime = CRIME_NONE; break;
} }
if(crime == CRIME_NONE) #ifdef VC_PED_PORTS
return; 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 playerPedCoors = FindPlayerPed()->GetPosition();
CVector playerCoors = FindPlayerCoors(); CVector playerCoors = FindPlayerCoors();

View File

@ -63,4 +63,4 @@ public:
static void ReportCrimeForEvent(eEventType type, int32, bool); static void ReportCrimeForEvent(eEventType type, int32, bool);
}; };
extern CEvent *gaEvent; extern CEvent gaEvent[NUMEVENTS];

View File

@ -181,6 +181,7 @@ ScaleAndCenterX(float x)
#endif #endif
#define isPlainTextScreen(screen) (screen == MENUPAGE_BRIEFS || screen == MENUPAGE_STATS) #define isPlainTextScreen(screen) (screen == MENUPAGE_BRIEFS || screen == MENUPAGE_STATS)
#ifdef PS2_LIKE_MENU #ifdef PS2_LIKE_MENU
#define ChangeScreen(screen, option, updateDelay, withReverseAlpha) \ #define ChangeScreen(screen, option, updateDelay, withReverseAlpha) \
do { \ do { \
@ -235,67 +236,100 @@ ScaleAndCenterX(float x)
m_nHoverOption = HOVEROPTION_NOT_HOVERING; \ m_nHoverOption = HOVEROPTION_NOT_HOVERING; \
} while(0) } while(0)
#define ScrollUpListByOne() \ // --- Functions not in the game/inlined starts
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)
#define ScrollDownListByOne() \ inline void
do { \ CMenuManager::ScrollUpListByOne()
if (m_nSelectedListRow == m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1) { \ {
if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { \ if (m_nSelectedListRow == m_nFirstVisibleRowOnList) {
m_nSelectedListRow++; \ if (m_nFirstVisibleRowOnList > 0) {
m_nFirstVisibleRowOnList++; \ m_nSelectedListRow--;
m_nCurListItemY += LIST_HEIGHT / m_nTotalListRow; \ m_nFirstVisibleRowOnList--;
} \ m_nCurListItemY -= LIST_HEIGHT / m_nTotalListRow;
} else { \ }
if (m_nSelectedListRow < m_nTotalListRow - 1) { \ } else {
m_nSelectedListRow++; \ m_nSelectedListRow--;
} \ }
} \ }
} while(0)
#define PageUpList(playSoundOnSuccess) \ inline void
do { \ CMenuManager::ScrollDownListByOne()
if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { \ {
if (m_nFirstVisibleRowOnList > 0) { \ if (m_nSelectedListRow == m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1) {
if(playSoundOnSuccess) \ if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) {
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); \ m_nSelectedListRow++;
\ m_nFirstVisibleRowOnList++;
m_nFirstVisibleRowOnList = max(0, m_nFirstVisibleRowOnList - MAX_VISIBLE_LIST_ROW); \ m_nCurListItemY += LIST_HEIGHT / m_nTotalListRow;
m_nSelectedListRow = min(m_nSelectedListRow, m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1); \ }
} else { \ } else {
m_nFirstVisibleRowOnList = 0; \ if (m_nSelectedListRow < m_nTotalListRow - 1) {
m_nSelectedListRow = 0; \ m_nSelectedListRow++;
} \ }
m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; \ }
} \ }
} while(0)
#define PageDownList(playSoundOnSuccess) \ inline void
do { \ CMenuManager::PageUpList(bool playSoundOnSuccess)
if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { \ {
if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { \ if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) {
if(playSoundOnSuccess) \ if (m_nFirstVisibleRowOnList > 0) {
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); \ 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); \ m_nFirstVisibleRowOnList = max(0, m_nFirstVisibleRowOnList - MAX_VISIBLE_LIST_ROW);
} else { \ m_nSelectedListRow = min(m_nSelectedListRow, m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1);
m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW; \ } else {
m_nSelectedListRow = m_nTotalListRow - 1; \ m_nFirstVisibleRowOnList = 0;
} \ m_nSelectedListRow = 0;
m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; \ }
} \ m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
} while(0) }
}
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 void
CMenuManager::BuildStatLine(char *text, void *stat, uint8 aFloat, void *stat2) CMenuManager::BuildStatLine(char *text, void *stat, uint8 aFloat, void *stat2)
@ -1173,7 +1207,6 @@ void CMenuManager::DrawFrontEnd()
bbNames[5] = { "FESZ_QU",MENUPAGE_EXIT }; bbNames[5] = { "FESZ_QU",MENUPAGE_EXIT };
bbTabCount = 6; bbTabCount = 6;
} }
m_nCurrScreen = MENUPAGE_NEW_GAME;
} else { } else {
if (bbTabCount != 8) { if (bbTabCount != 8) {
bbNames[0] = { "FEB_STA",MENUPAGE_STATS }; bbNames[0] = { "FEB_STA",MENUPAGE_STATS };
@ -1186,8 +1219,8 @@ void CMenuManager::DrawFrontEnd()
bbNames[7] = { "FESZ_QU",MENUPAGE_EXIT }; bbNames[7] = { "FESZ_QU",MENUPAGE_EXIT };
bbTabCount = 8; bbTabCount = 8;
} }
m_nCurrScreen = MENUPAGE_STATS;
} }
m_nCurrScreen = bbNames[0].screenId;
bottomBarActive = true; bottomBarActive = true;
curBottomBarOption = 0; curBottomBarOption = 0;
} }
@ -1285,7 +1318,6 @@ void CMenuManager::DrawFrontEndNormal()
eFrontendSprites currentSprite; eFrontendSprites currentSprite;
switch (m_nCurrScreen) { switch (m_nCurrScreen) {
case MENUPAGE_STATS: case MENUPAGE_STATS:
case MENUPAGE_NEW_GAME:
case MENUPAGE_START_MENU: case MENUPAGE_START_MENU:
case MENUPAGE_PAUSE_MENU: case MENUPAGE_PAUSE_MENU:
case MENUPAGE_EXIT: case MENUPAGE_EXIT:
@ -1315,7 +1347,7 @@ void CMenuManager::DrawFrontEndNormal()
currentSprite = FE_ICONCONTROLS; currentSprite = FE_ICONCONTROLS;
break; break;
default: default:
/* actually MENUPAGE_NEW_GAME too*/ /*case MENUPAGE_NEW_GAME: */
/*case MENUPAGE_BRIEFS: */ /*case MENUPAGE_BRIEFS: */
currentSprite = FE_ICONBRIEF; currentSprite = FE_ICONBRIEF;
break; 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)); 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) { if (m_nMenuFadeAlpha < 255) {
static int LastFade = 0; static uint32 LastFade = 0;
if (m_nMenuFadeAlpha <= 0 && reverseAlpha) { if (m_nMenuFadeAlpha <= 0 && reverseAlpha) {
reverseAlpha = false; reverseAlpha = false;
ChangeScreen(pendingScreen, pendingOption, true, false); ChangeScreen(pendingScreen, pendingOption, true, false);
} else if(CTimer::GetTimeInMillisecondsPauseMode() - LastFade > 10){ } else {
if (!reverseAlpha) if (!reverseAlpha)
m_nMenuFadeAlpha += 20; m_nMenuFadeAlpha += min((CTimer::GetTimeInMillisecondsPauseMode() - LastFade) / 33.0f, 1.0f) * 20.0f;
else 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(); LastFade = CTimer::GetTimeInMillisecondsPauseMode();
} }
@ -1537,12 +1569,18 @@ void CMenuManager::DrawFrontEndNormal()
} }
if (m_nMenuFadeAlpha < 255) { 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){ if(CTimer::GetTimeInMillisecondsPauseMode() - LastFade > 10){
m_nMenuFadeAlpha += 20; m_nMenuFadeAlpha += 20;
LastFade = CTimer::GetTimeInMillisecondsPauseMode(); LastFade = CTimer::GetTimeInMillisecondsPauseMode();
} }
#endif
if (m_nMenuFadeAlpha > 255){ if (m_nMenuFadeAlpha > 255){
m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 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 #else
void CMenuManager::Process(void) void CMenuManager::Process(void)
{ {
m_bMenuNotProcessed = false; m_bMenuStateChanged = false;
if (!m_bSaveMenuActive && TheCamera.GetScreenFadeStatus() != FADE_0) if (!m_bSaveMenuActive && TheCamera.GetScreenFadeStatus() != FADE_0)
return; return;
@ -2701,6 +2739,8 @@ CMenuManager::ProcessButtonPresses(void)
if (CPad::GetPad(0)->GetEnterJustDown() || CPad::GetPad(0)->GetCrossJustDown()) { if (CPad::GetPad(0)->GetEnterJustDown() || CPad::GetPad(0)->GetCrossJustDown()) {
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
bottomBarActive = false; bottomBarActive = false;
// If there's a menu change with fade ongoing, finish it now
if (reverseAlpha) if (reverseAlpha)
m_nMenuFadeAlpha = 0; m_nMenuFadeAlpha = 0;
return; return;
@ -3116,51 +3156,43 @@ CMenuManager::ProcessButtonPresses(void)
if (goBack) { if (goBack) {
CMenuManager::ResetHelperText(); CMenuManager::ResetHelperText();
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_EXIT, 0); 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 #ifdef PS2_LIKE_MENU
if (bottomBarActive){ if (m_nCurrScreen == MENUPAGE_PAUSE_MENU || bottomBarActive) {
bottomBarActive = false; #else
if (!m_bGameNotLoaded) { if (m_nCurrScreen == MENUPAGE_PAUSE_MENU) {
#endif
if (!m_bGameNotLoaded && !m_bMenuStateChanged) {
if (CMenuManager::m_PrefsVsyncDisp != CMenuManager::m_PrefsVsync) { if (CMenuManager::m_PrefsVsyncDisp != CMenuManager::m_PrefsVsync) {
CMenuManager::m_PrefsVsync = CMenuManager::m_PrefsVsyncDisp; CMenuManager::m_PrefsVsync = CMenuManager::m_PrefsVsyncDisp;
} }
CMenuManager::RequestFrontEndShutDown(); CMenuManager::RequestFrontEndShutDown();
} }
// We're already resuming, we don't need further processing.
#if defined(FIX_BUGS) || defined(PS2_LIKE_MENU)
return; 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 #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 (oldScreen != -1) {
if ((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && strcmp(m_aSkinName, m_PrefsSkinFile) != 0) { ThingsToDoBeforeLeavingPage();
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();
}
#ifdef PS2_LIKE_MENU #ifdef PS2_LIKE_MENU
if (!bottomBarActive && if (!bottomBarActive &&
@ -3168,10 +3200,8 @@ CMenuManager::ProcessButtonPresses(void)
bottomBarActive = true; bottomBarActive = true;
} else } else
#endif #endif
{
ChangeScreen(oldScreen, oldOption, true, true); 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?! // We will go back for sure at this point, why process other things?!
@ -3512,11 +3542,16 @@ WRAPPER void CMenuManager::SwitchMenuOnAndOff() { EAXJMP(0x488790); }
#else #else
void CMenuManager::SwitchMenuOnAndOff() void CMenuManager::SwitchMenuOnAndOff()
{ {
if (!!(CPad::GetPad(0)->NewState.Start && !CPad::GetPad(0)->OldState.Start) bool menuWasActive = !!m_bMenuActive;
|| m_bShutDownFrontEndRequested || m_bStartUpFrontEndRequested) {
if (!m_bMenuActive) // Reminder: You need REGISTER_START_BUTTON defined to make it work.
m_bMenuActive = true; if (CPad::GetPad(0)->GetStartJustDown()
#ifdef FIX_BUGS
&& !m_bGameNotLoaded
#endif
|| m_bShutDownFrontEndRequested || m_bStartUpFrontEndRequested) {
m_bMenuActive = !m_bMenuActive;
if (m_bShutDownFrontEndRequested) if (m_bShutDownFrontEndRequested)
m_bMenuActive = false; m_bMenuActive = false;
@ -3525,8 +3560,13 @@ void CMenuManager::SwitchMenuOnAndOff()
if (m_bMenuActive) { if (m_bMenuActive) {
CTimer::StartUserPause(); CTimer::StartUserPause();
} } else {
else { #ifdef PS2_LIKE_MENU
bottomBarActive = false;
#endif
#ifdef FIX_BUGS
ThingsToDoBeforeLeavingPage();
#endif
ShutdownJustMenu(); ShutdownJustMenu();
SaveSettings(); SaveSettings();
m_bStartUpFrontEndRequested = false; m_bStartUpFrontEndRequested = false;
@ -3553,7 +3593,7 @@ void CMenuManager::SwitchMenuOnAndOff()
PcSaveHelper.PopulateSlotInfo(); PcSaveHelper.PopulateSlotInfo();
m_nCurrOption = 0; m_nCurrOption = 0;
} }
/* // Unused? /* // PS2 leftover?
if (m_nCurrScreen != MENUPAGE_SOUND_SETTINGS && gMusicPlaying) if (m_nCurrScreen != MENUPAGE_SOUND_SETTINGS && gMusicPlaying)
{ {
DMAudio.StopFrontEndTrack(); DMAudio.StopFrontEndTrack();
@ -3561,8 +3601,8 @@ void CMenuManager::SwitchMenuOnAndOff()
gMusicPlaying = 0; gMusicPlaying = 0;
} }
*/ */
if (!m_bMenuActive) if (m_bMenuActive != menuWasActive)
m_bMenuNotProcessed = true; m_bMenuStateChanged = true;
m_bStartUpFrontEndRequested = false; m_bStartUpFrontEndRequested = false;
m_bShutDownFrontEndRequested = false; m_bShutDownFrontEndRequested = false;

View File

@ -403,7 +403,7 @@ public:
int32 m_nHelperTextMsgId; int32 m_nHelperTextMsgId;
bool m_bLanguageLoaded; bool m_bLanguageLoaded;
bool m_bMenuActive; bool m_bMenuActive;
bool m_bMenuNotProcessed; bool m_bMenuStateChanged;
bool m_bWaitingForNewKeyBind; bool m_bWaitingForNewKeyBind;
bool m_bStartGameLoading; bool m_bStartGameLoading;
bool m_bFirstTime; bool m_bFirstTime;
@ -540,8 +540,14 @@ public:
void WaitForUserCD(); void WaitForUserCD();
void PrintController(); void PrintController();
// New content: // New (not in function or inlined in the game)
uint8 GetNumberOfMenuOptions(); void ThingsToDoBeforeLeavingPage();
void ScrollUpListByOne();
void ScrollDownListByOne();
void PageUpList(bool);
void PageDownList(bool);
// uint8 GetNumberOfMenuOptions();
}; };
static_assert(sizeof(CMenuManager) == 0x564, "CMenuManager: error"); static_assert(sizeof(CMenuManager) == 0x564, "CMenuManager: error");

View File

@ -2,7 +2,7 @@
class CTimer class CTimer
{ {
public:
static uint32 &m_snTimeInMilliseconds; static uint32 &m_snTimeInMilliseconds;
static uint32 &m_snTimeInMillisecondsPauseMode; static uint32 &m_snTimeInMillisecondsPauseMode;
static uint32 &m_snTimeInMillisecondsNonClipped; static uint32 &m_snTimeInMillisecondsNonClipped;
@ -11,19 +11,20 @@ public:
static float &ms_fTimeScale; static float &ms_fTimeScale;
static float &ms_fTimeStep; static float &ms_fTimeStep;
static float &ms_fTimeStepNonClipped; static float &ms_fTimeStepNonClipped;
public:
static bool &m_UserPause; static bool &m_UserPause;
static bool &m_CodePause; 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 void SetTimeStep(float ts) { ms_fTimeStep = ts; }
static float GetTimeStepInSeconds() { return ms_fTimeStep / 50.0f; } static float GetTimeStepInSeconds() { return ms_fTimeStep / 50.0f; }
static float GetTimeStepInMilliseconds() { return ms_fTimeStep / 50.0f * 1000.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 float GetTimeStepNonClippedInSeconds(void) { return ms_fTimeStepNonClipped / 50.0f; }
static void SetTimeStepNonClipped(float ts) { ms_fTimeStepNonClipped = ts; } 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 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 void SetTimeInMilliseconds(uint32 t) { m_snTimeInMilliseconds = t; }
static uint32 GetTimeInMillisecondsNonClipped(void) { return m_snTimeInMillisecondsNonClipped; } static uint32 GetTimeInMillisecondsNonClipped(void) { return m_snTimeInMillisecondsNonClipped; }
static void SetTimeInMillisecondsNonClipped(uint32 t) { m_snTimeInMillisecondsNonClipped = t; } static void SetTimeInMillisecondsNonClipped(uint32 t) { m_snTimeInMillisecondsNonClipped = t; }
@ -31,7 +32,7 @@ public:
static void SetTimeInMillisecondsPauseMode(uint32 t) { m_snTimeInMillisecondsPauseMode = t; } static void SetTimeInMillisecondsPauseMode(uint32 t) { m_snTimeInMillisecondsPauseMode = t; }
static uint32 GetPreviousTimeInMilliseconds(void) { return m_snPreviousTimeInMilliseconds; } static uint32 GetPreviousTimeInMilliseconds(void) { return m_snPreviousTimeInMilliseconds; }
static void SetPreviousTimeInMilliseconds(uint32 t) { m_snPreviousTimeInMilliseconds = t; } 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 void SetTimeScale(float ts) { ms_fTimeScale = ts; }
static bool GetIsPaused() { return m_UserPause || m_CodePause; } static bool GetIsPaused() { return m_UserPause || m_CodePause; }

View File

@ -101,6 +101,8 @@ enum Config {
NUMPEDGROUPS = 31, NUMPEDGROUPS = 31,
NUMMODELSPERPEDGROUP = 8, NUMMODELSPERPEDGROUP = 8,
NUMROADBLOCKS = 600,
NUMVISIBLEENTITIES = 2000, NUMVISIBLEENTITIES = 2000,
NUMINVISIBLEENTITIES = 150, NUMINVISIBLEENTITIES = 150,
@ -169,10 +171,11 @@ enum Config {
#endif #endif
#define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more #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 // Pad
#define KANGAROO_CHEAT #define KANGAROO_CHEAT
#define REGISTER_START_BUTTON // currently only in menu sadly. resumes the game
// Hud, frontend and radar // Hud, frontend and radar
#define ASPECT_RATIO_SCALE // Not just makes everything scale with aspect ratio, also adds support for all aspect ratios #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 // Peds
#define ANIMATE_PED_COL_MODEL #define ANIMATE_PED_COL_MODEL
#define VC_PED_PORTS // various ports from VC's CPed, mostly subtle #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 #define CANCELLABLE_CAR_ENTER

View File

@ -7,8 +7,11 @@
#include "Vehicle.h" #include "Vehicle.h"
#include "RpAnimBlend.h" #include "RpAnimBlend.h"
#include "General.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) CCopPed::CCopPed(eCopType copType) : CPed(PEDTYPE_COP)
{ {
@ -58,11 +61,16 @@ CCopPed::CCopPed(eCopType copType) : CPed(PEDTYPE_COP)
m_bIsDisabledCop = false; m_bIsDisabledCop = false;
field_1356 = 0; field_1356 = 0;
m_attackTimer = 0; m_attackTimer = 0;
field_1351 = 0; m_bBeatingSuspect = false;
m_bZoneDisabledButClose = false; m_bZoneDisabledButClose = false;
m_bZoneDisabled = false; m_bZoneDisabled = false;
field_1364 = -1; field_1364 = -1;
m_pPointGunAt = nil; m_pPointGunAt = nil;
// VC also initializes in here, but it keeps object
#ifdef FIX_BUGS
m_wRoadblockNode = -1;
#endif
} }
CCopPed::~CCopPed() 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 void
CCopPed::SetPursuit(bool iMayAlreadyBeInPursuit) CCopPed::SetPursuit(bool ignoreCopLimit)
{ {
CWanted *wanted = FindPlayerPed()->m_pWanted; CWanted *wanted = FindPlayerPed()->m_pWanted;
if (m_bIsInPursuit || !IsPedInControl()) if (m_bIsInPursuit || !IsPedInControl())
return; 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) { for (int i = 0; i < wanted->m_MaxCops; ++i) {
if (!wanted->m_pCops[i]) { if (!wanted->m_pCops[i]) {
m_bIsInPursuit = true; 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 class CCopPed_ : public CCopPed
{ {
public: public:
@ -290,4 +566,5 @@ STARTPATCHES
InjectHook(0x4C27D0, &CCopPed::SetPursuit, PATCH_JUMP); InjectHook(0x4C27D0, &CCopPed::SetPursuit, PATCH_JUMP);
InjectHook(0x4C2C90, &CCopPed::ArrestPlayer, PATCH_JUMP); InjectHook(0x4C2C90, &CCopPed::ArrestPlayer, PATCH_JUMP);
InjectHook(0x4C26A0, &CCopPed::ScanForCrimes, PATCH_JUMP); InjectHook(0x4C26A0, &CCopPed::ScanForCrimes, PATCH_JUMP);
InjectHook(0x4C1B50, &CCopPed::CopAI, PATCH_JUMP);
ENDPATCHES ENDPATCHES

View File

@ -17,9 +17,9 @@ public:
int8 field_1343; int8 field_1343;
float m_fDistanceToTarget; float m_fDistanceToTarget;
int8 m_bIsInPursuit; int8 m_bIsInPursuit;
int8 m_bIsDisabledCop; int8 m_bIsDisabledCop; // What disabled cop actually is?
int8 field_1350; int8 field_1350;
int8 field_1351; bool m_bBeatingSuspect;
int8 m_bZoneDisabledButClose; int8 m_bZoneDisabledButClose;
int8 m_bZoneDisabled; int8 m_bZoneDisabled;
int8 field_1354; int8 field_1354;
@ -40,6 +40,7 @@ public:
void SetPursuit(bool); void SetPursuit(bool);
void ArrestPlayer(void); void ArrestPlayer(void);
void ScanForCrimes(void); void ScanForCrimes(void);
void CopAI(void);
}; };
static_assert(sizeof(CCopPed) == 0x558, "CCopPed: error"); static_assert(sizeof(CCopPed) == 0x558, "CCopPed: error");

View File

@ -2720,6 +2720,10 @@ CPed::SetObjective(eObjective newObj, void *entity)
return; return;
} }
#ifdef VC_PED_PORTS
SetObjectiveTimer(0);
ClearPointGunAt();
#endif
bObjectiveCompleted = false; bObjectiveCompleted = false;
if (!IsTemporaryObjective(m_objective) || IsTemporaryObjective(newObj)) { if (!IsTemporaryObjective(m_objective) || IsTemporaryObjective(newObj)) {
if (m_objective != newObj) { if (m_objective != newObj) {
@ -3444,8 +3448,12 @@ CPed::ClearAll(void)
m_fleeFrom = nil; m_fleeFrom = nil;
m_fleeTimer = 0; m_fleeTimer = 0;
bUsesCollision = true; bUsesCollision = true;
#ifdef VC_PED_PORTS
ClearPointGunAt();
#else
ClearAimFlag(); ClearAimFlag();
ClearLookFlag(); ClearLookFlag();
#endif
bIsPointingGunAt = false; bIsPointingGunAt = false;
bRenderPedInCar = true; bRenderPedInCar = true;
bKnockedUpIntoAir = false; bKnockedUpIntoAir = false;

View File

@ -576,7 +576,7 @@ CPopulation::AddToPopulation(float minDist, float maxDist, float minDistOffScree
} }
// Yeah, float // Yeah, float
float maxPossiblePedsForArea = (zoneInfo.pedDensity + zoneInfo.carDensity) * playerInfo->m_fRoadDensity * PedDensityMultiplier * CIniFile::PedNumberMultiplier; 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) { if (ms_nTotalPeds < maxPossiblePedsForArea || addCop) {
int decisionThreshold = CGeneral::GetRandomNumberInRange(0, 1000); int decisionThreshold = CGeneral::GetRandomNumberInRange(0, 1000);

View File

@ -61,9 +61,9 @@ do {\
MakeSpaceForSizeInBufferPointer(presize, buf, postsize);\ MakeSpaceForSizeInBufferPointer(presize, buf, postsize);\
save_func(buf, &size);\ save_func(buf, &size);\
CopySizeAndPreparePointer(presize, buf, postsize, reserved, 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;\ return false;\
totalSize += size;\ totalSize += buf - work_buff;\
} while (0) } while (0)
bool bool
@ -74,7 +74,6 @@ GenericSave(int file)
uint32 reserved; uint32 reserved;
uint32 totalSize; uint32 totalSize;
uint32 i;
wchar *lastMissionPassed; wchar *lastMissionPassed;
wchar suffix[6]; wchar suffix[6];
@ -85,13 +84,11 @@ GenericSave(int file)
CheckSum = 0; CheckSum = 0;
buf = work_buff; buf = work_buff;
reserved = 0; reserved = 0;
totalSize = 0;
// Save simple vars // Save simple vars
INITSAVEBUF
lastMissionPassed = TheText.Get(CStats::LastMissionPassedName); lastMissionPassed = TheText.Get(CStats::LastMissionPassedName);
if (*lastMissionPassed) { if (*lastMissionPassed) {
AsciiToUnicode("'...", suffix); AsciiToUnicode("...'", suffix);
TextCopy(saveName, lastMissionPassed); TextCopy(saveName, lastMissionPassed);
int len = UnicodeStrlen(saveName); int len = UnicodeStrlen(saveName);
saveName[len] = '\0'; saveName[len] = '\0';
@ -104,20 +101,20 @@ INITSAVEBUF
WriteDataToBufferPointer(buf, saveTime); WriteDataToBufferPointer(buf, saveTime);
WriteDataToBufferPointer(buf, SIZE_OF_ONE_GAME_IN_BYTES); WriteDataToBufferPointer(buf, SIZE_OF_ONE_GAME_IN_BYTES);
WriteDataToBufferPointer(buf, CGame::currLevel); WriteDataToBufferPointer(buf, CGame::currLevel);
WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.x); WriteDataToBufferPointer(buf, TheCamera.GetPosition().x);
WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.y); WriteDataToBufferPointer(buf, TheCamera.GetPosition().y);
WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.z); WriteDataToBufferPointer(buf, TheCamera.GetPosition().z);
WriteDataToBufferPointer(buf, CClock::ms_nMillisecondsPerGameMinute); WriteDataToBufferPointer(buf, CClock::ms_nMillisecondsPerGameMinute);
WriteDataToBufferPointer(buf, CClock::ms_nLastClockTick); WriteDataToBufferPointer(buf, CClock::ms_nLastClockTick);
WriteDataToBufferPointer(buf, CClock::ms_nGameClockHours); WriteDataToBufferPointer(buf, CClock::ms_nGameClockHours);
WriteDataToBufferPointer(buf, CClock::ms_nGameClockMinutes); WriteDataToBufferPointer(buf, CClock::ms_nGameClockMinutes);
currPad = CPad::GetPad(0); currPad = CPad::GetPad(0);
WriteDataToBufferPointer(buf, currPad->Mode); WriteDataToBufferPointer(buf, currPad->Mode);
WriteDataToBufferPointer(buf, CTimer::m_snTimeInMilliseconds); WriteDataToBufferPointer(buf, CTimer::GetTimeInMilliseconds());
WriteDataToBufferPointer(buf, CTimer::ms_fTimeScale); WriteDataToBufferPointer(buf, CTimer::GetTimeScale());
WriteDataToBufferPointer(buf, CTimer::ms_fTimeStep); WriteDataToBufferPointer(buf, CTimer::GetTimeStep());
WriteDataToBufferPointer(buf, CTimer::ms_fTimeStepNonClipped); WriteDataToBufferPointer(buf, CTimer::GetTimeStepNonClipped());
WriteDataToBufferPointer(buf, CTimer::m_FrameCounter); WriteDataToBufferPointer(buf, CTimer::GetFrameCounter());
WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeStep); WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeStep);
WriteDataToBufferPointer(buf, CTimeStep::ms_fFramesPerUpdate); WriteDataToBufferPointer(buf, CTimeStep::ms_fFramesPerUpdate);
WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeScale); WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeScale);
@ -134,10 +131,8 @@ INITSAVEBUF
WriteDataToBufferPointer(buf, CWeather::WeatherTypeInList); WriteDataToBufferPointer(buf, CWeather::WeatherTypeInList);
WriteDataToBufferPointer(buf, TheCamera.CarZoomIndicator); WriteDataToBufferPointer(buf, TheCamera.CarZoomIndicator);
WriteDataToBufferPointer(buf, TheCamera.PedZoomIndicator); WriteDataToBufferPointer(buf, TheCamera.PedZoomIndicator);
#ifdef VALIDATE_SAVE_SIZE
_saveBufCount = buf - work_buff; assert(buf - work_buff == SIZE_OF_SIMPLEVARS);
#endif
VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
// Save scripts, block is nested within the same block as simple vars for some reason // Save scripts, block is nested within the same block as simple vars for some reason
presize = buf; presize = buf;
@ -145,9 +140,10 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
postsize = buf; postsize = buf;
CTheScripts::SaveAllScripts(buf, &size); CTheScripts::SaveAllScripts(buf, &size);
CopySizeAndPreparePointer(presize, buf, postsize, reserved, 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; return false;
totalSize += size + SIZE_OF_SIMPLEVARS;
totalSize = buf - work_buff;
// Save the rest // Save the rest
WRITE_BLOCK(CPools::SavePedPool); WRITE_BLOCK(CPools::SavePedPool);
@ -171,8 +167,7 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
WRITE_BLOCK(CPedType::Save); WRITE_BLOCK(CPedType::Save);
// Write padding // Write padding
i = 0; for (int i = 0; i < 4; i++) {
do {
size = align4bytes(SIZE_OF_ONE_GAME_IN_BYTES - totalSize - 4); size = align4bytes(SIZE_OF_ONE_GAME_IN_BYTES - totalSize - 4);
if (size > sizeof(work_buff)) if (size > sizeof(work_buff))
size = sizeof(work_buff); size = sizeof(work_buff);
@ -181,15 +176,15 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
return false; return false;
totalSize += size; totalSize += size;
} }
i++; }
} while (i < 4);
// Write checksum and close // Write checksum and close
CFileMgr::Write(file, (const char *) &CheckSum, sizeof(CheckSum)); CFileMgr::Write(file, (const char *) &CheckSum, sizeof(CheckSum));
if (CFileMgr::GetErrorReadWrite(file)) { if (CFileMgr::GetErrorReadWrite(file)) {
PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE;
if (CloseFile(file)) if (!CloseFile(file))
PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE;
return false; return false;
} }

View File

@ -38,7 +38,7 @@ C_PcSave::SaveSlot(int32 slot)
if (file != 0) { if (file != 0) {
DoGameSpecificStuffBeforeSave(); DoGameSpecificStuffBeforeSave();
if (GenericSave(file)) { if (GenericSave(file)) {
if (CFileMgr::CloseFile(file) != 0) if (!!CFileMgr::CloseFile(file))
nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE;
return true; return true;
} }
@ -55,21 +55,21 @@ C_PcSave::PcClassSaveRoutine(int32 file, uint8 *data, uint32 size)
CFileMgr::Write(file, (const char*)&size, sizeof(size)); CFileMgr::Write(file, (const char*)&size, sizeof(size));
if (CFileMgr::GetErrorReadWrite(file)) { if (CFileMgr::GetErrorReadWrite(file)) {
nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; nErrorCode = SAVESTATUS_ERR_SAVE_WRITE;
strncpy(SaveFileNameJustSaved, ValidSaveName, 259); strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1);
return false; return false;
} }
CFileMgr::Write(file, (const char*)data, align4bytes(size)); CFileMgr::Write(file, (const char*)data, align4bytes(size));
CheckSum += ((uint8*)&size)[0]; CheckSum += (uint8) size;
CheckSum += ((uint8*)&size)[1]; CheckSum += (uint8) (size >> 8);
CheckSum += ((uint8*)&size)[2]; CheckSum += (uint8) (size >> 16);
CheckSum += ((uint8*)&size)[3]; CheckSum += (uint8) (size >> 24);
for (int i = 0; i < align4bytes(size); i++) { for (int i = 0; i < align4bytes(size); i++) {
CheckSum += *data++; CheckSum += *data++;
} }
if (CFileMgr::GetErrorReadWrite(file)) { if (CFileMgr::GetErrorReadWrite(file)) {
nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; nErrorCode = SAVESTATUS_ERR_SAVE_WRITE;
strncpy(SaveFileNameJustSaved, ValidSaveName, 259); strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1);
return false; return false;
} }