Initial commit

This commit is contained in:
Shinovon 2026-04-22 07:30:27 +05:00
commit 77cdaaf97e
827 changed files with 418745 additions and 0 deletions

128
src/core/Accident.cpp Normal file
View file

@ -0,0 +1,128 @@
#include "common.h"
#include "Accident.h"
#include "Ped.h"
#include "Pools.h"
#include "World.h"
CAccidentManager gAccidentManager;
CAccident*
CAccidentManager::GetNextFreeAccident()
{
for (int i = 0; i < NUM_ACCIDENTS; i++) {
if (m_aAccidents[i].m_pVictim == nil)
return &m_aAccidents[i];
}
return nil;
}
void
CAccidentManager::ReportAccident(CPed *ped)
{
if (!ped->IsPlayer() && ped->CharCreatedBy != MISSION_CHAR && !ped->bRenderScorched && !ped->bBodyPartJustCameOff && ped->bAllowMedicsToReviveMe && !ped->bIsInWater) {
for (int i = 0; i < NUM_ACCIDENTS; i++) {
if (m_aAccidents[i].m_pVictim != nil && m_aAccidents[i].m_pVictim == ped)
return;
}
if (ped->m_pCurrentPhysSurface == nil) {
CVector point = ped->GetPosition();
point.z -= 2.0f;
CColPoint colPoint;
CEntity *pEntity;
if (!CWorld::ProcessVerticalLine(point, -100.0f, colPoint, pEntity, true, false, false, false, false, false, nil)) {
CAccident *accident = GetNextFreeAccident();
if (accident != nil) {
accident->m_pVictim = ped;
ped->RegisterReference((CEntity**)&accident->m_pVictim);
accident->m_nMedicsPerformingCPR = 0;
accident->m_nMedicsAttending = 0;
ped->m_lastAccident = accident;
WorkToDoForMedics();
}
}
}
}
}
void
CAccidentManager::Update()
{
#ifdef SQUEEZE_PERFORMANCE
// Handled after injury registered.
return;
#endif
int32 e;
if (CEventList::GetEvent(EVENT_INJURED_PED, &e)) {
CPed *ped = CPools::GetPed(gaEvent[e].entityRef);
if (ped) {
ReportAccident(ped);
CEventList::ClearEvent(e);
}
}
}
CAccident*
CAccidentManager::FindNearestAccident(CVector vecPos, float *pDistance)
{
for (int i = 0; i < MAX_MEDICS_TO_ATTEND_ACCIDENT; i++){
int accidentId = -1;
float minDistance = 999999;
for (int j = 0; j < NUM_ACCIDENTS; j++){
CPed* pVictim = m_aAccidents[j].m_pVictim;
if (!pVictim)
continue;
if (pVictim->CharCreatedBy == MISSION_CHAR)
continue;
if (pVictim->m_fHealth != 0.0f)
continue;
if (m_aAccidents[j].m_nMedicsPerformingCPR != i)
continue;
float distance = (pVictim->GetPosition() - vecPos).Magnitude2D();
if (distance / 2 > pVictim->GetPosition().z - vecPos.z && distance < minDistance){
minDistance = distance;
accidentId = j;
}
}
*pDistance = minDistance;
if (accidentId != -1)
return &m_aAccidents[accidentId];
}
return nil;
}
uint16
CAccidentManager::CountActiveAccidents()
{
uint16 accidents = 0;
for (int i = 0; i < NUM_ACCIDENTS; i++) {
if (m_aAccidents[i].m_pVictim)
accidents++;
}
return accidents;
}
bool
CAccidentManager::WorkToDoForMedics()
{
for (int i = 0; i < NUM_ACCIDENTS; i++) {
if (m_aAccidents[i].m_pVictim != nil && m_aAccidents[i].m_nMedicsAttending < MAX_MEDICS_TO_ATTEND_ACCIDENT)
return true;
}
return false;
}
bool
CAccidentManager::UnattendedAccidents()
{
for (int i = 0; i < NUM_ACCIDENTS; i++) {
if (m_aAccidents[i].m_pVictim != nil && m_aAccidents[i].m_nMedicsAttending == 0)
return true;
}
return false;
}

31
src/core/Accident.h Normal file
View file

@ -0,0 +1,31 @@
#pragma once
#include "config.h"
class CPed;
class CAccident
{
public:
CPed *m_pVictim;
uint32 m_nMedicsAttending;
uint32 m_nMedicsPerformingCPR;
CAccident() : m_pVictim(nil), m_nMedicsAttending(0), m_nMedicsPerformingCPR(0) {}
};
class CAccidentManager
{
CAccident m_aAccidents[NUM_ACCIDENTS];
enum {
MAX_MEDICS_TO_ATTEND_ACCIDENT = 2
};
public:
CAccident *GetNextFreeAccident();
void ReportAccident(CPed *ped);
void Update();
CAccident *FindNearestAccident(CVector vecPos, float *pDistance);
uint16 CountActiveAccidents();
bool UnattendedAccidents();
bool WorkToDoForMedics();
};
extern CAccidentManager gAccidentManager;

422
src/core/AnimViewer.cpp Normal file
View file

@ -0,0 +1,422 @@
#include "common.h"
#include "Font.h"
#include "Pad.h"
#include "Text.h"
#include "main.h"
#include "Timer.h"
#include "DMAudio.h"
#include "FileMgr.h"
#include "Streaming.h"
#include "TxdStore.h"
#include "General.h"
#include "Camera.h"
#include "Vehicle.h"
#include "PlayerSkin.h"
#include "PlayerInfo.h"
#include "World.h"
#include "Renderer.h"
#include "AnimManager.h"
#include "AnimViewer.h"
#include "PlayerPed.h"
#include "Pools.h"
#include "References.h"
#include "PathFind.h"
#include "HandlingMgr.h"
#include "TempColModels.h"
#include "Particle.h"
#include "CdStream.h"
#include "Messages.h"
#include "CarCtrl.h"
#include "FileLoader.h"
#include "ModelIndices.h"
#include "Clock.h"
#include "Timecycle.h"
#include "RpAnimBlend.h"
#include "AnimBlendAssociation.h"
#include "Shadows.h"
#include "Radar.h"
#include "Hud.h"
#include "debugmenu.h"
int CAnimViewer::animTxdSlot = 0;
CEntity *CAnimViewer::pTarget = nil;
void
CAnimViewer::Render(void) {
if (pTarget) {
// pTarget->GetPosition() = CVector(0.0f, 0.0f, 0.0f); // Only on Mobile
if (pTarget) {
#ifdef FIX_BUGS
#ifdef PED_SKIN
if(pTarget->IsPed() && IsClumpSkinned(pTarget->GetClump()))
((CPed*)pTarget)->UpdateRpHAnim();
#endif
#endif
pTarget->Render();
CRenderer::RenderOneNonRoad(pTarget);
}
}
}
void
CAnimViewer::Initialise(void) {
// we need messages, messages needs hud, hud needs this
CHud::m_Wants_To_Draw_Hud = false;
animTxdSlot = CTxdStore::AddTxdSlot("generic");
CTxdStore::Create(animTxdSlot);
int hudSlot = CTxdStore::AddTxdSlot("hud");
CTxdStore::LoadTxd(hudSlot, "MODELS/HUD.TXD");
int particleSlot = CTxdStore::AddTxdSlot("particle");
CTxdStore::LoadTxd(particleSlot, "MODELS/PARTICLE.TXD");
CTxdStore::SetCurrentTxd(animTxdSlot);
CPools::Initialise();
CReferences::Init();
TheCamera.Init();
TheCamera.SetRwCamera(Scene.camera);
TheCamera.Cams[TheCamera.ActiveCam].Distance = 5.0f;
ThePaths.Init();
ThePaths.AllocatePathFindInfoMem(4500);
CCollision::Init();
CWorld::Initialise();
mod_HandlingManager.Initialise();
CTempColModels::Initialise();
CAnimManager::Initialise();
CModelInfo::Initialise();
CParticle::Initialise();
CCarCtrl::Init();
CPedStats::Initialise();
CMessages::Init();
CdStreamAddImage("MODELS\\GTA3.IMG");
CFileLoader::LoadLevel("DATA\\ANIMVIEWER.DAT");
CStreaming::Init();
CStreaming::LoadInitialPeds();
CStreaming::RequestSpecialModel(MI_PLAYER, "player", STREAMFLAGS_DONT_REMOVE);
CStreaming::LoadAllRequestedModels(false);
CRenderer::Init();
CRadar::Initialise();
CRadar::LoadTextures();
CVehicleModelInfo::LoadVehicleColours();
#ifdef FIX_BUGS
CVehicleModelInfo::LoadEnvironmentMaps();
#endif
CAnimManager::LoadAnimFiles();
CWorld::PlayerInFocus = 0;
CWeapon::InitialiseWeapons();
CShadows::Init();
CPed::Initialise();
CTimer::Initialise();
CClock::Initialise(60000);
CTimeCycle::Initialise();
CCarCtrl::Init();
CPlayerPed *player = new CPlayerPed();
player->SetPosition(0.0f, 0.0f, 0.0f); // This is 1000.f for all axes on Xbox, but 0.f on mobile?
CWorld::Players[0].m_pPed = player;
CDraw::SetFOV(120.0f);
CDraw::ms_fLODDistance = 500.0f;
int fd = CFileMgr::OpenFile("DATA\\SPECIAL.TXT", "r");
char animGroup[32], modelName[32];
if (fd) {
for (int lineId = 0; lineId < NUM_OF_SPECIAL_CHARS; lineId++) {
if (!CFileMgr::ReadLine(fd, gString, 255))
break;
sscanf(gString, "%s %s", modelName, animGroup);
int groupId;
for (groupId = 0; groupId < NUM_ANIM_ASSOC_GROUPS; groupId++) {
if (!strcmp(animGroup, CAnimManager::GetAnimGroupName((AssocGroupId)groupId)))
break;
}
if (groupId != NUM_ANIM_ASSOC_GROUPS)
((CPedModelInfo*)CModelInfo::GetModelInfo(MI_SPECIAL01 + lineId))->m_animGroup = groupId;
CStreaming::RequestSpecialChar(lineId, modelName, STREAMFLAGS_DONT_REMOVE);
}
CFileMgr::CloseFile(fd);
} else {
// From xbox
CStreaming::RequestSpecialChar(0, "luigi", STREAMFLAGS_DONT_REMOVE);
CStreaming::RequestSpecialChar(1, "joey", STREAMFLAGS_DONT_REMOVE);
CStreaming::RequestSpecialChar(2, "tony", STREAMFLAGS_DONT_REMOVE);
CStreaming::RequestSpecialChar(3, "curly", STREAMFLAGS_DONT_REMOVE);
}
}
int
LastPedModelId(int modelId)
{
CBaseModelInfo *model;
for(;;){
assert(modelId < MODELINFOSIZE);
model = CModelInfo::GetModelInfo(modelId);
if (model && model->GetModelType() == MITYPE_PED)
break;
modelId--;
}
return modelId;
}
int
FirstCarModelId(int modelId)
{
CBaseModelInfo *model;
for(;;){
assert(modelId < MODELINFOSIZE);
model = CModelInfo::GetModelInfo(modelId);
if (model && model->GetModelType() == MITYPE_VEHICLE)
break;
modelId++;
}
return modelId;
}
int
NextModelId(int modelId, int wantedChange)
{
// Max. 2 trials wasn't here, it's me that added it.
int tryCount = 2;
int ogModelId = modelId;
while(tryCount != 0) {
modelId += wantedChange;
if (modelId < 0 || modelId >= MODELINFOSIZE) {
tryCount--;
wantedChange = -wantedChange;
} else if (modelId != 5 && modelId != 6 && modelId != 405) {
CBaseModelInfo *model = CModelInfo::GetModelInfo(modelId);
if (model)
{
//int type = model->m_type;
return modelId;
}
}
}
return ogModelId;
}
void
PlayAnimation(RpClump *clump, AssocGroupId animGroup, AnimationId anim)
{
CAnimBlendAssociation *currentAssoc = RpAnimBlendClumpGetAssociation(clump, anim);
if (currentAssoc && currentAssoc->IsPartial())
delete currentAssoc;
RpAnimBlendClumpSetBlendDeltas(clump, ASSOC_PARTIAL, -8.0f);
CAnimBlendAssociation *animAssoc = CAnimManager::BlendAnimation(clump, animGroup, anim, 8.0f);
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
animAssoc->SetCurrentTime(0.0f);
animAssoc->SetRun();
}
void
CAnimViewer::Update(void)
{
static int modelId = 0;
static int animId = 0;
static bool reloadIFP = false;
AssocGroupId animGroup = ASSOCGRP_STD;
int nextModelId = modelId;
CBaseModelInfo *modelInfo = CModelInfo::GetModelInfo(modelId);
if (modelInfo->GetModelType() == MITYPE_PED) {
int animGroup = ((CPedModelInfo*)modelInfo)->m_animGroup;
if (animId > ANIM_STD_IDLE)
animGroup = ASSOCGRP_STD;
if (reloadIFP) {
if (pTarget) {
CWorld::Remove(pTarget);
if (pTarget)
delete pTarget;
}
pTarget = nil;
// These calls were inside of LoadIFP function.
CAnimManager::Shutdown();
CAnimManager::Initialise();
CAnimManager::LoadAnimFiles();
reloadIFP = false;
}
} else {
animGroup = ASSOCGRP_STD;
}
CPad::UpdatePads();
CPad* pad = CPad::GetPad(0);
#ifdef DEBUGMENU
DebugMenuProcess();
#endif
CStreaming::UpdateForAnimViewer();
CStreaming::RequestModel(modelId, 0);
if (CStreaming::HasModelLoaded(modelId)) {
if (!pTarget) {
if (modelInfo->GetModelType() == MITYPE_VEHICLE) {
CVehicleModelInfo* veh = (CVehicleModelInfo*)modelInfo;
if (veh->m_vehicleType == VEHICLE_TYPE_CAR) {
pTarget = new CAutomobile(modelId, RANDOM_VEHICLE);
} else if (veh->m_vehicleType == VEHICLE_TYPE_BOAT) {
pTarget = new CBoat(modelId, RANDOM_VEHICLE);
} else {
pTarget = new CObject(modelId, true);
if (!modelInfo->GetColModel()) {
modelInfo->SetColModel(&CTempColModels::ms_colModelWheel1);
}
}
pTarget->SetStatus(STATUS_ABANDONED);
} else if (modelInfo->GetModelType() == MITYPE_PED) {
pTarget = new CPed(PEDTYPE_CIVMALE);
pTarget->SetModelIndex(modelId);
} else {
pTarget = new CObject(modelId, true);
if (!modelInfo->GetColModel())
{
modelInfo->SetColModel(&CTempColModels::ms_colModelWheel1);
}
pTarget->SetStatus(STATUS_ABANDONED);
}
pTarget->SetPosition(0.0f, 0.0f, 0.0f);
CWorld::Add(pTarget);
TheCamera.TakeControl(pTarget, CCam::MODE_MODELVIEW, JUMP_CUT, CAMCONTROL_SCRIPT);
}
if (pTarget->IsVehicle() || pTarget->IsPed() || pTarget->IsObject()) {
((CPhysical*)pTarget)->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
}
#ifdef FIX_BUGS
// so we don't end up in the water
pTarget->GetMatrix().GetPosition().z = 10.0f;
#else
pTarget->GetMatrix().GetPosition().z = 0.0f;
#endif
if (modelInfo->GetModelType() == MITYPE_PED) {
((CPed*)pTarget)->bKindaStayInSamePlace = true;
// Triangle in mobile
if (pad->GetSquareJustDown()) {
reloadIFP = true;
AsciiToUnicode("IFP reloaded", gUString);
CMessages::AddMessage(gUString, 1000, 0);
} else if (pad->GetCrossJustDown()) {
PlayAnimation(pTarget->GetClump(), animGroup, (AnimationId)animId);
AsciiToUnicode("Animation restarted", gUString);
CMessages::AddMessage(gUString, 1000, 0);
} else if (pad->GetCircleJustDown()) {
PlayAnimation(pTarget->GetClump(), animGroup, ANIM_STD_IDLE);
AsciiToUnicode("Idle animation playing", gUString);
CMessages::AddMessage(gUString, 1000, 0);
} else if (pad->GetDPadUpJustDown()) {
animId--;
if (animId < 0) {
animId = ANIM_STD_NUM - 1;
}
PlayAnimation(pTarget->GetClump(), animGroup, (AnimationId)animId);
sprintf(gString, "Current anim: %d", animId);
AsciiToUnicode(gString, gUString);
CMessages::AddMessage(gUString, 1000, 0);
} else if (pad->GetDPadDownJustDown()) {
animId = (animId == (ANIM_STD_NUM - 1) ? 0 : animId + 1);
PlayAnimation(pTarget->GetClump(), animGroup, (AnimationId)animId);
sprintf(gString, "Current anim: %d", animId);
AsciiToUnicode(gString, gUString);
CMessages::AddMessage(gUString, 1000, 0);
} else if (pad->GetStartJustDown()) {
} else if (pad->GetLeftShoulder1JustDown()) {
nextModelId = FirstCarModelId(modelId);
AsciiToUnicode("Switched to vehicles", gUString);
CMessages::AddMessage(gUString, 1000, 0);
// Originally it was GetPad(1)->LeftShoulder2
} else if (pad->NewState.Triangle) {
#ifdef PED_SKIN
if(IsClumpSkinned(pTarget->GetClump()))
((CPedModelInfo *)CModelInfo::GetModelInfo(pTarget->GetModelIndex()))->AnimatePedColModelSkinned(pTarget->GetClump());
else
#endif
CPedModelInfo::AnimatePedColModel(((CPedModelInfo *)CModelInfo::GetModelInfo(pTarget->GetModelIndex()))->GetHitColModel(),
RpClumpGetFrame(pTarget->GetClump()));
AsciiToUnicode("Ped Col model will be animated as long as you hold the button", gUString);
CMessages::AddMessage(gUString, 100, 0);
}
} else if (modelInfo->GetModelType() == MITYPE_VEHICLE) {
if (pad->GetLeftShoulder1JustDown()) {
nextModelId = LastPedModelId(modelId);
AsciiToUnicode("Switched to peds", gUString);
CMessages::AddMessage(gUString, 1000, 0);
// Start in mobile
} else if (pad->GetSquareJustDown()) {
CVehicleModelInfo::LoadVehicleColours();
AsciiToUnicode("Carcols.dat reloaded", gUString);
CMessages::AddMessage(gUString, 1000, 0);
}
}
}
if (pad->GetDPadLeftJustDown()) {
nextModelId = NextModelId(modelId, -1);
sprintf(gString, "Current model ID: %d", nextModelId);
AsciiToUnicode(gString, gUString);
CMessages::AddMessage(gUString, 1000, 0);
} else if (pad->GetDPadRightJustDown()) {
nextModelId = NextModelId(modelId, 1);
sprintf(gString, "Current model ID: %d", nextModelId);
AsciiToUnicode(gString, gUString);
CMessages::AddMessage(gUString, 1000, 0);
}
// There were extra codes here to let us change model id by 50, but xbox CPad struct is different, so I couldn't port.
if (nextModelId != modelId) {
modelId = nextModelId;
if (pTarget) {
CWorld::Remove(pTarget);
if (pTarget)
delete pTarget;
}
pTarget = nil;
return;
}
CTimeCycle::Update();
CWorld::Process();
if (pTarget)
TheCamera.Process();
}
void
CAnimViewer::Shutdown(void)
{
if (CWorld::Players[0].m_pPed)
delete CWorld::Players[0].m_pPed;
CWorld::ShutDown();
CModelInfo::ShutDown();
CAnimManager::Shutdown();
CTimer::Shutdown();
CStreaming::Shutdown();
CTxdStore::RemoveTxdSlot(animTxdSlot);
}

12
src/core/AnimViewer.h Normal file
View file

@ -0,0 +1,12 @@
#pragma once
class CAnimViewer {
public:
static int animTxdSlot;
static CEntity *pTarget;
static void Initialise();
static void Render();
static void Shutdown();
static void Update();
};

5410
src/core/Cam.cpp Normal file

File diff suppressed because it is too large Load diff

3726
src/core/Camera.cpp Normal file

File diff suppressed because it is too large Load diff

653
src/core/Camera.h Normal file
View file

@ -0,0 +1,653 @@
#pragma once
#include "Placeable.h"
class CEntity;
class CPed;
class CAutomobile;
class CGarage;
extern int16 DebugCamMode;
enum
{
NUMBER_OF_VECTORS_FOR_AVERAGE = 2,
MAX_NUM_OF_SPLINETYPES = 4,
MAX_NUM_OF_NODES = 800 // for trains
};
#define DEFAULT_NEAR (0.9f)
enum
{
CAM_ZOOM_1STPRS,
CAM_ZOOM_1,
CAM_ZOOM_2,
CAM_ZOOM_3,
CAM_ZOOM_TOPDOWN,
CAM_ZOOM_CINEMATIC,
};
#ifdef FREE_CAM // LCS values
#define FREE_CAR_ZOOM_VALUE_1 (-1.0f)
#define FREE_CAR_ZOOM_VALUE_2 (2.0f)
#define FREE_CAR_ZOOM_VALUE_3 (6.0f)
#define FREE_BOAT_ZOOM_VALUE_1 (-2.41f)
#define FREE_BOAT_ZOOM_VALUE_2 (6.49f)
#define FREE_BOAT_ZOOM_VALUE_3 (15.0f)
#endif
#define DEFAULT_CAR_ZOOM_VALUE_1 (0.05f)
#define DEFAULT_CAR_ZOOM_VALUE_2 (1.9f)
#define DEFAULT_CAR_ZOOM_VALUE_3 (3.9f)
const float DefaultFOV = 70.0f; // beta: 80.0f
class CCam
{
public:
enum
{
MODE_NONE = 0,
MODE_TOPDOWN,
MODE_GTACLASSIC,
MODE_BEHINDCAR,
MODE_FOLLOWPED,
MODE_AIMING,
MODE_DEBUG,
MODE_SNIPER,
MODE_ROCKETLAUNCHER,
MODE_MODELVIEW,
MODE_BILL,
MODE_SYPHON,
MODE_CIRCLE,
MODE_CHEESYZOOM,
MODE_WHEELCAM,
MODE_FIXED,
MODE_1STPERSON,
MODE_FLYBY,
MODE_CAM_ON_A_STRING,
MODE_REACTION,
MODE_FOLLOW_PED_WITH_BIND,
MODE_CHRIS,
MODE_BEHINDBOAT,
MODE_PLAYER_FALLEN_WATER,
MODE_CAM_ON_TRAIN_ROOF,
MODE_CAM_RUNNING_SIDE_TRAIN,
MODE_BLOOD_ON_THE_TRACKS,
MODE_IM_THE_PASSENGER_WOOWOO,
MODE_SYPHON_CRIM_IN_FRONT,
MODE_PED_DEAD_BABY,
MODE_PILLOWS_PAPS,
MODE_LOOK_AT_CARS,
MODE_ARRESTCAM_ONE,
MODE_ARRESTCAM_TWO,
MODE_M16_1STPERSON,
MODE_SPECIAL_FIXED_FOR_SYPHON,
MODE_FIGHT_CAM,
MODE_TOP_DOWN_PED,
MODE_SNIPER_RUNABOUT,
MODE_ROCKETLAUNCHER_RUNABOUT,
MODE_1STPERSON_RUNABOUT,
MODE_M16_1STPERSON_RUNABOUT,
MODE_FIGHT_CAM_RUNABOUT,
MODE_EDITOR,
MODE_HELICANNON_1STPERSON, // vice city leftover
};
bool bBelowMinDist; //used for follow ped mode
bool bBehindPlayerDesired; //used for follow ped mode
bool m_bCamLookingAtVector;
bool m_bCollisionChecksOn;
bool m_bFixingBeta; //used for camera on a string
bool m_bTheHeightFixerVehicleIsATrain;
bool LookBehindCamWasInFront;
bool LookingBehind;
bool LookingLeft;
bool LookingRight;
bool ResetStatics; //for interpolation type stuff to work
bool Rotating;
int16 Mode; // CameraMode
uint32 m_uiFinishTime;
int m_iDoCollisionChecksOnFrameNum;
int m_iDoCollisionCheckEveryNumOfFrames;
int m_iFrameNumWereAt;
int m_iRunningVectorArrayPos;
int m_iRunningVectorCounter;
int DirectionWasLooking;
float f_max_role_angle; //=DEGTORAD(5.0f);
float f_Roll; //used for adding a slight roll to the camera in the
float f_rollSpeed;
float m_fSyphonModeTargetZOffSet;
float m_fRoadOffSet;
float m_fAmountFractionObscured;
float m_fAlphaSpeedOverOneFrame;
float m_fBetaSpeedOverOneFrame;
float m_fBufferedTargetBeta;
float m_fBufferedTargetOrientation;
float m_fBufferedTargetOrientationSpeed;
float m_fCamBufferedHeight;
float m_fCamBufferedHeightSpeed;
float m_fCloseInPedHeightOffset;
float m_fCloseInPedHeightOffsetSpeed;
float m_fCloseInCarHeightOffset;
float m_fCloseInCarHeightOffsetSpeed;
float m_fDimensionOfHighestNearCar;
float m_fDistanceBeforeChanges;
float m_fFovSpeedOverOneFrame;
float m_fMinDistAwayFromCamWhenInterPolating;
float m_fPedBetweenCameraHeightOffset;
float m_fPlayerInFrontSyphonAngleOffSet;
float m_fRadiusForDead;
float m_fRealGroundDist; //used for follow ped mode
float m_fTargetBeta;
float m_fTimeElapsedFloat;
float m_fTransitionBeta;
float m_fTrueBeta;
float m_fTrueAlpha;
float m_fInitialPlayerOrientation; //used for first person
float Alpha;
float AlphaSpeed;
float FOV;
float FOVSpeed;
float Beta;
float BetaSpeed;
float Distance;
float DistanceSpeed;
float CA_MIN_DISTANCE;
float CA_MAX_DISTANCE;
float SpeedVar;
CVector m_cvecSourceSpeedOverOneFrame;
CVector m_cvecTargetSpeedOverOneFrame;
CVector m_cvecUpOverOneFrame;
CVector m_cvecTargetCoorsForFudgeInter;
CVector m_cvecCamFixedModeVector;
CVector m_cvecCamFixedModeSource;
CVector m_cvecCamFixedModeUpOffSet;
CVector m_vecLastAboveWaterCamPosition; //helper for when the player has gone under the water
CVector m_vecBufferedPlayerBodyOffset;
// The three vectors that determine this camera for this frame
CVector Front; // Direction of looking in
CVector Source; // Coors in world space
CVector SourceBeforeLookBehind;
CVector Up; // Just that
CVector m_arrPreviousVectors[NUMBER_OF_VECTORS_FOR_AVERAGE]; // used to average stuff
CEntity *CamTargetEntity;
float m_fCameraDistance;
float m_fIdealAlpha;
float m_fPlayerVelocity;
CAutomobile *m_pLastCarEntered; // So interpolation works
CPed *m_pLastPedLookedAt;// So interpolation works
bool m_bFirstPersonRunAboutActive;
CCam(void) { Init(); }
void Init(void);
void Process(void);
void ProcessSpecialHeightRoutines(void);
void GetVectorsReadyForRW(void);
CVector DoAverageOnVector(const CVector &vec);
float GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies);
void WorkOutCamHeightWeeCar(CVector &TargetCoors, float TargetOrientation);
void WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight);
bool RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation);
bool FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation);
void Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist);
void FixCamWhenObscuredByVehicle(const CVector &TargetCoors);
void LookBehind(void);
void LookLeft(void);
void LookRight(void);
void ClipIfPedInFrontOfPlayer(void);
void KeepTrackOfTheSpeed(const CVector &source, const CVector &target, const CVector &up, const float &alpha, const float &beta, const float &fov);
bool Using3rdPersonMouseCam(void);
bool GetWeaponFirstPersonOn(void);
bool IsTargetInWater(const CVector &CamCoors);
void AvoidWallsTopDownPed(const CVector &TargetCoors, const CVector &Offset, float *Adjuster, float *AdjusterSpeed, float yDistLimit);
void PrintMode(void);
void Process_Debug(const CVector&, float, float, float);
#ifdef GTA_SCENE_EDIT
void Process_Editor(const CVector&, float, float, float);
#endif
void Process_ModelView(const CVector &CameraTarget, float, float, float);
void Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_FollowPedWithMouse(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_TopDown(const CVector &CameraTarget, float TargetOrientation, float SpeedVar, float TargetSpeedVar);
void Process_TopDownPed(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_Rocket(const CVector &CameraTarget, float, float, float);
void Process_M16_1stPerson(const CVector &CameraTarget, float, float, float);
void Process_1stPerson(const CVector &CameraTarget, float, float, float);
void Process_1rstPersonPedOnPC(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_Sniper(const CVector &CameraTarget, float, float, float);
void Process_Syphon(const CVector &CameraTarget, float, float, float);
void Process_Syphon_Crim_In_Front(const CVector &CameraTarget, float, float, float);
void Process_BehindBoat(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_Fight_Cam(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_FlyBy(const CVector&, float, float, float);
void Process_WheelCam(const CVector&, float, float, float);
void Process_Fixed(const CVector &CameraTarget, float, float, float);
void Process_Player_Fallen_Water(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_Circle(const CVector &CameraTarget, float, float, float);
void Process_SpecialFixedForSyphon(const CVector &CameraTarget, float, float, float);
void ProcessPedsDeadBaby(void);
bool ProcessArrestCamOne(void);
bool ProcessArrestCamTwo(void);
/* Some of the unused PS2 cams */
void Process_Chris_With_Binding_PlusRotation(const CVector &CameraTarget, float, float, float);
void Process_ReactionCam(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_FollowPed_WithBinding(const CVector &CameraTarget, float TargetOrientation, float, float);
// TODO:
// CCam::Process_CushyPillows_Arse
// CCam::Process_Look_At_Cars
// CCam::Process_CheesyZoom
// CCam::Process_Aiming
void Process_Bill(const CVector &CameraTarget, float TargetOrientation, float SpeedVar, float TargetSpeedVar);
void Process_Im_The_Passenger_Woo_Woo(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_Blood_On_The_Tracks(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_Cam_Running_Side_Train(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_Cam_On_Train_Roof(const CVector &CameraTarget, float TargetOrientation, float, float);
// custom stuff
void Process_FollowPed_Rotation(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_FollowCar_SA(const CVector &CameraTarget, float TargetOrientation, float, float);
};
VALIDATE_SIZE(CCam, 0x1A4);
class CCamPathSplines
{
public:
enum {MAXPATHLENGTH=800};
float m_arr_PathData[MAXPATHLENGTH];
CCamPathSplines(void);
};
struct CTrainCamNode
{
CVector m_cvecCamPosition;
CVector m_cvecPointToLookAt;
CVector m_cvecMinPointInRange;
CVector m_cvecMaxPointInRange;
float m_fDesiredFOV;
float m_fNearClip;
};
struct CQueuedMode
{
int16 Mode;
float Duration;
int16 MinZoom;
int16 MaxZoom;
};
enum
{
LOOKING_BEHIND,
LOOKING_LEFT,
LOOKING_RIGHT,
LOOKING_FORWARD,
};
enum
{
// TODO: find better names
FADE_0, // faded in
FADE_1, // mid fade
FADE_2, // faded out
// Direction
FADE_OUT = 0,
FADE_IN,
FADE_NONE
};
enum
{
MOTION_BLUR_NONE = 0,
MOTION_BLUR_SNIPER,
MOTION_BLUR_LIGHT_SCENE,
MOTION_BLUR_SECURITY_CAM,
MOTION_BLUR_CUT_SCENE,
MOTION_BLUR_INTRO,
MOTION_BLUR_INTRO2,
MOTION_BLUR_SNIPER_ZOOM,
MOTION_BLUR_INTRO3,
MOTION_BLUR_INTRO4,
};
enum
{
NONE = 0,
INTERPOLATION,
JUMP_CUT
};
enum
{
CAMCONTROL_GAME,
CAMCONTROL_SCRIPT,
CAMCONTROL_OBBE
};
class CCamera : public CPlaceable
{
public:
bool m_bAboveGroundTrainNodesLoaded;
bool m_bBelowGroundTrainNodesLoaded;
bool m_bCamDirectlyBehind;
bool m_bCamDirectlyInFront;
bool m_bCameraJustRestored;
bool m_bcutsceneFinished;
bool m_bCullZoneChecksOn;
bool m_bFirstPersonBeingUsed;
bool m_bUnknown;
bool m_bIdleOn;
bool m_bInATunnelAndABigVehicle;
bool m_bInitialNodeFound;
bool m_bInitialNoNodeStaticsSet;
bool m_bIgnoreFadingStuffForMusic;
bool m_bPlayerIsInGarage;
bool m_bJustCameOutOfGarage;
bool m_bJustInitalised;
bool m_bJust_Switched;
bool m_bLookingAtPlayer;
bool m_bLookingAtVector;
bool m_bMoveCamToAvoidGeom;
bool m_bObbeCinematicPedCamOn;
bool m_bObbeCinematicCarCamOn;
bool m_bRestoreByJumpCut;
bool m_bUseNearClipScript;
bool m_bStartInterScript;
bool m_bStartingSpline;
bool m_bTargetJustBeenOnTrain;
bool m_bTargetJustCameOffTrain;
bool m_bUseSpecialFovTrain;
bool m_bUseTransitionBeta;
bool m_bUseScriptZoomValuePed;
bool m_bUseScriptZoomValueCar;
bool m_bWaitForInterpolToFinish;
bool m_bItsOkToLookJustAtThePlayer;
bool m_bWantsToSwitchWidescreenOff;
bool m_WideScreenOn;
bool m_1rstPersonRunCloseToAWall;
bool m_bHeadBob;
bool m_bFailedCullZoneTestPreviously;
bool m_FadeTargetIsSplashScreen;
bool WorldViewerBeingUsed;
uint8 ActiveCam;
uint32 m_uiCamShakeStart;
uint32 m_uiFirstPersonCamLastInputTime;
uint32 m_uiLongestTimeInMill;
uint32 m_uiNumberOfTrainCamNodes;
uint8 m_uiTransitionJUSTStarted;
uint8 m_uiTransitionState; // 0:one mode 1:transition
uint32 m_uiTimeLastChange;
uint32 m_uiTimeWeEnteredIdle;
uint32 m_uiTimeTransitionStart;
uint32 m_uiTransitionDuration;
int m_BlurBlue;
int m_BlurGreen;
int m_BlurRed;
int m_BlurType;
uint32 unknown; // some counter having to do with music
int m_iWorkOutSpeedThisNumFrames;
int m_iNumFramesSoFar;
int m_iCurrentTrainCamNode;
int m_motionBlur;
int m_imotionBlurAddAlpha;
int m_iCheckCullZoneThisNumFrames;
int m_iZoneCullFrameNumWereAt;
int WhoIsInControlOfTheCamera;
float CamFrontXNorm;
float CamFrontYNorm;
#ifdef FIX_BUGS
int32 CarZoomIndicator;
#else
float CarZoomIndicator;
#endif
float CarZoomValue;
float CarZoomValueSmooth;
float DistanceToWater;
#ifndef PS2_CAM_TRANSITION
float FOVDuringInter;
#endif
float LODDistMultiplier;
float GenerationDistMultiplier;
#ifndef PS2_CAM_TRANSITION
float m_fAlphaSpeedAtStartInter;
float m_fAlphaWhenInterPol;
float m_fAlphaDuringInterPol;
float m_fBetaDuringInterPol;
float m_fBetaSpeedAtStartInter;
float m_fBetaWhenInterPol;
float m_fFOVWhenInterPol;
float m_fFOVSpeedAtStartInter;
float m_fStartingBetaForInterPol;
float m_fStartingAlphaForInterPol;
#endif
float m_PedOrientForBehindOrInFront;
float m_CameraAverageSpeed;
float m_CameraSpeedSoFar;
float m_fCamShakeForce;
float m_fCarZoomValueScript;
float m_fFovForTrain;
float m_fFOV_Wide_Screen;
float m_fNearClipScript;
float m_fOldBetaDiff;
float m_fPedZoomValue;
float m_fPedZoomValueScript;
float m_fPedZoomValueSmooth;
float m_fPositionAlongSpline;
float m_ScreenReductionPercentage;
float m_ScreenReductionSpeed;
float m_AlphaForPlayerAnim1rstPerson;
float Orientation;
#ifdef FIX_BUGS
int32 PedZoomIndicator;
#else
float PedZoomIndicator;
#endif
float PlayerExhaustion;
float SoundDistUp, SoundDistLeft, SoundDistRight;
float SoundDistUpAsRead, SoundDistLeftAsRead, SoundDistRightAsRead;
float SoundDistUpAsReadOld, SoundDistLeftAsReadOld, SoundDistRightAsReadOld;
float m_fWideScreenReductionAmount;
float m_fStartingFOVForInterPol;
// not static yet
float m_fMouseAccelHorzntl;// acceleration multiplier for 1st person controls
float m_fMouseAccelVertical;// acceleration multiplier for 1st person controls
float m_f3rdPersonCHairMultX;
float m_f3rdPersonCHairMultY;
CCam Cams[3];
CGarage *pToGarageWeAreIn;
CGarage *pToGarageWeAreInForHackAvoidFirstPerson;
CQueuedMode m_PlayerMode;
CQueuedMode PlayerWeaponMode;
CVector m_PreviousCameraPosition;
CVector m_RealPreviousCameraPosition;
CVector m_cvecAimingTargetCoors;
CVector m_vecFixedModeVector;
CVector m_vecFixedModeSource;
CVector m_vecFixedModeUpOffSet;
CVector m_vecCutSceneOffset;
#ifndef PS2_CAM_TRANSITION
CVector m_cvecStartingSourceForInterPol;
CVector m_cvecStartingTargetForInterPol;
CVector m_cvecStartingUpForInterPol;
CVector m_cvecSourceSpeedAtStartInter;
CVector m_cvecTargetSpeedAtStartInter;
CVector m_cvecUpSpeedAtStartInter;
CVector m_vecSourceWhenInterPol;
CVector m_vecTargetWhenInterPol;
CVector m_vecUpWhenInterPol;
#endif
CVector m_vecGameCamPos;
#ifndef PS2_CAM_TRANSITION
CVector SourceDuringInter;
CVector TargetDuringInter;
CVector UpDuringInter;
#endif
RwCamera *m_pRwCamera;
CEntity *pTargetEntity;
CCamPathSplines m_arrPathArray[MAX_NUM_OF_SPLINETYPES];
CTrainCamNode m_arrTrainCamNode[MAX_NUM_OF_NODES];
CMatrix m_cameraMatrix;
bool m_bGarageFixedCamPositionSet;
bool m_vecDoingSpecialInterPolation;
bool m_bScriptParametersSetForInterPol;
bool m_bFading;
bool m_bMusicFading;
CMatrix m_viewMatrix;
CVector m_vecFrustumNormals[4];
CVector m_vecOldSourceForInter;
CVector m_vecOldFrontForInter;
CVector m_vecOldUpForInter;
float m_vecOldFOVForInter;
float m_fFLOATingFade;
float m_fFLOATingFadeMusic;
float m_fTimeToFadeOut;
float m_fTimeToFadeMusic;
float m_fFractionInterToStopMoving;
float m_fFractionInterToStopCatchUp;
float m_fGaitSwayBuffer;
float m_fScriptPercentageInterToStopMoving;
float m_fScriptPercentageInterToCatchUp;
uint32 m_fScriptTimeForInterPolation;
int16 m_iFadingDirection;
int m_iModeObbeCamIsInForCar;
int16 m_iModeToGoTo;
int16 m_iMusicFadingDirection;
int16 m_iTypeOfSwitch;
uint32 m_uiFadeTimeStarted;
uint32 m_uiFadeTimeStartedMusic;
static bool m_bUseMouse3rdPerson;
#ifdef FREE_CAM
static bool bFreeCam;
#endif
// High level and misc
CCamera(void);
CCamera(float);
void Init(void);
void Process(void);
void CamControl(void);
void UpdateTargetEntity(void);
void UpdateSoundDistances(void);
void InitialiseCameraForDebugMode(void);
void CamShake(float strength, float x, float y, float z);
bool Get_Just_Switched_Status() { return m_bJust_Switched; }
// Who's in control
void TakeControl(CEntity *target, int16 mode, int16 typeOfSwitch, int32 controller);
void TakeControlNoEntity(const CVector &position, int16 typeOfSwitch, int32 controller);
void TakeControlWithSpline(int16 typeOfSwitch);
void Restore(void);
void RestoreWithJumpCut(void);
void SetCamPositionForFixedMode(const CVector &Source, const CVector &UppOffSet);
// Transition
void StartTransition(int16 mode);
void StartTransitionWhenNotFinishedInter(int16 mode);
void StoreValuesDuringInterPol(CVector &source, CVector &target, CVector &up, float &FOV);
// Widescreen borders
void SetWideScreenOn(void);
void SetWideScreenOff(void);
void ProcessWideScreenOn(void);
void DrawBordersForWideScreen(void);
// Obbe's cam
bool IsItTimeForNewcam(int32 obbeMode, int32 time);
bool TryToStartNewCamMode(int32 obbeMode);
void DontProcessObbeCinemaCamera(void);
void ProcessObbeCinemaCameraCar(void);
void ProcessObbeCinemaCameraPed(void);
// Train
void LoadTrainCamNodes(char const *name);
void Process_Train_Camera_Control(void);
// Script
void LoadPathSplines(int file);
void FinishCutscene(void);
float GetPositionAlongSpline(void) { return m_fPositionAlongSpline; }
uint32 GetCutSceneFinishTime(void);
void SetCamCutSceneOffSet(const CVector &pos);
void SetPercentAlongCutScene(float percent);
void SetParametersForScriptInterpolation(float stopMoving, float catchUp, int32 time);
void SetZoomValueFollowPedScript(int16 dist);
void SetZoomValueCamStringScript(int16 dist);
void SetNearClipScript(float);
// Fading
void ProcessFade(void);
void ProcessMusicFade(void);
void Fade(float timeout, int16 direction);
void SetFadeColour(uint8 r, uint8 g, uint8 b);
bool GetFading(void);
int GetFadingDirection(void);
int GetScreenFadeStatus(void);
// Motion blur
void RenderMotionBlur(void);
void SetMotionBlur(int r, int g, int b, int a, int type);
void SetMotionBlurAlpha(int a);
// Player looking and aiming
int GetLookDirection(void);
bool GetLookingForwardFirstPerson(void);
bool GetLookingLRBFirstPerson(void);
void SetCameraDirectlyInFrontForFollowPed_CamOnAString(void);
void SetCameraDirectlyBehindForFollowPed_CamOnAString(void);
void SetNewPlayerWeaponMode(int16 mode, int16 minZoom, int16 maxZoom);
void ClearPlayerWeaponMode(void);
void UpdateAimingCoors(CVector const &coors);
bool Find3rdPersonCamTargetVector(float dist, CVector pos, CVector &source, CVector &target);
float Find3rdPersonQuickAimPitch(void);
// Physical camera
void SetRwCamera(RwCamera *cam);
const CMatrix& GetCameraMatrix(void) { return m_cameraMatrix; }
CVector &GetGameCamPosition(void) { return m_vecGameCamPos; }
void CalculateDerivedValues(void);
bool IsPointVisible(const CVector &center, const CMatrix *mat);
bool IsSphereVisible(const CVector &center, float radius, Const CMatrix *mat);
bool IsSphereVisible(const CVector &center, float radius);
bool IsBoxVisible(CVUVECTOR *box, const CMatrix *mat);
};
VALIDATE_SIZE(CCamera, 0xE9D8);
extern CCamera TheCamera;
void CamShakeNoPos(CCamera*, float);
void MakeAngleLessThan180(float &Angle);
void WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSpeed, float Acceleration, bool IsAngle);

538
src/core/CdStream.cpp Normal file
View file

@ -0,0 +1,538 @@
#ifdef _WIN32
#define WITHWINDOWS
#include "common.h"
#include "CdStream.h"
#include "rwcore.h"
#include "RwHelper.h"
#include "MemoryMgr.h"
struct CdReadInfo
{
uint32 nSectorOffset;
uint32 nSectorsToRead;
void *pBuffer;
char field_C;
bool bLocked;
bool bReading;
int32 nStatus;
HANDLE pDoneSemaphore; // used for CdStreamSync
HANDLE hFile;
OVERLAPPED Overlapped;
};
VALIDATE_SIZE(CdReadInfo, 0x30);
char gCdImageNames[MAX_CDIMAGES+1][64];
int32 gNumImages;
int32 gNumChannels;
HANDLE gImgFiles[MAX_CDIMAGES];
HANDLE _gCdStreamThread;
HANDLE gCdStreamSema; // released when we have new thing to read(so channel is set)
DWORD _gCdStreamThreadId;
CdReadInfo *gpReadInfo;
Queue gChannelRequestQ;
int32 lastPosnRead;
BOOL _gbCdStreamOverlapped;
BOOL _gbCdStreamAsync;
DWORD _gdwCdStreamFlags;
DWORD WINAPI CdStreamThread(LPVOID lpThreadParameter);
void
CdStreamInitThread(void)
{
SetLastError(0);
if ( gNumChannels > 0 )
{
for ( int32 i = 0; i < gNumChannels; i++ )
{
gpReadInfo[i].pDoneSemaphore = CreateSemaphore(nil, 0, 2, nil);
if ( gpReadInfo[i].pDoneSemaphore == nil )
{
printf("%s: failed to create sync semaphore\n", "cdvd_stream");
ASSERT(0);
return;
}
}
}
gChannelRequestQ.items = (int32 *)LocalAlloc(LMEM_ZEROINIT, sizeof(int32) * (gNumChannels + 1));
gChannelRequestQ.head = 0;
gChannelRequestQ.tail = 0;
gChannelRequestQ.size = gNumChannels + 1;
ASSERT(gChannelRequestQ.items != nil );
#ifdef FIX_BUGS
gCdStreamSema = CreateSemaphore(nil, 0, 5, nil);
#else
gCdStreamSema = CreateSemaphore(nil, 0, 5, "CdStream");
#endif
if ( gCdStreamSema == nil )
{
printf("%s: failed to create stream semaphore\n", "cdvd_stream");
ASSERT(0);
return;
}
_gCdStreamThread = CreateThread(nil, 64*1024/*64KB*/, CdStreamThread, nil, CREATE_SUSPENDED, &_gCdStreamThreadId);
if ( _gCdStreamThread == nil )
{
printf("%s: failed to create streaming thread\n", "cdvd_stream");
ASSERT(0);
return;
}
SetThreadPriority(_gCdStreamThread, GetThreadPriority(GetCurrentThread()) - 1);
ResumeThread(_gCdStreamThread);
}
void
CdStreamInit(int32 numChannels)
{
DWORD SectorsPerCluster;
DWORD BytesPerSector;
DWORD NumberOfFreeClusters;
DWORD TotalNumberOfClusters;
GetDiskFreeSpace(nil, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters);
_gdwCdStreamFlags = 0;
#ifndef FIX_BUGS // this just slows down streaming
if ( BytesPerSector <= CDSTREAM_SECTOR_SIZE )
{
_gdwCdStreamFlags |= FILE_FLAG_NO_BUFFERING;
debug("Using no buffered loading for streaming\n");
}
#endif
_gbCdStreamOverlapped = TRUE;
_gdwCdStreamFlags |= FILE_FLAG_OVERLAPPED;
_gbCdStreamAsync = FALSE;
void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, BytesPerSector);
ASSERT( pBuffer != nil );
SetLastError(0);
gNumImages = 0;
gNumChannels = numChannels;
gpReadInfo = (CdReadInfo *)LocalAlloc(LMEM_ZEROINIT, sizeof(CdReadInfo) * numChannels);
ASSERT( gpReadInfo != nil );
debug("%s: read info %p\n", "cdvd_stream", gpReadInfo);
CdStreamAddImage("MODELS\\GTA3.IMG");
int32 nStatus = CdStreamRead(0, pBuffer, 0, 1);
CdStreamRemoveImages();
if ( nStatus == STREAM_SUCCESS )
{
_gbCdStreamAsync = TRUE;
debug("Using async loading for streaming\n");
}
else
{
_gdwCdStreamFlags &= ~FILE_FLAG_OVERLAPPED;
_gbCdStreamOverlapped = FALSE;
_gbCdStreamAsync = TRUE;
debug("Using sync loading for streaming\n");
}
CdStreamInitThread();
ASSERT( pBuffer != nil );
RwFreeAlign(pBuffer);
}
uint32
GetGTA3ImgSize(void)
{
ASSERT( gImgFiles[0] != nil );
return (uint32)GetFileSize(gImgFiles[0], nil);
}
void
CdStreamShutdown(void)
{
if ( _gbCdStreamAsync )
{
LocalFree(gChannelRequestQ.items);
CloseHandle(gCdStreamSema);
CloseHandle(_gCdStreamThread);
for ( int32 i = 0; i < gNumChannels; i++ )
CloseHandle(gpReadInfo[i].pDoneSemaphore);
}
LocalFree(gpReadInfo);
}
int32
CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size)
{
ASSERT( channel < gNumChannels );
ASSERT( buffer != nil );
lastPosnRead = size + offset;
ASSERT( _GET_INDEX(offset) < MAX_CDIMAGES );
HANDLE hImage = gImgFiles[_GET_INDEX(offset)];
ASSERT( hImage != nil );
CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil );
pChannel->hFile = hImage;
SetLastError(0);
if ( _gbCdStreamAsync )
{
if ( pChannel->nSectorsToRead != 0 || pChannel->bReading )
return STREAM_NONE;
pChannel->nStatus = STREAM_NONE;
pChannel->nSectorOffset = _GET_OFFSET(offset);
pChannel->nSectorsToRead = size;
pChannel->pBuffer = buffer;
pChannel->bLocked = 0;
AddToQueue(&gChannelRequestQ, channel);
if ( !ReleaseSemaphore(gCdStreamSema, 1, nil) )
printf("Signal Sema Error\n");
return STREAM_SUCCESS;
}
if ( _gbCdStreamOverlapped )
{
ASSERT( channel < gNumChannels );
CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil );
pChannel->Overlapped.Offset = _GET_OFFSET(offset) * CDSTREAM_SECTOR_SIZE;
if ( !ReadFile(hImage, buffer, size * CDSTREAM_SECTOR_SIZE, NULL, &pChannel->Overlapped)
&& GetLastError() != ERROR_IO_PENDING )
return STREAM_NONE;
else
return STREAM_SUCCESS;
}
#ifdef BIG_IMG
LARGE_INTEGER liDistanceToMove;
liDistanceToMove.QuadPart = _GET_OFFSET(offset);
liDistanceToMove.QuadPart *= CDSTREAM_SECTOR_SIZE;
SetFilePointerEx(hImage, liDistanceToMove, nil, FILE_BEGIN);
#else
SetFilePointer(hImage, _GET_OFFSET(offset) * CDSTREAM_SECTOR_SIZE, nil, FILE_BEGIN);
#endif
DWORD NumberOfBytesRead;
if ( !ReadFile(hImage, buffer, size * CDSTREAM_SECTOR_SIZE, &NumberOfBytesRead, nil) )
return STREAM_NONE;
else
return STREAM_SUCCESS;
}
int32
CdStreamGetStatus(int32 channel)
{
ASSERT( channel < gNumChannels );
CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil );
if ( _gbCdStreamAsync )
{
if ( pChannel->bReading )
return STREAM_READING;
if ( pChannel->nSectorsToRead != 0 )
return STREAM_WAITING;
if ( pChannel->nStatus != STREAM_NONE )
{
int32 status = pChannel->nStatus;
pChannel->nStatus = STREAM_NONE;
return status;
}
return STREAM_NONE;
}
if ( _gbCdStreamOverlapped )
{
ASSERT( pChannel->hFile != nil );
if ( WaitForSingleObjectEx(pChannel->hFile, 0, TRUE) == WAIT_OBJECT_0 )
return STREAM_NONE;
else
return STREAM_READING;
}
return STREAM_NONE;
}
int32
CdStreamGetLastPosn(void)
{
return lastPosnRead;
}
// wait for channel to finish reading
int32
CdStreamSync(int32 channel)
{
ASSERT( channel < gNumChannels );
CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil );
if ( _gbCdStreamAsync )
{
if ( pChannel->nSectorsToRead != 0 )
{
pChannel->bLocked = true;
ASSERT( pChannel->pDoneSemaphore != nil );
// Deadlock fix 1
#ifdef FIX_BUGS
// This is while loop on Posix streamer, for spurious wakeups
if (pChannel->bLocked && pChannel->nSectorsToRead != 0){
WaitForSingleObject(pChannel->pDoneSemaphore, INFINITE);
}
pChannel->bLocked = false;
#else
WaitForSingleObject(pChannel->pDoneSemaphore, INFINITE);
#endif
}
pChannel->bReading = false;
return pChannel->nStatus;
}
DWORD NumberOfBytesTransferred;
if ( _gbCdStreamOverlapped && pChannel->hFile )
{
ASSERT(pChannel->hFile != nil );
// Beware: This is blocking call (because of last parameter)
if ( GetOverlappedResult(pChannel->hFile, &pChannel->Overlapped, &NumberOfBytesTransferred, TRUE) )
return STREAM_NONE;
else
return STREAM_ERROR;
}
return STREAM_NONE;
}
void
AddToQueue(Queue *queue, int32 item)
{
ASSERT( queue != nil );
ASSERT( queue->items != nil );
queue->items[queue->tail] = item;
queue->tail = (queue->tail + 1) % queue->size;
if ( queue->head == queue->tail )
debug("Queue is full\n");
}
int32
GetFirstInQueue(Queue *queue)
{
ASSERT( queue != nil );
if ( queue->head == queue->tail )
return -1;
ASSERT( queue->items != nil );
return queue->items[queue->head];
}
void
RemoveFirstInQueue(Queue *queue)
{
ASSERT( queue != nil );
if ( queue->head == queue->tail )
{
debug("Queue is empty\n");
return;
}
queue->head = (queue->head + 1) % queue->size;
}
DWORD
WINAPI CdStreamThread(LPVOID lpThreadParameter)
{
debug("Created cdstream thread\n");
while ( true )
{
WaitForSingleObject(gCdStreamSema, INFINITE);
int32 channel = GetFirstInQueue(&gChannelRequestQ);
ASSERT( channel < gNumChannels );
CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil );
pChannel->bReading = true;
if ( pChannel->nStatus == STREAM_NONE )
{
if ( _gbCdStreamOverlapped )
{
pChannel->Overlapped.Offset = pChannel->nSectorOffset * CDSTREAM_SECTOR_SIZE;
ASSERT(pChannel->hFile != nil );
ASSERT(pChannel->pBuffer != nil );
DWORD NumberOfBytesTransferred;
if ( ReadFile(pChannel->hFile,
pChannel->pBuffer,
pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE,
NULL,
&pChannel->Overlapped) )
{
pChannel->nStatus = STREAM_NONE;
}
// Beware: This is blocking call (because of last parameter)
else if ( GetLastError() == ERROR_IO_PENDING
&& GetOverlappedResult(pChannel->hFile, &pChannel->Overlapped, &NumberOfBytesTransferred, TRUE) )
{
pChannel->nStatus = STREAM_NONE;
}
else
{
pChannel->nStatus = STREAM_ERROR;
}
}
else
{
ASSERT(pChannel->hFile != nil );
ASSERT(pChannel->pBuffer != nil );
SetFilePointer(pChannel->hFile, pChannel->nSectorOffset * CDSTREAM_SECTOR_SIZE, nil, FILE_BEGIN);
DWORD NumberOfBytesRead;
if ( ReadFile(pChannel->hFile,
pChannel->pBuffer,
pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE,
&NumberOfBytesRead,
NULL) )
{
pChannel->nStatus = STREAM_NONE;
}
}
}
RemoveFirstInQueue(&gChannelRequestQ);
pChannel->nSectorsToRead = 0;
if ( pChannel->bLocked )
{
ASSERT( pChannel->pDoneSemaphore != nil );
// Deadlock fix 2
#ifdef FIX_BUGS
pChannel->bLocked = 0;
#endif
ReleaseSemaphore(pChannel->pDoneSemaphore, 1, NULL);
}
pChannel->bReading = false;
}
}
bool
CdStreamAddImage(char const *path)
{
ASSERT(path != nil);
ASSERT(gNumImages < MAX_CDIMAGES);
SetLastError(0);
gImgFiles[gNumImages] = CreateFile(path,
GENERIC_READ,
FILE_SHARE_READ,
nil,
OPEN_EXISTING,
_gdwCdStreamFlags | FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_READONLY,
nil);
ASSERT( gImgFiles[gNumImages] != nil );
if ( gImgFiles[gNumImages] == NULL )
return false;
strcpy(gCdImageNames[gNumImages], path);
gNumImages++;
return true;
}
char *
CdStreamGetImageName(int32 cd)
{
ASSERT(cd < MAX_CDIMAGES);
if ( gImgFiles[cd] != nil )
return gCdImageNames[cd];
return nil;
}
void
CdStreamRemoveImages(void)
{
for ( int32 i = 0; i < gNumChannels; i++ )
CdStreamSync(i);
for ( int32 i = 0; i < gNumImages; i++ )
{
SetLastError(0);
CloseHandle(gImgFiles[i]);
gImgFiles[i] = nil;
}
gNumImages = 0;
}
int32
CdStreamGetNumImages(void)
{
return gNumImages;
}
#endif

48
src/core/CdStream.h Normal file
View file

@ -0,0 +1,48 @@
#pragma once
#define CDSTREAM_SECTOR_SIZE 2048
#define _GET_INDEX(a) (a >> 24)
#define _GET_OFFSET(a) (a & 0xFFFFFF)
enum
{
STREAM_NONE = uint8( 0),
STREAM_SUCCESS = uint8( 1),
STREAM_READING = uint8(-1), // 0xFF,
STREAM_ERROR = uint8(-2), // 0xFE,
STREAM_ERROR_NOCD = uint8(-3), // 0xFD,
STREAM_ERROR_WRONGCD = uint8(-4), // 0xFC,
STREAM_ERROR_OPENCD = uint8(-5), // 0xFB,
STREAM_WAITING = uint8(-6) // 0xFA,
};
struct Queue
{
int32 *items;
int32 head;
int32 tail;
int32 size;
};
VALIDATE_SIZE(Queue, 0x10);
void CdStreamInitThread(void);
void CdStreamInit(int32 numChannels);
uint32 GetGTA3ImgSize(void);
void CdStreamShutdown(void);
int32 CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size);
int32 CdStreamGetStatus(int32 channel);
int32 CdStreamGetLastPosn(void);
int32 CdStreamSync(int32 channel);
void AddToQueue(Queue *queue, int32 item);
int32 GetFirstInQueue(Queue *queue);
void RemoveFirstInQueue(Queue *queue);
bool CdStreamAddImage(char const *path);
char *CdStreamGetImageName(int32 cd);
void CdStreamRemoveImages(void);
int32 CdStreamGetNumImages(void);
#ifdef FLUSHABLE_STREAMING
extern bool flushStream[MAX_CDCHANNELS];
#endif

604
src/core/CdStreamPosix.cpp Normal file
View file

@ -0,0 +1,604 @@
#ifndef _WIN32
#include "common.h"
#include "crossplatform.h"
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <stdarg.h>
#include <limits.h>
#ifdef __linux__
#include <sys/syscall.h>
#endif
#include "CdStream.h"
#include "rwcore.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__)
#ifdef FLUSHABLE_STREAMING
bool flushStream[MAX_CDCHANNELS];
#endif
#ifdef USE_UNNAMED_SEM
#define RE3_SEM_OPEN(name, ...) re3_sem_open()
sem_t*
re3_sem_open(void)
{
sem_t* sem = (sem_t*)malloc(sizeof(sem_t));
if (sem_init(sem, 0, 1) == -1) {
sem = SEM_FAILED;
}
return sem;
}
#define RE3_SEM_CLOSE(sem, format, ...) re3_sem_close(sem)
void
re3_sem_close(sem_t* sem)
{
sem_destroy(sem);
free(sem);
}
#else
#define RE3_SEM_OPEN re3_sem_open
sem_t*
re3_sem_open(const char* format, ...)
{
char semName[21];
va_list va;
va_start(va, format);
vsprintf(semName, format, va);
return sem_open(semName, O_CREAT, 0644, 1);
}
#define RE3_SEM_CLOSE re3_sem_close
void
re3_sem_close(sem_t* sem, const char* format, ...)
{
sem_close(sem);
char semName[21];
va_list va;
va_start(va, format);
vsprintf(semName, format, va);
sem_unlink(semName);
}
#endif
struct CdReadInfo
{
uint32 nSectorOffset;
uint32 nSectorsToRead;
void *pBuffer;
bool bLocked;
bool bReading;
int32 nStatus;
#ifdef ONE_THREAD_PER_CHANNEL
int8 nThreadStatus; // 0: created 1:priority set up 2:abort now
pthread_t pChannelThread;
sem_t *pStartSemaphore;
#endif
sem_t *pDoneSemaphore; // used for CdStreamSync
int32 hFile;
};
char gCdImageNames[MAX_CDIMAGES+1][64];
int32 gNumImages;
int32 gNumChannels;
int32 gImgFiles[MAX_CDIMAGES]; // -1: error 0:unused otherwise: fd
char *gImgNames[MAX_CDIMAGES];
#ifndef ONE_THREAD_PER_CHANNEL
pthread_t _gCdStreamThread;
sem_t *gCdStreamSema; // released when we have new thing to read(so channel is set)
int8 gCdStreamThreadStatus; // 0: created 1:priority set up 2:abort now
Queue gChannelRequestQ;
bool _gbCdStreamOverlapped;
#endif
CdReadInfo *gpReadInfo;
int32 lastPosnRead;
int _gdwCdStreamFlags;
void *CdStreamThread(void* channelId);
void
CdStreamInitThread(void)
{
int status;
#ifndef ONE_THREAD_PER_CHANNEL
gChannelRequestQ.items = (int32 *)calloc(gNumChannels + 1, sizeof(int32));
gChannelRequestQ.head = 0;
gChannelRequestQ.tail = 0;
gChannelRequestQ.size = gNumChannels + 1;
ASSERT(gChannelRequestQ.items != nil );
gCdStreamSema = RE3_SEM_OPEN("/semaphore_cd_stream");
if (gCdStreamSema == SEM_FAILED) {
CDTRACE("failed to create stream semaphore");
ASSERT(0);
return;
}
#endif
if ( gNumChannels > 0 )
{
for ( int32 i = 0; i < gNumChannels; i++ )
{
gpReadInfo[i].pDoneSemaphore = RE3_SEM_OPEN("/semaphore_done%d", i);
if (gpReadInfo[i].pDoneSemaphore == SEM_FAILED)
{
CDTRACE("failed to create sync semaphore");
ASSERT(0);
return;
}
#ifdef ONE_THREAD_PER_CHANNEL
gpReadInfo[i].pStartSemaphore = RE3_SEM_OPEN("/semaphore_start%d", i);
if (gpReadInfo[i].pStartSemaphore == SEM_FAILED)
{
CDTRACE("failed to create start semaphore");
ASSERT(0);
return;
}
gpReadInfo[i].nThreadStatus = 0;
int *channelI = (int*)malloc(sizeof(int));
*channelI = i;
status = pthread_create(&gpReadInfo[i].pChannelThread, NULL, CdStreamThread, (void*)channelI);
if (status == -1)
{
CDTRACE("failed to create sync thread");
ASSERT(0);
return;
}
#endif
}
}
#ifndef ONE_THREAD_PER_CHANNEL
debug("Using one streaming thread for all channels\n");
gCdStreamThreadStatus = 0;
status = pthread_create(&_gCdStreamThread, NULL, CdStreamThread, nil);
if (status == -1)
{
CDTRACE("failed to create sync thread");
ASSERT(0);
return;
}
#else
debug("Using separate streaming threads for each channel\n");
#endif
}
void
CdStreamInit(int32 numChannels)
{
struct statvfs fsInfo;
if((statvfs("models/gta3.img", &fsInfo)) < 0)
{
CDTRACE("can't get filesystem info");
ASSERT(0);
return;
}
#ifdef __linux__
_gdwCdStreamFlags = O_RDONLY | O_NOATIME;
#else
_gdwCdStreamFlags = O_RDONLY;
#endif
// People say it's slower
/*
if ( fsInfo.f_bsize <= CDSTREAM_SECTOR_SIZE )
{
_gdwCdStreamFlags |= O_DIRECT;
debug("Using no buffered loading for streaming\n");
}
*/
void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, (RwUInt32)fsInfo.f_bsize);
ASSERT( pBuffer != nil );
gNumImages = 0;
gNumChannels = numChannels;
ASSERT( gNumChannels != 0 );
gpReadInfo = (CdReadInfo *)calloc(numChannels, sizeof(CdReadInfo));
ASSERT( gpReadInfo != nil );
CDDEBUG("read info %p", gpReadInfo);
CdStreamInitThread();
ASSERT( pBuffer != nil );
RwFreeAlign(pBuffer);
}
uint32
GetGTA3ImgSize(void)
{
ASSERT( gImgFiles[0] > 0 );
struct stat statbuf;
char path[PATH_MAX];
realpath(gImgNames[0], path);
if (stat(path, &statbuf) == -1) {
// Try case-insensitivity
char* real = casepath(gImgNames[0], false);
if (real)
{
realpath(real, path);
free(real);
if (stat(path, &statbuf) != -1)
goto ok;
}
CDTRACE("can't get size of gta3.img");
ASSERT(0);
return 0;
}
ok:
return (uint32)statbuf.st_size;
}
void
CdStreamShutdown(void)
{
// Destroying semaphores and free(gpReadInfo) will be done at threads
#ifndef ONE_THREAD_PER_CHANNEL
gCdStreamThreadStatus = 2;
sem_post(gCdStreamSema);
pthread_join(_gCdStreamThread, nil);
#else
for ( int32 i = 0; i < gNumChannels; i++ ) {
gpReadInfo[i].nThreadStatus = 2;
sem_post(gpReadInfo[i].pStartSemaphore);
pthread_join(gpReadInfo[i].pChannelThread, nil);
}
#endif
}
int32
CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size)
{
ASSERT( channel < gNumChannels );
ASSERT( buffer != nil );
lastPosnRead = size + offset;
ASSERT( _GET_INDEX(offset) < MAX_CDIMAGES );
int32 hImage = gImgFiles[_GET_INDEX(offset)];
ASSERT( hImage > 0 );
CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil );
if ( pChannel->nSectorsToRead != 0 || pChannel->bReading ) {
if (pChannel->hFile == hImage - 1 && pChannel->nSectorOffset == _GET_OFFSET(offset) && pChannel->nSectorsToRead >= size)
return STREAM_SUCCESS;
#ifdef FLUSHABLE_STREAMING
flushStream[channel] = 1;
CdStreamSync(channel);
#else
return STREAM_NONE;
#endif
}
pChannel->hFile = hImage - 1;
pChannel->nStatus = STREAM_NONE;
pChannel->nSectorOffset = _GET_OFFSET(offset);
pChannel->nSectorsToRead = size;
pChannel->pBuffer = buffer;
pChannel->bLocked = 0;
#ifndef ONE_THREAD_PER_CHANNEL
AddToQueue(&gChannelRequestQ, channel);
if ( sem_post(gCdStreamSema) != 0 )
printf("Signal Sema Error\n");
#else
if ( sem_post(pChannel->pStartSemaphore) != 0 )
printf("Signal Sema Error\n");
#endif
return STREAM_SUCCESS;
}
int32
CdStreamGetStatus(int32 channel)
{
ASSERT( channel < gNumChannels );
CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil );
#ifdef ONE_THREAD_PER_CHANNEL
if (pChannel->nThreadStatus == 2)
return STREAM_NONE;
#else
if (gCdStreamThreadStatus == 2)
return STREAM_NONE;
#endif
if ( pChannel->bReading )
return STREAM_READING;
if ( pChannel->nSectorsToRead != 0 )
return STREAM_WAITING;
if ( pChannel->nStatus != STREAM_NONE )
{
int32 status = pChannel->nStatus;
pChannel->nStatus = STREAM_NONE;
return status;
}
return STREAM_NONE;
}
int32
CdStreamGetLastPosn(void)
{
return lastPosnRead;
}
// wait for channel to finish reading
int32
CdStreamSync(int32 channel)
{
ASSERT( channel < gNumChannels );
CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil );
#ifdef FLUSHABLE_STREAMING
if (flushStream[channel]) {
pChannel->nSectorsToRead = 0;
#ifdef ONE_THREAD_PER_CHANNEL
pthread_kill(pChannel->pChannelThread, SIGUSR1);
if (pChannel->bReading) {
pChannel->bLocked = true;
#else
if (pChannel->bReading) {
pChannel->bLocked = true;
pthread_kill(_gCdStreamThread, SIGUSR1);
#endif
while (pChannel->bLocked)
sem_wait(pChannel->pDoneSemaphore);
}
pChannel->bReading = false;
flushStream[channel] = false;
return STREAM_NONE;
}
#endif
if ( pChannel->nSectorsToRead != 0 )
{
pChannel->bLocked = true;
while (pChannel->bLocked && pChannel->nSectorsToRead != 0){
sem_wait(pChannel->pDoneSemaphore);
}
pChannel->bLocked = false;
}
pChannel->bReading = false;
return pChannel->nStatus;
}
void
AddToQueue(Queue *queue, int32 item)
{
ASSERT( queue != nil );
ASSERT( queue->items != nil );
queue->items[queue->tail] = item;
queue->tail = (queue->tail + 1) % queue->size;
if ( queue->head == queue->tail )
debug("Queue is full\n");
}
int32
GetFirstInQueue(Queue *queue)
{
ASSERT( queue != nil );
if ( queue->head == queue->tail )
return -1;
ASSERT( queue->items != nil );
return queue->items[queue->head];
}
void
RemoveFirstInQueue(Queue *queue)
{
ASSERT( queue != nil );
if ( queue->head == queue->tail )
{
debug("Queue is empty\n");
return;
}
queue->head = (queue->head + 1) % queue->size;
}
void *CdStreamThread(void *param)
{
debug("Created cdstream thread\n");
#ifndef ONE_THREAD_PER_CHANNEL
while (gCdStreamThreadStatus != 2) {
sem_wait(gCdStreamSema);
int32 channel = GetFirstInQueue(&gChannelRequestQ);
// spurious wakeup
if (channel == -1)
continue;
#else
int channel = *((int*)param);
while (gpReadInfo[channel].nThreadStatus != 2){
sem_wait(gpReadInfo[channel].pStartSemaphore);
#endif
CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil );
// spurious wakeup or we sent interrupt signal for flushing
if(pChannel->nSectorsToRead == 0)
continue;
pChannel->bReading = true;
// Not standard POSIX :shrug:
#ifdef __linux__
#ifdef ONE_THREAD_PER_CHANNEL
if (gpReadInfo[channel].nThreadStatus == 0){
gpReadInfo[channel].nThreadStatus = 1;
#else
if (gCdStreamThreadStatus == 0){
gCdStreamThreadStatus = 1;
#endif
pid_t tid = syscall(SYS_gettid);
int ret = setpriority(PRIO_PROCESS, tid, getpriority(PRIO_PROCESS, getpid()) + 1);
}
#endif
if ( pChannel->nStatus == STREAM_NONE )
{
ASSERT(pChannel->hFile >= 0);
ASSERT(pChannel->pBuffer != nil );
lseek(pChannel->hFile, (size_t)pChannel->nSectorOffset * (size_t)CDSTREAM_SECTOR_SIZE, SEEK_SET);
if (read(pChannel->hFile, pChannel->pBuffer, pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE) == -1) {
// pChannel->nSectorsToRead == 0 at this point means we wanted to flush channel
// STREAM_WAITING is a little hack to make CStreaming not process this data
pChannel->nStatus = pChannel->nSectorsToRead == 0 ? STREAM_WAITING : STREAM_ERROR;
} else {
pChannel->nStatus = STREAM_NONE;
}
}
#ifndef ONE_THREAD_PER_CHANNEL
RemoveFirstInQueue(&gChannelRequestQ);
#endif
pChannel->nSectorsToRead = 0;
if ( pChannel->bLocked )
{
pChannel->bLocked = 0;
sem_post(pChannel->pDoneSemaphore);
}
pChannel->bReading = false;
}
char semName[20];
#ifndef ONE_THREAD_PER_CHANNEL
for ( int32 i = 0; i < gNumChannels; i++ )
{
RE3_SEM_CLOSE(gpReadInfo[i].pDoneSemaphore, "/semaphore_done%d", i);
}
RE3_SEM_CLOSE(gCdStreamSema, "/semaphore_cd_stream");
free(gChannelRequestQ.items);
#else
RE3_SEM_CLOSE(gpReadInfo[channel].pStartSemaphore, "/semaphore_start%d", channel);
RE3_SEM_CLOSE(gpReadInfo[channel].pDoneSemaphore, "/semaphore_done%d", channel);
#endif
if (gpReadInfo)
free(gpReadInfo);
gpReadInfo = nil;
pthread_exit(nil);
}
bool
CdStreamAddImage(char const *path)
{
ASSERT(path != nil);
ASSERT(gNumImages < MAX_CDIMAGES);
gImgFiles[gNumImages] = open(path, _gdwCdStreamFlags);
// Fix case sensitivity and backslashes.
if (gImgFiles[gNumImages] == -1) {
char* real = casepath(path, false);
if (real)
{
gImgFiles[gNumImages] = open(real, _gdwCdStreamFlags);
free(real);
}
}
if ( gImgFiles[gNumImages] == -1 ) {
assert(false);
return false;
}
gImgNames[gNumImages] = strdup(path);
gImgFiles[gNumImages]++; // because -1: error 0: not used
strcpy(gCdImageNames[gNumImages], path);
gNumImages++;
return true;
}
char *
CdStreamGetImageName(int32 cd)
{
ASSERT(cd < MAX_CDIMAGES);
if ( gImgFiles[cd] > 0)
return gCdImageNames[cd];
return nil;
}
void
CdStreamRemoveImages(void)
{
for ( int32 i = 0; i < gNumChannels; i++ ) {
#ifdef FLUSHABLE_STREAMING
flushStream[i] = 1;
#endif
CdStreamSync(i);
}
for ( int32 i = 0; i < gNumImages; i++ )
{
close(gImgFiles[i] - 1);
free(gImgNames[i]);
gImgFiles[i] = 0;
}
gNumImages = 0;
}
int32
CdStreamGetNumImages(void)
{
return gNumImages;
}
#endif

117
src/core/Clock.cpp Normal file
View file

@ -0,0 +1,117 @@
#include "common.h"
#include "Timer.h"
#include "Pad.h"
#include "Clock.h"
#include "Stats.h"
_TODO("gbFastTime");
bool gbFastTime;
uint8 CClock::ms_nGameClockHours;
uint8 CClock::ms_nGameClockMinutes;
uint16 CClock::ms_nGameClockSeconds;
uint8 CClock::ms_Stored_nGameClockHours;
uint8 CClock::ms_Stored_nGameClockMinutes;
uint16 CClock::ms_Stored_nGameClockSeconds;
uint32 CClock::ms_nMillisecondsPerGameMinute;
uint32 CClock::ms_nLastClockTick;
bool CClock::ms_bClockHasBeenStored;
void
CClock::Initialise(uint32 scale)
{
debug("Initialising CClock...\n");
ms_nGameClockHours = 12;
ms_nGameClockMinutes = 0;
ms_nGameClockSeconds = 0;
ms_nMillisecondsPerGameMinute = scale;
ms_nLastClockTick = CTimer::GetTimeInMilliseconds();
ms_bClockHasBeenStored = false;
debug("CClock ready\n");
}
void
CClock::Update(void)
{
if(CPad::GetPad(1)->GetRightShoulder1())
{
ms_nGameClockMinutes += 8;
ms_nLastClockTick = CTimer::GetTimeInMilliseconds();
if(ms_nGameClockMinutes >= 60)
{
ms_nGameClockHours++;
ms_nGameClockMinutes = 0;
if(ms_nGameClockHours >= 24)
ms_nGameClockHours = 0;
}
}
else if(CTimer::GetTimeInMilliseconds() - ms_nLastClockTick > ms_nMillisecondsPerGameMinute || gbFastTime)
{
ms_nGameClockMinutes++;
ms_nLastClockTick += ms_nMillisecondsPerGameMinute;
if ( gbFastTime )
ms_nLastClockTick = CTimer::GetTimeInMilliseconds();
if(ms_nGameClockMinutes >= 60)
{
ms_nGameClockHours++;
ms_nGameClockMinutes = 0;
if(ms_nGameClockHours >= 24)
{
CStats::DaysPassed++;
ms_nGameClockHours = 0;
}
}
}
ms_nGameClockSeconds = 60 * (CTimer::GetTimeInMilliseconds() - ms_nLastClockTick) / ms_nMillisecondsPerGameMinute;
}
void
CClock::SetGameClock(uint8 h, uint8 m)
{
ms_nGameClockHours = h;
ms_nGameClockMinutes = m;
ms_nGameClockSeconds = 0;
ms_nLastClockTick = CTimer::GetTimeInMilliseconds();
}
int32
CClock::GetGameClockMinutesUntil(uint8 h, uint8 m)
{
int32 now, then;
now = ms_nGameClockHours*60 + ms_nGameClockMinutes;
then = h*60 + m;
if(then < now)
then += 24*60;
return then-now;
}
bool
CClock::GetIsTimeInRange(uint8 h1, uint8 h2)
{
if(h1 > h2)
return ms_nGameClockHours >= h1 || ms_nGameClockHours < h2;
else
return ms_nGameClockHours >= h1 && ms_nGameClockHours < h2;
}
void
CClock::StoreClock(void)
{
ms_Stored_nGameClockHours = ms_nGameClockHours;
ms_Stored_nGameClockMinutes = ms_nGameClockMinutes;
ms_Stored_nGameClockSeconds = ms_nGameClockSeconds;
ms_bClockHasBeenStored = true;
}
void
CClock::RestoreClock(void)
{
ms_nGameClockHours = ms_Stored_nGameClockHours;
ms_nGameClockMinutes = ms_Stored_nGameClockMinutes;
ms_nGameClockSeconds = ms_Stored_nGameClockSeconds;
}

31
src/core/Clock.h Normal file
View file

@ -0,0 +1,31 @@
#pragma once
class CClock
{
public:
static uint8 ms_nGameClockHours;
static uint8 ms_nGameClockMinutes;
static uint16 ms_nGameClockSeconds;
static uint8 ms_Stored_nGameClockHours;
static uint8 ms_Stored_nGameClockMinutes;
static uint16 ms_Stored_nGameClockSeconds;
static uint32 ms_nMillisecondsPerGameMinute;
static uint32 ms_nLastClockTick;
static bool ms_bClockHasBeenStored;
static void Initialise(uint32 scale);
static void Update(void);
static void SetGameClock(uint8 h, uint8 m);
static int32 GetGameClockMinutesUntil(uint8 h, uint8 m);
static bool GetIsTimeInRange(uint8 h1, uint8 h2);
static void StoreClock(void);
static void RestoreClock(void);
static uint8 GetHours(void) { return ms_nGameClockHours; }
static uint8 GetMinutes(void) { return ms_nGameClockMinutes; }
static int16 GetSeconds(void) { return ms_nGameClockSeconds; }
static uint8 &GetHoursRef(void) { return ms_nGameClockHours; }
static uint8 &GetMinutesRef(void) { return ms_nGameClockMinutes; }
};

File diff suppressed because it is too large Load diff

226
src/core/ControllerConfig.h Normal file
View file

@ -0,0 +1,226 @@
#pragma once
#if defined RW_D3D9 || defined RWLIBS
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#endif
// based on x-gtasa
enum eControllerType
{
KEYBOARD = 0,
OPTIONAL_EXTRA,
MOUSE,
JOYSTICK,
MAX_CONTROLLERTYPES,
};
enum e_ControllerAction
{
PED_FIREWEAPON = 0,
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, // Unused
TOGGLE_DPAD,
SWITCH_DEBUG_CAM_ON,
TAKE_SCREEN_SHOT,
SHOW_MOUSE_POINTER_TOGGLE,
MAX_CONTROLLERACTIONS,
};
enum e_ControllerActionType
{
ACTIONTYPE_1RSTPERSON = 0,
ACTIONTYPE_3RDPERSON,
ACTIONTYPE_VEHICLE,
ACTIONTYPE_VEHICLE_3RDPERSON,
ACTIONTYPE_COMMON,
ACTIONTYPE_1RST3RDPERSON,
ACTIONTYPE_NONE,
};
enum eContSetOrder
{
SETORDER_NONE = 0,
SETORDER_1,
SETORDER_2,
SETORDER_3,
SETORDER_4,
MAX_SETORDERS,
};
enum eSimCheckers
{
SIM_X1 = 0, SIM_Y1, // DPad
SIM_X2, SIM_Y2, // LeftStick
MAX_SIMS
};
class CMouseControllerState;
class CControllerState;
#define JOY_BUTTONS 16
#define MAX_BUTTONS (JOY_BUTTONS+1)
#define ACTIONNAME_LENGTH 40
#ifdef RW_GL3
struct GlfwJoyState {
int8 id;
bool isGamepad;
uint8 numButtons;
uint8* buttons;
bool mappedButtons[17];
};
#endif
class CControllerConfigManager
{
public:
struct tControllerConfigBind
{
int32 m_Key;
int32 m_ContSetOrder;
tControllerConfigBind()
{
m_Key = 0;
m_ContSetOrder = 0;
}
};
bool m_bFirstCapture;
#if defined RW_GL3
GlfwJoyState m_OldState;
GlfwJoyState m_NewState;
#else
DIJOYSTATE2 m_OldState;
DIJOYSTATE2 m_NewState;
#endif
wchar m_aActionNames[MAX_CONTROLLERACTIONS][ACTIONNAME_LENGTH];
bool m_aButtonStates[MAX_BUTTONS];
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();
void MakeControllerActionsBlank();
int32 GetJoyButtonJustDown();
void SaveSettings(int32 file);
void LoadSettings(int32 file);
void InitDefaultControlConfiguration();
void InitDefaultControlConfigMouse(CMouseControllerState const &availableButtons);
void InitDefaultControlConfigJoyPad(uint32 buttons);
void InitialiseControllerActionNameArray();
void UpdateJoyInConfigMenus_ButtonDown (int32 button, int32 padnumber);
void AffectControllerStateOn_ButtonDown (int32 button, eControllerType type);
void AffectControllerStateOn_ButtonDown_Driving (int32 button, eControllerType type, CControllerState &state);
void AffectControllerStateOn_ButtonDown_FirstPersonOnly (int32 button, eControllerType type, CControllerState &state);
void AffectControllerStateOn_ButtonDown_ThirdPersonOnly (int32 button, eControllerType type, CControllerState &state);
void AffectControllerStateOn_ButtonDown_FirstAndThirdPersonOnly (int32 button, eControllerType type, CControllerState &state);
void AffectControllerStateOn_ButtonDown_AllStates (int32 button, eControllerType type, CControllerState &state);
void AffectControllerStateOn_ButtonDown_VehicleAndThirdPersonOnly(int32 button, eControllerType type, CControllerState &state);
void UpdateJoyInConfigMenus_ButtonUp(int32 button, int32 padnumber);
void AffectControllerStateOn_ButtonUp(int32 button, eControllerType type);
void AffectControllerStateOn_ButtonUp_All_Player_States(int32 button, eControllerType type, CControllerState &state);
void AffectPadFromKeyBoard();
void AffectPadFromMouse();
void ClearSimButtonPressCheckers();
bool GetIsKeyboardKeyDown (RsKeyCodes keycode);
bool GetIsKeyboardKeyJustDown(RsKeyCodes keycode);
bool GetIsMouseButtonDown (RsKeyCodes keycode);
bool GetIsMouseButtonUp (RsKeyCodes keycode);
void DeleteMatchingCommonControls (e_ControllerAction action, int32 key, eControllerType type);
void DeleteMatching3rdPersonControls (e_ControllerAction action, int32 key, eControllerType type);
void DeleteMatching1rst3rdPersonControls (e_ControllerAction action, int32 key, eControllerType type);
void DeleteMatchingVehicleControls (e_ControllerAction action, int32 key, eControllerType type);
void DeleteMatchingVehicle_3rdPersonControls(e_ControllerAction action, int32 key, eControllerType type);
void DeleteMatching1rstPersonControls (e_ControllerAction action, int32 key, eControllerType type);
void DeleteMatchingActionInitiators (e_ControllerAction action, int32 key, eControllerType type);
#ifdef RADIO_SCROLL_TO_PREV_STATION
bool IsAnyVehicleActionAssignedToMouseKey(int32 key);
#endif
bool GetIsKeyBlank(int32 key, eControllerType type);
e_ControllerActionType GetActionType(e_ControllerAction action);
void ClearSettingsAssociatedWithAction (e_ControllerAction action, eControllerType type);
wchar *GetControllerSettingTextWithOrderNumber(e_ControllerAction action, eContSetOrder setorder);
wchar *GetControllerSettingTextKeyBoard (e_ControllerAction action, eControllerType type);
wchar *GetControllerSettingTextMouse (e_ControllerAction action);
wchar *GetControllerSettingTextJoystick (e_ControllerAction action);
int32 GetNumOfSettingsForAction(e_ControllerAction action);
void GetWideStringOfCommandKeys(uint16 action, wchar *text, uint16 leight);
int32 GetControllerKeyAssociatedWithAction(e_ControllerAction action, eControllerType type);
void UpdateJoyButtonState(int32 padnumber);
bool GetIsActionAButtonCombo (e_ControllerAction action);
wchar *GetButtonComboText (e_ControllerAction action);
void SetControllerKeyAssociatedWithAction(e_ControllerAction action, int32 key, eControllerType type);
int32 GetMouseButtonAssociatedWithAction (e_ControllerAction action);
void SetMouseButtonAssociatedWithAction (e_ControllerAction action, int32 button);
void ResetSettingOrder (e_ControllerAction action);
};
#ifndef RW_GL3
VALIDATE_SIZE(CControllerConfigManager, 0x143C);
#endif
extern CControllerConfigManager ControlsManager;

36
src/core/Crime.h Normal file
View file

@ -0,0 +1,36 @@
#pragma once
enum eCrimeType {
CRIME_NONE,
CRIME_POSSESSION_GUN,
CRIME_HIT_PED,
CRIME_HIT_COP,
CRIME_SHOOT_PED,
CRIME_SHOOT_COP,
CRIME_STEAL_CAR,
CRIME_RUN_REDLIGHT,
CRIME_RECKLESS_DRIVING,
CRIME_SPEEDING,
CRIME_RUNOVER_PED,
CRIME_RUNOVER_COP,
CRIME_SHOOT_HELI,
CRIME_PED_BURNED,
CRIME_COP_BURNED,
CRIME_VEHICLE_BURNED,
CRIME_DESTROYED_CESSNA,
NUM_CRIME_TYPES
};
class CCrimeBeingQd
{
public:
eCrimeType m_nType;
int32 m_nId;
uint32 m_nTime;
CVector m_vecPosn;
bool m_bReported;
bool m_bPoliceDoesntCare;
CCrimeBeingQd() { };
~CCrimeBeingQd() { };
};

170
src/core/Debug.cpp Normal file
View file

@ -0,0 +1,170 @@
#include "common.h"
#include "RwHelper.h"
#include "Debug.h"
#include "Lines.h"
#include "Font.h"
#include "main.h"
#include "Text.h"
bool gbDebugStuffInRelease = false;
#define DEBUG_X_POS (300)
#define DEBUG_Y_POS (41)
#define DEBUG_LINE_HEIGHT (22)
int16 CDebug::ms_nCurrentTextLine;
char CDebug::ms_aTextBuffer[MAX_LINES][MAX_STR_LEN];
void
CDebug::DebugInitTextBuffer()
{
ms_nCurrentTextLine = 0;
}
void
CDebug::DebugAddText(const char *str)
{
int32 i = 0;
if (*str != '\0') {
while (i < MAX_STR_LEN - 1) {
ms_aTextBuffer[ms_nCurrentTextLine][i++] = *(str++);
if (*str == '\0')
break;
}
}
ms_aTextBuffer[ms_nCurrentTextLine++][i] = '\0';
if (ms_nCurrentTextLine >= MAX_LINES)
ms_nCurrentTextLine = 0;
}
void
CDebug::DebugDisplayTextBuffer()
{
#ifndef MASTER
if (gbDebugStuffInRelease)
{
int32 i = 0;
int32 y = DEBUG_Y_POS;
#ifdef FIX_BUGS
CFont::SetPropOn();
CFont::SetBackgroundOff();
CFont::SetScale(1.0f, 1.0f);
CFont::SetCentreOff();
CFont::SetRightJustifyOff();
CFont::SetJustifyOn();
CFont::SetRightJustifyWrap(0.0f);
CFont::SetBackGroundOnlyTextOff();
CFont::SetFontStyle(FONT_BANK);
#else
// this is not even readable
CFont::SetPropOff();
CFont::SetBackgroundOff();
CFont::SetScale(1.0f, 1.0f);
CFont::SetCentreOff();
CFont::SetRightJustifyOn();
CFont::SetRightJustifyWrap(0.0f);
CFont::SetBackGroundOnlyTextOff();
CFont::SetFontStyle(FONT_BANK);
CFont::SetPropOff();
#endif
do {
char *line;
while (true) {
line = ms_aTextBuffer[(ms_nCurrentTextLine + i++) % MAX_LINES];
if (*line != '\0')
break;
y += DEBUG_LINE_HEIGHT;
if (i == MAX_LINES) {
CFont::DrawFonts();
return;
}
}
AsciiToUnicode(line, gUString);
CFont::SetColor(CRGBA(0, 0, 0, 255));
CFont::PrintString(DEBUG_X_POS, y-1, gUString);
CFont::SetColor(CRGBA(255, 128, 128, 255));
CFont::PrintString(DEBUG_X_POS+1, y, gUString);
y += DEBUG_LINE_HEIGHT;
} while (i != MAX_LINES);
CFont::DrawFonts();
}
#endif
}
// custom
CDebug::ScreenStr CDebug::ms_aScreenStrs[MAX_SCREEN_STRS];
int CDebug::ms_nScreenStrs;
void
CDebug::DisplayScreenStrings()
{
int i;
CFont::SetPropOn();
CFont::SetBackgroundOff();
CFont::SetScale(1.0f, 1.0f);
CFont::SetCentreOff();
CFont::SetRightJustifyOff();
CFont::SetJustifyOff();
CFont::SetRightJustifyWrap(0.0f);
CFont::SetWrapx(9999.0f);
CFont::SetBackGroundOnlyTextOff();
CFont::SetFontStyle(FONT_BANK);
for(i = 0; i < ms_nScreenStrs; i++){
/*
AsciiToUnicode(ms_aScreenStrs[i].str, gUString);
CFont::SetColor(CRGBA(0, 0, 0, 255));
CFont::PrintString(ms_aScreenStrs[i].x, ms_aScreenStrs[i].y, gUString);
CFont::SetColor(CRGBA(255, 255, 255, 255));
CFont::PrintString(ms_aScreenStrs[i].x+1, ms_aScreenStrs[i].y+1, gUString);
*/
ObrsPrintfString(ms_aScreenStrs[i].str, ms_aScreenStrs[i].x, ms_aScreenStrs[i].y);
}
CFont::DrawFonts();
ms_nScreenStrs = 0;
}
void
CDebug::PrintAt(const char *str, int x, int y)
{
if(ms_nScreenStrs >= MAX_SCREEN_STRS)
return;
strncpy(ms_aScreenStrs[ms_nScreenStrs].str, str, 256);
ms_aScreenStrs[ms_nScreenStrs].x = x;//*12;
ms_aScreenStrs[ms_nScreenStrs].y = y;//*22;
ms_nScreenStrs++;
}
CDebug::Line CDebug::ms_aLines[MAX_DEBUG_LINES];
int CDebug::ms_nLines;
void
CDebug::AddLine(CVector p1, CVector p2, uint32 c1, uint32 c2)
{
if(ms_nLines >= MAX_DEBUG_LINES)
return;
ms_aLines[ms_nLines].p1 = p1;
ms_aLines[ms_nLines].p2 = p2;
ms_aLines[ms_nLines].c1 = c1;
ms_aLines[ms_nLines].c2 = c2;
ms_nLines++;
}
void
CDebug::DrawLines(void)
{
int i;
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
for(i = 0; i < ms_nLines; i++){
Line *l = &ms_aLines[i];
CLines::RenderLineWithClipping(l->p1.x, l->p1.y, l->p1.z, l->p2.x, l->p2.y, l->p2.z, l->c1, l->c2);
}
ms_nLines = 0;
}

45
src/core/Debug.h Normal file
View file

@ -0,0 +1,45 @@
#pragma once
class CDebug
{
enum
{
MAX_LINES = 15,
MAX_STR_LEN = 80,
MAX_SCREEN_STRS = 100,
MAX_DEBUG_LINES = 100,
};
static int16 ms_nCurrentTextLine;
static char ms_aTextBuffer[MAX_LINES][MAX_STR_LEN];
// custom
struct ScreenStr {
int x, y;
char str[256];
};
static ScreenStr ms_aScreenStrs[MAX_SCREEN_STRS];
static int ms_nScreenStrs;
struct Line {
CVector p1, p2;
uint32 c1, c2;
};
static Line ms_aLines[MAX_DEBUG_LINES];
static int ms_nLines;
public:
static void DebugInitTextBuffer();
static void DebugDisplayTextBuffer();
static void DebugAddText(const char *str);
// custom
static void PrintAt(const char *str, int x, int y);
static void DisplayScreenStrings();
static void AddLine(CVector p1, CVector p2, uint32 c1, uint32 c2);
static void DrawLines(void);
};
extern bool gbDebugStuffInRelease;

74
src/core/Directory.cpp Normal file
View file

@ -0,0 +1,74 @@
#include "common.h"
#include "General.h"
#include "FileMgr.h"
#include "Directory.h"
CDirectory::CDirectory(int32 maxEntries)
: numEntries(0), maxEntries(maxEntries)
{
entries = new DirectoryInfo[maxEntries];
}
CDirectory::~CDirectory(void)
{
delete[] entries;
}
void
CDirectory::ReadDirFile(const char *filename)
{
int fd;
DirectoryInfo dirinfo;
fd = CFileMgr::OpenFile(filename, "rb");
while(CFileMgr::Read(fd, (char*)&dirinfo, sizeof(dirinfo)))
AddItem(dirinfo);
CFileMgr::CloseFile(fd);
}
bool
CDirectory::WriteDirFile(const char *filename)
{
int fd;
size_t n;
fd = CFileMgr::OpenFileForWriting(filename);
n = CFileMgr::Write(fd, (char*)entries, numEntries*sizeof(DirectoryInfo));
CFileMgr::CloseFile(fd);
return n == numEntries*sizeof(DirectoryInfo);
}
void
CDirectory::AddItem(const DirectoryInfo &dirinfo)
{
assert(numEntries < maxEntries);
#ifdef FIX_BUGS
// don't add if already exists
uint32 offset, size;
if(FindItem(dirinfo.name, offset, size))
return;
#endif
entries[numEntries++] = dirinfo;
}
void
CDirectory::AddItem(const DirectoryInfo &dirinfo, int32 imgId)
{
DirectoryInfo di = dirinfo;
di.offset |= imgId<<24;
AddItem(di);
}
bool
CDirectory::FindItem(const char *name, uint32 &offset, uint32 &size)
{
int i;
for(i = 0; i < numEntries; i++)
if(!CGeneral::faststricmp(entries[i].name, name)){
offset = entries[i].offset;
size = entries[i].size;
return true;
}
return false;
}

23
src/core/Directory.h Normal file
View file

@ -0,0 +1,23 @@
#pragma once
class CDirectory
{
public:
struct DirectoryInfo {
uint32 offset;
uint32 size;
char name[24];
};
DirectoryInfo *entries;
int32 maxEntries;
int32 numEntries;
CDirectory(int32 maxEntries);
~CDirectory(void);
void ReadDirFile(const char *filename);
bool WriteDirFile(const char *filename);
void AddItem(const DirectoryInfo &dirinfo);
void AddItem(const DirectoryInfo &dirinfo, int32 imgId);
bool FindItem(const char *name, uint32 &offset, uint32 &size);
};

237
src/core/EventList.cpp Normal file
View file

@ -0,0 +1,237 @@
#include "common.h"
#include "Pools.h"
#include "ModelIndices.h"
#include "World.h"
#include "Wanted.h"
#include "EventList.h"
#include "Messages.h"
#include "Text.h"
#include "main.h"
#include "Accident.h"
int32 CEventList::ms_nFirstFreeSlotIndex;
CEvent gaEvent[NUMEVENTS];
enum
{
EVENT_STATE_0,
EVENT_STATE_CANDELETE,
EVENT_STATE_CLEAR,
};
void
CEventList::Initialise(void)
{
int i;
debug("Initialising CEventList...");
for(i = 0; i < NUMEVENTS; i++){
gaEvent[i].type = EVENT_NULL;
gaEvent[i].entityType = EVENT_ENTITY_NONE;
gaEvent[i].entityRef = 0;
gaEvent[i].posn.x = 0.0f;
gaEvent[i].posn.y = 0.0f;
gaEvent[i].posn.z = 0.0f;
gaEvent[i].timeout = 0;
gaEvent[i].state = EVENT_STATE_0;
}
ms_nFirstFreeSlotIndex = 0;
}
void
CEventList::Update(void)
{
int i;
ms_nFirstFreeSlotIndex = 0;
for(i = 0; i < NUMEVENTS; i++){
if(gaEvent[i].type == EVENT_NULL)
continue;
if(CTimer::GetTimeInMilliseconds() > gaEvent[i].timeout || gaEvent[i].state == EVENT_STATE_CANDELETE){
gaEvent[i].type = EVENT_NULL;
gaEvent[i].state = EVENT_STATE_0;
}
if(gaEvent[i].state == EVENT_STATE_CLEAR)
gaEvent[i].state = EVENT_STATE_CANDELETE;
}
}
void
CEventList::RegisterEvent(eEventType type, eEventEntity entityType, CEntity *ent, CPed *criminal, int32 timeout)
{
int i;
int ref;
bool copsDontCare;
#ifdef SQUEEZE_PERFORMANCE
if (type == EVENT_INJURED_PED) {
gAccidentManager.ReportAccident((CPed*)ent);
return;
}
#endif
copsDontCare = false;
switch(entityType){
case EVENT_ENTITY_PED:
ref = CPools::GetPedRef((CPed*)ent);
if(ent->GetModelIndex() >= MI_GANG01 && ent->GetModelIndex() <= MI_CRIMINAL02)
copsDontCare = true;
break;
case EVENT_ENTITY_VEHICLE:
ref = CPools::GetVehicleRef((CVehicle*)ent);
break;
case EVENT_ENTITY_OBJECT:
ref = CPools::GetObjectRef((CObject*)ent);
break;
default:
Error("Undefined entity type, RegisterEvent, EventList.cpp");
ref = 0;
break;
}
// only update time if event exists already
for(i = 0; i < NUMEVENTS; i++)
if(gaEvent[i].type == type &&
gaEvent[i].entityType == entityType &&
gaEvent[i].entityRef == ref){
gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout;
return;
}
for(i = ms_nFirstFreeSlotIndex; i < NUMEVENTS; i++)
if(gaEvent[i].type == EVENT_NULL){
ms_nFirstFreeSlotIndex = i;
break;
}
if(i < NUMEVENTS){
gaEvent[i].type = type;
gaEvent[i].entityType = entityType;
gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout;
gaEvent[i].entityRef = ref;
gaEvent[i].posn = ent->GetPosition();
gaEvent[i].criminal = criminal;
if(gaEvent[i].criminal)
gaEvent[i].criminal->RegisterReference((CEntity**)&gaEvent[i].criminal);
if(type == EVENT_GUNSHOT)
gaEvent[i].state = EVENT_STATE_CLEAR;
else
gaEvent[i].state = EVENT_STATE_0;
}
if(criminal == FindPlayerPed())
ReportCrimeForEvent(type, (intptr)ent, copsDontCare);
}
void
CEventList::RegisterEvent(eEventType type, CVector posn, int32 timeout)
{
int i;
// only update time if event exists already
for(i = 0; i < NUMEVENTS; i++)
if(gaEvent[i].type == type &&
gaEvent[i].posn.x == posn.x &&
gaEvent[i].posn.y == posn.y &&
gaEvent[i].posn.z == posn.z &&
gaEvent[i].entityType == EVENT_ENTITY_NONE){
gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout;
return;
}
for(i = ms_nFirstFreeSlotIndex; i < NUMEVENTS; i++)
if(gaEvent[i].type == EVENT_NULL){
ms_nFirstFreeSlotIndex = i;
break;
}
if(i < NUMEVENTS){
gaEvent[i].type = type;
gaEvent[i].entityType = EVENT_ENTITY_NONE;
gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout;
gaEvent[i].posn = posn;
gaEvent[i].entityRef = 0;
if(type == EVENT_GUNSHOT)
gaEvent[i].state = EVENT_STATE_CLEAR;
else
gaEvent[i].state = EVENT_STATE_0;
}
}
bool
CEventList::GetEvent(eEventType type, int32 *event)
{
int i;
for(i = 0; i < NUMEVENTS; i++)
if(gaEvent[i].type == type){
*event = i;
return true;
}
return false;
}
void
CEventList::ClearEvent(int32 event)
{
if(gaEvent[event].state != EVENT_STATE_CANDELETE)
gaEvent[event].state = EVENT_STATE_CLEAR;
}
bool
CEventList::FindClosestEvent(eEventType type, CVector posn, int32 *event)
{
int i;
float dist;
bool found = false;
float mindist = 60.0f;
for(i = 0; i < NUMEVENTS; i++){
if(gaEvent[i].type != type)
continue;
dist = (posn - gaEvent[i].posn).Magnitude();
if(dist < mindist){
mindist = dist;
found = true;
*event = i;
}
}
return found;
}
void
CEventList::ReportCrimeForEvent(eEventType type, intptr crimeId, bool copsDontCare)
{
eCrimeType crime;
switch(type){
case EVENT_ASSAULT: crime = CRIME_HIT_PED; break;
case EVENT_RUN_REDLIGHT: crime = CRIME_RUN_REDLIGHT; break;
case EVENT_ASSAULT_POLICE: crime = CRIME_HIT_COP; break;
case EVENT_GUNSHOT: crime = CRIME_POSSESSION_GUN; break;
case EVENT_STEAL_CAR: crime = CRIME_STEAL_CAR; break;
case EVENT_HIT_AND_RUN: crime = CRIME_RUNOVER_PED; break;
case EVENT_HIT_AND_RUN_COP: crime = CRIME_RUNOVER_COP; break;
case EVENT_SHOOT_PED: crime = CRIME_SHOOT_PED; break;
case EVENT_SHOOT_COP: crime = CRIME_SHOOT_COP; break;
case EVENT_PED_SET_ON_FIRE: crime = CRIME_PED_BURNED; break;
case EVENT_COP_SET_ON_FIRE: crime = CRIME_COP_BURNED; break;
case EVENT_CAR_SET_ON_FIRE: crime = CRIME_VEHICLE_BURNED; break;
default: crime = CRIME_NONE; break;
}
if(crime == CRIME_NONE)
return;
CVector playerPedCoors = FindPlayerPed()->GetPosition();
CVector playerCoors = FindPlayerCoors();
if(CWanted::WorkOutPolicePresence(playerCoors, 14.0f) != 0){
FindPlayerPed()->m_pWanted->RegisterCrime_Immediately(crime, playerPedCoors, crimeId, copsDontCare);
FindPlayerPed()->m_pWanted->SetWantedLevelNoDrop(1);
}else
FindPlayerPed()->m_pWanted->RegisterCrime(crime, playerPedCoors, crimeId, copsDontCare);
if(type == EVENT_ASSAULT_POLICE)
FindPlayerPed()->SetWantedLevelNoDrop(1);
if(type == EVENT_SHOOT_COP)
FindPlayerPed()->SetWantedLevelNoDrop(2);
}

65
src/core/EventList.h Normal file
View file

@ -0,0 +1,65 @@
#pragma once
class CEntity;
class CPed;
enum eEventType
{
EVENT_NULL,
EVENT_ASSAULT,
EVENT_RUN_REDLIGHT,
EVENT_ASSAULT_POLICE,
EVENT_GUNSHOT,
EVENT_INJURED_PED,
EVENT_DEAD_PED,
EVENT_FIRE,
EVENT_STEAL_CAR,
EVENT_HIT_AND_RUN,
EVENT_HIT_AND_RUN_COP,
EVENT_SHOOT_PED,
EVENT_SHOOT_COP,
EVENT_EXPLOSION,
EVENT_PED_SET_ON_FIRE,
EVENT_COP_SET_ON_FIRE,
EVENT_CAR_SET_ON_FIRE,
EVENT_ASSAULT_NASTYWEAPON, // not sure
EVENT_ICECREAM,
EVENT_ATM,
EVENT_SHOPSTALL, // used on graffitis
EVENT_LAST_EVENT
};
enum eEventEntity
{
EVENT_ENTITY_NONE,
EVENT_ENTITY_PED,
EVENT_ENTITY_VEHICLE,
EVENT_ENTITY_OBJECT
};
struct CEvent
{
eEventType type;
eEventEntity entityType;
int32 entityRef;
CPed *criminal;
CVector posn;
uint32 timeout;
int32 state;
};
class CEventList
{
static int32 ms_nFirstFreeSlotIndex;
public:
static void Initialise(void);
static void Update(void);
static void RegisterEvent(eEventType type, eEventEntity entityType, CEntity *ent, CPed *criminal, int32 timeout);
static void RegisterEvent(eEventType type, CVector posn, int32 timeout);
static bool GetEvent(eEventType type, int32 *event);
static void ClearEvent(int32 event);
static bool FindClosestEvent(eEventType type, CVector posn, int32 *event);
static void ReportCrimeForEvent(eEventType type, intptr, bool);
};
extern CEvent gaEvent[NUMEVENTS];

1852
src/core/FileLoader.cpp Normal file

File diff suppressed because it is too large Load diff

49
src/core/FileLoader.h Normal file
View file

@ -0,0 +1,49 @@
#pragma once
class CFileLoader
{
static char ms_line[256];
public:
static void LoadLevel(const char *filename);
static void LoadCollisionFromDatFile(int currlevel);
static char *LoadLine(int fd);
static RwTexDictionary *LoadTexDictionary(const char *filename);
static void LoadCollisionFile(const char *filename);
static void LoadCollisionModel(uint8 *buf, struct CColModel &model, char *name);
static void LoadModelFile(const char *filename);
static RpAtomic *FindRelatedModelInfoCB(RpAtomic *atomic, void *data);
static void LoadClumpFile(const char *filename);
static bool LoadClumpFile(RwStream *stream, uint32 id);
static bool StartLoadClumpFile(RwStream *stream, uint32 id);
static bool FinishLoadClumpFile(RwStream *stream, uint32 id);
static bool LoadAtomicFile(RwStream *stream, uint32 id);
static RpAtomic *SetRelatedModelInfoCB(RpAtomic *atomic, void *data);
static RpClump *LoadAtomicFile2Return(const char *filename);
static void AddTexDictionaries(RwTexDictionary *dst, RwTexDictionary *src);
static void LoadObjectTypes(const char *filename);
static void LoadObject(const char *line);
static int LoadMLO(const char *line);
static void LoadMLOInstance(int id, const char *line);
static void LoadTimeObject(const char *line);
static void LoadClumpObject(const char *line);
static void LoadVehicleObject(const char *line);
static void LoadPedObject(const char *line);
static int LoadPathHeader(const char *line, char *type);
static void LoadPedPathNode(const char *line, int id, int node);
static void LoadCarPathNode(const char *line, int id, int node);
static void Load2dEffect(const char *line);
static void LoadScene(const char *filename);
static void LoadObjectInstance(const char *line);
static void LoadZone(const char *line);
static void LoadCullZone(const char *line);
static void LoadPickup(const char *line);
static void LoadMapZones(const char *filename);
static void ReloadPaths(const char *filename);
static void ReloadObjectTypes(const char *filename);
static void ReloadObject(const char *line);
static void ReLoadScene(const char *filename); // unused mobile function
};

313
src/core/FileMgr.cpp Normal file
View file

@ -0,0 +1,313 @@
#define _CRT_SECURE_NO_WARNINGS
#include <fcntl.h>
#ifdef _WIN32
#include <direct.h>
#endif
#include "common.h"
#include "crossplatform.h"
#include "FileMgr.h"
const char *_psGetUserFilesFolder();
/*
* Windows FILE is BROKEN for GTA.
*
* We need to support mapping between LF and CRLF for text files
* but we do NOT want to end the file at the first sight of a SUB character.
* So here is a simple implementation of a FILE interface that works like GTA expects.
*/
struct myFILE
{
bool isText;
FILE *file;
};
#define NUMFILES 20
static myFILE myfiles[NUMFILES];
#if !defined(_WIN32)
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#define _getcwd getcwd
// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
void mychdir(char const *path)
{
char* r = casepath(path, false);
if (r) {
chdir(r);
free(r);
} else {
errno = ENOENT;
}
}
#else
#define mychdir chdir
#endif
/* Force file to open as binary but remember if it was text mode */
static int
myfopen(const char *filename, const char *mode)
{
int fd;
char realmode[10], *p;
for(fd = 1; fd < NUMFILES; fd++)
if(myfiles[fd].file == nil)
goto found;
return 0; // no free fd
found:
myfiles[fd].isText = strchr(mode, 'b') == nil;
p = realmode;
while(*mode)
if(*mode != 't' && *mode != 'b')
*p++ = *mode++;
else
mode++;
*p++ = 'b';
*p = '\0';
myfiles[fd].file = fcaseopen(filename, realmode);
if(myfiles[fd].file == nil)
return 0;
return fd;
}
static int
myfclose(int fd)
{
int ret;
assert(fd < NUMFILES);
if(myfiles[fd].file){
ret = fclose(myfiles[fd].file);
myfiles[fd].file = nil;
return ret;
}
return EOF;
}
static int
myfgetc(int fd)
{
int c;
c = fgetc(myfiles[fd].file);
if(myfiles[fd].isText && c == 015){
/* translate CRLF to LF */
c = fgetc(myfiles[fd].file);
if(c == 012)
return c;
ungetc(c, myfiles[fd].file);
return 015;
}
return c;
}
static int
myfputc(int c, int fd)
{
/* translate LF to CRLF */
if(myfiles[fd].isText && c == 012)
fputc(015, myfiles[fd].file);
return fputc(c, myfiles[fd].file);
}
static char*
myfgets(char *buf, int len, int fd)
{
int c;
char *p;
p = buf;
len--; // NUL byte
while(len--){
c = myfgetc(fd);
if(c == EOF){
if(p == buf)
return nil;
break;
}
*p++ = c;
if(c == '\n')
break;
}
*p = '\0';
return buf;
}
static size_t
myfread(void *buf, size_t elt, size_t n, int fd)
{
if(myfiles[fd].isText){
unsigned char *p;
size_t i;
int c;
n *= elt;
p = (unsigned char*)buf;
for(i = 0; i < n; i++){
c = myfgetc(fd);
if(c == EOF)
break;
*p++ = (unsigned char)c;
}
return i / elt;
}
return fread(buf, elt, n, myfiles[fd].file);
}
static size_t
myfwrite(void *buf, size_t elt, size_t n, int fd)
{
if(myfiles[fd].isText){
unsigned char *p;
size_t i;
int c;
n *= elt;
p = (unsigned char*)buf;
for(i = 0; i < n; i++){
c = *p++;
myfputc(c, fd);
if(feof(myfiles[fd].file)) // is this right?
break;
}
return i / elt;
}
return fwrite(buf, elt, n, myfiles[fd].file);
}
static int
myfseek(int fd, long offset, int whence)
{
return fseek(myfiles[fd].file, offset, whence);
}
static int
myfeof(int fd)
{
return feof(myfiles[fd].file);
// return ferror(myfiles[fd].file);
}
char CFileMgr::ms_rootDirName[128] = {'\0'};
char CFileMgr::ms_dirName[128];
void
CFileMgr::Initialise(void)
{
_getcwd(ms_rootDirName, 128);
strcat(ms_rootDirName, "\\");
}
void
CFileMgr::ChangeDir(const char *dir)
{
if(*dir == '\\'){
strcpy(ms_dirName, ms_rootDirName);
dir++;
}
if(*dir != '\0'){
strcat(ms_dirName, dir);
// BUG in the game it seems, it's off by one
if(dir[strlen(dir)-1] != '\\')
strcat(ms_dirName, "\\");
}
mychdir(ms_dirName);
}
void
CFileMgr::SetDir(const char *dir)
{
strcpy(ms_dirName, ms_rootDirName);
if(*dir != '\0'){
strcat(ms_dirName, dir);
// BUG in the game it seems, it's off by one
if(dir[strlen(dir)-1] != '\\')
strcat(ms_dirName, "\\");
}
mychdir(ms_dirName);
}
void
CFileMgr::SetDirMyDocuments(void)
{
SetDir(""); // better start at the root if user directory is relative
mychdir(_psGetUserFilesFolder());
}
ssize_t
CFileMgr::LoadFile(const char *file, uint8 *buf, int maxlen, const char *mode)
{
int fd;
ssize_t n, len;
fd = myfopen(file, mode);
if(fd == 0)
return -1;
len = 0;
do{
n = myfread(buf + len, 1, 0x4000, fd);
#ifndef FIX_BUGS
if (n < 0)
return -1;
#endif
len += n;
assert(len < maxlen);
}while(n == 0x4000);
buf[len] = 0;
myfclose(fd);
return len;
}
int
CFileMgr::OpenFile(const char *file, const char *mode)
{
return myfopen(file, mode);
}
int
CFileMgr::OpenFileForWriting(const char *file)
{
return OpenFile(file, "wb");
}
size_t
CFileMgr::Read(int fd, const char *buf, ssize_t len)
{
return myfread((void*)buf, 1, len, fd);
}
size_t
CFileMgr::Write(int fd, const char *buf, ssize_t len)
{
return myfwrite((void*)buf, 1, len, fd);
}
bool
CFileMgr::Seek(int fd, int offset, int whence)
{
return !!myfseek(fd, offset, whence);
}
bool
CFileMgr::ReadLine(int fd, char *buf, int len)
{
return myfgets(buf, len, fd) != nil;
}
int
CFileMgr::CloseFile(int fd)
{
return myfclose(fd);
}
int
CFileMgr::GetErrorReadWrite(int fd)
{
return myfeof(fd);
}

23
src/core/FileMgr.h Normal file
View file

@ -0,0 +1,23 @@
#pragma once
class CFileMgr
{
static char ms_rootDirName[128];
static char ms_dirName[128];
public:
static void Initialise(void);
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 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);
static size_t Read(int fd, const char *buf, ssize_t len);
static size_t Write(int fd, const char *buf, ssize_t len);
static bool Seek(int fd, int offset, int whence);
static bool ReadLine(int fd, char *buf, int len);
static int CloseFile(int fd);
static int GetErrorReadWrite(int fd);
static char *GetRootDirName() { return ms_rootDirName; }
};

440
src/core/Fire.cpp Normal file
View file

@ -0,0 +1,440 @@
#include "common.h"
#include "Vector.h"
#include "PlayerPed.h"
#include "Entity.h"
#include "PointLights.h"
#include "Particle.h"
#include "Timer.h"
#include "Vehicle.h"
#include "Shadows.h"
#include "Automobile.h"
#include "World.h"
#include "General.h"
#include "EventList.h"
#include "DamageManager.h"
#include "Ped.h"
#include "Fire.h"
CFireManager gFireManager;
CFire::CFire()
{
m_bIsOngoing = false;
m_bIsScriptFire = false;
m_bPropagationFlag = true;
m_bAudioSet = true;
m_vecPos = CVector(0.0f, 0.0f, 0.0f);
m_pEntity = nil;
m_pSource = nil;
m_nFiremenPuttingOut = 0;
m_nExtinguishTime = 0;
m_nStartTime = 0;
field_20 = 1;
m_nNextTimeToAddFlames = 0;
m_fStrength = 0.8f;
}
CFire::~CFire() {}
void
CFire::ProcessFire(void)
{
float fDamagePlayer;
float fDamagePeds;
float fDamageVehicle;
int16 nRandNumber;
float fGreen;
float fRed;
CVector lightpos;
CVector firePos;
CPed *ped = (CPed *)m_pEntity;
CVehicle *veh = (CVehicle*)m_pEntity;
if (m_pEntity) {
m_vecPos = m_pEntity->GetPosition();
if (((CPed *)m_pEntity)->IsPed()) {
if (ped->m_pFire != this) {
Extinguish();
return;
}
if (ped->m_nMoveState != PEDMOVE_RUN)
m_vecPos.z -= 1.0f;
if (ped->bInVehicle && ped->m_pMyVehicle) {
if (ped->m_pMyVehicle->IsCar())
ped->m_pMyVehicle->m_fHealth = 75.0f;
} else if (m_pEntity == (CPed *)FindPlayerPed()) {
fDamagePlayer = 1.2f * CTimer::GetTimeStep();
((CPlayerPed *)m_pEntity)->InflictDamage(
(CPlayerPed *)m_pSource, WEAPONTYPE_FLAMETHROWER,
fDamagePlayer, PEDPIECE_TORSO, 0);
} else {
fDamagePeds = 1.2f * CTimer::GetTimeStep();
if (((CPlayerPed *)m_pEntity)->InflictDamage(
(CPlayerPed *)m_pSource, WEAPONTYPE_FLAMETHROWER,
fDamagePeds, PEDPIECE_TORSO, 0)) {
m_pEntity->bRenderScorched = true;
}
}
} else if (m_pEntity->IsVehicle()) {
if (veh->m_pCarFire != this) {
Extinguish();
return;
}
if (!m_bIsScriptFire) {
fDamageVehicle = 1.2f * CTimer::GetTimeStep();
veh->InflictDamage((CVehicle *)m_pSource, WEAPONTYPE_FLAMETHROWER, fDamageVehicle);
}
}
}
if (!FindPlayerVehicle() &&
#ifdef FIX_BUGS
FindPlayerPed() &&
#endif
!FindPlayerPed()->m_pFire && !(FindPlayerPed()->bFireProof)
&& ((FindPlayerPed()->GetPosition() - m_vecPos).MagnitudeSqr() < 2.0f)) {
FindPlayerPed()->DoStuffToGoOnFire();
gFireManager.StartFire(FindPlayerPed(), m_pSource, 0.8f, 1);
}
if (CTimer::GetTimeInMilliseconds() > m_nNextTimeToAddFlames) {
m_nNextTimeToAddFlames = CTimer::GetTimeInMilliseconds() + 80;
firePos = m_vecPos;
if (veh && veh->IsVehicle() && veh->IsCar()) {
CVehicleModelInfo *mi = ((CVehicleModelInfo*)CModelInfo::GetModelInfo(veh->GetModelIndex()));
CVector ModelInfo = mi->m_positions[CAR_POS_HEADLIGHTS];
ModelInfo = m_pEntity->GetMatrix() * ModelInfo;
firePos.x = ModelInfo.x;
firePos.y = ModelInfo.y;
firePos.z = ModelInfo.z + 0.15f;
}
CParticle::AddParticle(PARTICLE_CARFLAME, firePos,
CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.0125f, 0.1f) * m_fStrength),
0, m_fStrength, 0, 0, 0, 0);
CGeneral::GetRandomNumber(); CGeneral::GetRandomNumber(); CGeneral::GetRandomNumber(); /* unsure why these three rands are called */
CParticle::AddParticle(PARTICLE_CARFLAME_SMOKE, firePos,
CVector(0.0f, 0.0f, 0.0f), 0, 0.0f, 0, 0, 0, 0);
}
if (CTimer::GetTimeInMilliseconds() < m_nExtinguishTime || m_bIsScriptFire) {
if (CTimer::GetTimeInMilliseconds() > m_nStartTime)
m_nStartTime = CTimer::GetTimeInMilliseconds() + 400;
nRandNumber = CGeneral::GetRandomNumber() & 127;
lightpos.x = m_vecPos.x;
lightpos.y = m_vecPos.y;
lightpos.z = m_vecPos.z + 5.0f;
if (!m_pEntity) {
CShadows::StoreStaticShadow((uintptr)this, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &lightpos, 7.0f, 0.0f, 0.0f, -7.0f, 0, nRandNumber / 2,
nRandNumber / 2, 0, 10.0f, 1.0f, 40.0f, 0, 0.0f);
}
fGreen = nRandNumber / 128.f;
fRed = nRandNumber / 128.f;
CPointLights::AddLight(CPointLights::LIGHT_POINT, m_vecPos, CVector(0.0f, 0.0f, 0.0f), 12.0f, fRed, fGreen, 0, 0, 0);
} else {
Extinguish();
}
}
void
CFire::ReportThisFire(void)
{
gFireManager.m_nTotalFires++;
CEventList::RegisterEvent(EVENT_FIRE, m_vecPos, 1000);
}
void
CFire::Extinguish(void)
{
if (m_bIsOngoing) {
if (!m_bIsScriptFire)
gFireManager.m_nTotalFires--;
m_nExtinguishTime = 0;
m_bIsOngoing = false;
if (m_pEntity) {
if (m_pEntity->IsPed()) {
((CPed *)m_pEntity)->RestorePreviousState();
((CPed *)m_pEntity)->m_pFire = nil;
} else if (m_pEntity->IsVehicle()) {
((CVehicle *)m_pEntity)->m_pCarFire = nil;
}
m_pEntity = nil;
}
}
}
void
CFireManager::StartFire(CVector pos, float size, bool propagation)
{
CFire *fire = GetNextFreeFire();
if (fire) {
fire->m_bIsOngoing = true;
fire->m_bIsScriptFire = false;
fire->m_bPropagationFlag = propagation;
fire->m_bAudioSet = true;
fire->m_vecPos = pos;
fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + 10000;
fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400;
fire->m_pEntity = nil;
fire->m_pSource = nil;
fire->m_nNextTimeToAddFlames = 0;
fire->ReportThisFire();
fire->m_fStrength = size;
}
}
CFire *
CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, bool propagation)
{
CPed *ped = (CPed *)entityOnFire;
CVehicle *veh = (CVehicle *)entityOnFire;
if (entityOnFire->IsPed()) {
if (ped->m_pFire)
return nil;
if (!ped->IsPedInControl())
return nil;
} else if (entityOnFire->IsVehicle()) {
if (veh->m_pCarFire)
return nil;
if (veh->IsCar() && ((CAutomobile *)veh)->Damage.GetEngineStatus() >= 225)
return nil;
}
CFire *fire = GetNextFreeFire();
if (fire) {
if (entityOnFire->IsPed()) {
ped->m_pFire = fire;
if (ped != FindPlayerPed()) {
if (fleeFrom) {
ped->SetFlee(fleeFrom, 10000);
} else {
CVector2D pos = entityOnFire->GetPosition();
ped->SetFlee(pos, 10000);
ped->m_fleeFrom = nil;
}
ped->bDrawLast = false;
ped->SetMoveState(PEDMOVE_SPRINT);
ped->SetMoveAnim();
ped->SetPedState(PED_ON_FIRE);
}
if (fleeFrom) {
if (ped->m_nPedType == PEDTYPE_COP) {
CEventList::RegisterEvent(EVENT_COP_SET_ON_FIRE, EVENT_ENTITY_PED,
entityOnFire, (CPed *)fleeFrom, 10000);
} else {
CEventList::RegisterEvent(EVENT_PED_SET_ON_FIRE, EVENT_ENTITY_PED,
entityOnFire, (CPed *)fleeFrom, 10000);
}
}
} else {
if (entityOnFire->IsVehicle()) {
veh->m_pCarFire = fire;
if (fleeFrom) {
CEventList::RegisterEvent(EVENT_CAR_SET_ON_FIRE, EVENT_ENTITY_VEHICLE,
entityOnFire, (CPed *)fleeFrom, 10000);
}
}
}
fire->m_bIsOngoing = true;
fire->m_bIsScriptFire = false;
fire->m_vecPos = entityOnFire->GetPosition();
if (entityOnFire && entityOnFire->IsPed() && ped->IsPlayer()) {
fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + 3333;
} else if (entityOnFire->IsVehicle()) {
fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(4000, 5000);
} else {
fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(10000, 11000);
}
fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400;
fire->m_pEntity = entityOnFire;
entityOnFire->RegisterReference(&fire->m_pEntity);
fire->m_pSource = fleeFrom;
if (fleeFrom)
fleeFrom->RegisterReference(&fire->m_pSource);
fire->ReportThisFire();
fire->m_nNextTimeToAddFlames = 0;
fire->m_fStrength = strength;
fire->m_bPropagationFlag = propagation;
fire->m_bAudioSet = true;
}
return fire;
}
void
CFireManager::Update(void)
{
for (int i = 0; i < NUM_FIRES; i++) {
if (m_aFires[i].m_bIsOngoing)
m_aFires[i].ProcessFire();
}
}
CFire* CFireManager::FindNearestFire(CVector vecPos, float *pDistance)
{
for (int i = 0; i < MAX_FIREMEN_ATTENDING; i++) {
int fireId = -1;
float minDistance = 999999;
for (int j = 0; j < NUM_FIRES; j++) {
if (!m_aFires[j].m_bIsOngoing)
continue;
if (m_aFires[j].m_bIsScriptFire)
continue;
if (m_aFires[j].m_nFiremenPuttingOut != i)
continue;
float distance = (m_aFires[j].m_vecPos - vecPos).Magnitude2D();
if (distance < minDistance) {
minDistance = distance;
fireId = j;
}
}
*pDistance = minDistance;
if (fireId != -1)
return &m_aFires[fireId];
}
return nil;
}
CFire *
CFireManager::FindFurthestFire_NeverMindFireMen(CVector coords, float minRange, float maxRange)
{
int furthestFire = -1;
float lastFireDist = 0.0f;
float fireDist;
for (int i = 0; i < NUM_FIRES; i++) {
if (m_aFires[i].m_bIsOngoing && !m_aFires[i].m_bIsScriptFire) {
fireDist = (m_aFires[i].m_vecPos - coords).Magnitude2D();
if (fireDist > minRange && fireDist < maxRange && fireDist > lastFireDist) {
lastFireDist = fireDist;
furthestFire = i;
}
}
}
if (furthestFire == -1)
return nil;
else
return &m_aFires[furthestFire];
}
CFire *
CFireManager::GetNextFreeFire(void)
{
for (int i = 0; i < NUM_FIRES; i++) {
if (!m_aFires[i].m_bIsOngoing && !m_aFires[i].m_bIsScriptFire)
return &m_aFires[i];
}
return nil;
}
uint32
CFireManager::GetTotalActiveFires(void) const
{
return m_nTotalFires;
}
void
CFireManager::ExtinguishPoint(CVector point, float range)
{
for (int i = 0; i < NUM_FIRES; i++) {
if (m_aFires[i].m_bIsOngoing) {
if ((point - m_aFires[i].m_vecPos).MagnitudeSqr() < sq(range))
m_aFires[i].Extinguish();
}
}
}
int32
CFireManager::StartScriptFire(const CVector &pos, CEntity *target, float strength, bool propagation)
{
CFire *fire;
CPed *ped = (CPed *)target;
CVehicle *veh = (CVehicle *)target;
if (target) {
if (target->IsPed()) {
if (ped->m_pFire)
ped->m_pFire->Extinguish();
} else if (target->IsVehicle()) {
if (veh->m_pCarFire)
veh->m_pCarFire->Extinguish();
if (veh->IsCar() && ((CAutomobile *)veh)->Damage.GetEngineStatus() >= 225) {
((CAutomobile *)veh)->Damage.SetEngineStatus(215);
}
}
}
fire = GetNextFreeFire();
fire->m_bIsOngoing = true;
fire->m_bIsScriptFire = true;
fire->m_bPropagationFlag = propagation;
fire->m_bAudioSet = true;
fire->m_vecPos = pos;
fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400;
fire->m_pEntity = target;
if (target)
target->RegisterReference(&fire->m_pEntity);
fire->m_pSource = nil;
fire->m_nNextTimeToAddFlames = 0;
fire->m_fStrength = strength;
if (target) {
if (target->IsPed()) {
ped->m_pFire = fire;
if (target != FindPlayerPed()) {
CVector2D pos = target->GetPosition();
ped->SetFlee(pos, 10000);
ped->SetMoveAnim();
ped->SetPedState(PED_ON_FIRE);
}
} else if (target->IsVehicle()) {
veh->m_pCarFire = fire;
}
}
return fire - m_aFires;
}
bool
CFireManager::IsScriptFireExtinguish(int16 index)
{
return !m_aFires[index].m_bIsOngoing;
}
void
CFireManager::RemoveAllScriptFires(void)
{
for (int i = 0; i < NUM_FIRES; i++) {
if (m_aFires[i].m_bIsScriptFire) {
m_aFires[i].Extinguish();
m_aFires[i].m_bIsScriptFire = false;
}
}
}
void
CFireManager::RemoveScriptFire(int16 index)
{
m_aFires[index].Extinguish();
m_aFires[index].m_bIsScriptFire = false;
}
void
CFireManager::SetScriptFireAudio(int16 index, bool state)
{
m_aFires[index].m_bAudioSet = state;
}

51
src/core/Fire.h Normal file
View file

@ -0,0 +1,51 @@
#pragma once
class CEntity;
class CFire
{
public:
bool m_bIsOngoing;
bool m_bIsScriptFire;
bool m_bPropagationFlag;
bool m_bAudioSet;
CVector m_vecPos;
CEntity *m_pEntity;
CEntity *m_pSource;
uint32 m_nExtinguishTime;
uint32 m_nStartTime;
int32 field_20;
uint32 m_nNextTimeToAddFlames;
uint32 m_nFiremenPuttingOut;
float m_fStrength;
CFire();
~CFire();
void ProcessFire(void);
void ReportThisFire(void);
void Extinguish(void);
};
class CFireManager
{
enum {
MAX_FIREMEN_ATTENDING = 2,
};
public:
uint32 m_nTotalFires;
CFire m_aFires[NUM_FIRES];
void StartFire(CVector pos, float size, bool propagation);
CFire *StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, bool propagation);
void Update(void);
CFire *FindFurthestFire_NeverMindFireMen(CVector coords, float minRange, float maxRange);
CFire *FindNearestFire(CVector vecPos, float *pDistance);
CFire *GetNextFreeFire(void);
uint32 GetTotalActiveFires() const;
void ExtinguishPoint(CVector point, float range);
int32 StartScriptFire(const CVector &pos, CEntity *target, float strength, bool propagation);
bool IsScriptFireExtinguish(int16 index);
void RemoveAllScriptFires(void);
void RemoveScriptFire(int16 index);
void SetScriptFireAudio(int16 index, bool state);
};
extern CFireManager gFireManager;

File diff suppressed because it is too large Load diff

750
src/core/FrontEndControls.h Normal file
View file

@ -0,0 +1,750 @@
#pragma once
enum {
NUM_MULTICHOICE_OPTIONS = 16,
// 50 actual lines and 15 for spacing
NUM_LINELISTER_LINES = 50,
NUM_LINELISTER_LINES_TOTAL = NUM_LINELISTER_LINES + 15,
NUM_PAGE_WIDGETS = 10,
};
class CTriggerCaller
{
bool bHasTrigger;
void *pTrigger;
void (*pFunc)(void *);
int field_C;
public:
CTriggerCaller() : bHasTrigger(false), pFunc(nil)
{}
void SetTrigger(void *func, void *trigger)
{
if ( !bHasTrigger )
{
pFunc = (void (*)(void *))func;
pTrigger = trigger;
bHasTrigger = true;
}
}
void CallTrigger(void)
{
if ( bHasTrigger && pFunc != nil )
pFunc(pTrigger);
bHasTrigger = false;
pFunc = nil;
}
bool CanCall()
{
return bHasTrigger;
}
};
class CPlaceableText
{
public:
CVector2D m_position;
CRGBA m_color;
wchar *m_text;
CPlaceableText(void)
: m_position(0.0f, 0.0f), m_color(255, 255, 255, 255), m_text(nil) {}
void SetPosition(float x, float y) { m_position.x = x; m_position.y = y; }
void SetColor(const CRGBA &color) { m_color = color; }
CRGBA GetColor(void) { return m_color; }
void SetAlpha(uint8 alpha) { m_color.alpha = alpha; }
};
// No trace of this in the game but it makes the other classes simpler
class CPlaceableTextTwoLines
{
public:
CPlaceableText m_line1;
CPlaceableText m_line2;
void SetColor(const CRGBA &color) { m_line1.SetColor(color); m_line2.SetColor(color); }
void SetAlpha(uint8 alpha) { m_line1.SetAlpha(alpha); m_line2.SetAlpha(alpha); }
};
// No trace of this in the game but it makes the other classes simpler
class CShadowInfo
{
public:
bool m_bRightJustify;
bool m_bDropShadow;
CRGBA m_shadowColor;
CVector2D m_shadowOffset;
CShadowInfo(void)
: m_bRightJustify(false), m_bDropShadow(false),
m_shadowColor(255, 255, 255, 255),
m_shadowOffset(-1.0f, -1.0f) {}
CRGBA GetShadowColor(void) { return m_shadowColor; }
void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset){
m_bDropShadow = bDropShadows;
m_shadowColor = shadowColor;
m_shadowOffset = shadowOffset;
}
};
// No trace of this in the game but it makes the other classes simpler
class CSelectable
{
public:
bool m_bSelected;
CRGBA m_selectedColor;
CSelectable(void) : m_bSelected(false) {}
CRGBA GetSelectedColor(void) { return m_selectedColor; }
};
class CPlaceableShText : public CPlaceableText, public CShadowInfo
{
public:
using CPlaceableText::SetPosition;
void SetPosition(float x, float y, bool bRightJustify) { SetPosition(x, y); m_bRightJustify = bRightJustify; }
void SetAlpha(uint8 alpha) { m_shadowColor.alpha = alpha; CPlaceableText::SetAlpha(alpha); }
void Draw(float x, float y);
void Draw(const CRGBA &color, float x, float y);
// unused arguments it seems
void DrawShWrap(float x, float y, float wrapX, float wrapY) { Draw(x, y); }
};
class CPlaceableShTextTwoLines : public CPlaceableTextTwoLines, public CShadowInfo
{
public:
void SetAlpha(uint8 alpha) { m_shadowColor.alpha = alpha; CPlaceableTextTwoLines::SetAlpha(alpha); }
void Draw(float x, float y);
void Draw(const CRGBA &color, float x, float y);
};
class CPlaceableShOption : public CPlaceableShText, public CSelectable
{
public:
void SetColors(const CRGBA &normal, const CRGBA &selection) { CPlaceableShText::SetColor(normal); m_selectedColor = selection; }
void SetAlpha(uint8 alpha) { m_selectedColor.alpha = alpha; CPlaceableShText::SetAlpha(alpha); }
using CPlaceableShText::Draw;
void Draw(const CRGBA &highlightColor, float x, float y, bool bHighlight);
};
class CPlaceableShOptionTwoLines : public CPlaceableShTextTwoLines, public CSelectable
{
public:
void SetColors(const CRGBA &normal, const CRGBA &selection) { CPlaceableShTextTwoLines::SetColor(normal); m_selectedColor = selection; }
void SetAlpha(uint8 alpha) { m_selectedColor.alpha = alpha; CPlaceableShTextTwoLines::SetAlpha(alpha); }
using CPlaceableShTextTwoLines::Draw;
void Draw(const CRGBA &highlightColor, float x, float y, bool bHighlight);
};
class CPlaceableSprite
{
public:
CSprite2d *m_pSprite;
CVector2D m_position;
CVector2D m_size;
CRGBA m_color;
CPlaceableSprite(void)
: m_pSprite(nil), m_position(0.0f, 0.0f),
m_size(0.0f, 0.0f), m_color(255, 255, 255, 255) {}
void SetPosition(float x, float y) { m_position.x = x; m_position.y = y; }
void SetAlpha(uint8 alpha) { m_color.alpha = alpha; }
void Draw(float x, float y);
void Draw(const CRGBA &color, float x, float y);
};
class CPlaceableShSprite
{
public:
CPlaceableSprite m_sprite;
CPlaceableSprite m_shadow;
bool m_bDropShadow;
CPlaceableShSprite(void) : m_bDropShadow(false) {}
void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset){
m_bDropShadow = bDropShadows;
m_shadow.m_color = shadowColor;
m_shadow.m_position = shadowOffset;
}
void SetAlpha(uint8 alpha) { m_sprite.SetAlpha(alpha); m_shadow.SetAlpha(alpha); }
void Draw(float x, float y);
};
class CMenuBase
{
public:
CVector2D m_position;
bool m_bTwoState;
CMenuBase(void)
: m_position(0.0f, 0.0f), m_bTwoState(false) {}
void SetPosition(float x, float y) { m_position.x = x; m_position.y = y; }
virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y) = 0;
virtual void DrawNormal(float x, float y) = 0;
virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y) = 0;
virtual void SetAlpha(uint8 alpha) = 0;
virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset) = 0;
virtual bool GoNext(void) = 0;
virtual bool GoPrev(void) = 0;
virtual bool GoDown(void) = 0;
virtual bool GoUp(void) = 0;
virtual bool GoDownStill(void) = 0;
virtual bool GoUpStill(void) = 0;
virtual bool GoLeft(void) = 0;
virtual bool GoRight(void) = 0;
virtual bool GoLeftStill(void) = 0;
virtual bool GoRightStill(void) = 0;
virtual bool GoFirst(void) = 0;
virtual bool GoLast(void) = 0;
virtual void SelectCurrentOptionUnderCursor(void) = 0;
virtual void SelectDefaultCancelAction(void) = 0;
virtual void ActivateMenu(bool first) = 0;
virtual void DeactivateMenu(void) = 0;
virtual int GetMenuSelection(void) = 0;
virtual void SetMenuSelection(int selection) = 0;
};
class CMenuDummy : public CMenuBase
{
public:
bool m_bActive;
virtual void Draw(const CRGBA &, const CRGBA &, float x, float y) {}
virtual void DrawNormal(float x, float y) {}
virtual void DrawHighlighted(const CRGBA &, float x, float y) {}
virtual void SetAlpha(uint8 alpha) {}
virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset) {}
virtual bool GoNext(void) { DeactivateMenu(); return false; }
virtual bool GoPrev(void) { DeactivateMenu(); return false; }
virtual bool GoDown(void) { return GoNext(); }
virtual bool GoUp(void) { return GoPrev(); }
virtual bool GoDownStill(void) { return false; }
virtual bool GoUpStill(void) { return false; }
virtual bool GoLeft(void) { return true; }
virtual bool GoRight(void) { return true; }
virtual bool GoLeftStill(void) { return true; }
virtual bool GoRightStill(void) { return true; }
virtual bool GoFirst(void) { ActivateMenu(true); return true; }
virtual bool GoLast(void) { ActivateMenu(true); return true; }
virtual void SelectCurrentOptionUnderCursor(void) {}
virtual void SelectDefaultCancelAction(void) {}
virtual void ActivateMenu(bool first) { m_bActive = true; }
virtual void DeactivateMenu(void) { m_bActive = false; }
virtual int GetMenuSelection(void) { return -1; }
virtual void SetMenuSelection(int) {}
};
class CMenuPictureAndText : public CMenuBase
{
public:
int m_numSprites;
CPlaceableShSprite m_sprites[5];
int m_numTexts;
CPlaceableShText m_texts[20];
CVector2D m_oldTextScale;
CVector2D m_textScale;
bool m_bSetTextScale;
float m_wrapX;
float m_oldWrapx;
bool m_bWrap;
// missing some?
CMenuPictureAndText(void)
: m_numSprites(0), m_numTexts(0),
m_bSetTextScale(false), m_bWrap(false) {}
void SetNewOldShadowWrapX(bool bWrapX, float newWrapX, float oldWrapX);
void SetNewOldTextScale(bool bTextScale, const CVector2D &newScale, const CVector2D &oldScale);
void SetTextsColor(const CRGBA &color);
void AddText(wchar *text, float positionX, float positionY, const CRGBA &color, bool bRightJustify);
void AddPicture(CSprite2d *sprite, CSprite2d *shadow, float positionX, float positionY, float width, float height, const CRGBA &color);
void AddPicture(CSprite2d *sprite, float positionX, float positionY, float width, float height, const CRGBA &color);
virtual void Draw(const CRGBA &, const CRGBA &, float x, float y);
virtual void DrawNormal(float x, float y) { Draw(CRGBA(0,0,0,0), CRGBA(0,0,0,0), x, y); }
virtual void DrawHighlighted(const CRGBA &, float x, float y) { Draw(CRGBA(0,0,0,0), CRGBA(0,0,0,0), x, y); }
virtual void SetAlpha(uint8 alpha);
virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
virtual bool GoNext(void) { return false; }
virtual bool GoPrev(void) { return false; }
virtual bool GoDown(void) { return GoNext(); }
virtual bool GoUp(void) { return GoPrev(); }
virtual bool GoDownStill(void) { return false; }
virtual bool GoUpStill(void) { return false; }
virtual bool GoLeft(void) { return true; }
virtual bool GoRight(void) { return true; }
virtual bool GoLeftStill(void) { return true; }
virtual bool GoRightStill(void) { return true; }
virtual bool GoFirst(void) { return false; }
virtual bool GoLast(void) { return false; }
virtual void SelectCurrentOptionUnderCursor(void) {}
virtual void SelectDefaultCancelAction(void) {}
virtual void ActivateMenu(bool first) {}
virtual void DeactivateMenu(void) {}
virtual int GetMenuSelection(void) { return -1; }
virtual void SetMenuSelection(int) {}
};
class CMenuMultiChoice : public CMenuBase
{
public:
int m_numOptions;
CPlaceableShText m_title;
CPlaceableShOption m_options[NUM_MULTICHOICE_OPTIONS];
int m_cursor;
CVector2D m_oldTextScale;
CVector2D m_textScale;
bool m_bSetTextScale;
bool m_bSetTitleTextScale;
CMenuMultiChoice(void)
: m_numOptions(0), m_cursor(-1),
m_bSetTextScale(false), m_bSetTitleTextScale(false) {}
void AddTitle(wchar *text, float positionX, float positionY, bool bRightJustify);
CPlaceableShOption *AddOption(wchar *text, float positionX, float positionY, bool bSelected, bool bRightJustify);
void SetColors(const CRGBA &title, const CRGBA &normal, const CRGBA &selected);
void SetNewOldTextScale(bool bTextScale, const CVector2D &newScale, const CVector2D &oldScale, bool bTitleTextScale);
virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
virtual void DrawNormal(float x, float y);
virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
virtual void SetAlpha(uint8 alpha);
virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
virtual bool GoNext(void);
virtual bool GoPrev(void);
virtual bool GoDown(void) { return GoNext(); }
virtual bool GoUp(void) { return GoPrev(); }
virtual bool GoDownStill(void) { return false; }
virtual bool GoUpStill(void) { return false; }
virtual bool GoLeft(void) { return GoPrev(); }
virtual bool GoRight(void) { return GoNext(); }
virtual bool GoLeftStill(void) { return true; }
virtual bool GoRightStill(void) { return true; }
virtual bool GoFirst(void) { m_cursor = 0; return true; }
virtual bool GoLast(void) { m_cursor = m_numOptions-1; return true; }
virtual void SelectCurrentOptionUnderCursor(void);
virtual void SelectDefaultCancelAction(void) {}
virtual void ActivateMenu(bool first) { m_cursor = first ? 0 : m_numOptions-1; }
virtual void DeactivateMenu(void) { m_cursor = -1; }
virtual int GetMenuSelection(void);
virtual void SetMenuSelection(int selection);
};
class CMenuMultiChoiceTriggered : public CMenuMultiChoice
{
public:
typedef void (*Trigger)(CMenuMultiChoiceTriggered *);
Trigger m_triggers[NUM_MULTICHOICE_OPTIONS];
Trigger m_defaultCancel;
CMenuMultiChoiceTriggered(void) { Initialise(); }
void Initialise(void);
CPlaceableShOption *AddOption(wchar *text, float positionX, float positionY, Trigger trigger, bool bSelected, bool bRightJustify);
virtual void SelectCurrentOptionUnderCursor(void);
virtual void SelectDefaultCancelAction(void);
};
class CMenuMultiChoiceTriggeredAlways : public CMenuMultiChoiceTriggered
{
public:
Trigger m_alwaysNormalTrigger;
Trigger m_alwaysHighlightTrigger;
Trigger m_alwaysTrigger;
CMenuMultiChoiceTriggeredAlways(void)
: m_alwaysNormalTrigger(nil), m_alwaysHighlightTrigger(nil), m_alwaysTrigger(nil) {}
virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
virtual void DrawNormal(float x, float y);
virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
};
class CMenuMultiChoicePictured : public CMenuMultiChoice
{
public:
CPlaceableSprite m_sprites[NUM_MULTICHOICE_OPTIONS];
bool m_bHasSprite[NUM_MULTICHOICE_OPTIONS];
CMenuMultiChoicePictured(void) { Initialise(); }
void Initialise(void);
using CMenuMultiChoice::AddOption;
CPlaceableShOption *AddOption(CSprite2d *sprite, float positionX, float positionY, const CVector2D &size, bool bSelected);
virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
virtual void DrawNormal(float x, float y);
virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
virtual void SetAlpha(uint8 alpha);
// unnecessary - same as base class
// virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
};
class CMenuMultiChoicePicturedTriggered : public CMenuMultiChoicePictured
{
public:
typedef void (*Trigger)(CMenuMultiChoicePicturedTriggered *);
Trigger m_triggers[NUM_MULTICHOICE_OPTIONS];
Trigger m_defaultCancel;
CMenuMultiChoicePicturedTriggered(void) { Initialise(); }
void Initialise(void);
using CMenuMultiChoicePictured::AddOption;
CPlaceableShOption *AddOption(CSprite2d *sprite, float positionX, float positionY, const CVector2D &size, Trigger trigger, bool bSelected);
virtual void SelectCurrentOptionUnderCursor(void);
virtual void SelectDefaultCancelAction(void);
};
struct FEC_MOVETAB
{
int8 right;
int8 left;
int8 down;
int8 up;
};
class CMenuMultiChoicePicturedTriggeredAnyMove : public CMenuMultiChoicePicturedTriggered
{
public:
FEC_MOVETAB m_moveTab[NUM_MULTICHOICE_OPTIONS];
CMenuMultiChoicePicturedTriggeredAnyMove(void) { Initialise(); }
void Initialise(void);
using CMenuMultiChoicePicturedTriggered::AddOption;
CPlaceableShOption *AddOption(CSprite2d *sprite, FEC_MOVETAB *moveTab, float positionX, float positionY, const CVector2D &size, Trigger trigger, bool bSelected);
virtual bool GoDown(void);
virtual bool GoUp(void);
virtual bool GoLeft(void);
virtual bool GoRight(void);
};
// copy of CMenuMultiChoice pretty much except for m_options type
class CMenuMultiChoiceTwoLines : public CMenuBase
{
public:
int m_numOptions;
CPlaceableShText m_title;
CPlaceableShOptionTwoLines m_options[NUM_MULTICHOICE_OPTIONS];
int m_cursor;
CVector2D m_oldTextScale;
CVector2D m_textScale;
bool m_bSetTextScale;
bool m_bSetTitleTextScale;
CMenuMultiChoiceTwoLines(void)
: m_numOptions(0), m_cursor(-1),
m_bSetTextScale(false), m_bSetTitleTextScale(false) {}
void AddTitle(wchar *text, float positionX, float positionY, bool bRightJustify);
CPlaceableShOptionTwoLines *AddOption(wchar *text, float positionX, float positionY, bool bSelected, bool bRightJustify);
CPlaceableShOptionTwoLines *AddOption(wchar *text1, float positionX1, float positionY1, wchar *text2, float positionX2, float positionY2, bool bSelected, bool bRightJustify);
void SetColors(const CRGBA &title, const CRGBA &normal, const CRGBA &selected);
void SetNewOldTextScale(bool bTextScale, const CVector2D &newScale, const CVector2D &oldScale, bool bTitleTextScale);
virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
virtual void DrawNormal(float x, float y);
virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
virtual void SetAlpha(uint8 alpha);
virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
virtual bool GoNext(void);
virtual bool GoPrev(void);
virtual bool GoDown(void) { return GoNext(); }
virtual bool GoUp(void) { return GoPrev(); }
virtual bool GoDownStill(void) { return true; }
virtual bool GoUpStill(void) { return true; }
virtual bool GoLeft(void) { return GoPrev(); }
virtual bool GoRight(void) { return GoNext(); }
virtual bool GoLeftStill(void) { return true; }
virtual bool GoRightStill(void) { return true; }
virtual bool GoFirst(void) { m_cursor = 0; return true; }
virtual bool GoLast(void) { m_cursor = m_numOptions-1; return true; }
virtual void SelectCurrentOptionUnderCursor(void);
virtual void SelectDefaultCancelAction(void) {}
virtual void ActivateMenu(bool first) { m_cursor = first ? 0 : m_numOptions-1; }
virtual void DeactivateMenu(void) { m_cursor = -1; }
virtual int GetMenuSelection(void);
virtual void SetMenuSelection(int selection);
};
// copy of CMenuMultiChoiceTriggered except for m_options
class CMenuMultiChoiceTwoLinesTriggered : public CMenuMultiChoiceTwoLines
{
public:
typedef void (*Trigger)(CMenuMultiChoiceTwoLinesTriggered *);
Trigger m_triggers[NUM_MULTICHOICE_OPTIONS];
Trigger m_defaultCancel;
CMenuMultiChoiceTwoLinesTriggered(void) { Initialise(); }
void Initialise(void);
CPlaceableShOptionTwoLines *AddOption(wchar *text, float positionX, float positionY, Trigger trigger, bool bSelected, bool bRightJustify);
CPlaceableShOptionTwoLines *AddOption(wchar *text1, float positionX1, float positionY1, wchar *text2, float positionX2, float positionY2, Trigger trigger, bool bSelected, bool bRightJustify);
virtual void SelectCurrentOptionUnderCursor(void);
virtual void SelectDefaultCancelAction(void);
};
class CMenuOnOff : public CMenuBase
{
public:
CPlaceableShOption m_title;
CPlaceableShText m_options[2];
bool m_bActive;
bool m_bSetTextScale;
bool m_bSetTitleTextScale;
CVector2D m_textScale;
CVector2D m_oldTextScale;
int m_type; // 0: on/off 1: yes/no
void SetColors(const CRGBA &title, const CRGBA &options);
void SetNewOldTextScale(bool bTextScale, const CVector2D &newScale, const CVector2D &oldScale, bool bTitleTextScale);
void SetOptionPosition(float x, float y, bool bRightJustify);
void AddTitle(wchar *text, bool bSelected, float positionX, float positionY, bool bRightJustify);
virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
virtual void DrawNormal(float x, float y);
virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
virtual void SetAlpha(uint8 alpha);
virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
virtual bool GoNext(void) { DeactivateMenu(); return false; }
virtual bool GoPrev(void) { DeactivateMenu(); return false; }
virtual bool GoDown(void) { return GoNext(); }
virtual bool GoUp(void) { return GoPrev(); }
virtual bool GoDownStill(void) { return false; }
virtual bool GoUpStill(void) { return false; }
virtual bool GoLeft(void) { SelectCurrentOptionUnderCursor(); return true; }
virtual bool GoRight(void) { SelectCurrentOptionUnderCursor(); return true; }
virtual bool GoLeftStill(void) { return true; }
virtual bool GoRightStill(void) { return true; }
virtual bool GoFirst(void) { ActivateMenu(true); return true; }
virtual bool GoLast(void) { ActivateMenu(true); return true; }
virtual void SelectCurrentOptionUnderCursor(void) { m_title.m_bSelected ^= 1; }
virtual void SelectDefaultCancelAction(void) {}
virtual void ActivateMenu(bool first) { m_bActive = true; }
virtual void DeactivateMenu(void) { m_bActive = false; }
virtual int GetMenuSelection(void) { return m_title.m_bSelected; }
virtual void SetMenuSelection(int selection) { m_title.m_bSelected = selection; }
};
class CMenuOnOffTriggered : public CMenuOnOff
{
public:
typedef void (*Trigger)(CMenuOnOffTriggered *);
Trigger m_trigger;
void SetOptionPosition(float x, float y, Trigger trigger, bool bRightJustify);
virtual void SelectCurrentOptionUnderCursor(void);
};
class CMenuSlider : public CMenuBase
{
public:
CPlaceableShText m_title;
CPlaceableShText m_box; // not really a text
CRGBA m_colors[2]; // left and right
CVector2D m_size[2]; // left and right
int m_value;
CPlaceableShText m_percentageText;
bool m_bDrawPercentage;
// char field_8D;
// char field_8E;
// char field_8F;
uint8 m_someAlpha;
// char field_91;
// char field_92;
// char field_93;
bool m_bActive;
int m_style;
static char Buf8[8];
static wchar Buf16[8];
CMenuSlider(void)
: m_value(0), m_bDrawPercentage(false), m_bActive(false), m_style(0)
{
AddTickBox(0.0f, 0.0f, 100.0f, 10.0f, 10.0f); //todo
}
void SetColors(const CRGBA &title, const CRGBA &percentage, const CRGBA &left, const CRGBA &right);
void DrawTicks(const CVector2D &position, const CVector2D &size, float heightRight, float level, const CRGBA &leftCol, const CRGBA &selCol, const CRGBA &rightCol, bool bShadow, const CVector2D &shadowOffset, const CRGBA &shadowColor);
void DrawTicks(const CVector2D &position, const CVector2D &size, float heightRight, float level, const CRGBA &leftCol, const CRGBA &rightCol, bool bShadow, const CVector2D &shadowOffset, const CRGBA &shadowColor);
void AddTickBox(float positionX, float positionY, float width, float heigthLeft, float heightRight);
void AddTitle(wchar *text, float positionX, float positionY);
virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
virtual void DrawNormal(float x, float y);
virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
virtual void SetAlpha(uint8 alpha);
virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
virtual bool GoNext(void) { DeactivateMenu(); return false; }
virtual bool GoPrev(void) { DeactivateMenu(); return false; }
virtual bool GoDown(void) { return GoNext(); }
virtual bool GoUp(void) { return GoPrev(); }
virtual bool GoDownStill(void) { return false; }
virtual bool GoUpStill(void) { return false; }
virtual bool GoLeft(void) { if(m_value < 0) m_value = 0; return true; }
virtual bool GoRight(void) { if(m_value > 1000) m_value = 1000; return true; }
virtual bool GoLeftStill(void) { m_value -= 8; if(m_value < 0) m_value = 0; return true; }
virtual bool GoRightStill(void) { m_value += 8; if(m_value > 1000) m_value = 1000; return true; }
virtual bool GoFirst(void) { ActivateMenu(true); return true; }
virtual bool GoLast(void) { ActivateMenu(true); return true; }
virtual void SelectCurrentOptionUnderCursor(void) {}
virtual void SelectDefaultCancelAction(void) {}
virtual void ActivateMenu(bool first) { m_bActive = true; }
virtual void DeactivateMenu(void) { m_bActive = false; }
virtual int GetMenuSelection(void) { return m_value/10; }
virtual void SetMenuSelection(int selection) { m_value = selection*10; }
};
class CMenuSliderTriggered : public CMenuSlider
{
public:
typedef void (*Trigger)(CMenuSliderTriggered *);
Trigger m_trigger;
Trigger m_alwaysTrigger;
CMenuSliderTriggered(void)
: m_trigger(nil), m_alwaysTrigger(nil) {}
void AddTickBox(float positionX, float positionY, float width, float heigthLeft, float heightRight, Trigger trigger, Trigger alwaysTrigger);
virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
virtual bool GoLeft(void);
virtual bool GoRight(void);
virtual bool GoLeftStill(void);
virtual bool GoRightStill(void);
};
class CMenuLineLister : public CMenuBase
{
public:
float m_width;
float m_height;
int m_numLines;
CPlaceableShText m_linesLeft[NUM_LINELISTER_LINES_TOTAL];
CPlaceableShText m_linesRight[NUM_LINELISTER_LINES_TOTAL];
uint8 m_lineAlphas[NUM_LINELISTER_LINES_TOTAL];
int8 m_lineFade[NUM_LINELISTER_LINES_TOTAL];
float m_scrollPosition;
float m_scrollSpeed;
int field_10E8;
float m_lineSpacing;
CMenuLineLister(void);
void SetLinesColor(const CRGBA &color);
void ResetNumberOfTextLines(void);
bool AddTextLine(wchar *left, wchar *right);
CPlaceableShText *GetLeftLine(int i) { return &m_linesLeft[(i%NUM_LINELISTER_LINES) + 15]; };
CPlaceableShText *GetRightLine(int i) { return &m_linesRight[(i%NUM_LINELISTER_LINES) + 15]; };
virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
virtual void DrawNormal(float x, float y) { Draw(CRGBA(0,0,0,0), CRGBA(0,0,0,0), x, y); }
virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y) { Draw(CRGBA(0,0,0,0), CRGBA(0,0,0,0), x, y); }
virtual void SetAlpha(uint8 alpha);
virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
virtual bool GoNext(void) { return false; }
virtual bool GoPrev(void) { return false; }
virtual bool GoDown(void) { return GoNext(); }
virtual bool GoUp(void) { return GoPrev(); }
virtual bool GoDownStill(void) { m_scrollSpeed = 0.0f; return true; }
virtual bool GoUpStill(void) { m_scrollSpeed *= 6.0f; return true; }
virtual bool GoLeft(void) { return true; }
virtual bool GoRight(void) { return true; }
virtual bool GoLeftStill(void) { return true; }
virtual bool GoRightStill(void) { return true; }
virtual bool GoFirst(void) { return true; }
virtual bool GoLast(void) { return true; }
virtual void SelectCurrentOptionUnderCursor(void) {}
virtual void SelectDefaultCancelAction(void) {}
virtual void ActivateMenu(bool first) {}
virtual void DeactivateMenu(void) {}
virtual int GetMenuSelection(void) { return -1; }
virtual void SetMenuSelection(int selection) {}
};
class CMenuPage
{
public:
CMenuBase *m_controls[NUM_PAGE_WIDGETS];
int m_numControls;
CMenuBase *m_pCurrentControl;
int m_cursor;
CMenuPage(void) { Initialise(); }
void Initialise(void);
bool AddMenu(CMenuBase *widget);
bool IsActiveMenuTwoState(void);
void ActiveMenuTwoState_SelectNextPosition(void);
void Draw(const CRGBA &,const CRGBA &, float, float);
void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
void DrawNormal(float x, float y);
void ActivatePage(void);
void SetAlpha(uint8 alpha);
void SetShadows(bool, const CRGBA &, const CVector2D &);
void GoPrev(void) { if(m_pCurrentControl) { if(!m_pCurrentControl->GoPrev()) m_pCurrentControl->GoLast(); } }
void GoNext(void) { if(m_pCurrentControl) { if(!m_pCurrentControl->GoNext()) m_pCurrentControl->GoFirst(); } }
void GoLeft(void) { if(m_pCurrentControl) { if(!m_pCurrentControl->GoLeft()) m_pCurrentControl->GoLast(); } }
void GoRight(void) { if(m_pCurrentControl) { if(!m_pCurrentControl->GoRight()) m_pCurrentControl->GoFirst(); } }
void GoUp(void) { if(m_pCurrentControl) { if(!m_pCurrentControl->GoUp()) m_pCurrentControl->GoLast(); } }
void GoDown(void) { if(m_pCurrentControl) { if(!m_pCurrentControl->GoDown()) m_pCurrentControl->GoFirst(); } }
void GoLeftStill(void) { if(m_pCurrentControl) m_pCurrentControl->GoLeftStill(); }
void GoRightStill(void) { if(m_pCurrentControl) m_pCurrentControl->GoRightStill(); }
void GoUpStill(void) { if(m_pCurrentControl) m_pCurrentControl->GoUpStill(); }
void GoDownStill(void) { if(m_pCurrentControl) m_pCurrentControl->GoDownStill(); }
void SelectDefaultCancelAction(void) { if(m_pCurrentControl) m_pCurrentControl->SelectDefaultCancelAction(); }
void SelectCurrentOptionUnderCursor(void) { if(m_pCurrentControl) m_pCurrentControl->SelectCurrentOptionUnderCursor(); }
virtual void GoUpMenuOnPage(void);
virtual void GoDownMenuOnPage(void);
virtual void GoLeftMenuOnPage(void);
virtual void GoRightMenuOnPage(void);
};
class CMenuPageAnyMove : public CMenuPage
{
public:
FEC_MOVETAB m_moveTab[NUM_PAGE_WIDGETS];
CMenuPageAnyMove(void) { Initialise(); }
void Initialise(void);
using CMenuPage::AddMenu;
bool AddMenu(CMenuBase *widget, FEC_MOVETAB *moveTab);
virtual void GoUpMenuOnPage(void);
virtual void GoDownMenuOnPage(void);
virtual void GoLeftMenuOnPage(void);
virtual void GoRightMenuOnPage(void);
};

6802
src/core/Frontend.cpp Normal file

File diff suppressed because it is too large Load diff

839
src/core/Frontend.h Normal file
View file

@ -0,0 +1,839 @@
#pragma once
#ifdef PS2_MENU
#include "Frontend_PS2.h"
#else
#include "Sprite2d.h"
#ifdef PS2_LIKE_MENU
#define MENUHEADER_POS_X 50.0f
#define MENUHEADER_POS_Y 75.0f
#define MENUHEADER_HEIGHT 1.3f
#else
#define MENUHEADER_POS_X 35.0f
#define MENUHEADER_POS_Y 93.0f
#define MENUHEADER_HEIGHT 1.6f
#endif
#define MENUHEADER_WIDTH 0.84f
#define MENU_X_MARGIN 40.0f
#define MENUACTION_POS_Y 60.0f
#define MENUACTION_SCALE_MULT 0.9f
#define MENURADIO_ICON_SCALE 60.0f
#define MENUSLIDER_X 256.0f
#define MENUSLIDER_UNK 256.0f
#define MENUSLIDER_BARS 16
#define MENUSLIDER_LOGICAL_BARS MENUSLIDER_BARS
#define BIGTEXT_X_SCALE 0.75f // For FONT_HEADING
#define BIGTEXT_Y_SCALE 0.9f
#define MEDIUMTEXT_X_SCALE 0.55f // For FONT_HEADING
#define MEDIUMTEXT_Y_SCALE 0.8f
#define SMALLTEXT_X_SCALE 0.45f // used for FONT_HEADING and FONT_BANK, but looks off for HEADING
#define SMALLTEXT_Y_SCALE 0.7f
#define SMALLESTTEXT_X_SCALE 0.4f // used for both FONT_HEADING and FONT_BANK
#define SMALLESTTEXT_Y_SCALE 0.6f
#define HELPER_TEXT_LEFT_MARGIN 320.0f
#define HELPER_TEXT_BOTTOM_MARGIN 120.0f
#define PLAYERSETUP_LIST_TOP 28.0f
#define PLAYERSETUP_LIST_BOTTOM 125.0f
#define PLAYERSETUP_LIST_LEFT 200.0f
#define PLAYERSETUP_LIST_RIGHT 36.0f
#ifdef FIX_BUGS // See the scrollbar button drawing code
#define PLAYERSETUP_SCROLLBAR_WIDTH 19.0f
#else
#define PLAYERSETUP_SCROLLBAR_WIDTH 16.0f
#endif
#define PLAYERSETUP_SCROLLBUTTON_HEIGHT 17.0f
#define PLAYERSETUP_SCROLLBUTTON_TXD_DIMENSION 64
#define PLAYERSETUP_SKIN_COLUMN_LEFT 220.0f
#define PLAYERSETUP_DATE_COLUMN_RIGHT 56.0f
#define PLAYERSETUP_LIST_BODY_TOP 47
#define PLAYERSETUP_ROW_HEIGHT 9
#define STATS_SLIDE_Y_PER_SECOND 30.0f
#define STATS_ROW_HEIGHT 20.0f
#define STATS_ROW_X_MARGIN 50.0f
#define STATS_BOTTOM_MARGIN 135.0f
#define STATS_TOP_MARGIN 40.0f
#define STATS_TOP_DIMMING_AREA_LENGTH (93.0f - STATS_TOP_MARGIN)
#define STATS_BOTTOM_DIMMING_AREA_LENGTH 55.0f
#define STATS_PUT_BACK_TO_BOTTOM_Y 50.0f
#define STATS_RATING_X 24.0f
#define STATS_RATING_Y 20.0f
#define BRIEFS_TOP_MARGIN 40.0f
#define BRIEFS_LINE_X 50.0f
#define BRIEFS_LINE_HEIGHT 60.0f
#define CONTSETUP_STANDARD_ROW_HEIGHT 10.7f
#define CONTSETUP_CLASSIC_ROW_HEIGHT 9.0f
#define CONTSETUP_BOUND_HIGHLIGHT_HEIGHT 10
#define CONTSETUP_BOUND_COLUMN_WIDTH 190.0f
#define CONTSETUP_LIST_HEADER_HEIGHT 20.0f
#define CONTSETUP_LIST_TOP 28.0f
#define CONTSETUP_LIST_RIGHT 18.0f
#define CONTSETUP_LIST_BOTTOM 120.0f
#define CONTSETUP_LIST_LEFT 18.0f
#define CONTSETUP_COLUMN_1_X 40.0f
#define CONTSETUP_COLUMN_2_X 210.0f
#define CONTSETUP_COLUMN_3_X (CONTSETUP_COLUMN_2_X + CONTSETUP_BOUND_COLUMN_WIDTH + 10.0f)
#define CONTSETUP_BACK_RIGHT 35.0f
#define CONTSETUP_BACK_BOTTOM 122.0f
#define CONTSETUP_BACK_HEIGHT 25.0f
enum eFrontendSprites
{
FE2_MAINPANEL_UL,
FE2_MAINPANEL_UR,
FE2_MAINPANEL_DL,
FE2_MAINPANEL_DR,
FE2_MAINPANEL_DR2,
FE2_TABACTIVE,
FE_ICONBRIEF,
FE_ICONSTATS,
FE_ICONCONTROLS,
FE_ICONSAVE,
FE_ICONAUDIO,
FE_ICONDISPLAY,
FE_ICONLANGUAGE,
FE_CONTROLLER,
FE_CONTROLLERSH,
FE_ARROWS1,
FE_ARROWS2,
FE_ARROWS3,
FE_ARROWS4,
FE_RADIO1,
FE_RADIO2,
FE_RADIO3,
FE_RADIO4,
FE_RADIO5,
FE_RADIO6,
FE_RADIO7,
FE_RADIO8,
FE_RADIO9,
NUM_FE_SPRITES
};
enum eMenuSprites
{
MENUSPRITE_CONNECTION,
MENUSPRITE_FINDGAME,
MENUSPRITE_HOSTGAME,
MENUSPRITE_MAINMENU,
MENUSPRITE_PLAYERSET,
MENUSPRITE_SINGLEPLAYER,
MENUSPRITE_MULTIPLAYER,
MENUSPRITE_DMALOGO,
MENUSPRITE_GTALOGO,
MENUSPRITE_RSTARLOGO,
MENUSPRITE_GAMESPY,
MENUSPRITE_MOUSE,
MENUSPRITE_MOUSET,
MENUSPRITE_MP3LOGO,
MENUSPRITE_DOWNOFF,
MENUSPRITE_DOWNON,
MENUSPRITE_UPOFF,
MENUSPRITE_UPON,
MENUSPRITE_GTA3LOGO,
MENUSPRITE_UNUSED,
NUM_MENU_SPRITES
};
enum eSaveSlot
{
SAVESLOT_NONE,
SAVESLOT_0,
SAVESLOT_1,
SAVESLOT_2,
SAVESLOT_3,
SAVESLOT_4,
SAVESLOT_5,
SAVESLOT_6,
SAVESLOT_7,
SAVESLOT_8,
SAVESLOT_LABEL = 36,
};
#ifdef MENU_MAP
enum MapSprites
{
MAPMID1,
MAPMID2,
MAPMID3,
MAPBOT1,
MAPBOT2,
MAPBOT3,
MAPTOP1,
MAPTOP2,
MAPTOP3,
NUM_MAP_SPRITES
};
#endif
enum eMenuScreen
{
MENUPAGE_DISABLED = -1,
MENUPAGE_NONE = 0,
MENUPAGE_STATS = 1,
MENUPAGE_NEW_GAME = 2,
MENUPAGE_BRIEFS = 3,
MENUPAGE_CONTROLLER_SETTINGS = 4,
MENUPAGE_SOUND_SETTINGS = 5,
MENUPAGE_DISPLAY_SETTINGS = 6,
MENUPAGE_LANGUAGE_SETTINGS = 7,
MENUPAGE_CHOOSE_LOAD_SLOT = 8,
MENUPAGE_CHOOSE_DELETE_SLOT = 9,
MENUPAGE_NEW_GAME_RELOAD = 10,
MENUPAGE_LOAD_SLOT_CONFIRM = 11,
MENUPAGE_DELETE_SLOT_CONFIRM = 12,
MENUPAGE_NO_MEMORY_CARD = 13, // hud adjustment page in mobile
MENUPAGE_LOADING_IN_PROGRESS = 14,
MENUPAGE_DELETING_IN_PROGRESS = 15,
MENUPAGE_PS2_LOAD_FAILED = 16,
MENUPAGE_DELETE_FAILED = 17,
MENUPAGE_DEBUG_MENU = 18,
MENUPAGE_MEMORY_CARD_DEBUG = 19,
MENUPAGE_MEMORY_CARD_TEST = 20,
MENUPAGE_MULTIPLAYER_MAIN = 21,
MENUPAGE_PS2_SAVE_FAILED = 22,
MENUPAGE_PS2_SAVE_FAILED_2 = 23,
MENUPAGE_SAVE = 24,
MENUPAGE_NO_MEMORY_CARD_2 = 25,
MENUPAGE_CHOOSE_SAVE_SLOT = 26,
MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27,
MENUPAGE_MULTIPLAYER_MAP = 28,
MENUPAGE_MULTIPLAYER_CONNECTION = 29,
MENUPAGE_MULTIPLAYER_FIND_GAME = 30,
MENUPAGE_MULTIPLAYER_MODE = 31,
MENUPAGE_MULTIPLAYER_CREATE = 32,
MENUPAGE_MULTIPLAYER_START = 33,
MENUPAGE_SKIN_SELECT_OLD = 34,
MENUPAGE_CONTROLLER_PC = 35,
MENUPAGE_CONTROLLER_PC_OLD1 = 36,
MENUPAGE_CONTROLLER_PC_OLD2 = 37,
MENUPAGE_CONTROLLER_PC_OLD3 = 38,
MENUPAGE_CONTROLLER_PC_OLD4 = 39,
MENUPAGE_CONTROLLER_DEBUG = 40,
MENUPAGE_OPTIONS = 41,
MENUPAGE_EXIT = 42,
MENUPAGE_SAVING_IN_PROGRESS = 43,
MENUPAGE_SAVE_SUCCESSFUL = 44,
MENUPAGE_DELETING = 45,
MENUPAGE_DELETE_SUCCESS = 46,
MENUPAGE_SAVE_FAILED = 47,
MENUPAGE_LOAD_FAILED = 48,
MENUPAGE_LOAD_FAILED_2 = 49,
MENUPAGE_FILTER_GAME = 50,
MENUPAGE_START_MENU = 51,
MENUPAGE_PAUSE_MENU = 52,
MENUPAGE_CHOOSE_MODE = 53,
MENUPAGE_SKIN_SELECT = 54,
MENUPAGE_KEYBOARD_CONTROLS = 55,
MENUPAGE_MOUSE_CONTROLS = 56,
MENUPAGE_MISSION_RETRY = 57,
#ifdef CUSTOM_FRONTEND_OPTIONS
#ifdef MENU_MAP
MENUPAGE_MAP = 58,
#endif
#ifdef GRAPHICS_MENU_OPTIONS
MENUPAGE_GRAPHICS_SETTINGS,
#endif
#ifdef DETECT_JOYSTICK_MENU
MENUPAGE_DETECT_JOYSTICK,
#endif
#endif
MENUPAGE_UNK, // originally 58. Custom screens are inserted above, because last screen in CMenuScreens should always be empty to make CFO work
MENUPAGES
};
enum eMenuAction
{
#ifdef CUSTOM_FRONTEND_OPTIONS
MENUACTION_CFO_SLIDER = -3,
MENUACTION_CFO_SELECT = -2,
MENUACTION_CFO_DYNAMIC = -1,
#endif
MENUACTION_NOTHING,
MENUACTION_LABEL,
MENUACTION_CHANGEMENU,
MENUACTION_CTRLVIBRATION,
MENUACTION_CTRLCONFIG,
MENUACTION_CTRLDISPLAY,
MENUACTION_FRAMESYNC,
MENUACTION_FRAMELIMIT,
MENUACTION_TRAILS,
MENUACTION_SUBTITLES,
MENUACTION_WIDESCREEN,
MENUACTION_BRIGHTNESS,
MENUACTION_DRAWDIST,
MENUACTION_MUSICVOLUME,
MENUACTION_SFXVOLUME,
MENUACTION_UNK15,
MENUACTION_RADIO,
MENUACTION_LANG_ENG,
MENUACTION_LANG_FRE,
MENUACTION_LANG_GER,
MENUACTION_LANG_ITA,
MENUACTION_LANG_SPA,
MENUACTION_POPULATESLOTS_CHANGEMENU,
MENUACTION_CHECKSAVE,
MENUACTION_UNK24,
MENUACTION_NEWGAME,
MENUACTION_RELOADIDE,
MENUACTION_RELOADIPL,
MENUACTION_SETDBGFLAG,
MENUACTION_SWITCHBIGWHITEDEBUGLIGHT,
MENUACTION_PEDROADGROUPS,
MENUACTION_CARROADGROUPS,
MENUACTION_COLLISIONPOLYS,
MENUACTION_REGMEMCARD1,
MENUACTION_TESTFORMATMEMCARD1,
MENUACTION_TESTUNFORMATMEMCARD1,
MENUACTION_CREATEROOTDIR,
MENUACTION_CREATELOADICONS,
MENUACTION_FILLWITHGUFF,
MENUACTION_SAVEONLYTHEGAME,
MENUACTION_SAVEGAME,
MENUACTION_SAVEGAMEUNDERGTA,
MENUACTION_CREATECOPYPROTECTED,
MENUACTION_TESTSAVE,
MENUACTION_TESTLOAD,
MENUACTION_TESTDELETE,
MENUACTION_PARSEHEAP,
MENUACTION_SHOWCULL,
MENUACTION_MEMCARDSAVECONFIRM,
MENUACTION_RESUME_FROM_SAVEZONE,
MENUACTION_UNK50,
MENUACTION_DEBUGSTREAM,
MENUACTION_MPMAP_LIBERTY,
MENUACTION_MPMAP_REDLIGHT,
MENUACTION_MPMAP_CHINATOWN,
MENUACTION_MPMAP_TOWER,
MENUACTION_MPMAP_SEWER,
MENUACTION_MPMAP_INDUSTPARK,
MENUACTION_MPMAP_DOCKS,
MENUACTION_MPMAP_STAUNTON,
MENUACTION_MPMAP_DEATHMATCH1,
MENUACTION_MPMAP_DEATHMATCH2,
MENUACTION_MPMAP_TEAMDEATH1,
MENUACTION_MPMAP_TEAMDEATH2,
MENUACTION_MPMAP_STASH,
MENUACTION_MPMAP_CAPTURE,
MENUACTION_MPMAP_RATRACE,
MENUACTION_MPMAP_DOMINATION,
MENUACTION_STARTMP,
MENUACTION_UNK69,
MENUACTION_UNK70,
MENUACTION_FINDMP,
MENUACTION_KEYBOARDCTRLS,
MENUACTION_UNK73,
MENUACTION_INITMP,
MENUACTION_MP_PLAYERCOLOR,
MENUACTION_MP_PLAYERNAME,
MENUACTION_MP_GAMENAME,
MENUACTION_GETKEY,
MENUACTION_SHOWHEADBOB,
MENUACTION_UNK80,
MENUACTION_INVVERT,
MENUACTION_CANCELGAME,
MENUACTION_MP_PLAYERNUMBER,
MENUACTION_MOUSESENS,
MENUACTION_CHECKMPGAMES,
MENUACTION_CHECKMPPING,
MENUACTION_MP_SERVER,
MENUACTION_MP_MAP,
MENUACTION_MP_GAMETYPE,
MENUACTION_MP_LAN,
MENUACTION_MP_INTERNET,
MENUACTION_RESUME,
MENUACTION_DONTCANCEL,
MENUACTION_SCREENRES,
MENUACTION_AUDIOHW,
MENUACTION_SPEAKERCONF,
MENUACTION_PLAYERSETUP,
MENUACTION_RESTOREDEF,
MENUACTION_CTRLMETHOD,
MENUACTION_DYNAMICACOUSTIC,
MENUACTION_LOADRADIO,
MENUACTION_MOUSESTEER,
MENUACTION_UNK103,
MENUACTION_UNK104,
MENUACTION_UNK105,
MENUACTION_UNK106,
MENUACTION_UNK107,
MENUACTION_UNK108,
MENUACTION_UNK109,
MENUACTION_UNK110,
MENUACTION_UNK111,
MENUACTION_UNK112,
MENUACTION_REJECT_RETRY,
MENUACTION_UNK114,
//#ifdef ANISOTROPIC_FILTERING
// MENUACTION_MIPMAPS,
// MENUACTION_TEXTURE_FILTERING,
//#endif
};
enum eCheckHover
{
HOVEROPTION_0,
HOVEROPTION_1,
HOVEROPTION_RANDOM_ITEM,
HOVEROPTION_3,
HOVEROPTION_4,
HOVEROPTION_5,
HOVEROPTION_6,
HOVEROPTION_7,
HOVEROPTION_8,
HOVEROPTION_BACK, // also layer in controller setup and skin menu
HOVEROPTION_10,
HOVEROPTION_11,
HOVEROPTION_OVER_SCROLL_UP,
HOVEROPTION_OVER_SCROLL_DOWN,
HOVEROPTION_CLICKED_SCROLL_UP,
HOVEROPTION_CLICKED_SCROLL_DOWN,
HOVEROPTION_HOLDING_SCROLLBAR,
HOVEROPTION_PAGEUP,
HOVEROPTION_PAGEDOWN,
HOVEROPTION_LIST, // also layer in controller setup and skin menu
HOVEROPTION_SKIN,
HOVEROPTION_USESKIN, // also layer in controller setup and skin menu
HOVEROPTION_RADIO_0,
HOVEROPTION_RADIO_1,
HOVEROPTION_RADIO_2,
HOVEROPTION_RADIO_3,
HOVEROPTION_RADIO_4,
HOVEROPTION_RADIO_5,
HOVEROPTION_RADIO_6,
HOVEROPTION_RADIO_7,
HOVEROPTION_RADIO_8,
HOVEROPTION_RADIO_9,
HOVEROPTION_INCREASE_BRIGHTNESS,
HOVEROPTION_DECREASE_BRIGHTNESS,
HOVEROPTION_INCREASE_DRAWDIST,
HOVEROPTION_DECREASE_DRAWDIST,
HOVEROPTION_INCREASE_MUSICVOLUME,
HOVEROPTION_DECREASE_MUSICVOLUME,
HOVEROPTION_INCREASE_SFXVOLUME,
HOVEROPTION_DECREASE_SFXVOLUME,
HOVEROPTION_INCREASE_MOUSESENS,
HOVEROPTION_DECREASE_MOUSESENS,
#ifdef CUSTOM_FRONTEND_OPTIONS
HOVEROPTION_INCREASE_CFO_SLIDER,
HOVEROPTION_DECREASE_CFO_SLIDER,
#endif
HOVEROPTION_NOT_HOVERING,
};
enum
{
NUM_MENUROWS = 18,
};
enum eControlMethod
{
CONTROL_STANDARD = 0,
CONTROL_CLASSIC,
};
// Why??
enum ControllerSetupColumn
{
CONTSETUP_PED_COLUMN = 0,
CONTSETUP_VEHICLE_COLUMN = 14,
};
struct tSkinInfo
{
int32 skinId;
char skinNameDisplayed[256];
char skinNameOriginal[256];
char date[256];
tSkinInfo *nextSkin;
};
struct BottomBarOption
{
char name[8];
int32 screenId;
};
#ifndef CUSTOM_FRONTEND_OPTIONS
struct CMenuScreen
{
char m_ScreenName[8];
int32 unk; // 2 on MENUPAGE_MULTIPLAYER_START, 1 on everywhere else, 0 on unused.
int32 m_PreviousPage[2]; // eMenuScreen
int32 m_ParentEntry[2]; // row
struct CMenuEntry
{
int32 m_Action; // eMenuAction
char m_EntryName[8];
int32 m_SaveSlot; // eSaveSlot
int32 m_TargetMenu; // eMenuScreen
} m_aEntries[NUM_MENUROWS];
};
extern CMenuScreen aScreens[MENUPAGES];
#else
#include "frontendoption.h"
struct CCustomScreenLayout {
eMenuSprites sprite;
int columnWidth;
int headerHeight;
int lineHeight;
int8 font;
int8 alignment;
bool showLeftRightHelper;
float fontScaleX;
float fontScaleY;
};
struct CCFO
{
void *value;
const char *saveCat;
const char *save;
};
struct CCFOSelect : CCFO
{
char** rightTexts;
int8 numRightTexts;
bool onlyApplyOnEnter;
int8 displayedValue; // only if onlyApplyOnEnter enabled for now
int8 lastSavedValue; // only if onlyApplyOnEnter enabled
ChangeFunc changeFunc;
bool disableIfGameLoaded;
CCFOSelect() {};
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;
this->onlyApplyOnEnter = onlyApplyOnEnter;
this->changeFunc = changeFunc;
this->disableIfGameLoaded = disableIfGameLoaded;
}
};
// Value is float in here
struct CCFOSlider : CCFO
{
ChangeFuncFloat changeFunc;
float min;
float max;
CCFOSlider() {};
CCFOSlider(float* value, const char* saveCat, const char* save, float min, float max, ChangeFuncFloat changeFunc = nil){
this->value = value;
this->saveCat = saveCat;
this->save = save;
this->changeFunc = changeFunc;
this->min = min;
this->max = max;
}
};
struct CCFODynamic : CCFO
{
DrawFunc drawFunc;
ButtonPressFunc buttonPressFunc;
CCFODynamic() {};
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;
}
};
struct CMenuScreenCustom
{
char m_ScreenName[8];
int32 m_PreviousPage[2]; // eMenuScreen
CCustomScreenLayout *layout;
ReturnPrevPageFunc returnPrevPageFunc;
struct CMenuEntry
{
int32 m_Action; // eMenuAction - below zero is CFO
char m_EntryName[8];
struct {
union {
CCFO *m_CFO; // for initializing
CCFOSelect *m_CFOSelect;
CCFODynamic *m_CFODynamic;
CCFOSlider *m_CFOSlider;
};
int32 m_SaveSlot; // eSaveSlot
int32 m_TargetMenu; // eMenuScreen
};
} m_aEntries[NUM_MENUROWS];
};
extern CMenuScreenCustom aScreens[MENUPAGES];
#endif
class CMenuManager
{
public:
int32 m_nPrefsVideoMode;
int32 m_nDisplayVideoMode;
int8 m_nPrefsAudio3DProviderIndex;
bool m_bKeyChangeNotProcessed;
char m_aSkinName[256];
int32 m_nHelperTextMsgId;
bool m_bLanguageLoaded;
bool m_bMenuActive;
bool m_bMenuStateChanged;
bool m_bWaitingForNewKeyBind;
bool m_bWantToRestart;
bool m_bFirstTime;
bool m_bGameNotLoaded;
int32 m_nMousePosX;
int32 m_nMousePosY;
int32 m_nMouseTempPosX;
int32 m_nMouseTempPosY;
bool m_bShowMouse;
tSkinInfo m_pSkinListHead;
tSkinInfo *m_pSelectedSkin;
int32 m_nFirstVisibleRowOnList;
float m_nScrollbarTopMargin;
int32 m_nTotalListRow;
int32 m_nSkinsTotal;
char _unk0[4];
int32 m_nSelectedListRow;
bool m_bSkinsEnumerated;
bool m_bQuitGameNoCD;
bool m_bRenderGameInMenu;
bool m_bSaveMenuActive;
bool m_bWantToLoad;
char field_455;
bool m_bStartWaitingForKeyBind;
bool m_bSpritesLoaded;
CSprite2d m_aFrontEndSprites[NUM_FE_SPRITES];
CSprite2d m_aMenuSprites[NUM_MENU_SPRITES];
int32 field_518;
int32 m_nMenuFadeAlpha;
bool m_bPressedPgUpOnList;
bool m_bPressedPgDnOnList;
bool m_bPressedUpOnList;
bool m_bPressedDownOnList;
bool m_bPressedScrollButton;
int32 m_CurrCntrlAction;
char _unk1[4];
int32 m_nSelectedContSetupColumn;
bool m_bKeyIsOK;
bool field_535;
int8 m_nCurrExLayer;
int32 m_nHelperTextAlpha;
int32 m_nMouseOldPosX;
int32 m_nMouseOldPosY;
int32 m_nHoverOption;
int32 m_nCurrScreen;
int32 m_nCurrOption;
int32 m_nOptionMouseHovering;
int32 m_nPrevScreen;
uint32 field_558;
int32 m_nCurrSaveSlot;
int32 m_nScreenChangeDelayTimer;
#ifdef IMPROVED_VIDEOMODE
int32 m_nPrefsWidth;
int32 m_nPrefsHeight;
int32 m_nPrefsDepth;
int32 m_nPrefsWindowed;
int32 m_nPrefsSubsystem;
int32 m_nSelectedScreenMode;
#endif
#ifdef MULTISAMPLING
static int8 m_nPrefsMSAALevel;
static int8 m_nDisplayMSAALevel;
#endif
enum LANGUAGE
{
LANGUAGE_AMERICAN,
LANGUAGE_FRENCH,
LANGUAGE_GERMAN,
LANGUAGE_ITALIAN,
LANGUAGE_SPANISH,
#ifdef MORE_LANGUAGES
LANGUAGE_POLISH,
LANGUAGE_RUSSIAN,
LANGUAGE_JAPANESE,
#endif
};
public:
bool GetIsMenuActive() {return !!m_bMenuActive;}
public:
static int32 OS_Language;
static int8 m_PrefsUseVibration;
static int8 m_DisplayControllerOnFoot;
static int8 m_PrefsUseWideScreen;
static int8 m_PrefsRadioStation;
static int8 m_PrefsVsync;
static int8 m_PrefsVsyncDisp;
static int8 m_PrefsFrameLimiter;
static int8 m_PrefsShowSubtitles;
static int8 m_PrefsSpeakers;
static int32 m_ControlMethod;
static int8 m_PrefsDMA;
static int32 m_PrefsLanguage;
static int32 m_PrefsBrightness;
static float m_PrefsLOD;
static int8 m_bFrontEnd_ReloadObrTxtGxt;
static int32 m_PrefsMusicVolume;
static int32 m_PrefsSfxVolume;
static char m_PrefsSkinFile[256];
static int32 m_KeyPressedCode;
static bool m_bStartUpFrontEndRequested;
static bool m_bShutDownFrontEndRequested;
static bool m_PrefsAllowNastyGame;
static uint8 m_PrefsStereoMono;
static int32 m_SelectedMap;
static int32 m_SelectedGameType;
static uint8 m_PrefsPlayerRed;
static uint8 m_PrefsPlayerGreen;
static uint8 m_PrefsPlayerBlue;
#ifdef CUTSCENE_BORDERS_SWITCH
static bool m_PrefsCutsceneBorders;
#endif
#ifndef MASTER
static bool m_PrefsMarketing;
static bool m_PrefsDisableTutorials;
#endif // !MASTER
#ifdef MENU_MAP
static bool bMenuMapActive;
static float fMapSize;
static float fMapCenterY;
static float fMapCenterX;
static CSprite2d m_aMapSprites[NUM_MAP_SPRITES];
void PrintMap();
#endif
#ifdef NO_ISLAND_LOADING
enum
{
ISLAND_LOADING_LOW = 0,
ISLAND_LOADING_MEDIUM,
ISLAND_LOADING_HIGH
};
static int8 m_PrefsIslandLoading;
#define ISLAND_LOADING_IS(p) if (CMenuManager::m_PrefsIslandLoading == CMenuManager::ISLAND_LOADING_##p)
#define ISLAND_LOADING_ISNT(p) if (CMenuManager::m_PrefsIslandLoading != CMenuManager::ISLAND_LOADING_##p)
#else
#define ISLAND_LOADING_IS(p)
#define ISLAND_LOADING_ISNT(p)
#endif
#ifdef GAMEPAD_MENU
enum
{
CONTROLLER_DUALSHOCK2 = 0,
CONTROLLER_DUALSHOCK3,
CONTROLLER_DUALSHOCK4,
CONTROLLER_XBOX360,
CONTROLLER_XBOXONE,
CONTROLLER_NINTENDO_SWITCH,
};
static int8 m_PrefsControllerType;
#endif
public:
static void BuildStatLine(Const char *text, void *stat, bool itsFloat, void *stat2);
static void CentreMousePointer();
void CheckCodesForControls(int);
bool CheckHover(int x1, int x2, int y1, int y2);
void CheckSliderMovement(int);
int CostructStatLine(int);
void DisplayHelperText();
int DisplaySlider(float, float, float, float, float, float);
void DoSettingsBeforeStartingAGame();
void Draw();
void DrawControllerBound(int32, int32, int32, int8);
void DrawControllerScreenExtraText(int, int, int);
void DrawControllerSetupScreen();
void DrawFrontEnd();
void DrawFrontEndNormal();
#ifdef PS2_SAVE_DIALOG
void DrawFrontEndSaveZone();
#endif
void DrawPlayerSetupScreen();
int FadeIn(int alpha);
void FilterOutColorMarkersFromString(wchar*, CRGBA &);
int GetStartOptionsCntrlConfigScreens();
static void InitialiseChangedLanguageSettings();
void LoadAllTextures();
void LoadSettings();
void MessageScreen(const char *);
void PickNewPlayerColour();
void PrintBriefs();
static void PrintErrorMessage();
void PrintStats();
void Process();
void ProcessButtonPresses();
void ProcessOnOffMenuOptions();
static void RequestFrontEndShutDown();
static void RequestFrontEndStartUp();
void ResetHelperText();
void SaveLoadFileError_SetUpErrorScreen();
void SaveSettings();
void SetHelperText(int text);
void ShutdownJustMenu();
float StretchX(float);
float StretchY(float);
void SwitchMenuOnAndOff();
void UnloadTextures();
void WaitForUserCD();
void PrintController();
int GetNumOptionsCntrlConfigScreens();
int ConstructStatLine(int);
// Those are either inlined in game, not in function yet, or I can't believe that they're not inlined.
// Names were made up by me.
void ThingsToDoBeforeGoingBack();
void ScrollUpListByOne();
void ScrollDownListByOne();
void PageUpList(bool);
void PageDownList(bool);
int8 GetPreviousPageOption();
void ProcessList(bool &goBack, bool &optionSelected);
#ifdef GAMEPAD_MENU
void LoadController(int8 type);
#endif
};
#ifndef IMPROVED_VIDEOMODE
VALIDATE_SIZE(CMenuManager, 0x564);
#endif
extern CMenuManager FrontEndMenuManager;
#endif

1393
src/core/FrontendTriggers.h Normal file

File diff suppressed because it is too large Load diff

3033
src/core/Frontend_PS2.cpp Normal file

File diff suppressed because it is too large Load diff

245
src/core/Frontend_PS2.h Normal file
View file

@ -0,0 +1,245 @@
#pragma once
#include "Sprite2d.h"
enum
{
PAGE_STATS,
PAGE_LOAD,
PAGE_BRIEFS,
PAGE_CONTROLS,
PAGE_AUDIO,
PAGE_DISPLAY,
PAGE_LANGUAGE,
NUM_PAGES,
PAGE_FIRST = PAGE_STATS,
PAGE_LAST = PAGE_LANGUAGE,
};
enum
{
PAGESTATE_NORMAL = 0,
PAGESTATE_HIGHLIGHTED,
PAGESTATE_SELECTED
};
enum eFrontendSprites
{
FE2_MAINPANEL_UL,
FE2_MAINPANEL_UR,
FE2_MAINPANEL_DL,
FE2_MAINPANEL_DR,
FE2_MAINPANEL_DR2,
FE2_TABACTIVE,
FE_ICONBRIEF,
FE_ICONSTATS,
FE_ICONCONTROLS,
FE_ICONSAVE,
FE_ICONAUDIO,
FE_ICONDISPLAY,
FE_ICONLANGUAGE,
FE_CONTROLLER,
FE_CONTROLLERSH,
FE_ARROWS1,
FE_ARROWS2,
FE_ARROWS3,
FE_ARROWS4,
FE_RADIO1,
FE_RADIO2,
FE_RADIO3,
FE_RADIO4,
FE_RADIO5,
FE_RADIO6,
FE_RADIO7,
FE_RADIO8,
FE_RADIO9,
NUM_FE_SPRITES
};
class CSprite2d;
class CVector2D;
#ifdef GTA_PC
enum eControlMethod
{
CONTROL_STANDARD = 0,
CONTROL_CLASSIC,
};
#endif
class CMenuManager
{
public:
enum LANGUAGE
{
LANGUAGE_AMERICAN,
LANGUAGE_FRENCH,
LANGUAGE_GERMAN,
LANGUAGE_ITALIAN,
LANGUAGE_SPANISH,
#ifdef MORE_LANGUAGES
LANGUAGE_POLISH,
LANGUAGE_RUSSIAN,
LANGUAGE_JAPANESE,
#endif
};
enum CONTRCONFIG
{
CONFIG_1 = 0,
CONFIG_2,
CONFIG_3,
CONFIG_4,
};
enum
{
NUM_SPRIRES = 28,
};
enum
{
PAGESTATE_NORMAL = 0,
PAGESTATE_HIGHLIGHTED = 1,
PAGESTATE_SELELECTED = 2,
};
enum
{
SLIDE_TO_BOTTOM = 0,
SLIDE_TO_RIGHT,
SLIDE_TO_TOP,
SLIDE_TO_LEFT,
SLIDE_MAX
};
int32 m_currentPage;
int32 m_newPage;
int32 m_pageState;
uint32 m_nPageLeftTimer;
uint32 m_nPageRightTimer;
uint32 m_nChangePageTimer;
int field_18;
uint8 m_fade;
uint8 m_someAlpha;
//char field_1E; // unused ?
//char field_1F; // unused ?
uint32 m_nStartPauseTimer;
uint32 m_nEndPauseTimer;
CVector2D m_position;
uint8 m_nSlidingDir;
//char field_31; // unused ?
//char field_32; // unused ?
//char field_33; // unused ?
bool m_bInitialised;
bool m_bWantToUpdateContent;
bool m_bMenuActive;
bool m_bWantToRestart;
//char field_38; //unused ?
bool m_bRenderGameInMenu;
bool m_bSaveMenuActive;
bool m_bInSaveZone;
char field_3C;
bool m_bTexturesLoaded;
//char field_3E; //unused ?
//char field_3F; //unused ?
CSprite2d m_sprites[NUM_SPRIRES];
static int32 m_PrefsSfxVolume;
static int32 m_PrefsMusicVolume;
static int32 m_PrefsBrightness;
static bool m_PrefsShowTrails;
static bool m_PrefsShowSubtitles;
static bool m_PrefsAllowNastyGame;
static int32 m_PrefsRadioStation;
static int32 m_PrefsStereoMono;
static int8 m_PrefsUseWideScreen;
static int32 m_PrefsLanguage;
static CONTRCONFIG m_PrefsControllerConfig;
static bool m_PrefsUseVibration;
#define ISLAND_LOADING_IS(p)
#define ISLAND_LOADING_ISNT(p)
#ifdef GTA_PC
bool m_bQuitGameNoCD;
int32 m_nMouseTempPosX;
int32 m_nMouseTempPosY;
int32 m_nPrefsVideoMode;
int32 m_nDisplayVideoMode;
int8 m_nPrefsAudio3DProviderIndex;
static int32 OS_Language;
static int8 m_PrefsVsync;
static int8 m_PrefsVsyncDisp;
static int8 m_PrefsFrameLimiter;
static int8 m_PrefsSpeakers;
static int32 m_ControlMethod;
static int8 m_PrefsDMA;
static float m_PrefsLOD;
static char m_PrefsSkinFile[256];
#ifndef MASTER
static bool m_PrefsMarketing;
static bool m_PrefsDisableTutorials;
#endif // !MASTER
#ifdef MENU_MAP
static bool bMenuMapActive;
static float fMapSize;
static float fMapCenterY;
static float fMapCenterX;
#endif
#ifdef IMPROVED_VIDEOMODE
int32 m_nPrefsWidth = 640;
int32 m_nPrefsHeight = 480;
int32 m_nPrefsDepth = 32;
int32 m_nPrefsWindowed = 1;
int32 m_nPrefsSubsystem;
int32 m_nSelectedScreenMode;
#endif
void WaitForUserCD() { }
#endif
bool GetIsMenuActive() {return !!m_bMenuActive;}
CMenuManager(void);
#ifdef FIX_BUGS
~CMenuManager(void)
{
UnloadTextures();
}
#endif
void LoadAllTextures(void);
void UnloadTextures(void);
void InitialiseMenusOnce(void);
void InitialiseChangedLanguageSettings(void);
void InitialiseMenuContents(void);
void AnaliseMenuContents(void);
void InitialiseMenuContentsAfterLoadingGame(void);
void DrawFrontEnd(void);
void DrawFrontEndNormal(void);
void DrawFrontEndSaveZone(void);
void DrawMemoryCardStartUpMenus(void);
void Process(void);
void WorkOutMenuState(uint8 bExit);
void ProcessControllerInput(void);
void ProcessDPadLeftJustDown(void);
void ProcessDPadRightJustDown(void);
void ProcessDPadUpJustDown(void);
void ProcessDPadDownJustDown(void);
void ProcessDPadTriangleJustDown(void);
void ProcessDPadCrossJustDown(void);
void DoHackingMenusAtPageBrowse(void);
void SetSoundLevelsForMusicMenu(void);
void FilterOutColorMarkersFromString(wchar *string, CRGBA &color);
};
extern CMenuManager FrontEndMenuManager;

1464
src/core/Game.cpp Normal file

File diff suppressed because it is too large Load diff

49
src/core/Game.h Normal file
View file

@ -0,0 +1,49 @@
#pragma once
enum eLevelName {
LEVEL_IGNORE = -1, // beware, this is only used in CPhysical's m_nZoneLevel
LEVEL_GENERIC = 0,
LEVEL_INDUSTRIAL,
LEVEL_COMMERCIAL,
LEVEL_SUBURBAN,
NUM_LEVELS
};
class CGame
{
public:
static eLevelName currLevel;
static bool bDemoMode;
static bool nastyGame;
static bool frenchGame;
static bool germanGame;
#ifdef MORE_LANGUAGES
static bool russianGame;
static bool japaneseGame;
#endif
static bool noProstitutes;
static bool playingIntro;
static char aDatFile[32];
static bool InitialiseOnceBeforeRW(void);
static bool InitialiseRenderWare(void);
static void ShutdownRenderWare(void);
static bool InitialiseOnceAfterRW(void);
static void FinalShutdown(void);
#if GTA_VERSION <= GTA3_PS2_160
static bool Initialise(void);
#else
static bool Initialise(const char *datFile);
#endif
static bool ShutDown(void);
static void ReInitGameObjectVariables(void);
static void ReloadIPLs(void);
static void ShutDownForRestart(void);
static void InitialiseWhenRestarting(void);
static void Process(void);
// NB: these do something on PS2
static void TidyUpMemory(bool, bool);
static void DrasticTidyUpMemory(bool);
static void ProcessTidyUpMemory(void);
};

157
src/core/General.h Normal file
View file

@ -0,0 +1,157 @@
#pragma once
#include <ctype.h>
class CGeneral
{
public:
static float GetATanOfXY(float x, float y){
if(x == 0.0f && y == 0.0f)
return 0.0f;
float xabs = Abs(x);
float yabs = Abs(y);
if(xabs < yabs){
if(y > 0.0f){
if(x > 0.0f)
return 0.5f*PI - Atan2(x / y, 1.0f);
else
return 0.5f*PI + Atan2(-x / y, 1.0f);
}else{
if(x > 0.0f)
return 1.5f*PI + Atan2(x / -y, 1.0f);
else
return 1.5f*PI - Atan2(-x / -y, 1.0f);
}
}else{
if(y > 0.0f){
if(x > 0.0f)
return Atan2(y / x, 1.0f);
else
return PI - Atan2(y / -x, 1.0f);
}else{
if(x > 0.0f)
return 2.0f*PI - Atan2(-y / x, 1.0f);
else
return PI + Atan2(-y / -x, 1.0f);
}
}
}
static float LimitAngle(float angle)
{
float result = angle;
while (result >= 180.0f) {
result -= 2 * 180.0f;
}
while (result < -180.0f) {
result += 2 * 180.0f;
}
return result;
}
static float LimitRadianAngle(float angle)
{
float result = Clamp(angle, -25.0f, 25.0f);
while (result >= PI) {
result -= 2 * PI;
}
while (result < -PI) {
result += 2 * PI;
}
return result;
}
// Returns an angle such that x2/y2 looks at x1/y1 with its forward vector if rotated by that angle
static float GetRadianAngleBetweenPoints(float x1, float y1, float x2, float y2)
{
float x = x2 - x1;
float y = y2 - y1;
if (y == 0.0f)
y = 0.0001f;
if (x > 0.0f) {
if (y > 0.0f)
return PI - Atan2(x / y, 1.0f);
else
return -Atan2(x / y, 1.0f);
} else {
if (y > 0.0f)
return -(PI + Atan2(x / y, 1.0f));
else
return -Atan2(x / y, 1.0f);
}
}
static float GetAngleBetweenPoints(float x1, float y1, float x2, float y2)
{
return RADTODEG(GetRadianAngleBetweenPoints(x1, y1, x2, y2));
}
// should return direction in 0-8 range. fits perfectly to peds' path directions.
static int GetNodeHeadingFromVector(float x, float y)
{
float angle = CGeneral::GetRadianAngleBetweenPoints(x, y, 0.0f, 0.0f);
if (angle < 0.0f)
angle += TWOPI;
angle = DEGTORAD(22.5f) + TWOPI - angle;
if (angle >= TWOPI)
angle -= TWOPI;
return (int)Floor(angle / DEGTORAD(45.0f));
}
// Unlike usual string comparison functions, these don't care about greater or lesser
static bool faststrcmp(const char *str1, const char *str2)
{
for (; *str1; str1++, str2++) {
if (*str1 != *str2)
return true;
}
return *str2 != '\0';
}
static bool faststrncmp(const char *str1, const char *str2, uint32 count)
{
for(uint32 i = 0; *str1 && i < count; str1++, str2++, i++) {
if (*str1 != *str2)
return true;
}
return false;
}
static bool faststricmp(const char *str1, const char *str2)
{
for (; *str1; str1++, str2++) {
#ifndef ASCII_STRCMP
if (toupper(*str1) != toupper(*str2))
#else
if (__ascii_toupper(*str1) != __ascii_toupper(*str2))
#endif
return true;
}
return *str2 != '\0';
}
// not too sure about all these...
static uint16 GetRandomNumber(void)
{ return myrand() & MYRAND_MAX; }
static bool GetRandomTrueFalse(void)
{ return GetRandomNumber() < MYRAND_MAX / 2; }
// Probably don't want to ever reach high
static float GetRandomNumberInRange(float low, float high)
{ return low + (high - low)*(GetRandomNumber()/float(MYRAND_MAX + 1)); }
static int32 GetRandomNumberInRange(int32 low, int32 high)
{ return low + (high - low)*(GetRandomNumber()/float(MYRAND_MAX + 1)); }
};

28
src/core/IniFile.cpp Normal file
View file

@ -0,0 +1,28 @@
#include "common.h"
#include "IniFile.h"
#include "CarCtrl.h"
#include "FileMgr.h"
#include "main.h"
#include "Population.h"
float CIniFile::PedNumberMultiplier = 1.0f;
float CIniFile::CarNumberMultiplier = 1.0f;
void CIniFile::LoadIniFile()
{
CFileMgr::SetDir("");
int f = CFileMgr::OpenFile("gta3.ini", "r");
if (f){
CFileMgr::ReadLine(f, gString, 200);
sscanf(gString, "%f", &PedNumberMultiplier);
PedNumberMultiplier = Min(3.0f, Max(0.5f, PedNumberMultiplier));
CFileMgr::ReadLine(f, gString, 200);
sscanf(gString, "%f", &CarNumberMultiplier);
CarNumberMultiplier = Min(3.0f, Max(0.5f, CarNumberMultiplier));
CFileMgr::CloseFile(f);
}
CPopulation::MaxNumberOfPedsInUse = DEFAULT_MAX_NUMBER_OF_PEDS * PedNumberMultiplier;
CCarCtrl::MaxNumberOfCarsInUse = DEFAULT_MAX_NUMBER_OF_CARS * CarNumberMultiplier;
}

13
src/core/IniFile.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#define DEFAULT_MAX_NUMBER_OF_PEDS 25.0f
#define DEFAULT_MAX_NUMBER_OF_CARS 12.0f
class CIniFile
{
public:
static void LoadIniFile();
static float PedNumberMultiplier;
static float CarNumberMultiplier;
};

26
src/core/Lists.cpp Normal file
View file

@ -0,0 +1,26 @@
#include "common.h"
#include "Pools.h"
#include "Lists.h"
void*
CPtrNode::operator new(size_t){
CPtrNode *node = CPools::GetPtrNodePool()->New();
assert(node);
return node;
}
void
CPtrNode::operator delete(void *p, size_t){
CPools::GetPtrNodePool()->Delete((CPtrNode*)p);
}
void*
CEntryInfoNode::operator new(size_t){
CEntryInfoNode *node = CPools::GetEntryInfoNodePool()->New();
assert(node);
return node;
}
void
CEntryInfoNode::operator delete(void *p, size_t){
CPools::GetEntryInfoNodePool()->Delete((CEntryInfoNode*)p);
}

130
src/core/Lists.h Normal file
View file

@ -0,0 +1,130 @@
#pragma once
class CPtrNode
{
public:
void *item;
CPtrNode *prev;
CPtrNode *next;
void *operator new(size_t);
void operator delete(void *p, size_t);
};
class CPtrList
{
public:
CPtrNode *first;
CPtrList(void) { first = nil; }
~CPtrList(void) { Flush(); }
CPtrNode *FindItem(void *item){
CPtrNode *node;
for(node = first; node; node = node->next)
if(node->item == item)
return node;
return nil;
}
CPtrNode *InsertNode(CPtrNode *node){
node->prev = nil;
node->next = first;
if(first)
first->prev = node;
first = node;
return node;
}
CPtrNode *InsertItem(void *item){
CPtrNode *node = new CPtrNode;
node->item = item;
InsertNode(node);
return node;
}
void RemoveNode(CPtrNode *node){
if(node == first)
first = node->next;
if(node->prev)
node->prev->next = node->next;
if(node->next)
node->next->prev = node->prev;
}
void DeleteNode(CPtrNode *node){
RemoveNode(node);
delete node;
}
void RemoveItem(void *item){
CPtrNode *node, *next;
for(node = first; node; node = next){
next = node->next;
if(node->item == item)
DeleteNode(node);
}
}
void Flush(void){
CPtrNode *node, *next;
for(node = first; node; node = next){
next = node->next;
DeleteNode(node);
}
}
};
class CSector;
// This records in which sector list a Physical is
class CEntryInfoNode
{
public:
CPtrList *list; // list in sector
CPtrNode *listnode; // node in list
CSector *sector;
CEntryInfoNode *prev;
CEntryInfoNode *next;
void *operator new(size_t);
void operator delete(void *p, size_t);
};
class CEntryInfoList
{
public:
CEntryInfoNode *first;
CEntryInfoList(void) { first = nil; }
~CEntryInfoList(void) { Flush(); }
CEntryInfoNode *InsertNode(CEntryInfoNode *node){
node->prev = nil;
node->next = first;
if(first)
first->prev = node;
first = node;
return node;
}
CEntryInfoNode *InsertItem(CPtrList *list, CPtrNode *listnode, CSector *sect){
CEntryInfoNode *node = new CEntryInfoNode;
node->list = list;
node->listnode = listnode;
node->sector = sect;
InsertNode(node);
return node;
}
void RemoveNode(CEntryInfoNode *node){
if(node == first)
first = node->next;
if(node->prev)
node->prev->next = node->next;
if(node->next)
node->next->prev = node->prev;
}
void DeleteNode(CEntryInfoNode *node){
RemoveNode(node);
delete node;
}
void Flush(void){
CEntryInfoNode *node, *next;
for(node = first; node; node = next){
next = node->next;
DeleteNode(node);
}
}
};

453
src/core/MenuScreens.cpp Normal file
View file

@ -0,0 +1,453 @@
#include "common.h"
#include "Frontend.h"
#ifdef PC_MENU
// Please don't touch this file, except for bug fixing or ports.
// Check MenuScreensCustom.cpp
#ifndef CUSTOM_FRONTEND_OPTIONS
CMenuScreen aScreens[MENUPAGES] = {
// MENUPAGE_NONE = 0
{ "", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, },
// MENUPAGE_STATS = 1
{ "FET_STA", 1, MENUPAGE_NONE, MENUPAGE_NONE, 5, 2,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_NEW_GAME = 2
{ "FET_SGA", 1, MENUPAGE_NONE, MENUPAGE_NONE, 0, 1,
MENUACTION_CHANGEMENU, "FES_SNG", SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD,
MENUACTION_POPULATESLOTS_CHANGEMENU, "GMLOAD", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT,
MENUACTION_POPULATESLOTS_CHANGEMENU, "FES_DGA", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_BRIEFS = 3
{ "FET_BRE", 1, MENUPAGE_NONE, MENUPAGE_NONE, 6, 3,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_CONTROLLER_SETTINGS = 4
{ "FET_CON", 1, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 0, 0,
MENUACTION_CTRLCONFIG, "FEC_CCF", SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS,
MENUACTION_CTRLDISPLAY, "FEC_CDP", SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS,
MENUACTION_CTRLVIBRATION, "FEC_VIB", SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_SOUND_SETTINGS = 5
{ "FET_AUD", 1, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 1, 1,
MENUACTION_MUSICVOLUME, "FEA_MUS", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
MENUACTION_SFXVOLUME, "FEA_SFX", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
#ifdef EXTERNAL_3D_SOUND
MENUACTION_AUDIOHW, "FEA_3DH", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
MENUACTION_SPEAKERCONF, "FEA_SPK", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
#endif
#ifdef AUDIO_REFLECTIONS
MENUACTION_DYNAMICACOUSTIC, "FET_DAM", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
#endif
MENUACTION_RADIO, "FEA_RSS", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
MENUACTION_RESTOREDEF, "FET_DEF", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_DISPLAY_SETTINGS = 6
{ "FET_DIS", 1, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 2, 2,
MENUACTION_BRIGHTNESS, "FED_BRI", SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS,
MENUACTION_DRAWDIST, "FEM_LOD", SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS,
MENUACTION_FRAMESYNC, "FEM_VSC", SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS,
MENUACTION_FRAMELIMIT, "FEM_FRM", SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS,
MENUACTION_TRAILS, "FED_TRA", SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS,
MENUACTION_SUBTITLES, "FED_SUB", SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS,
MENUACTION_WIDESCREEN, "FED_WIS", SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS,
MENUACTION_SCREENRES, "FED_RES", SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS,
MENUACTION_RESTOREDEF, "FET_DEF", SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_LANGUAGE_SETTINGS = 7
{ "FET_LAN", 1, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 3, 3,
MENUACTION_LANG_ENG, "FEL_ENG", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS,
MENUACTION_LANG_FRE, "FEL_FRE", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS,
MENUACTION_LANG_GER, "FEL_GER", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS,
MENUACTION_LANG_ITA, "FEL_ITA", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS,
MENUACTION_LANG_SPA, "FEL_SPA", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_CHOOSE_LOAD_SLOT = 8
{ "FET_LG", 1, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 1, 1,
MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
MENUACTION_CHECKSAVE, "FEM_SL0", SAVESLOT_1, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL1", SAVESLOT_2, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL2", SAVESLOT_3, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL3", SAVESLOT_4, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL4", SAVESLOT_5, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL5", SAVESLOT_6, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL6", SAVESLOT_7, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL7", SAVESLOT_8, MENUPAGE_LOAD_SLOT_CONFIRM,
},
// MENUPAGE_CHOOSE_DELETE_SLOT = 9
{ "FET_DG", 1, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 2, 2,
MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
MENUACTION_CHANGEMENU, "FEM_SL0", SAVESLOT_1, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL1", SAVESLOT_2, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL2", SAVESLOT_3, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL3", SAVESLOT_4, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL4", SAVESLOT_5, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL5", SAVESLOT_6, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL6", SAVESLOT_7, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL7", SAVESLOT_8, MENUPAGE_DELETE_SLOT_CONFIRM,
},
// MENUPAGE_NEW_GAME_RELOAD = 10
{ "FET_NG", 1, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 0, 0,
MENUACTION_LABEL, "FESZ_QR", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
MENUACTION_NEWGAME, "FEM_YES", SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD,
},
// MENUPAGE_LOAD_SLOT_CONFIRM = 11
{ "FET_LG", 1, MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, 0, 0,
MENUACTION_LABEL, "FESZ_QL", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT,
MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_LOADING_IN_PROGRESS,
},
// MENUPAGE_DELETE_SLOT_CONFIRM = 12
{ "FET_DG", 1, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0,
MENUACTION_LABEL, "FESZ_QD", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_DELETING,
},
// MENUPAGE_NO_MEMORY_CARD = 13
{ "FES_NOC", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
// hud adjustment page in mobile
},
// MENUPAGE_LOADING_IN_PROGRESS = 14
{ "FET_LG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_LABEL, "FED_LDW", SAVESLOT_NONE, MENUPAGE_LOAD_SLOT_CONFIRM,
},
// MENUPAGE_DELETING_IN_PROGRESS = 15
{ "FET_DG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_LABEL, "FEDL_WR", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_PS2_LOAD_FAILED = 16
{ "FET_LG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_LABEL, "FES_LOE", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_DELETE_FAILED = 17
{ "FET_DG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_LABEL, "FES_DEE", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
},
// MENUPAGE_DEBUG_MENU = 18
{ "FED_DBG", 1, MENUPAGE_NONE, MENUPAGE_NONE, 4, 0,
MENUACTION_RELOADIDE, "FED_RID", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_RELOADIPL, "FED_RIP", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_SETDBGFLAG, "FED_DFL", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_SWITCHBIGWHITEDEBUGLIGHT, "FED_DLS", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_PEDROADGROUPS, "FED_SPR", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CARROADGROUPS, "FED_SCR", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_COLLISIONPOLYS, "FED_SCP", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_PARSEHEAP, "FED_PAH", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_SHOWCULL, "FED_SCZ", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_DEBUGSTREAM, "FED_DSR", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_MEMORY_CARD_DEBUG = 19
{ "FEM_MCM", 1, MENUPAGE_NONE, MENUPAGE_NONE, 7, 0,
MENUACTION_REGMEMCARD1, "FEM_RMC", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_TESTFORMATMEMCARD1, "FEM_TFM", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_TESTUNFORMATMEMCARD1, "FEM_TUM", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CREATEROOTDIR, "FEM_CRD", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CREATELOADICONS, "FEM_CLI", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_FILLWITHGUFF, "FEM_FFF", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_SAVEONLYTHEGAME, "FEM_SOG", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_SAVEGAME, "FEM_STG", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_SAVEGAMEUNDERGTA, "FEM_STS", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CREATECOPYPROTECTED, "FEM_CPD", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_MEMORY_CARD_TEST = 20
{ "FEM_MC2", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MULTIPLAYER_MAIN = 21
{ "FET_MP", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_PS2_SAVE_FAILED = 22
{ "MCDNSP", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_PS2_SAVE_FAILED_2 = 23
{ "MCGNSP", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE,
},
// Unused in PC but anyway
// MENUPAGE_SAVE = 24
#ifdef PS2_SAVE_DIALOG
{ "FET_SG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_CHANGEMENU, "FESZ_SA", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
MENUACTION_RESUME_FROM_SAVEZONE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE,
},
#else
{ "FET_SG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_LABEL, "FES_SCG", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_POPULATESLOTS_CHANGEMENU, "GMSAVE", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
MENUACTION_RESUME_FROM_SAVEZONE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE,
},
#endif
// MENUPAGE_NO_MEMORY_CARD_2 = 25
{ "FES_NOC", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_CHOOSE_SAVE_SLOT = 26
{ "FET_SG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_RESUME_FROM_SAVEZONE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEM_SL1", SAVESLOT_1, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL2", SAVESLOT_2, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL3", SAVESLOT_3, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL4", SAVESLOT_4, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL5", SAVESLOT_5, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL6", SAVESLOT_6, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL7", SAVESLOT_7, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_CHANGEMENU, "FEM_SL8", SAVESLOT_8, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
},
// MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27
{ "FET_SG", 1, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
MENUACTION_LABEL, "FESZ_QO", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_SAVING_IN_PROGRESS,
MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
},
// MENUPAGE_MULTIPLAYER_MAP = 28
{ "FET_MAP", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MULTIPLAYER_CONNECTION = 29
{ "FET_CON", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MULTIPLAYER_FIND_GAME = 30
{ "FET_FG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MULTIPLAYER_MODE = 31
{ "FET_GT", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MULTIPLAYER_CREATE = 32
{ "FET_HG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MULTIPLAYER_START = 33
{ "FEN_STA", 2, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_SKIN_SELECT_OLD = 34
{ "FET_PS", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_CONTROLLER_PC = 35
{ "FET_CTL", 1, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 0, 0,
#ifdef PC_PLAYER_CONTROLS
MENUACTION_CTRLMETHOD, "FET_CME", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
#endif
MENUACTION_KEYBOARDCTRLS,"FET_RDK", SAVESLOT_NONE, MENUPAGE_KEYBOARD_CONTROLS,
MENUACTION_CHANGEMENU, "FET_AMS", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS,
MENUACTION_RESTOREDEF, "FET_DEF", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_CONTROLLER_PC_OLD1 = 36
{ "FET_CTL", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 0, 0,
MENUACTION_GETKEY, "FEC_PLB", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1,
MENUACTION_GETKEY, "FEC_CWL", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1,
MENUACTION_GETKEY, "FEC_CWR", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1,
MENUACTION_GETKEY, "FEC_LKT", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1,
MENUACTION_GETKEY, "FEC_PJP", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1,
MENUACTION_GETKEY, "FEC_PSP", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1,
MENUACTION_GETKEY, "FEC_TLF", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1,
MENUACTION_GETKEY, "FEC_TRG", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1,
MENUACTION_GETKEY, "FEC_CCM", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_CONTROLLER_PC_OLD2 = 37
{ "FET_CTL", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 1, 1,
},
// MENUPAGE_CONTROLLER_PC_OLD3 = 38
{ "FET_CTL", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 2, 2,
MENUACTION_GETKEY, "FEC_LUP", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3,
MENUACTION_GETKEY, "FEC_LDN", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3,
MENUACTION_GETKEY, "FEC_SMS", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3,
MENUACTION_SHOWHEADBOB, "FEC_GSL", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_CONTROLLER_PC_OLD4 = 39
{ "FET_CTL", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 3, 3,
},
// MENUPAGE_CONTROLLER_DEBUG = 40
{ "FEC_DBG", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 3, 3,
MENUACTION_GETKEY, "FEC_TGD", SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG,
MENUACTION_GETKEY, "FEC_TDO", SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG,
MENUACTION_GETKEY, "FEC_TSS", SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG,
MENUACTION_GETKEY, "FEC_SMS", SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_OPTIONS = 41
{ "FET_OPT", 1, MENUPAGE_NONE, MENUPAGE_NONE, 1, 4,
MENUACTION_CHANGEMENU, "FET_CTL", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
MENUACTION_LOADRADIO, "FET_AUD", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
MENUACTION_CHANGEMENU, "FET_DIS", SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS,
MENUACTION_CHANGEMENU, "FET_LAN", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS,
MENUACTION_PLAYERSETUP, "FET_PSU", SAVESLOT_NONE, MENUPAGE_SKIN_SELECT,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_EXIT = 42
{ "FET_QG", 1, MENUPAGE_NONE, MENUPAGE_NONE, 2, 5,
MENUACTION_LABEL, "FEQ_SRE", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_DONTCANCEL, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CANCELGAME, "FEM_YES", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_SAVING_IN_PROGRESS = 43
{ "", 1, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
MENUACTION_LABEL, "FES_WAR", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_SAVE_SUCCESSFUL = 44
{ "FET_SG", 1, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
MENUACTION_LABEL, "FES_SSC", SAVESLOT_LABEL, MENUPAGE_NONE,
MENUACTION_RESUME_FROM_SAVEZONE, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
},
// MENUPAGE_DELETING = 45
{ "FET_DG", 1, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0,
MENUACTION_LABEL, "FED_DLW", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_DELETE_SUCCESS = 46
{ "FET_DG", 1, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0,
MENUACTION_LABEL, "DEL_FNM", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
},
// MENUPAGE_SAVE_FAILED = 47
{ "FET_SG", 1, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
MENUACTION_LABEL, "FEC_SVU", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
},
// MENUPAGE_LOAD_FAILED = 48
{ "FET_SG", 1, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
MENUACTION_LABEL, "FEC_SVU", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_LOAD_FAILED_2 = 49
{ "FET_LG", 1, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
MENUACTION_LABEL, "FEC_LUN", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT,
},
// MENUPAGE_FILTER_GAME = 50
{ "FIL_FLT", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_START_MENU = 51
{ "FEM_MM", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_CHANGEMENU, "FEN_STA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
MENUACTION_CHANGEMENU, "FET_OPT", SAVESLOT_NONE, MENUPAGE_OPTIONS,
MENUACTION_CHANGEMENU, "FEM_QT", SAVESLOT_NONE, MENUPAGE_EXIT,
},
// MENUPAGE_PAUSE_MENU = 52
{ "FET_PAU", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_RESUME, "FEM_RES", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEN_STA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
MENUACTION_CHANGEMENU, "FEP_STA", SAVESLOT_NONE, MENUPAGE_STATS,
MENUACTION_CHANGEMENU, "FEP_BRI", SAVESLOT_NONE, MENUPAGE_BRIEFS,
MENUACTION_CHANGEMENU, "FET_OPT", SAVESLOT_NONE, MENUPAGE_OPTIONS,
MENUACTION_CHANGEMENU, "FEM_QT", SAVESLOT_NONE, MENUPAGE_EXIT,
},
// MENUPAGE_CHOOSE_MODE = 53
{ "FEN_STA", 1, MENUPAGE_NONE, MENUPAGE_NONE, 0, 1,
MENUACTION_CHANGEMENU, "FET_SP", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
MENUACTION_INITMP, "FET_MP", SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_SKIN_SELECT = 54
{ "FET_PSU", 1, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 4, 4,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN,
},
// MENUPAGE_KEYBOARD_CONTROLS = 55
{ "FET_STI", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 1, 1,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
},
// MENUPAGE_MOUSE_CONTROLS = 56
{ "FET_MTI", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 2, 2,
MENUACTION_MOUSESENS, "FEC_MSH", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS,
MENUACTION_INVVERT, "FEC_IVV", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS,
MENUACTION_MOUSESTEER, "FET_MST", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_MISSION_RETRY = 57
#ifdef MISSION_REPLAY
{ "M_FAIL", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_LABEL, "FESZ_RM", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_LOADING_IN_PROGRESS,
MENUACTION_REJECT_RETRY, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NONE
},
#else
{ "", 0, MENUPAGE_NONE, MENUPAGE_NONE, 0, 0,
// mission failed, wanna restart page in mobile
},
#endif
// MENUPAGE_UNK
{ "", 0, MENUPAGE_NONE, MENUPAGE_NONE, 0, 0,
},
};
#endif
#endif

View file

@ -0,0 +1,936 @@
#include "common.h"
#if defined DETECT_JOYSTICK_MENU && defined XINPUT
#include <windows.h>
#include <xinput.h>
#if !defined(PSAPI_VERSION) || (PSAPI_VERSION > 1)
#pragma comment( lib, "Xinput9_1_0.lib" )
#else
#pragma comment( lib, "Xinput.lib" )
#endif
#endif
#include "platform.h"
#include "crossplatform.h"
#include "Renderer.h"
#include "Frontend.h"
#include "Font.h"
#include "Camera.h"
#include "main.h"
#include "MBlur.h"
#include "postfx.h"
#include "custompipes.h"
#include "RwHelper.h"
#include "Text.h"
#include "Streaming.h"
#include "FileLoader.h"
#include "Collision.h"
#include "ModelInfo.h"
#include "Pad.h"
#include "ControllerConfig.h"
#include "IniFile.h"
#include "CarCtrl.h"
#include "Population.h"
// Menu screens array is at the bottom of the file.
#ifdef PC_MENU
#ifdef CUSTOM_FRONTEND_OPTIONS
#if defined(IMPROVED_VIDEOMODE) && !defined(GTA_HANDHELD)
#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, "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, "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, "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, "Graphics", "PS2AlphaTest", off_on, 2, false) },
#else
#define DUALPASS_SELECTOR
#endif
#ifdef PED_CAR_DENSITY_SLIDERS
// 0.2f - 3.4f makes it possible to have 1.0f somewhere inbetween
#define DENSITY_SLIDERS \
MENUACTION_CFO_SLIDER, "FEM_PED", { new CCFOSlider(&CIniFile::PedNumberMultiplier, "Display", "PedDensity", 0.2f, 3.4f, PedDensityChange) }, \
MENUACTION_CFO_SLIDER, "FEM_CAR", { new CCFOSlider(&CIniFile::CarNumberMultiplier, "Display", "CarDensity", 0.2f, 3.4f, CarDensityChange) },
#else
#define DENSITY_SLIDERS
#endif
#ifdef NO_ISLAND_LOADING
#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, "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, "Controller", "InvertPad", off_on, 2, false) },
#else
#define INVERT_PAD_SELECTOR
#endif
#ifdef GAMEPAD_MENU
#define SELECT_CONTROLLER_TYPE MENUACTION_CFO_SELECT, "FEC_TYP", { new CCFOSelect((int8*)&CMenuManager::m_PrefsControllerType, "Controller", "Type", controllerTypes, ARRAY_SIZE(controllerTypes), false, ControllerTypeAfterChange) },
#else
#define SELECT_CONTROLLER_TYPE
#endif
const char *filterNames[] = { "FEM_NON", "FEM_SIM", "FEM_NRM", "FEM_MOB" };
const char *off_on[] = { "FEM_OFF", "FEM_ON" };
void RestoreDefGraphics(int8 action) {
if (action != FEOPTION_ACTION_SELECT)
return;
#ifdef PS2_ALPHA_TEST
gPS2alphaTest = false;
#endif
#ifdef MULTISAMPLING
FrontEndMenuManager.m_nPrefsMSAALevel = FrontEndMenuManager.m_nDisplayMSAALevel = 0;
#endif
#ifdef NO_ISLAND_LOADING
if (!FrontEndMenuManager.m_bGameNotLoaded) {
FrontEndMenuManager.m_PrefsIslandLoading = FrontEndMenuManager.ISLAND_LOADING_LOW;
CCollision::bAlreadyLoaded = false;
CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel);
CStreaming::RemoveUnusedBigBuildings(CGame::currLevel);
CStreaming::RemoveUnusedBuildings(CGame::currLevel);
CStreaming::RequestIslands(CGame::currLevel);
CStreaming::LoadAllRequestedModels(true);
} else
FrontEndMenuManager.m_PrefsIslandLoading = FrontEndMenuManager.ISLAND_LOADING_LOW;
#endif
#ifdef GRAPHICS_MENU_OPTIONS // otherwise Frontend will handle those
CMenuManager::m_PrefsFrameLimiter = true;
CMenuManager::m_PrefsVsyncDisp = true;
CMenuManager::m_PrefsVsync = true;
CMenuManager::m_PrefsUseWideScreen = false;
FrontEndMenuManager.m_nDisplayVideoMode = FrontEndMenuManager.m_nPrefsVideoMode;
#if GTA_VERSION >= GTA3_PC_11
if (_dwOperatingSystemVersion == OS_WIN98) {
CMBlur::BlurOn = false;
CMBlur::MotionBlurClose();
} else {
CMBlur::BlurOn = true;
CMBlur::MotionBlurOpen(Scene.camera);
}
#else
CMBlur::BlurOn = true;
#endif
FrontEndMenuManager.SaveSettings();
#endif
}
void RestoreDefDisplay(int8 action) {
if (action != FEOPTION_ACTION_SELECT)
return;
#ifdef CUTSCENE_BORDERS_SWITCH
CMenuManager::m_PrefsCutsceneBorders = true;
#endif
#ifdef FREE_CAM
TheCamera.bFreeCam = false;
#endif
#ifdef PED_CAR_DENSITY_SLIDERS
CIniFile::LoadIniFile();
#endif
#ifdef GRAPHICS_MENU_OPTIONS // otherwise Frontend will handle those
CMenuManager::m_PrefsBrightness = 256;
CMenuManager::m_PrefsLOD = 1.2f;
CRenderer::ms_lodDistScale = 1.2f;
CMenuManager::m_PrefsShowSubtitles = true;
FrontEndMenuManager.SaveSettings();
#endif
}
#ifdef NO_ISLAND_LOADING
const char *islandLoadingOpts[] = { "FEM_LOW", "FEM_MED", "FEM_HIG" };
void IslandLoadingAfterChange(int8 before, int8 after) {
if (!FrontEndMenuManager.m_bGameNotLoaded) {
if (after > FrontEndMenuManager.ISLAND_LOADING_LOW) {
FrontEndMenuManager.m_PrefsIslandLoading = before; // calls below needs previous mode :shrug:
if (after == FrontEndMenuManager.ISLAND_LOADING_HIGH)
CStreaming::RemoveIslandsNotUsed(LEVEL_GENERIC);
if (before == FrontEndMenuManager.ISLAND_LOADING_LOW) {
if (CGame::currLevel != LEVEL_INDUSTRIAL)
CFileLoader::LoadCollisionFromDatFile(LEVEL_INDUSTRIAL);
if (CGame::currLevel != LEVEL_COMMERCIAL)
CFileLoader::LoadCollisionFromDatFile(LEVEL_COMMERCIAL);
if (CGame::currLevel != LEVEL_SUBURBAN)
CFileLoader::LoadCollisionFromDatFile(LEVEL_SUBURBAN);
CCollision::bAlreadyLoaded = true;
FrontEndMenuManager.m_PrefsIslandLoading = after;
CStreaming::RequestBigBuildings(CGame::currLevel);
} else if (before == FrontEndMenuManager.ISLAND_LOADING_HIGH) {
FrontEndMenuManager.m_PrefsIslandLoading = after;
CStreaming::RequestIslands(CGame::currLevel);
} else
FrontEndMenuManager.m_PrefsIslandLoading = after;
} else { // low
CCollision::bAlreadyLoaded = false;
CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel);
CStreaming::RemoveUnusedBigBuildings(CGame::currLevel);
CStreaming::RemoveUnusedBuildings(CGame::currLevel);
CStreaming::RequestIslands(CGame::currLevel);
}
CStreaming::LoadAllRequestedModels(true);
}
FrontEndMenuManager.SetHelperText(0);
}
#endif
#ifdef PED_CAR_DENSITY_SLIDERS
void PedDensityChange(float before, float after) {
CPopulation::MaxNumberOfPedsInUse = DEFAULT_MAX_NUMBER_OF_PEDS * after;
}
void CarDensityChange(float before, float after) {
CCarCtrl::MaxNumberOfCarsInUse = DEFAULT_MAX_NUMBER_OF_CARS * after;
}
#endif
#ifndef MULTISAMPLING
void GraphicsGoBack() {
}
#else
void GraphicsGoBack() {
FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel;
}
void MultiSamplingButtonPress(int8 action) {
if (action == FEOPTION_ACTION_SELECT) {
if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) {
FrontEndMenuManager.m_nPrefsMSAALevel = FrontEndMenuManager.m_nDisplayMSAALevel;
_psSelectScreenVM(FrontEndMenuManager.m_nPrefsVideoMode);
FrontEndMenuManager.SetHelperText(0);
FrontEndMenuManager.SaveSettings();
}
} else if (action == FEOPTION_ACTION_LEFT || action == FEOPTION_ACTION_RIGHT) {
if (FrontEndMenuManager.m_bGameNotLoaded) {
FrontEndMenuManager.m_nDisplayMSAALevel += (action == FEOPTION_ACTION_RIGHT ? 1 : -1);
int i = 0;
int maxAA = RwD3D8EngineGetMaxMultiSamplingLevels();
while (maxAA != 1) {
i++;
maxAA >>= 1;
}
if (FrontEndMenuManager.m_nDisplayMSAALevel < 0)
FrontEndMenuManager.m_nDisplayMSAALevel = i;
else if (FrontEndMenuManager.m_nDisplayMSAALevel > i)
FrontEndMenuManager.m_nDisplayMSAALevel = 0;
}
} else if (action == FEOPTION_ACTION_FOCUSLOSS) {
if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) {
FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel;
FrontEndMenuManager.SetHelperText(3);
}
}
}
wchar* MultiSamplingDraw(bool *disabled, bool userHovering) {
static wchar unicodeTemp[64];
if (userHovering) {
if (FrontEndMenuManager.m_nDisplayMSAALevel == FrontEndMenuManager.m_nPrefsMSAALevel) {
if (FrontEndMenuManager.m_nHelperTextMsgId == 1) // Press enter to apply
FrontEndMenuManager.ResetHelperText();
} else {
FrontEndMenuManager.SetHelperText(1);
}
} else {
if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) {
FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel;
}
}
if (!FrontEndMenuManager.m_bGameNotLoaded)
*disabled = true;
switch (FrontEndMenuManager.m_nDisplayMSAALevel) {
case 0:
return TheText.Get("FEM_OFF");
default:
sprintf(gString, "%iX", 1 << (FrontEndMenuManager.m_nDisplayMSAALevel));
AsciiToUnicode(gString, unicodeTemp);
return unicodeTemp;
}
}
#endif
#ifdef IMPROVED_VIDEOMODE
const char* screenModes[] = { "FED_FLS", "FED_WND" };
void ScreenModeAfterChange(int8 before, int8 after)
{
_psSelectScreenVM(FrontEndMenuManager.m_nPrefsVideoMode); // apply same resolution
FrontEndMenuManager.SetHelperText(0);
}
#endif
#ifdef DETECT_JOYSTICK_MENU
wchar selectedJoystickUnicode[128];
int cachedButtonNum = -1;
wchar* DetectJoystickDraw(bool* disabled, bool userHovering) {
#if defined RW_GL3 && !defined LIBRW_SDL2
int numButtons;
int found = -1;
const char *joyname;
if (userHovering) {
for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) {
if ((joyname = glfwGetJoystickName(i))) {
const uint8* buttons = glfwGetJoystickButtons(i, &numButtons);
for (int j = 0; j < numButtons; j++) {
if (buttons[j]) {
found = i;
break;
}
}
if (found != -1)
break;
}
}
if (found != -1 && PSGLOBAL(joy1id) != found) {
if (PSGLOBAL(joy1id) != -1 && PSGLOBAL(joy1id) != found)
PSGLOBAL(joy2id) = PSGLOBAL(joy1id);
else
PSGLOBAL(joy2id) = -1;
strcpy(gSelectedJoystickName, joyname);
PSGLOBAL(joy1id) = found;
cachedButtonNum = numButtons;
}
}
if (PSGLOBAL(joy1id) == -1)
#elif defined XINPUT
int found = -1;
XINPUT_STATE xstate;
memset(&xstate, 0, sizeof(XINPUT_STATE));
if (userHovering) {
for (int i = 0; i <= 3; i++) {
if (XInputGetState(i, &xstate) == ERROR_SUCCESS) {
if (xstate.Gamepad.bLeftTrigger || xstate.Gamepad.bRightTrigger) {
found = i;
break;
}
for (int j = XINPUT_GAMEPAD_DPAD_UP; j != XINPUT_GAMEPAD_Y << 1; j = (j << 1)) {
if (xstate.Gamepad.wButtons & j) {
found = i;
break;
}
}
if (found != -1)
break;
}
}
if (found != -1 && CPad::XInputJoy1 != found) {
// We should never leave pads -1, so we can process them when they're connected and kinda support hotplug.
CPad::XInputJoy2 = (CPad::XInputJoy1 == -1 ? (found + 1) % 4 : CPad::XInputJoy1);
CPad::XInputJoy1 = found;
cachedButtonNum = 0; // fake too, because xinput bypass CControllerConfig
}
}
sprintf(gSelectedJoystickName, "%d", CPad::XInputJoy1); // fake, on xinput we only store gamepad ids(thanks MS) so this is a temp variable to be used below
if (CPad::XInputJoy1 == -1)
#endif
AsciiToUnicode("Not found", selectedJoystickUnicode);
else
AsciiToUnicode(gSelectedJoystickName, selectedJoystickUnicode);
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
#ifdef GAMEPAD_MENU
const char* controllerTypes[] = { "FEC_DS2", "FEC_DS3", "FEC_DS4", "FEC_360", "FEC_ONE", "FEC_NSW" };
void ControllerTypeAfterChange(int8 before, int8 after)
{
FrontEndMenuManager.LoadController(after);
}
#endif
CMenuScreenCustom aScreens[MENUPAGES] = {
// MENUPAGE_NONE = 0
{ "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, },
// MENUPAGE_STATS = 1
{ "FET_STA", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil,
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_NEW_GAME = 2
{ "FET_SGA", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil,
MENUACTION_CHANGEMENU, "FES_SNG", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD },
MENUACTION_POPULATESLOTS_CHANGEMENU, "GMLOAD", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT },
MENUACTION_POPULATESLOTS_CHANGEMENU, "FES_DGA", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_BRIEFS = 3
{ "FET_BRE", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil,
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_CONTROLLER_SETTINGS = 4
#if defined(GAMEPAD_MENU) && !defined(GTA_HANDHELD)
{ "FET_AGS", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil,
#else
{ "FET_AGS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil,
#endif
MENUACTION_CTRLCONFIG, "FEC_CCF", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS },
MENUACTION_CTRLDISPLAY, "FEC_CDP", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS },
INVERT_PAD_SELECTOR
MENUACTION_CTRLVIBRATION, "FEC_VIB", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS },
SELECT_CONTROLLER_TYPE
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_SOUND_SETTINGS = 5
{ "FET_AUD", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil,
MENUACTION_MUSICVOLUME, "FEA_MUS", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS },
MENUACTION_SFXVOLUME, "FEA_SFX", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS },
#ifdef EXTERNAL_3D_SOUND
MENUACTION_AUDIOHW, "FEA_3DH", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS },
MENUACTION_SPEAKERCONF, "FEA_SPK", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS },
#endif
#ifdef AUDIO_REFLECTIONS
MENUACTION_DYNAMICACOUSTIC, "FET_DAM", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS },
#endif
MENUACTION_RADIO, "FEA_RSS", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS },
MENUACTION_RESTOREDEF, "FET_DEF", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
#ifndef GRAPHICS_MENU_OPTIONS
// MENUPAGE_DISPLAY_SETTINGS = 6
{ "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil,
MENUACTION_BRIGHTNESS, "FED_BRI", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
MENUACTION_DRAWDIST, "FEM_LOD", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
DENSITY_SLIDERS
MENUACTION_FRAMESYNC, "FEM_VSC", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
MENUACTION_FRAMELIMIT, "FEM_FRM", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
#ifndef EXTENDED_COLOURFILTER
MENUACTION_TRAILS, "FED_TRA", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
#endif
MENUACTION_SUBTITLES, "FED_SUB", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
MENUACTION_WIDESCREEN, "FED_WIS", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
MENUACTION_SCREENRES, "FED_RES", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
VIDEOMODE_SELECTOR
MULTISAMPLING_SELECTOR
ISLAND_LOADING_SELECTOR
DUALPASS_SELECTOR
CUTSCENE_BORDERS_TOGGLE
FREE_CAM_TOGGLE
POSTFX_SELECTORS
// re3.cpp inserts here pipeline selectors if neo/neo.txd exists and EXTENDED_PIPELINES defined
MENUACTION_RESTOREDEF, "FET_DEF", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
#else
// MENUPAGE_DISPLAY_SETTINGS = 6
{ "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil,
MENUACTION_BRIGHTNESS, "FED_BRI", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
MENUACTION_DRAWDIST, "FEM_LOD", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
DENSITY_SLIDERS
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, nil, RestoreDefDisplay) },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
#endif
// MENUPAGE_LANGUAGE_SETTINGS = 7
{ "FET_LAN", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil,
MENUACTION_LANG_ENG, "FEL_ENG", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS },
MENUACTION_LANG_FRE, "FEL_FRE", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS },
MENUACTION_LANG_GER, "FEL_GER", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS },
MENUACTION_LANG_ITA, "FEL_ITA", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS },
MENUACTION_LANG_SPA, "FEL_SPA", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS },
// CustomFrontendOptionsPopulate will add languages here, if files are found
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_CHOOSE_LOAD_SLOT = 8
{ "FET_LG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, nil, nil,
MENUACTION_CHANGEMENU, "FESZ_CA", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME },
MENUACTION_CHECKSAVE, "FEM_SL0", { nil, SAVESLOT_1, MENUPAGE_LOAD_SLOT_CONFIRM },
MENUACTION_CHECKSAVE, "FEM_SL1", { nil, SAVESLOT_2, MENUPAGE_LOAD_SLOT_CONFIRM },
MENUACTION_CHECKSAVE, "FEM_SL2", { nil, SAVESLOT_3, MENUPAGE_LOAD_SLOT_CONFIRM },
MENUACTION_CHECKSAVE, "FEM_SL3", { nil, SAVESLOT_4, MENUPAGE_LOAD_SLOT_CONFIRM },
MENUACTION_CHECKSAVE, "FEM_SL4", { nil, SAVESLOT_5, MENUPAGE_LOAD_SLOT_CONFIRM },
MENUACTION_CHECKSAVE, "FEM_SL5", { nil, SAVESLOT_6, MENUPAGE_LOAD_SLOT_CONFIRM },
MENUACTION_CHECKSAVE, "FEM_SL6", { nil, SAVESLOT_7, MENUPAGE_LOAD_SLOT_CONFIRM },
MENUACTION_CHECKSAVE, "FEM_SL7", { nil, SAVESLOT_8, MENUPAGE_LOAD_SLOT_CONFIRM },
},
// MENUPAGE_CHOOSE_DELETE_SLOT = 9
{ "FET_DG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, nil, nil,
MENUACTION_CHANGEMENU, "FESZ_CA", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME },
MENUACTION_CHANGEMENU, "FEM_SL0", { nil, SAVESLOT_1, MENUPAGE_DELETE_SLOT_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL1", { nil, SAVESLOT_2, MENUPAGE_DELETE_SLOT_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL2", { nil, SAVESLOT_3, MENUPAGE_DELETE_SLOT_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL3", { nil, SAVESLOT_4, MENUPAGE_DELETE_SLOT_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL4", { nil, SAVESLOT_5, MENUPAGE_DELETE_SLOT_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL5", { nil, SAVESLOT_6, MENUPAGE_DELETE_SLOT_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL6", { nil, SAVESLOT_7, MENUPAGE_DELETE_SLOT_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL7", { nil, SAVESLOT_8, MENUPAGE_DELETE_SLOT_CONFIRM },
},
// MENUPAGE_NEW_GAME_RELOAD = 10
{ "FET_NG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, nil, nil,
MENUACTION_LABEL, "FESZ_QR", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CHANGEMENU, "FEM_NO", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME },
MENUACTION_NEWGAME, "FEM_YES", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD },
},
// MENUPAGE_LOAD_SLOT_CONFIRM = 11
{ "FET_LG", MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, nil, nil,
MENUACTION_LABEL, "FESZ_QL", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CHANGEMENU, "FEM_NO", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT },
MENUACTION_CHANGEMENU, "FEM_YES", { nil, SAVESLOT_NONE, MENUPAGE_LOADING_IN_PROGRESS },
},
// MENUPAGE_DELETE_SLOT_CONFIRM = 12
{ "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, nil, nil,
MENUACTION_LABEL, "FESZ_QD", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CHANGEMENU, "FEM_NO", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT },
MENUACTION_CHANGEMENU, "FEM_YES", { nil, SAVESLOT_NONE, MENUPAGE_DELETING },
},
// MENUPAGE_NO_MEMORY_CARD = 13
{ "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
// hud adjustment page in mobile
},
// MENUPAGE_LOADING_IN_PROGRESS = 14
{ "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
MENUACTION_LABEL, "FED_LDW", { nil, SAVESLOT_NONE, MENUPAGE_LOAD_SLOT_CONFIRM },
},
// MENUPAGE_DELETING_IN_PROGRESS = 15
{ "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
MENUACTION_LABEL, "FEDL_WR", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_PS2_LOAD_FAILED = 16
{ "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
MENUACTION_LABEL, "FES_LOE", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_DELETE_FAILED = 17
{ "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
MENUACTION_LABEL, "FES_DEE", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CHANGEMENU, "FEC_OKK", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT },
},
// MENUPAGE_DEBUG_MENU = 18
{ "FED_DBG", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil,
MENUACTION_RELOADIDE, "FED_RID", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_RELOADIPL, "FED_RIP", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_SETDBGFLAG, "FED_DFL", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_SWITCHBIGWHITEDEBUGLIGHT, "FED_DLS", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_PEDROADGROUPS, "FED_SPR", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CARROADGROUPS, "FED_SCR", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_COLLISIONPOLYS, "FED_SCP", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_PARSEHEAP, "FED_PAH", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_SHOWCULL, "FED_SCZ", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_DEBUGSTREAM, "FED_DSR", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_MEMORY_CARD_DEBUG = 19
{ "FEM_MCM", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil,
MENUACTION_REGMEMCARD1, "FEM_RMC", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_TESTFORMATMEMCARD1, "FEM_TFM", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_TESTUNFORMATMEMCARD1, "FEM_TUM", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CREATEROOTDIR, "FEM_CRD", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CREATELOADICONS, "FEM_CLI", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_FILLWITHGUFF, "FEM_FFF", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_SAVEONLYTHEGAME, "FEM_SOG", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_SAVEGAME, "FEM_STG", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_SAVEGAMEUNDERGTA, "FEM_STS", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CREATECOPYPROTECTED, "FEM_CPD", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_MEMORY_CARD_TEST = 20
{ "FEM_MC2", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
},
// MENUPAGE_MULTIPLAYER_MAIN = 21
{ "FET_MP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
},
// MENUPAGE_PS2_SAVE_FAILED = 22
{ "MCDNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_PS2_SAVE_FAILED_2 = 23
{ "MCGNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// Unused in PC but anyway
// MENUPAGE_SAVE = 24
#ifdef PS2_SAVE_DIALOG
{ "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
MENUACTION_CHANGEMENU, "FESZ_SA", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT },
MENUACTION_RESUME_FROM_SAVEZONE, "FESZ_CA", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
#else
{ "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
MENUACTION_LABEL, "FES_SCG", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_POPULATESLOTS_CHANGEMENU, "GMSAVE", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT },
MENUACTION_RESUME_FROM_SAVEZONE, "FESZ_CA", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
#endif
// MENUPAGE_NO_MEMORY_CARD_2 = 25
{ "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
MENUACTION_CHANGEMENU, "FESZ_CA", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_CHOOSE_SAVE_SLOT = 26
{ "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
MENUACTION_RESUME_FROM_SAVEZONE, "FESZ_CA", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CHANGEMENU, "FEM_SL1", { nil, SAVESLOT_1, MENUPAGE_SAVE_OVERWRITE_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL2", { nil, SAVESLOT_2, MENUPAGE_SAVE_OVERWRITE_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL3", { nil, SAVESLOT_3, MENUPAGE_SAVE_OVERWRITE_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL4", { nil, SAVESLOT_4, MENUPAGE_SAVE_OVERWRITE_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL5", { nil, SAVESLOT_5, MENUPAGE_SAVE_OVERWRITE_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL6", { nil, SAVESLOT_6, MENUPAGE_SAVE_OVERWRITE_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL7", { nil, SAVESLOT_7, MENUPAGE_SAVE_OVERWRITE_CONFIRM },
MENUACTION_CHANGEMENU, "FEM_SL8", { nil, SAVESLOT_8, MENUPAGE_SAVE_OVERWRITE_CONFIRM },
},
// MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27
{ "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, nil, nil,
MENUACTION_LABEL, "FESZ_QO", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CHANGEMENU, "FEM_YES", { nil, SAVESLOT_NONE, MENUPAGE_SAVING_IN_PROGRESS },
MENUACTION_CHANGEMENU, "FEM_NO", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT },
},
// MENUPAGE_MULTIPLAYER_MAP = 28
{ "FET_MAP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
},
// MENUPAGE_MULTIPLAYER_CONNECTION = 29
{ "FET_CON", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
},
// MENUPAGE_MULTIPLAYER_FIND_GAME = 30
{ "FET_FG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
},
// MENUPAGE_MULTIPLAYER_MODE = 31
{ "FET_GT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
},
// MENUPAGE_MULTIPLAYER_CREATE = 32
{ "FET_HG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
},
// MENUPAGE_MULTIPLAYER_START = 33
{ "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
},
// MENUPAGE_SKIN_SELECT_OLD = 34
{ "FET_PS", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
},
// MENUPAGE_CONTROLLER_PC = 35
{ "FET_CTL", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil,
#ifdef PC_PLAYER_CONTROLS
MENUACTION_CTRLMETHOD, "FET_CME", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC },
#endif
MENUACTION_KEYBOARDCTRLS,"FET_RDK", { nil, SAVESLOT_NONE, MENUPAGE_KEYBOARD_CONTROLS },
#ifdef GAMEPAD_MENU
MENUACTION_CHANGEMENU, "FET_AGS", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS },
#endif
#ifdef DETECT_JOYSTICK_MENU
MENUACTION_CHANGEMENU, "FEC_JOD", { nil, SAVESLOT_NONE, MENUPAGE_DETECT_JOYSTICK },
#endif
MENUACTION_CHANGEMENU, "FET_AMS", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS },
MENUACTION_RESTOREDEF, "FET_DEF", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_CONTROLLER_PC_OLD1 = 36
{ "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil,
MENUACTION_GETKEY, "FEC_PLB", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 },
MENUACTION_GETKEY, "FEC_CWL", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 },
MENUACTION_GETKEY, "FEC_CWR", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 },
MENUACTION_GETKEY, "FEC_LKT", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 },
MENUACTION_GETKEY, "FEC_PJP", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 },
MENUACTION_GETKEY, "FEC_PSP", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 },
MENUACTION_GETKEY, "FEC_TLF", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 },
MENUACTION_GETKEY, "FEC_TRG", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 },
MENUACTION_GETKEY, "FEC_CCM", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_CONTROLLER_PC_OLD2 = 37
{ "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil,
},
// MENUPAGE_CONTROLLER_PC_OLD3 = 38
{ "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil,
MENUACTION_GETKEY, "FEC_LUP", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3 },
MENUACTION_GETKEY, "FEC_LDN", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3 },
MENUACTION_GETKEY, "FEC_SMS", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3 },
MENUACTION_SHOWHEADBOB, "FEC_GSL", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3 },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_CONTROLLER_PC_OLD4 = 39
{ "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil,
},
// MENUPAGE_CONTROLLER_DEBUG = 40
{ "FEC_DBG", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil,
MENUACTION_GETKEY, "FEC_TGD", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG },
MENUACTION_GETKEY, "FEC_TDO", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG },
MENUACTION_GETKEY, "FEC_TSS", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG },
MENUACTION_GETKEY, "FEC_SMS", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_OPTIONS = 41
{ "FET_OPT", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil,
#ifdef GTA_HANDHELD
MENUACTION_CHANGEMENU, "FET_CTL", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS },
#else
MENUACTION_CHANGEMENU, "FET_CTL", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC },
#endif
MENUACTION_LOADRADIO, "FET_AUD", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS },
MENUACTION_CHANGEMENU, "FET_DIS", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
#ifdef GRAPHICS_MENU_OPTIONS
MENUACTION_CHANGEMENU, "FET_GFX", { nil, SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS },
#endif
MENUACTION_CHANGEMENU, "FET_LAN", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS },
MENUACTION_PLAYERSETUP, "FET_PSU", { nil, SAVESLOT_NONE, MENUPAGE_SKIN_SELECT },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_EXIT = 42
{ "FET_QG", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil,
MENUACTION_LABEL, "FEQ_SRE", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_DONTCANCEL, "FEM_NO", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CANCELGAME, "FEM_YES", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_SAVING_IN_PROGRESS = 43
{ "", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, nil, nil,
MENUACTION_LABEL, "FES_WAR", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_SAVE_SUCCESSFUL = 44
{ "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, nil, nil,
MENUACTION_LABEL, "FES_SSC", { nil, SAVESLOT_LABEL, MENUPAGE_NONE },
MENUACTION_RESUME_FROM_SAVEZONE, "FEC_OKK", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT },
},
// MENUPAGE_DELETING = 45
{ "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, nil, nil,
MENUACTION_LABEL, "FED_DLW", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_DELETE_SUCCESS = 46
{ "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, nil, nil,
MENUACTION_LABEL, "DEL_FNM", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CHANGEMENU, "FEC_OKK", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT },
},
// MENUPAGE_SAVE_FAILED = 47
{ "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, nil, nil,
MENUACTION_LABEL, "FEC_SVU", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CHANGEMENU, "FEC_OKK", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT },
},
// MENUPAGE_LOAD_FAILED = 48
{ "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, nil, nil,
MENUACTION_LABEL, "FEC_SVU", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_LOAD_FAILED_2 = 49
{ "FET_LG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, nil, nil,
MENUACTION_LABEL, "FEC_LUN", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT },
},
// MENUPAGE_FILTER_GAME = 50
{ "FIL_FLT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
},
// MENUPAGE_START_MENU = 51
{ "FEM_MM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
MENUACTION_CHANGEMENU, "FEN_STA", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME },
MENUACTION_CHANGEMENU, "FET_OPT", { nil, SAVESLOT_NONE, MENUPAGE_OPTIONS },
MENUACTION_CHANGEMENU, "FEM_QT", { nil, SAVESLOT_NONE, MENUPAGE_EXIT },
},
// MENUPAGE_PAUSE_MENU = 52
{ "FET_PAU", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
MENUACTION_RESUME, "FEM_RES", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CHANGEMENU, "FEN_STA", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME },
// CMenuManager::LoadAllTextures will add map here, if MENU_MAP enabled and map textures are found
MENUACTION_CHANGEMENU, "FEP_STA", { nil, SAVESLOT_NONE, MENUPAGE_STATS },
MENUACTION_CHANGEMENU, "FEP_BRI", { nil, SAVESLOT_NONE, MENUPAGE_BRIEFS },
MENUACTION_CHANGEMENU, "FET_OPT", { nil, SAVESLOT_NONE, MENUPAGE_OPTIONS },
MENUACTION_CHANGEMENU, "FEM_QT", { nil, SAVESLOT_NONE, MENUPAGE_EXIT },
},
// MENUPAGE_CHOOSE_MODE = 53
{ "FEN_STA", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil,
MENUACTION_CHANGEMENU, "FET_SP", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME },
MENUACTION_INITMP, "FET_MP", { nil, SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_SKIN_SELECT = 54
{ "FET_PSU", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil,
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN },
},
// MENUPAGE_KEYBOARD_CONTROLS = 55
{ "FET_STI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil,
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC },
},
// MENUPAGE_MOUSE_CONTROLS = 56
{ "FET_MTI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil,
MENUACTION_MOUSESENS, "FEC_MSH", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS },
MENUACTION_INVVERT, "FEC_IVV", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS },
#ifndef GAMEPAD_MENU
INVERT_PAD_SELECTOR
#endif
MENUACTION_MOUSESTEER, "FET_MST", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
// MENUPAGE_MISSION_RETRY = 57
#ifdef MISSION_REPLAY
{ "M_FAIL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil,
MENUACTION_LABEL, "FESZ_RM", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CHANGEMENU, "FEM_YES", { nil, SAVESLOT_NONE, MENUPAGE_LOADING_IN_PROGRESS },
MENUACTION_REJECT_RETRY, "FEM_NO", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
#else
{ "", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil,
// mission failed, wanna restart page in mobile
},
#endif
#ifdef MENU_MAP
// MENUPAGE_MAP
{ "FEG_MAP", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil,
MENUACTION_UNK110, "", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, // to prevent cross/enter to go back
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
#endif
#ifdef GRAPHICS_MENU_OPTIONS
// MENUPAGE_GRAPHICS_SETTINGS
{ "FET_GFX", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS,
new CCustomScreenLayout({MENUSPRITE_MAINMENU, 50, 0, 20, FONT_HEADING, FESCREEN_LEFT_ALIGN, true, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE}), GraphicsGoBack,
#ifndef GTA_HANDHELD
MENUACTION_SCREENRES, "FED_RES", { nil, SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS },
#endif
MENUACTION_WIDESCREEN, "FED_WIS", { nil, SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS },
VIDEOMODE_SELECTOR
MENUACTION_FRAMESYNC, "FEM_VSC", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
MENUACTION_FRAMELIMIT, "FEM_FRM", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
MULTISAMPLING_SELECTOR
ISLAND_LOADING_SELECTOR
DUALPASS_SELECTOR
#ifdef EXTENDED_COLOURFILTER
POSTFX_SELECTORS
#else
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, nil, RestoreDefGraphics) },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
#endif
#ifdef DETECT_JOYSTICK_MENU
// 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}), DetectJoystickGoBack,
MENUACTION_LABEL, "FEC_JPR", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
MENUACTION_CFO_DYNAMIC, "FEC_JDE", { new CCFODynamic(nil, nil, nil, DetectJoystickDraw, nil) },
MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE },
},
#endif
// MENUPAGE_UNK
{ "", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil,
},
};
#endif
#endif

3025
src/core/Pad.cpp Normal file

File diff suppressed because it is too large Load diff

474
src/core/Pad.h Normal file
View file

@ -0,0 +1,474 @@
#pragma once
enum {
PLAYERCONTROL_ENABLED = 0,
PLAYERCONTROL_CAMERA = 1,
PLAYERCONTROL_UNK2 = 2,
PLAYERCONTROL_GARAGE = 4,
PLAYERCONTROL_UNK8 = 8,
PLAYERCONTROL_UNK10 = 16,
PLAYERCONTROL_PLAYERINFO = 32,
PLAYERCONTROL_PHONE = 64,
PLAYERCONTROL_CUTSCENE = 128,
};
class CControllerState
{
public:
int16 LeftStickX, LeftStickY;
int16 RightStickX, RightStickY;
int16 LeftShoulder1, LeftShoulder2;
int16 RightShoulder1, RightShoulder2;
int16 DPadUp, DPadDown, DPadLeft, DPadRight;
int16 Start, Select;
int16 Square, Triangle, Cross, Circle;
int16 LeftShock, RightShock;
int16 NetworkTalk;
float GetLeftStickX(void) { return LeftStickX/32767.0f; };
float GetLeftStickY(void) { return LeftStickY/32767.0f; };
float GetRightStickX(void) { return RightStickX/32767.0f; };
float GetRightStickY(void) { return RightStickY/32767.0f; };
bool CheckForInput();
void Clear(void);
};
VALIDATE_SIZE(CControllerState, 0x2A);
class CMouseControllerState
{
public:
//uint32 btns; // bit 0-2 button 1-3
bool LMB;
bool RMB;
bool MMB;
bool WHEELUP;
bool WHEELDN;
bool MXB1;
bool MXB2;
char _pad0;
float x, y;
CMouseControllerState();
void Clear();
};
VALIDATE_SIZE(CMouseControllerState, 0x10);
class CMousePointerStateHelper
{
public:
bool bInvertHorizontally;
bool bInvertVertically;
CMouseControllerState GetMouseSetUp();
};
VALIDATE_SIZE(CMousePointerStateHelper, 0x2);
extern CMousePointerStateHelper MousePointerStateHelper;
class CKeyboardState
{
public:
int16 F[12];
int16 VK_KEYS[256];
int16 ESC;
int16 INS;
int16 DEL;
int16 HOME;
int16 END;
int16 PGUP;
int16 PGDN;
int16 UP;
int16 DOWN;
int16 LEFT;
int16 RIGHT;
int16 SCROLLLOCK;
int16 PAUSE;
int16 NUMLOCK;
int16 DIV;
int16 MUL;
int16 SUB;
int16 ADD;
int16 ENTER;
int16 DECIMAL;
int16 NUM1;
int16 NUM2;
int16 NUM3;
int16 NUM4;
int16 NUM5;
int16 NUM6;
int16 NUM7;
int16 NUM8;
int16 NUM9;
int16 NUM0;
int16 BACKSP;
int16 TAB;
int16 CAPSLOCK;
int16 EXTENTER;
int16 LSHIFT;
int16 RSHIFT;
int16 SHIFT;
int16 LCTRL;
int16 RCTRL;
int16 LALT;
int16 RALT;
int16 LWIN;
int16 RWIN;
int16 APPS;
void Clear();
};
VALIDATE_SIZE(CKeyboardState, 0x270);
enum
{
// taken from miss2
PAD1 = 0,
PAD2,
MAX_PADS
};
class CPad
{
public:
enum
{
HORNHISTORY_SIZE = 5,
};
CControllerState NewState;
CControllerState OldState;
CControllerState PCTempKeyState;
CControllerState PCTempJoyState;
CControllerState PCTempMouseState;
// straight out of my IDB
int16 Phase;
int16 Mode;
int16 ShakeDur;
uint8 ShakeFreq;
bool bHornHistory[HORNHISTORY_SIZE];
uint8 iCurrHornHistory;
uint8 DisablePlayerControls;
int8 bApplyBrakes;
char CheatString[12];
int32 LastTimeTouched;
int32 AverageWeapon;
int32 AverageEntries;
#ifdef DETECT_PAD_INPUT_SWITCH
static bool IsAffectedByController;
#endif
CPad() { }
~CPad() { }
static bool bDisplayNoControllerMessage;
static bool bObsoleteControllerMessage;
static bool bOldDisplayNoControllerMessage;
static bool m_bMapPadOneToPadTwo;
#ifdef INVERT_LOOK_FOR_PAD
static bool bInvertLook4Pad;
#endif
static CKeyboardState OldKeyState;
static CKeyboardState NewKeyState;
static CKeyboardState TempKeyState;
static char KeyBoardCheatString[20];
static CMouseControllerState OldMouseControllerState;
static CMouseControllerState NewMouseControllerState;
static CMouseControllerState PCTempMouseControllerState;
#ifdef GTA_PS2_STUFF
static void Initialise(void);
#endif
void Clear(bool bResetPlayerControls);
void ClearMouseHistory();
void UpdateMouse();
CControllerState ReconcileTwoControllersInput(CControllerState const &State1, CControllerState const &State2);
void StartShake(int16 nDur, uint8 nFreq);
void StartShake_Distance(int16 nDur, uint8 nFreq, float fX, float fY, float fz);
void StartShake_Train(float fX, float fY);
#ifdef GTA_PS2_STUFF
void AddToCheatString(char c);
#endif
void AddToPCCheatString(char c);
static void UpdatePads(void);
void ProcessPCSpecificStuff(void);
void Update(int16 pad);
static void DoCheats(void);
void DoCheats(int16 unk);
static void StopPadsShaking(void);
void StopShaking(int16 pad);
static CPad *GetPad(int32 pad);
int16 GetSteeringLeftRight(void);
int16 GetSteeringUpDown(void);
int16 GetCarGunUpDown(void);
int16 GetCarGunLeftRight(void);
int16 GetPedWalkLeftRight(void);
int16 GetPedWalkUpDown(void);
int16 GetAnalogueUpDown(void);
bool GetLookLeft(void);
bool GetLookRight(void);
bool GetLookBehindForCar(void);
bool GetLookBehindForPed(void);
bool GetHorn(void);
bool HornJustDown(void);
bool GetCarGunFired(void);
bool CarGunJustDown(void);
int16 GetHandBrake(void);
int16 GetBrake(void);
bool GetExitVehicle(void);
bool ExitVehicleJustDown(void);
int32 GetWeapon(void);
bool WeaponJustDown(void);
int16 GetAccelerate(void);
bool CycleCameraModeUpJustDown(void);
bool CycleCameraModeDownJustDown(void);
bool ChangeStationJustDown(void);
bool CycleWeaponLeftJustDown(void);
bool CycleWeaponRightJustDown(void);
bool GetTarget(void);
bool TargetJustDown(void);
bool JumpJustDown(void);
bool GetSprint(void);
bool ShiftTargetLeftJustDown(void);
bool ShiftTargetRightJustDown(void);
bool GetAnaloguePadUp(void);
bool GetAnaloguePadDown(void);
bool GetAnaloguePadLeft(void);
bool GetAnaloguePadRight(void);
bool GetAnaloguePadLeftJustUp(void);
bool GetAnaloguePadRightJustUp(void);
bool ForceCameraBehindPlayer(void);
bool SniperZoomIn(void);
bool SniperZoomOut(void);
int16 SniperModeLookLeftRight(void);
int16 SniperModeLookUpDown(void);
int16 LookAroundLeftRight(void);
int16 LookAroundUpDown(void);
void ResetAverageWeapon(void);
static void PrintErrorMessage(void);
static void ResetCheats(void);
static char *EditString(char *pStr, int32 nSize);
static int32 *EditCodesForControls(int32 *pRsKeys, int32 nSize);
#ifdef XINPUT
static int XInputJoy1;
static int XInputJoy2;
void AffectFromXinput(uint32 pad);
#endif
// mouse
bool GetLeftMouseJustDown() { return !!(NewMouseControllerState.LMB && !OldMouseControllerState.LMB); }
bool GetRightMouseJustDown() { return !!(NewMouseControllerState.RMB && !OldMouseControllerState.RMB); }
bool GetMiddleMouseJustDown() { return !!(NewMouseControllerState.MMB && !OldMouseControllerState.MMB); }
bool GetMouseWheelUpJustDown() { return !!(NewMouseControllerState.WHEELUP && !OldMouseControllerState.WHEELUP); }
bool GetMouseWheelDownJustDown() { return !!(NewMouseControllerState.WHEELDN && !OldMouseControllerState.WHEELDN);}
bool GetMouseX1JustDown() { return !!(NewMouseControllerState.MXB1 && !OldMouseControllerState.MXB1); }
bool GetMouseX2JustDown() { return !!(NewMouseControllerState.MXB2 && !OldMouseControllerState.MXB2); }
bool GetLeftMouseJustUp() { return !!(!NewMouseControllerState.LMB && OldMouseControllerState.LMB); }
bool GetRightMouseJustUp() { return !!(!NewMouseControllerState.RMB && OldMouseControllerState.RMB); }
bool GetMiddleMouseJustUp() { return !!(!NewMouseControllerState.MMB && OldMouseControllerState.MMB); }
bool GetMouseWheelUpJustUp() { return !!(!NewMouseControllerState.WHEELUP && OldMouseControllerState.WHEELUP); }
bool GetMouseWheelDownJustUp() { return !!(!NewMouseControllerState.WHEELDN && OldMouseControllerState.WHEELDN); }
bool GetMouseX1JustUp() { return !!(!NewMouseControllerState.MXB1 && OldMouseControllerState.MXB1); }
bool GetMouseX2JustUp() { return !!(!NewMouseControllerState.MXB2 && OldMouseControllerState.MXB2); }
bool GetLeftMouse() { return NewMouseControllerState.LMB; }
bool GetRightMouse() { return NewMouseControllerState.RMB; }
bool GetMiddleMouse() { return NewMouseControllerState.MMB; }
bool GetMouseWheelUp() { return NewMouseControllerState.WHEELUP; }
bool GetMouseWheelDown() { return NewMouseControllerState.WHEELDN; }
bool GetMouseX1() { return NewMouseControllerState.MXB1; }
bool GetMouseX2() { return NewMouseControllerState.MXB2; }
bool GetLeftMouseUp() { return !OldMouseControllerState.LMB; }
bool GetRightMouseUp() { return !OldMouseControllerState.RMB; }
bool GetMiddleMouseUp() { return !OldMouseControllerState.MMB; }
bool GetMouseWheelUpUp() { return !OldMouseControllerState.WHEELUP; }
bool GetMouseWheelDownUp() { return !OldMouseControllerState.WHEELDN; }
bool GetMouseX1Up() { return !OldMouseControllerState.MXB1; }
bool GetMouseX2Up() { return !OldMouseControllerState.MXB2; }
float GetMouseX() { return NewMouseControllerState.x; }
float GetMouseY() { return NewMouseControllerState.y; }
// keyboard
bool GetCharJustDown(int32 c) { return !!(NewKeyState.VK_KEYS[c] && !OldKeyState.VK_KEYS[c]); }
bool GetFJustDown(int32 n) { return !!(NewKeyState.F[n] && !OldKeyState.F[n]); }
bool GetEscapeJustDown() { return !!(NewKeyState.ESC && !OldKeyState.ESC); }
bool GetInsertJustDown() { return !!(NewKeyState.INS && !OldKeyState.INS); }
bool GetDeleteJustDown() { return !!(NewKeyState.DEL && !OldKeyState.DEL); }
bool GetHomeJustDown() { return !!(NewKeyState.HOME && !OldKeyState.HOME); }
bool GetEndJustDown() { return !!(NewKeyState.END && !OldKeyState.END); }
bool GetPageUpJustDown() { return !!(NewKeyState.PGUP && !OldKeyState.PGUP); }
bool GetPageDownJustDown() { return !!(NewKeyState.PGDN && !OldKeyState.PGDN); }
bool GetUpJustDown() { return !!(NewKeyState.UP && !OldKeyState.UP); }
bool GetDownJustDown() { return !!(NewKeyState.DOWN && !OldKeyState.DOWN); }
bool GetLeftJustDown() { return !!(NewKeyState.LEFT && !OldKeyState.LEFT); }
bool GetRightJustDown() { return !!(NewKeyState.RIGHT && !OldKeyState.RIGHT); }
bool GetScrollLockJustDown() { return !!(NewKeyState.SCROLLLOCK && !OldKeyState.SCROLLLOCK); }
bool GetPauseJustDown() { return !!(NewKeyState.PAUSE && !OldKeyState.PAUSE); }
bool GetNumLockJustDown() { return !!(NewKeyState.NUMLOCK && !OldKeyState.NUMLOCK); }
bool GetDivideJustDown() { return !!(NewKeyState.DIV && !OldKeyState.DIV); }
bool GetTimesJustDown() { return !!(NewKeyState.MUL && !OldKeyState.MUL); }
bool GetMinusJustDown() { return !!(NewKeyState.SUB && !OldKeyState.SUB); }
bool GetPlusJustDown() { return !!(NewKeyState.ADD && !OldKeyState.ADD); }
bool GetPadEnterJustDown() { return !!(NewKeyState.ENTER && !OldKeyState.ENTER); }
bool GetPadDelJustDown() { return !!(NewKeyState.DECIMAL && !OldKeyState.DECIMAL); }
bool GetPad1JustDown() { return !!(NewKeyState.NUM1 && !OldKeyState.NUM1); }
bool GetPad2JustDown() { return !!(NewKeyState.NUM2 && !OldKeyState.NUM2); }
bool GetPad3JustDown() { return !!(NewKeyState.NUM3 && !OldKeyState.NUM3); }
bool GetPad4JustDown() { return !!(NewKeyState.NUM4 && !OldKeyState.NUM4); }
bool GetPad5JustDown() { return !!(NewKeyState.NUM5 && !OldKeyState.NUM5); }
bool GetPad6JustDown() { return !!(NewKeyState.NUM6 && !OldKeyState.NUM6); }
bool GetPad7JustDown() { return !!(NewKeyState.NUM7 && !OldKeyState.NUM7); }
bool GetPad8JustDown() { return !!(NewKeyState.NUM8 && !OldKeyState.NUM8); }
bool GetPad9JustDown() { return !!(NewKeyState.NUM9 && !OldKeyState.NUM9); }
bool GetPad0JustDown() { return !!(NewKeyState.NUM0 && !OldKeyState.NUM0); }
bool GetBackspaceJustDown() { return !!(NewKeyState.BACKSP && !OldKeyState.BACKSP); }
bool GetTabJustDown() { return !!(NewKeyState.TAB && !OldKeyState.TAB); }
bool GetCapsLockJustDown() { return !!(NewKeyState.CAPSLOCK && !OldKeyState.CAPSLOCK); }
bool GetReturnJustDown() { return !!(NewKeyState.EXTENTER && !OldKeyState.EXTENTER); }
bool GetLeftShiftJustDown() { return !!(NewKeyState.LSHIFT && !OldKeyState.LSHIFT); }
bool GetShiftJustDown() { return !!(NewKeyState.SHIFT && !OldKeyState.SHIFT); }
bool GetRightShiftJustDown() { return !!(NewKeyState.RSHIFT && !OldKeyState.RSHIFT); }
bool GetLeftCtrlJustDown() { return !!(NewKeyState.LCTRL && !OldKeyState.LCTRL); }
bool GetRightCtrlJustDown() { return !!(NewKeyState.RCTRL && !OldKeyState.RCTRL); }
bool GetLeftAltJustDown() { return !!(NewKeyState.LALT && !OldKeyState.LALT); }
bool GetRightAltJustDown() { return !!(NewKeyState.RALT && !OldKeyState.RALT); }
bool GetLeftWinJustDown() { return !!(NewKeyState.LWIN && !OldKeyState.LWIN); }
bool GetRightWinJustDown() { return !!(NewKeyState.RWIN && !OldKeyState.RWIN); }
bool GetAppsJustDown() { return !!(NewKeyState.APPS && !OldKeyState.APPS); }
bool GetEnterJustDown() { return GetPadEnterJustDown() || GetReturnJustDown(); }
bool GetAltJustDown() { return GetLeftAltJustDown() || GetRightAltJustDown(); }
bool GetLeftJustUp() { return !!(!NewKeyState.LEFT && OldKeyState.LEFT); }
bool GetRightJustUp() { return !!(!NewKeyState.RIGHT && OldKeyState.RIGHT); }
bool GetEnterJustUp() { return GetPadEnterJustUp() || GetReturnJustUp(); }
bool GetReturnJustUp() { return !!(!NewKeyState.EXTENTER && OldKeyState.EXTENTER); }
bool GetPadEnterJustUp() { return !!(!NewKeyState.ENTER && OldKeyState.ENTER); }
bool GetChar(int32 c) { return NewKeyState.VK_KEYS[c]; }
bool GetF(int32 n) { return NewKeyState.F[n]; }
bool GetEscape() { return NewKeyState.ESC; }
bool GetInsert() { return NewKeyState.INS; }
bool GetDelete() { return NewKeyState.DEL; }
bool GetHome() { return NewKeyState.HOME; }
bool GetEnd() { return NewKeyState.END; }
bool GetPageUp() { return NewKeyState.PGUP; }
bool GetPageDown() { return NewKeyState.PGDN; }
bool GetUp() { return NewKeyState.UP; }
bool GetDown() { return NewKeyState.DOWN; }
bool GetLeft() { return NewKeyState.LEFT; }
bool GetRight() { return NewKeyState.RIGHT; }
bool GetScrollLock() { return NewKeyState.SCROLLLOCK; }
bool GetPause() { return NewKeyState.PAUSE; }
bool GetNumLock() { return NewKeyState.NUMLOCK; }
bool GetDivide() { return NewKeyState.DIV; }
bool GetTimes() { return NewKeyState.MUL; }
bool GetMinus() { return NewKeyState.SUB; }
bool GetPlus() { return NewKeyState.ADD; }
bool GetPadEnter() { return NewKeyState.ENTER; } // GetEnterJustDown
bool GetPadDel() { return NewKeyState.DECIMAL; }
bool GetPad1() { return NewKeyState.NUM1; }
bool GetPad2() { return NewKeyState.NUM2; }
bool GetPad3() { return NewKeyState.NUM3; }
bool GetPad4() { return NewKeyState.NUM4; }
bool GetPad5() { return NewKeyState.NUM5; }
bool GetPad6() { return NewKeyState.NUM6; }
bool GetPad7() { return NewKeyState.NUM7; }
bool GetPad8() { return NewKeyState.NUM8; }
bool GetPad9() { return NewKeyState.NUM9; }
bool GetPad0() { return NewKeyState.NUM0; }
bool GetBackspace() { return NewKeyState.BACKSP; }
bool GetTab() { return NewKeyState.TAB; }
bool GetCapsLock() { return NewKeyState.CAPSLOCK; }
bool GetEnter() { return NewKeyState.EXTENTER; }
bool GetLeftShift() { return NewKeyState.LSHIFT; }
bool GetShift() { return NewKeyState.SHIFT; }
bool GetRightShift() { return NewKeyState.RSHIFT; }
bool GetLeftCtrl() { return NewKeyState.LCTRL; }
bool GetRightCtrl() { return NewKeyState.RCTRL; }
bool GetLeftAlt() { return NewKeyState.LALT; }
bool GetRightAlt() { return NewKeyState.RALT; }
bool GetLeftWin() { return NewKeyState.LWIN; }
bool GetRightWin() { return NewKeyState.RWIN; }
bool GetApps() { return NewKeyState.APPS; }
// pad
bool GetTriangleJustDown() { return !!(NewState.Triangle && !OldState.Triangle); }
bool GetCircleJustDown() { return !!(NewState.Circle && !OldState.Circle); }
bool GetCrossJustDown() { return !!(NewState.Cross && !OldState.Cross); }
bool GetSquareJustDown() { return !!(NewState.Square && !OldState.Square); }
bool GetDPadUpJustDown() { return !!(NewState.DPadUp && !OldState.DPadUp); }
bool GetDPadDownJustDown() { return !!(NewState.DPadDown && !OldState.DPadDown); }
bool GetDPadLeftJustDown() { return !!(NewState.DPadLeft && !OldState.DPadLeft); }
bool GetDPadRightJustDown() { return !!(NewState.DPadRight && !OldState.DPadRight); }
bool GetLeftShoulder1JustDown() { return !!(NewState.LeftShoulder1 && !OldState.LeftShoulder1); }
bool GetLeftShoulder2JustDown() { return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); }
bool GetRightShoulder1JustDown() { return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); }
bool GetRightShoulder2JustDown() { return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); }
bool GetLeftShockJustDown() { return !!(NewState.LeftShock && !OldState.LeftShock); }
bool GetRightShockJustDown() { return !!(NewState.RightShock && !OldState.RightShock); }
bool GetStartJustDown() { return !!(NewState.Start && !OldState.Start); }
bool GetLeftStickXJustDown() { return !!(NewState.LeftStickX && !OldState.LeftStickX); }
bool GetLeftStickYJustDown() { return !!(NewState.LeftStickY && !OldState.LeftStickY); }
bool GetTriangleJustUp() { return !!(!NewState.Triangle && OldState.Triangle); }
bool GetCircleJustUp() { return !!(!NewState.Circle && OldState.Circle); }
bool GetCrossJustUp() { return !!(!NewState.Cross && OldState.Cross); }
bool GetSquareJustUp() { return !!(!NewState.Square && OldState.Square); }
bool GetDPadUpJustUp() { return !!(!NewState.DPadUp && OldState.DPadUp); }
bool GetDPadDownJustUp() { return !!(!NewState.DPadDown && OldState.DPadDown); }
bool GetDPadLeftJustUp() { return !!(!NewState.DPadLeft && OldState.DPadLeft); }
bool GetDPadRightJustUp() { return !!(!NewState.DPadRight && OldState.DPadRight); }
bool GetTriangle() { return !!NewState.Triangle; }
bool GetCircle() { return !!NewState.Circle; }
bool GetCross() { return !!NewState.Cross; }
bool GetSquare() { return !!NewState.Square; }
bool GetDPadUp() { return !!NewState.DPadUp; }
bool GetDPadDown() { return !!NewState.DPadDown; }
bool GetDPadLeft() { return !!NewState.DPadLeft; }
bool GetDPadRight() { return !!NewState.DPadRight; }
bool GetLeftShoulder1(void) { return !!NewState.LeftShoulder1; }
bool GetLeftShoulder2(void) { return !!NewState.LeftShoulder2; }
bool GetRightShoulder1(void) { return !!NewState.RightShoulder1; }
bool GetRightShoulder2(void) { return !!NewState.RightShoulder2; }
bool GetStart() { return !!NewState.Start; }
int16 GetLeftStickX(void) { return NewState.LeftStickX; }
int16 GetLeftStickY(void) { return NewState.LeftStickY; }
int16 GetRightStickX(void) { return NewState.RightStickX; }
int16 GetRightStickY(void) { return NewState.RightStickY; }
bool ArePlayerControlsDisabled(void) { return DisablePlayerControls != PLAYERCONTROL_ENABLED; }
void SetDisablePlayerControls(uint8 who) { DisablePlayerControls |= who; }
void SetEnablePlayerControls(uint8 who) { DisablePlayerControls &= ~who; }
bool IsPlayerControlsDisabledBy(uint8 who) { return DisablePlayerControls & who; }
int16 GetMode() { return Mode; }
void SetMode(int16 mode) { Mode = mode; }
static bool IsNoOrObsolete() { return bDisplayNoControllerMessage || bObsoleteControllerMessage; }
};
VALIDATE_SIZE(CPad, 0xFC);
extern CPad Pads[MAX_PADS];
#ifdef ALLCARSHELI_CHEAT
extern bool bAllCarCheat;
#endif

66
src/core/Placeable.cpp Normal file
View file

@ -0,0 +1,66 @@
#include "common.h"
#include "Placeable.h"
CPlaceable::CPlaceable(void)
{
m_matrix.SetScale(1.0f);
}
CPlaceable::~CPlaceable(void)
{
}
void
CPlaceable::SetHeading(float angle)
{
CVector pos = GetMatrix().GetPosition();
m_matrix.SetRotateZ(angle);
GetMatrix().Translate(pos);
}
bool
CPlaceable::IsWithinArea(float x1, float y1, float x2, float y2)
{
float tmp;
if(x1 > x2){
tmp = x1;
x1 = x2;
x2 = tmp;
}
if(y1 > y2){
tmp = y1;
y1 = y2;
y2 = tmp;
}
return x1 <= GetPosition().x && GetPosition().x <= x2 &&
y1 <= GetPosition().y && GetPosition().y <= y2;
}
bool
CPlaceable::IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2)
{
float tmp;
if(x1 > x2){
tmp = x1;
x1 = x2;
x2 = tmp;
}
if(y1 > y2){
tmp = y1;
y1 = y2;
y2 = tmp;
}
if(z1 > z2){
tmp = z1;
z1 = z2;
z2 = tmp;
}
return x1 <= GetPosition().x && GetPosition().x <= x2 &&
y1 <= GetPosition().y && GetPosition().y <= y2 &&
z1 <= GetPosition().z && GetPosition().z <= z2;
}

37
src/core/Placeable.h Normal file
View file

@ -0,0 +1,37 @@
#pragma once
class CPlaceable
{
protected:
CMatrix m_matrix;
public:
// disable allocation
static void *operator new(size_t) throw();
CPlaceable(void);
virtual ~CPlaceable(void);
const CVector &GetPosition(void) { return m_matrix.GetPosition(); }
void SetPosition(float x, float y, float z) {
m_matrix.GetPosition().x = x;
m_matrix.GetPosition().y = y;
m_matrix.GetPosition().z = z;
}
void SetPosition(const CVector &pos) { m_matrix.GetPosition() = pos; }
CVector &GetRight(void) { return m_matrix.GetRight(); }
CVector &GetForward(void) { return m_matrix.GetForward(); }
CVector &GetUp(void) { return m_matrix.GetUp(); }
CMatrix &GetMatrix(void) { return m_matrix; }
void SetMatrix(CMatrix &newMatrix) { m_matrix = newMatrix; }
void SetTransform(RwMatrix *m) { m_matrix = CMatrix(m, false); }
void SetHeading(float angle);
void SetOrientation(float x, float y, float z){
CVector pos = m_matrix.GetPosition();
m_matrix.SetRotate(x, y, z);
m_matrix.Translate(pos);
}
bool IsWithinArea(float x1, float y1, float x2, float y2);
bool IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2);
};
VALIDATE_SIZE(CPlaceable, 0x4C);

662
src/core/PlayerInfo.cpp Normal file
View file

@ -0,0 +1,662 @@
#include "common.h"
#include "Automobile.h"
#include "Bridge.h"
#include "Camera.h"
#include "CarCtrl.h"
#include "Cranes.h"
#include "Darkel.h"
#include "Explosion.h"
#include "Fire.h"
#include "Frontend.h"
#include "General.h"
#include "HandlingMgr.h"
#include "Messages.h"
#include "Pad.h"
#include "PathFind.h"
#include "PlayerInfo.h"
#include "PlayerPed.h"
#include "PlayerSkin.h"
#include "ProjectileInfo.h"
#include "Remote.h"
#include "Renderer.h"
#include "Replay.h"
#include "Script.h"
#include "SpecialFX.h"
#include "Stats.h"
#include "Streaming.h"
#include "Text.h"
#include "Wanted.h"
#include "WaterLevel.h"
#include "World.h"
#include "ZoneCull.h"
#include "main.h"
void
CPlayerInfo::Clear(void)
{
m_pPed = nil;
m_pRemoteVehicle = nil;
if (m_pVehicleEx) {
m_pVehicleEx->bUsingSpecialColModel = false;
m_pVehicleEx = nil;
}
m_nVisibleMoney = 0;
m_nMoney = m_nVisibleMoney;
m_WBState = WBSTATE_PLAYING;
m_nWBTime = 0;
m_nTrafficMultiplier = 0;
m_fRoadDensity = 1.0f;
m_bInRemoteMode = false;
m_bUnusedTaxiThing = false;
m_nUnusedTaxiTimer = 0;
m_nCollectedPackages = 0;
m_nTotalPackages = 3;
m_nTimeLastHealthLoss = 0;
m_nTimeLastArmourLoss = 0;
m_nNextSexFrequencyUpdateTime = 0;
m_nNextSexMoneyUpdateTime = 0;
m_nSexFrequency = 0;
m_pHooker = nil;
m_nTimeTankShotGun = 0;
field_248 = 0;
m_nUpsideDownCounter = 0;
m_bInfiniteSprint = false;
m_bFastReload = false;
m_bGetOutOfJailFree = false;
m_bGetOutOfHospitalFree = false;
m_nPreviousTimeRewardedForExplosion = 0;
m_nExplosionsSinceLastReward = 0;
}
void
CPlayerInfo::Process(void)
{
#ifdef FIX_BUGS
if (CReplay::IsPlayingBack())
return;
#endif
// Unused taxi feature. Gives you a dollar for every second with a passenger. Can be toggled via 0x29A opcode.
bool startTaxiTimer = true;
if (m_bUnusedTaxiThing && m_pPed->bInVehicle) {
CVehicle *veh = m_pPed->m_pMyVehicle;
if ((veh->GetModelIndex() == MI_TAXI || veh->GetModelIndex() == MI_CABBIE || veh->GetModelIndex() == MI_BORGNINE)
&& veh->pDriver == m_pPed && veh->m_nNumPassengers != 0) {
for (uint32 timePassed = CTimer::GetTimeInMilliseconds() - m_nUnusedTaxiTimer; timePassed >= 1000; m_nUnusedTaxiTimer += 1000) {
timePassed -= 1000;
++m_nMoney;
}
startTaxiTimer = false;
}
}
if (startTaxiTimer)
m_nUnusedTaxiTimer = CTimer::GetTimeInMilliseconds();
// The effect that makes money counter does while earning/losing money
if (m_nVisibleMoney != m_nMoney) {
int diff = m_nMoney - m_nVisibleMoney;
int diffAbs = Abs(diff);
int changeBy;
if (diffAbs > 100000)
changeBy = 12345;
else if (diffAbs > 10000)
changeBy = 1234;
else if (diffAbs > 1000)
changeBy = 123;
else if (diffAbs > 50)
changeBy = 42;
else
changeBy = 1;
if (diff < 0)
m_nVisibleMoney -= changeBy;
else
m_nVisibleMoney += changeBy;
}
if (!(CTimer::GetFrameCounter() & 15)) {
CVector2D playerPos = m_pPed->bInVehicle ? m_pPed->m_pMyVehicle->GetPosition() : m_pPed->GetPosition();
m_fRoadDensity = ThePaths.CalcRoadDensity(playerPos.x, playerPos.y);
}
m_fRoadDensity = Clamp(m_fRoadDensity, 0.4f, 1.45f);
// Because vehicle enter/exit use same key binding.
bool enterOrExitVeh;
if (m_pPed->bVehExitWillBeInstant && m_pPed->bInVehicle)
enterOrExitVeh = CPad::GetPad(0)->ExitVehicleJustDown();
else
enterOrExitVeh = CPad::GetPad(0)->GetExitVehicle();
if (enterOrExitVeh && m_pPed->m_nPedState != PED_SNIPER_MODE && m_pPed->m_nPedState != PED_ROCKET_MODE) {
if (m_pPed->bInVehicle) {
if (!m_pRemoteVehicle) {
CEntity *surfaceBelowVeh = m_pPed->m_pMyVehicle->m_pCurGroundEntity;
if (!surfaceBelowVeh || !CBridge::ThisIsABridgeObjectMovingUp(surfaceBelowVeh->GetModelIndex())) {
CVehicle *veh = m_pPed->m_pMyVehicle;
if (!veh->IsBoat() || veh->m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE) {
// This condition will always return true, else block was probably WIP Miami code.
if (veh->m_vehType != VEHICLE_TYPE_BIKE || veh->m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE) {
if (veh->GetStatus() != STATUS_WRECKED && veh->GetStatus() != STATUS_TRAIN_MOVING && veh->m_nDoorLock != CARLOCK_LOCKED_PLAYER_INSIDE) {
if (veh->m_vecMoveSpeed.Magnitude() < 0.17f && CTimer::GetTimeScale() >= 0.5f && !veh->bIsInWater) {
m_pPed->SetObjective(OBJECTIVE_LEAVE_CAR, veh);
}
}
} else {
CVector sth = 0.7f * veh->GetRight() + veh->GetPosition();
bool found = false;
float groundZ = CWorld::FindGroundZFor3DCoord(sth.x, sth.y, 2.0f + sth.z, &found);
if (found)
sth.z = 1.0f + groundZ;
m_pPed->SetPedState(PED_IDLE);
m_pPed->SetMoveState(PEDMOVE_STILL);
CPed::PedSetOutCarCB(0, m_pPed);
CAnimManager::BlendAnimation(m_pPed->GetClump(), m_pPed->m_animGroup, ANIM_STD_IDLE, 100.0f);
CAnimManager::BlendAnimation(m_pPed->GetClump(), ASSOCGRP_STD, ANIM_STD_FALL_LAND, 100.0f);
m_pPed->SetPosition(sth);
m_pPed->SetMoveState(PEDMOVE_STILL);
m_pPed->m_vecMoveSpeed = veh->m_vecMoveSpeed;
}
} else {
// The code in here was under CPed::SetExitBoat in VC, did the same for here.
m_pPed->SetExitBoat(veh);
m_pPed->bTryingToReachDryLand = true;
}
}
}
} else {
// Enter vehicle
if (CPad::GetPad(0)->ExitVehicleJustDown()) {
bool weAreOnBoat = false;
float lastCloseness = 0.0f;
CVehicle *carBelow = nil;
CEntity *surfaceBelow = m_pPed->m_pCurrentPhysSurface;
if (surfaceBelow && surfaceBelow->IsVehicle()) {
carBelow = (CVehicle*)surfaceBelow;
if (carBelow->IsBoat()) {
weAreOnBoat = true;
m_pPed->bOnBoat = true;
#ifdef VC_PED_PORTS
if (carBelow->GetStatus() != STATUS_WRECKED && carBelow->GetUp().z > 0.3f)
#else
if (carBelow->GetStatus() != STATUS_WRECKED)
#endif
m_pPed->SetSeekBoatPosition(carBelow);
}
}
// Find closest car
if (!weAreOnBoat) {
float minX = m_pPed->GetPosition().x - 10.0f;
float maxX = 10.0f + m_pPed->GetPosition().x;
float minY = m_pPed->GetPosition().y - 10.0f;
float maxY = 10.0f + m_pPed->GetPosition().y;
int minXSector = CWorld::GetSectorIndexX(minX);
if (minXSector < 0) minXSector = 0;
int minYSector = CWorld::GetSectorIndexY(minY);
if (minYSector < 0) minYSector = 0;
int maxXSector = CWorld::GetSectorIndexX(maxX);
if (maxXSector > NUMSECTORS_X - 1) maxXSector = NUMSECTORS_X - 1;
int maxYSector = CWorld::GetSectorIndexY(maxY);
if (maxYSector > NUMSECTORS_Y - 1) maxYSector = NUMSECTORS_Y - 1;
CWorld::AdvanceCurrentScanCode();
for (int curY = minYSector; curY <= maxYSector; curY++) {
for (int curX = minXSector; curX <= maxXSector; curX++) {
CSector *sector = CWorld::GetSector(curX, curY);
FindClosestCarSectorList(sector->m_lists[ENTITYLIST_VEHICLES], m_pPed,
minX, minY, maxX, maxY, &lastCloseness, &carBelow);
FindClosestCarSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], m_pPed,
minX, minY, maxX, maxY, &lastCloseness, &carBelow);
}
}
}
// carBelow is now closest vehicle
if (carBelow && !weAreOnBoat) {
if (carBelow->GetStatus() == STATUS_TRAIN_NOT_MOVING) {
m_pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, carBelow);
} else if (carBelow->IsBoat()) {
if (!carBelow->pDriver) {
m_pPed->m_vehDoor = 0;
m_pPed->SetEnterCar(carBelow, m_pPed->m_vehDoor);
}
} else {
m_pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, carBelow);
}
}
}
}
}
if (m_bInRemoteMode) {
uint32 timeWithoutRemoteCar = CTimer::GetTimeInMilliseconds() - m_nTimeLostRemoteCar;
if (CTimer::GetPreviousTimeInMilliseconds() - m_nTimeLostRemoteCar < 1000 && timeWithoutRemoteCar >= 1000 && m_WBState == WBSTATE_PLAYING) {
TheCamera.SetFadeColour(0, 0, 0);
TheCamera.Fade(1.0f, FADE_OUT);
}
if (timeWithoutRemoteCar > 2000) {
if (m_WBState == WBSTATE_PLAYING) {
TheCamera.RestoreWithJumpCut();
TheCamera.SetFadeColour(0, 0, 0);
TheCamera.Fade(1.0f, FADE_IN);
TheCamera.Process();
CTimer::Stop();
CCullZones::ForceCullZoneCoors(TheCamera.GetPosition());
CRenderer::RequestObjectsInFrustum();
CStreaming::LoadAllRequestedModels(false);
CTimer::Update();
}
m_bInRemoteMode = false;
CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle = nil;
if (FindPlayerVehicle()) {
FindPlayerVehicle()->SetStatus(STATUS_PLAYER);
}
}
}
if (!(CTimer::GetFrameCounter() & 31)) {
CVehicle *veh = FindPlayerVehicle();
if (veh && m_pPed->bInVehicle && veh->GetUp().z < 0.0f
&& veh->m_vecMoveSpeed.Magnitude() < 0.05f && veh->IsCar() && !veh->bIsInWater) {
if (veh->GetUp().z < -0.5f) {
m_nUpsideDownCounter += 2;
} else {
m_nUpsideDownCounter++;
}
} else {
m_nUpsideDownCounter = 0;
}
if (m_nUpsideDownCounter > 6 && veh->bCanBeDamaged) {
veh->m_fHealth = 249.0f < veh->m_fHealth ? 249.0f : veh->m_fHealth;
if (veh->IsCar()) {
CAutomobile* car = (CAutomobile*)veh;
car->Damage.SetEngineStatus(225);
car->m_pSetOnFireEntity = nil;
}
}
}
if (FindPlayerVehicle()) {
CVehicle *veh = FindPlayerVehicle();
veh->m_nZoneLevel = LEVEL_IGNORE;
for (int i = 0; i < ARRAY_SIZE(veh->pPassengers); i++) {
if (veh->pPassengers[i])
veh->pPassengers[i]->m_nZoneLevel = LEVEL_GENERIC;
}
CStats::DistanceTravelledInVehicle += veh->m_fDistanceTravelled;
} else {
CStats::DistanceTravelledOnFoot += FindPlayerPed()->m_fDistanceTravelled;
}
}
bool
CPlayerInfo::IsPlayerInRemoteMode()
{
return m_pRemoteVehicle || m_bInRemoteMode;
}
void
CPlayerInfo::SavePlayerInfo(uint8 *buf, uint32 *size)
{
// Interesting
*size = sizeof(CPlayerInfo);
#define CopyToBuf(buf, data) memcpy(buf, &data, sizeof(data)); buf += sizeof(data);
CopyToBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nMoney);
CopyToBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_WBState);
CopyToBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nWBTime);
CopyToBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nTrafficMultiplier);
CopyToBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_fRoadDensity);
CopyToBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nVisibleMoney);
CopyToBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages);
CopyToBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages);
CopyToBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint);
CopyToBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bFastReload);
CopyToBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfJailFree);
CopyToBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfHospitalFree);
CopyToBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName);
#undef CopyToBuf
}
void
CPlayerInfo::LoadPlayerInfo(uint8 *buf, uint32 size)
{
#define CopyFromBuf(buf, data) memcpy(&data, buf, sizeof(data)); buf += sizeof(data);
CopyFromBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nMoney);
CopyFromBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_WBState);
CopyFromBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nWBTime);
CopyFromBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nTrafficMultiplier);
CopyFromBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_fRoadDensity);
CopyFromBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nVisibleMoney);
CopyFromBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages);
CopyFromBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages);
CopyFromBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint);
CopyFromBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bFastReload);
CopyFromBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfJailFree);
CopyFromBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfHospitalFree);
CopyFromBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName)
#undef CopyFromBuf
}
void
CPlayerInfo::FindClosestCarSectorList(CPtrList& carList, CPed* ped, float unk1, float unk2, float unk3, float unk4, float* lastCloseness, CVehicle** closestCarOutput)
{
for (CPtrNode* node = carList.first; node; node = node->next) {
CVehicle *car = (CVehicle*)node->item;
if(car->m_scanCode != CWorld::GetCurrentScanCode()) {
if (!car->bUsesCollision || !car->IsVehicle())
continue;
car->m_scanCode = CWorld::GetCurrentScanCode();
if (car->GetStatus() != STATUS_WRECKED && car->GetStatus() != STATUS_TRAIN_MOVING
&& (car->GetUp().z > 0.3f || (car->IsVehicle() && ((CVehicle*)car)->m_vehType == VEHICLE_TYPE_BIKE))) {
CVector carCentre = car->GetBoundCentre();
if (Abs(ped->GetPosition().z - carCentre.z) < 2.0f) {
float dist = (ped->GetPosition() - carCentre).Magnitude2D();
if (dist <= 10.0f && !CCranes::IsThisCarBeingCarriedByAnyCrane(car)) {
EvaluateCarPosition(car, ped, dist, lastCloseness, closestCarOutput);
}
}
}
}
}
}
// lastCloseness is passed to other calls of this function
void
CPlayerInfo::EvaluateCarPosition(CEntity *carToTest, CPed *player, float carBoundCentrePedDist, float *lastCloseness, CVehicle **closestCarOutput)
{
// This dist used for determining the angle to face
CVector2D dist(carToTest->GetPosition() - player->GetPosition());
float neededTurn = CGeneral::GetATanOfXY(player->GetForward().x, player->GetForward().y) - CGeneral::GetATanOfXY(dist.x, dist.y);
while (neededTurn >= PI) {
neededTurn -= 2 * PI;
}
while (neededTurn < -PI) {
neededTurn += 2 * PI;
}
// This dist used for evaluating cars' distances, weird...
// Accounts inverted needed turn (or needed turn in long way) and car dist.
float closeness = (1.0f - Abs(neededTurn) / TWOPI) * (10.0f - carBoundCentrePedDist);
if (closeness > *lastCloseness) {
*lastCloseness = closeness;
*closestCarOutput = (CVehicle*)carToTest;
}
}
const CVector &
CPlayerInfo::GetPos()
{
#ifdef FIX_BUGS
if (!m_pPed)
return TheCamera.GetPosition();
#endif
if (m_pPed->InVehicle())
return m_pPed->m_pMyVehicle->GetPosition();
return m_pPed->GetPosition();
}
CVector
FindPlayerCoors(void)
{
#ifdef FIX_BUGS
if (CReplay::IsPlayingBack())
return TheCamera.GetPosition();
#endif
CPlayerPed *ped = FindPlayerPed();
if(ped->InVehicle())
return ped->m_pMyVehicle->GetPosition();
else
return ped->GetPosition();
}
const CVector &
FindPlayerSpeed(void)
{
#ifdef FIX_BUGS
static CVector vecTmpVector(0.0f, 0.0f, 0.0f);
if (CReplay::IsPlayingBack())
return vecTmpVector;
#endif
CPlayerPed *ped = FindPlayerPed();
if(ped->InVehicle())
return ped->m_pMyVehicle->m_vecMoveSpeed;
else
return ped->m_vecMoveSpeed;
}
CVehicle *
FindPlayerVehicle(void)
{
CPlayerPed *ped = FindPlayerPed();
if(ped && ped->InVehicle()) return ped->m_pMyVehicle;
return nil;
}
CEntity *
FindPlayerEntity(void)
{
CPlayerPed *ped = FindPlayerPed();
if(ped->InVehicle())
return ped->m_pMyVehicle;
else
return ped;
}
CVehicle *
FindPlayerTrain(void)
{
if(FindPlayerVehicle() && FindPlayerVehicle()->IsTrain())
return FindPlayerVehicle();
else
return nil;
}
CPlayerPed *
FindPlayerPed(void)
{
return CWorld::Players[CWorld::PlayerInFocus].m_pPed;
}
const CVector &
FindPlayerCentreOfWorld(int32 player)
{
#ifdef FIX_BUGS
if(CReplay::IsPlayingBack()) return TheCamera.GetPosition();
#endif
if(CCarCtrl::bCarsGeneratedAroundCamera) return TheCamera.GetPosition();
if(CWorld::Players[player].m_pRemoteVehicle) return CWorld::Players[player].m_pRemoteVehicle->GetPosition();
if(FindPlayerVehicle()) return FindPlayerVehicle()->GetPosition();
return CWorld::Players[player].m_pPed->GetPosition();
}
const CVector &
FindPlayerCentreOfWorld_NoSniperShift(void)
{
#ifdef FIX_BUGS
if (CReplay::IsPlayingBack()) return TheCamera.GetPosition();
#endif
if(CCarCtrl::bCarsGeneratedAroundCamera) return TheCamera.GetPosition();
if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle)
return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetPosition();
if(FindPlayerVehicle()) return FindPlayerVehicle()->GetPosition();
return FindPlayerPed()->GetPosition();
}
float
FindPlayerHeading(void)
{
if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle)
return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetForward().Heading();
if(FindPlayerVehicle()) return FindPlayerVehicle()->GetForward().Heading();
return FindPlayerPed()->GetForward().Heading();
}
bool
CPlayerInfo::IsRestartingAfterDeath()
{
return m_WBState == WBSTATE_WASTED;
}
bool
CPlayerInfo::IsRestartingAfterArrest()
{
return m_WBState == WBSTATE_BUSTED;
}
void
CPlayerInfo::KillPlayer()
{
if (m_WBState != WBSTATE_PLAYING) return;
m_WBState = WBSTATE_WASTED;
m_nWBTime = CTimer::GetTimeInMilliseconds();
CDarkel::ResetOnPlayerDeath();
CMessages::AddBigMessage(TheText.Get("DEAD"), 4000, 2);
CStats::TimesDied++;
}
void
CPlayerInfo::ArrestPlayer()
{
if (m_WBState != WBSTATE_PLAYING) return;
m_WBState = WBSTATE_BUSTED;
m_nWBTime = CTimer::GetTimeInMilliseconds();
CDarkel::ResetOnPlayerDeath();
CMessages::AddBigMessage(TheText.Get("BUSTED"), 5000, 2);
CStats::TimesArrested++;
}
void
CPlayerInfo::PlayerFailedCriticalMission()
{
if (m_WBState != WBSTATE_PLAYING)
return;
m_WBState = WBSTATE_FAILED_CRITICAL_MISSION;
m_nWBTime = CTimer::GetTimeInMilliseconds();
CDarkel::ResetOnPlayerDeath();
}
void
CPlayerInfo::CancelPlayerEnteringCars(CVehicle *car)
{
if (!car || car == m_pPed->m_pMyVehicle) {
if (m_pPed->EnteringCar())
m_pPed->QuitEnteringCar();
}
if (m_pPed->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || m_pPed->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER)
m_pPed->ClearObjective();
}
void
CPlayerInfo::MakePlayerSafe(bool toggle)
{
if (toggle) {
CTheScripts::ResetCountdownToMakePlayerUnsafe();
m_pPed->m_pWanted->m_bIgnoredByEveryone = true;
CWorld::StopAllLawEnforcersInTheirTracks();
CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_PLAYERINFO);
CPad::StopPadsShaking();
m_pPed->bBulletProof = true;
m_pPed->bFireProof = true;
m_pPed->bCollisionProof = true;
m_pPed->bMeleeProof = true;
m_pPed->bOnlyDamagedByPlayer = true;
m_pPed->bExplosionProof = true;
m_pPed->m_bCanBeDamaged = false;
((CPlayerPed*)m_pPed)->ClearAdrenaline();
CancelPlayerEnteringCars(nil);
gFireManager.ExtinguishPoint(GetPos(), 4000.0f);
CExplosion::RemoveAllExplosionsInArea(GetPos(), 4000.0f);
CProjectileInfo::RemoveAllProjectiles();
CWorld::SetAllCarsCanBeDamaged(false);
CWorld::ExtinguishAllCarFiresInArea(GetPos(), 4000.0f);
CReplay::DisableReplays();
} else if (!CGame::playingIntro && !CTheScripts::IsCountdownToMakePlayerUnsafeOn()) {
m_pPed->m_pWanted->m_bIgnoredByEveryone = false;
CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_PLAYERINFO);
m_pPed->bBulletProof = false;
m_pPed->bFireProof = false;
m_pPed->bCollisionProof = false;
m_pPed->bMeleeProof = false;
m_pPed->bOnlyDamagedByPlayer = false;
m_pPed->bExplosionProof = false;
m_pPed->m_bCanBeDamaged = true;
CWorld::SetAllCarsCanBeDamaged(true);
CReplay::EnableReplays();
}
}
void
CPlayerInfo::BlowUpRCBuggy(void)
{
if (!m_pRemoteVehicle || m_pRemoteVehicle->bRemoveFromWorld)
return;
CRemote::TakeRemoteControlledCarFromPlayer();
m_pRemoteVehicle->BlowUpCar(FindPlayerPed());
}
// There is something unfinished in here... Sadly all IDBs we have have it unfinished.
void
CPlayerInfo::AwardMoneyForExplosion(CVehicle *wreckedCar)
{
if (CTimer::GetTimeInMilliseconds() - m_nPreviousTimeRewardedForExplosion < 6000)
++m_nExplosionsSinceLastReward;
else
m_nExplosionsSinceLastReward = 1;
m_nPreviousTimeRewardedForExplosion = CTimer::GetTimeInMilliseconds();
int award = wreckedCar->pHandling->nMonetaryValue * 0.002f;
sprintf(gString, "$%d", award);
#ifdef MONEY_MESSAGES
// This line is a leftover from PS2, I don't know what it was meant to be.
// CVector sth(TheCamera.GetPosition() * 4.0f);
CMoneyMessages::RegisterOne(wreckedCar->GetPosition() + CVector(0.0f, 0.0f, 2.0f), gString, 0, 255, 0, 2.0f, 0.5f);
#endif
CWorld::Players[CWorld::PlayerInFocus].m_nMoney += award;
for (int i = m_nExplosionsSinceLastReward; i > 1; --i) {
CGeneral::GetRandomNumber();
CWorld::Players[CWorld::PlayerInFocus].m_nMoney += award;
}
}
#ifdef GTA_PC
void
CPlayerInfo::SetPlayerSkin(const char *skin)
{
strncpy(m_aSkinName, skin, 32);
LoadPlayerSkin();
}
void
CPlayerInfo::LoadPlayerSkin()
{
DeletePlayerSkin();
m_pSkinTexture = CPlayerSkin::GetSkinTexture(m_aSkinName);
if (!m_pSkinTexture)
m_pSkinTexture = CPlayerSkin::GetSkinTexture(DEFAULT_SKIN_NAME);
}
void
CPlayerInfo::DeletePlayerSkin()
{
if (m_pSkinTexture) {
RwTextureDestroy(m_pSkinTexture);
m_pSkinTexture = nil;
}
}
#endif

97
src/core/PlayerInfo.h Normal file
View file

@ -0,0 +1,97 @@
#pragma once
#include "ColModel.h"
enum eWastedBustedState
{
WBSTATE_PLAYING,
WBSTATE_WASTED,
WBSTATE_BUSTED,
WBSTATE_FAILED_CRITICAL_MISSION,
};
class CEntity;
class CPed;
class CVehicle;
class CPlayerPed;
class CCivilianPed;
class CPlayerInfo
{
public:
CPlayerPed *m_pPed;
CVehicle *m_pRemoteVehicle;
CColModel m_ColModel;
CVehicle *m_pVehicleEx; // vehicle using the col model above
char m_aPlayerName[70];
int32 m_nMoney;
int32 m_nVisibleMoney;
int32 m_nCollectedPackages;
int32 m_nTotalPackages;
uint32 m_nLastBumpPlayerCarTimer;
uint32 m_nUnusedTaxiTimer;
bool m_bUnusedTaxiThing;
uint32 m_nNextSexFrequencyUpdateTime;
uint32 m_nNextSexMoneyUpdateTime;
int32 m_nSexFrequency;
CCivilianPed *m_pHooker;
int8 m_WBState; // eWastedBustedState
uint32 m_nWBTime;
bool m_bInRemoteMode;
uint32 m_nTimeLostRemoteCar;
uint32 m_nTimeLastHealthLoss;
uint32 m_nTimeLastArmourLoss;
uint32 m_nTimeTankShotGun;
int32 m_nUpsideDownCounter;
int32 field_248;
int16 m_nTrafficMultiplier;
float m_fRoadDensity;
uint32 m_nPreviousTimeRewardedForExplosion;
int32 m_nExplosionsSinceLastReward;
int32 field_268;
int32 field_272;
bool m_bInfiniteSprint;
bool m_bFastReload;
bool m_bGetOutOfJailFree;
bool m_bGetOutOfHospitalFree;
#ifdef GTA_PC
char m_aSkinName[32];
RwTexture *m_pSkinTexture;
#endif
void MakePlayerSafe(bool);
void AwardMoneyForExplosion(CVehicle *vehicle);
const CVector &GetPos();
void Process(void);
void KillPlayer(void);
void ArrestPlayer(void);
bool IsPlayerInRemoteMode(void);
void PlayerFailedCriticalMission(void);
void Clear(void);
void BlowUpRCBuggy(void);
void CancelPlayerEnteringCars(CVehicle*);
bool IsRestartingAfterDeath(void);
bool IsRestartingAfterArrest(void);
void EvaluateCarPosition(CEntity*, CPed*, float, float*, CVehicle**);
void LoadPlayerInfo(uint8 *buf, uint32 size);
void SavePlayerInfo(uint8 *buf, uint32* size);
void FindClosestCarSectorList(CPtrList&, CPed*, float, float, float, float, float*, CVehicle**);
#ifdef GTA_PC
void LoadPlayerSkin();
void SetPlayerSkin(const char *skin);
void DeletePlayerSkin();
#endif
};
CPlayerPed *FindPlayerPed(void);
CVehicle *FindPlayerVehicle(void);
CVehicle *FindPlayerTrain(void);
CEntity *FindPlayerEntity(void);
CVector FindPlayerCoors(void);
const CVector &FindPlayerSpeed(void);
const CVector &FindPlayerCentreOfWorld(int32 player);
const CVector &FindPlayerCentreOfWorld_NoSniperShift(void);
float FindPlayerHeading(void);
VALIDATE_SIZE(CPlayerInfo, 0x13C);

585
src/core/Pools.cpp Normal file
View file

@ -0,0 +1,585 @@
#include "common.h"
#include "Pools.h"
#include "Boat.h"
#include "CarCtrl.h"
#ifdef MISSION_REPLAY
#include "GenericGameStorage.h"
#endif
#include "Population.h"
#include "ProjectileInfo.h"
#include "SaveBuf.h"
#include "Streaming.h"
#include "Wanted.h"
#include "World.h"
#include "MemoryHeap.h"
CCPtrNodePool *CPools::ms_pPtrNodePool;
CEntryInfoNodePool *CPools::ms_pEntryInfoNodePool;
CPedPool *CPools::ms_pPedPool;
CVehiclePool *CPools::ms_pVehiclePool;
CBuildingPool *CPools::ms_pBuildingPool;
CTreadablePool *CPools::ms_pTreadablePool;
CObjectPool *CPools::ms_pObjectPool;
CDummyPool *CPools::ms_pDummyPool;
CAudioScriptObjectPool *CPools::ms_pAudioScriptObjectPool;
#ifdef GTA_PS2 // or USE_CUSTOM_ALLOCATOR
#define CHECKMEM(msg) CMemCheck::AllocateMemCheckBlock(msg)
#else
#define CHECKMEM(msg)
#endif
void
CPools::Initialise(void)
{
PUSH_MEMID(MEMID_POOLS);
CHECKMEM("before pools");
ms_pPtrNodePool = new CCPtrNodePool(NUMPTRNODES);
CHECKMEM("after CPtrNodePool");
ms_pEntryInfoNodePool = new CEntryInfoNodePool(NUMENTRYINFOS);
CHECKMEM("after CEntryInfoNodePool");
ms_pPedPool = new CPedPool(NUMPEDS);
CHECKMEM("after CPedPool");
ms_pVehiclePool = new CVehiclePool(NUMVEHICLES);
CHECKMEM("after CVehiclePool");
ms_pBuildingPool = new CBuildingPool(NUMBUILDINGS);
CHECKMEM("after CBuildingPool");
ms_pTreadablePool = new CTreadablePool(NUMTREADABLES);
CHECKMEM("after CTreadablePool");
ms_pObjectPool = new CObjectPool(NUMOBJECTS);
CHECKMEM("after CObjectPool");
ms_pDummyPool = new CDummyPool(NUMDUMMIES);
CHECKMEM("after CDummyPool");
ms_pAudioScriptObjectPool = new CAudioScriptObjectPool(NUMAUDIOSCRIPTOBJECTS);
CHECKMEM("after pools");
POP_MEMID();
}
void
CPools::ShutDown(void)
{
debug("PtrNodes left %d\n", ms_pPtrNodePool->GetNoOfUsedSpaces());
debug("EntryInfoNodes left %d\n", ms_pEntryInfoNodePool->GetNoOfUsedSpaces());
debug("Peds left %d\n", ms_pPedPool->GetNoOfUsedSpaces());
debug("Vehicles left %d\n", ms_pVehiclePool->GetNoOfUsedSpaces());
debug("Buildings left %d\n", ms_pBuildingPool->GetNoOfUsedSpaces());
debug("Treadables left %d\n", ms_pTreadablePool->GetNoOfUsedSpaces());
debug("Objects left %d\n", ms_pObjectPool->GetNoOfUsedSpaces());
debug("Dummys left %d\n", ms_pDummyPool->GetNoOfUsedSpaces());
debug("AudioScriptObjects left %d\n", ms_pAudioScriptObjectPool->GetNoOfUsedSpaces());
printf("Shutdown pool started\n");
delete ms_pPtrNodePool;
delete ms_pEntryInfoNodePool;
delete ms_pPedPool;
delete ms_pVehiclePool;
delete ms_pBuildingPool;
delete ms_pTreadablePool;
delete ms_pObjectPool;
delete ms_pDummyPool;
delete ms_pAudioScriptObjectPool;
printf("Shutdown pool done\n");
}
int32 CPools::GetPedRef(CPed *ped) { return ms_pPedPool->GetIndex(ped); }
CPed *CPools::GetPed(int32 handle) { return ms_pPedPool->GetAt(handle); }
int32 CPools::GetVehicleRef(CVehicle *vehicle) { return ms_pVehiclePool->GetIndex(vehicle); }
CVehicle *CPools::GetVehicle(int32 handle) { return ms_pVehiclePool->GetAt(handle); }
int32 CPools::GetObjectRef(CObject *object) { return ms_pObjectPool->GetIndex(object); }
CObject *CPools::GetObject(int32 handle) { return ms_pObjectPool->GetAt(handle); }
void
CPools::CheckPoolsEmpty()
{
assert(ms_pPedPool->GetNoOfUsedSpaces() == 0);
assert(ms_pVehiclePool->GetNoOfUsedSpaces() == 0);
printf("pools have been cleared\n");
}
void
CPools::MakeSureSlotInObjectPoolIsEmpty(int32 slot)
{
if (ms_pObjectPool->GetIsFree(slot)) return;
CObject *object = ms_pObjectPool->GetSlot(slot);
if (object->ObjectCreatedBy == TEMP_OBJECT) {
CWorld::Remove(object);
delete object;
} else if (!CProjectileInfo::RemoveIfThisIsAProjectile(object)) {
// relocate to another slot??
CObject *newObject = new CObject(object->GetModelIndex(), false);
CWorld::Remove(object);
#if 0 // todo better
*newObject = *object;
#else
memcpy(newObject, object, ms_pObjectPool->GetMaxEntrySize());
#endif
CWorld::Add(newObject);
object->m_rwObject = nil;
delete object;
newObject->m_pFirstReference = nil;
}
}
#define CopyFromBuf(buf, data) memcpy(&data, buf, sizeof(data)); SkipSaveBuf(buf, sizeof(data));
#define CopyToBuf(buf, data) memcpy(buf, &data, sizeof(data)); SkipSaveBuf(buf, sizeof(data));
void CPools::LoadVehiclePool(uint8* buf, uint32 size)
{
INITSAVEBUF
int nNumCars, nNumBoats;
ReadSaveBuf(&nNumCars, buf);
ReadSaveBuf(&nNumBoats, buf);
for (int i = 0; i < nNumCars + nNumBoats; i++) {
uint32 type;
int16 model;
int32 slot;
ReadSaveBuf(&type, buf);
ReadSaveBuf(&model, buf);
CStreaming::RequestModel(model, STREAMFLAGS_DEPENDENCY);
CStreaming::LoadAllRequestedModels(false);
ReadSaveBuf(&slot, buf);
CVehicle* pVehicle;
#ifdef COMPATIBLE_SAVES
if (type == VEHICLE_TYPE_BOAT)
pVehicle = new(slot) CBoat(model, RANDOM_VEHICLE);
else if (type == VEHICLE_TYPE_CAR)
pVehicle = new(slot) CAutomobile(model, RANDOM_VEHICLE);
else
assert(0);
--CCarCtrl::NumRandomCars;
pVehicle->Load(buf);
CWorld::Add(pVehicle);
#else
char* vbuf = new char[Max(CAutomobile::nSaveStructSize, CBoat::nSaveStructSize)];
if (type == VEHICLE_TYPE_BOAT) {
memcpy(vbuf, buf, sizeof(CBoat));
SkipSaveBuf(buf, sizeof(CBoat));
CBoat* pBoat = new(slot) CBoat(model, RANDOM_VEHICLE);
pVehicle = pBoat;
--CCarCtrl::NumRandomCars;
}
else if (type == VEHICLE_TYPE_CAR) {
memcpy(vbuf, buf, sizeof(CAutomobile));
SkipSaveBuf(buf, sizeof(CAutomobile));
CStreaming::RequestModel(model, 0); // is it needed?
CStreaming::LoadAllRequestedModels(false);
CAutomobile* pAutomobile = new(slot) CAutomobile(model, RANDOM_VEHICLE);
pVehicle = pAutomobile;
CCarCtrl::NumRandomCars--; // why?
pAutomobile->Damage = ((CAutomobile*)vbuf)->Damage;
pAutomobile->SetupDamageAfterLoad();
}
else
assert(0);
CVehicle* pBufferVehicle = (CVehicle*)vbuf;
pVehicle->GetMatrix() = pBufferVehicle->GetMatrix();
pVehicle->VehicleCreatedBy = pBufferVehicle->VehicleCreatedBy;
pVehicle->m_currentColour1 = pBufferVehicle->m_currentColour1;
pVehicle->m_currentColour2 = pBufferVehicle->m_currentColour2;
pVehicle->m_nAlarmState = pBufferVehicle->m_nAlarmState;
pVehicle->m_nNumMaxPassengers = pBufferVehicle->m_nNumMaxPassengers;
pVehicle->field_1D0[0] = pBufferVehicle->field_1D0[0];
pVehicle->field_1D0[1] = pBufferVehicle->field_1D0[1];
pVehicle->field_1D0[2] = pBufferVehicle->field_1D0[2];
pVehicle->field_1D0[3] = pBufferVehicle->field_1D0[3];
pVehicle->m_fSteerAngle = pBufferVehicle->m_fSteerAngle;
pVehicle->m_fGasPedal = pBufferVehicle->m_fGasPedal;
pVehicle->m_fBrakePedal = pBufferVehicle->m_fBrakePedal;
pVehicle->bIsLawEnforcer = pBufferVehicle->bIsLawEnforcer;
pVehicle->bIsLocked = pBufferVehicle->bIsLocked;
pVehicle->bEngineOn = pBufferVehicle->bEngineOn;
pVehicle->bIsHandbrakeOn = pBufferVehicle->bIsHandbrakeOn;
pVehicle->bLightsOn = pBufferVehicle->bLightsOn;
pVehicle->bFreebies = pBufferVehicle->bFreebies;
pVehicle->m_fHealth = pBufferVehicle->m_fHealth;
pVehicle->m_nCurrentGear = pBufferVehicle->m_nCurrentGear;
pVehicle->m_fChangeGearTime = pBufferVehicle->m_fChangeGearTime;
pVehicle->m_nTimeOfDeath = pBufferVehicle->m_nTimeOfDeath;
#ifdef FIX_BUGS //must be copypaste
pVehicle->m_nBombTimer = pBufferVehicle->m_nBombTimer;
#else
pVehicle->m_nTimeOfDeath = pBufferVehicle->m_nTimeOfDeath;
#endif
pVehicle->m_nDoorLock = pBufferVehicle->m_nDoorLock;
pVehicle->SetStatus(pBufferVehicle->GetStatus());
pVehicle->SetType(pBufferVehicle->GetType());
(pVehicle->GetAddressOfEntityProperties())[0] = (pBufferVehicle->GetAddressOfEntityProperties())[0];
(pVehicle->GetAddressOfEntityProperties())[1] = (pBufferVehicle->GetAddressOfEntityProperties())[1];
pVehicle->AutoPilot = pBufferVehicle->AutoPilot;
CWorld::Add(pVehicle);
delete[] vbuf;
#endif
}
VALIDATESAVEBUF(size)
}
void CPools::SaveVehiclePool(uint8* buf, uint32* size)
{
INITSAVEBUF
int nNumCars = 0;
int nNumBoats = 0;
int nPoolSize = GetVehiclePool()->GetSize();
for (int i = 0; i < nPoolSize; i++) {
CVehicle* pVehicle = GetVehiclePool()->GetSlot(i);
if (!pVehicle)
continue;
bool bHasPassenger = false;
for (int j = 0; j < ARRAY_SIZE(pVehicle->pPassengers); j++) {
if (pVehicle->pPassengers[j])
bHasPassenger = true;
}
#ifdef MISSION_REPLAY
bool bForceSaving = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pMyVehicle == pVehicle && IsQuickSave;
#ifdef FIX_BUGS
if ((!pVehicle->pDriver && !bHasPassenger) || bForceSaving) {
#else
if (!pVehicle->pDriver && !bHasPassenger) {
#endif
if (pVehicle->IsCar() && (pVehicle->VehicleCreatedBy == MISSION_VEHICLE || bForceSaving))
++nNumCars;
if (pVehicle->IsBoat() && (pVehicle->VehicleCreatedBy == MISSION_VEHICLE || bForceSaving))
++nNumBoats;
#else
if (!pVehicle->pDriver && !bHasPassenger) {
if (pVehicle->IsCar() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE)
++nNumCars;
if (pVehicle->IsBoat() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE)
++nNumBoats;
#endif
}
}
*size = nNumCars * (sizeof(uint32) + sizeof(int16) + sizeof(int32) + CAutomobile::nSaveStructSize) + sizeof(int) +
nNumBoats * (sizeof(uint32) + sizeof(int16) + sizeof(int32) + CBoat::nSaveStructSize) + sizeof(int);
WriteSaveBuf(buf, nNumCars);
WriteSaveBuf(buf, nNumBoats);
for (int i = 0; i < nPoolSize; i++) {
CVehicle* pVehicle = GetVehiclePool()->GetSlot(i);
if (!pVehicle)
continue;
bool bHasPassenger = false;
for (int j = 0; j < ARRAY_SIZE(pVehicle->pPassengers); j++) {
if (pVehicle->pPassengers[j])
bHasPassenger = true;
}
#ifdef MISSION_REPLAY
bool bForceSaving = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pMyVehicle == pVehicle && IsQuickSave;
#endif
#if defined FIX_BUGS && defined MISSION_REPLAY
if ((!pVehicle->pDriver && !bHasPassenger) || bForceSaving) {
#else
if (!pVehicle->pDriver && !bHasPassenger) {
#endif
#ifdef COMPATIBLE_SAVES
#ifdef MISSION_REPLAY
if ((pVehicle->IsCar() || pVehicle->IsBoat()) && (pVehicle->VehicleCreatedBy == MISSION_VEHICLE || bForceSaving)) {
#else
if ((pVehicle->IsCar() || pVehicle->IsBoat()) && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) {
#endif
WriteSaveBuf(buf, pVehicle->m_vehType);
WriteSaveBuf(buf, pVehicle->GetModelIndex());
WriteSaveBuf(buf, GetVehicleRef(pVehicle));
pVehicle->Save(buf);
}
#else
#ifdef MISSION_REPLAY
if (pVehicle->IsCar() && (pVehicle->VehicleCreatedBy == MISSION_VEHICLE || bForceSaving)) {
#else
if (pVehicle->IsCar() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) {
#endif
WriteSaveBuf(buf, pVehicle->m_vehType);
WriteSaveBuf(buf, pVehicle->GetModelIndex());
WriteSaveBuf(buf, GetVehicleRef(pVehicle));
memcpy(buf, pVehicle, sizeof(CAutomobile));
SkipSaveBuf(buf, sizeof(CAutomobile));
}
#ifdef MISSION_REPLAY
if (pVehicle->IsBoat() && (pVehicle->VehicleCreatedBy == MISSION_VEHICLE || bForceSaving)) {
#else
if (pVehicle->IsBoat() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) {
#endif
WriteSaveBuf(buf, pVehicle->m_vehType);
WriteSaveBuf(buf, pVehicle->GetModelIndex());
WriteSaveBuf(buf, GetVehicleRef(pVehicle));
memcpy(buf, pVehicle, sizeof(CBoat));
SkipSaveBuf(buf, sizeof(CBoat));
}
#endif
}
}
VALIDATESAVEBUF(*size)
}
void CPools::SaveObjectPool(uint8* buf, uint32* size)
{
INITSAVEBUF
CProjectileInfo::RemoveAllProjectiles();
CObject::DeleteAllTempObjects();
int nObjects = 0;
int nPoolSize = GetObjectPool()->GetSize();
for (int i = 0; i < nPoolSize; i++) {
CObject* pObject = GetObjectPool()->GetSlot(i);
if (!pObject)
continue;
if (pObject->ObjectCreatedBy == MISSION_OBJECT)
++nObjects;
}
*size = nObjects * (sizeof(int16) + sizeof(int) + sizeof(CCompressedMatrix) +
sizeof(float) + sizeof(CCompressedMatrix) + sizeof(int8) + 7 * sizeof(bool) + sizeof(float) +
sizeof(int8) + sizeof(int8) + sizeof(uint32) + 2 * sizeof(uint32)) + sizeof(int);
CopyToBuf(buf, nObjects);
for (int i = 0; i < nPoolSize; i++) {
CObject* pObject = GetObjectPool()->GetSlot(i);
if (!pObject)
continue;
if (pObject->ObjectCreatedBy == MISSION_OBJECT) {
bool bIsPickup = pObject->bIsPickup;
bool bPickupObjWithMessage = pObject->bPickupObjWithMessage;
bool bOutOfStock = pObject->bOutOfStock;
bool bGlassCracked = pObject->bGlassCracked;
bool bGlassBroken = pObject->bGlassBroken;
bool bHasBeenDamaged = pObject->bHasBeenDamaged;
bool bUseVehicleColours = pObject->bUseVehicleColours;
CCompressedMatrix tmp;
CopyToBuf(buf, pObject->m_modelIndex);
int32 ref = GetObjectRef(pObject);
CopyToBuf(buf, ref);
tmp.CompressFromFullMatrix(pObject->GetMatrix());
CopyToBuf(buf, tmp);
CopyToBuf(buf, pObject->m_fUprootLimit);
tmp.CompressFromFullMatrix(pObject->m_objectMatrix);
CopyToBuf(buf, tmp);
CopyToBuf(buf, pObject->ObjectCreatedBy);
CopyToBuf(buf, bIsPickup);
CopyToBuf(buf, bPickupObjWithMessage);
CopyToBuf(buf, bOutOfStock);
CopyToBuf(buf, bGlassCracked);
CopyToBuf(buf, bGlassBroken);
CopyToBuf(buf, bHasBeenDamaged);
CopyToBuf(buf, bUseVehicleColours);
CopyToBuf(buf, pObject->m_fCollisionDamageMultiplier);
CopyToBuf(buf, pObject->m_nCollisionDamageEffect);
CopyToBuf(buf, pObject->m_nSpecialCollisionResponseCases);
CopyToBuf(buf, pObject->m_nEndOfLifeTime);
#ifdef COMPATIBLE_SAVES
pObject->SaveEntityFlags(buf);
#else
CopyToBuf(buf, (pObject->GetAddressOfEntityProperties())[0]);
CopyToBuf(buf, (pObject->GetAddressOfEntityProperties())[1]);
#endif
}
}
VALIDATESAVEBUF(*size)
}
void CPools::LoadObjectPool(uint8* buf, uint32 size)
{
INITSAVEBUF
int nObjects;
CopyFromBuf(buf, nObjects);
for (int i = 0; i < nObjects; i++) {
int16 mi;
CopyFromBuf(buf, mi);
int ref;
CopyFromBuf(buf, ref);
char* obuf = new char[sizeof(CObject)];
CObject* pBufferObject = (CObject*)obuf;
CCompressedMatrix tmp;
CopyFromBuf(buf, tmp);
tmp.DecompressIntoFullMatrix(pBufferObject->GetMatrix());
CopyFromBuf(buf, pBufferObject->m_fUprootLimit);
CopyFromBuf(buf, tmp);
tmp.DecompressIntoFullMatrix(pBufferObject->m_objectMatrix);
CopyFromBuf(buf, pBufferObject->ObjectCreatedBy);
int8 bitFlag;
CopyFromBuf(buf, bitFlag);
pBufferObject->bIsPickup = bitFlag;
CopyFromBuf(buf, bitFlag);
pBufferObject->bPickupObjWithMessage = bitFlag;
CopyFromBuf(buf, bitFlag);
pBufferObject->bOutOfStock = bitFlag;
CopyFromBuf(buf, bitFlag);
pBufferObject->bGlassCracked = bitFlag;
CopyFromBuf(buf, bitFlag);
pBufferObject->bGlassBroken = bitFlag;
CopyFromBuf(buf, bitFlag);
pBufferObject->bHasBeenDamaged = bitFlag;
CopyFromBuf(buf, bitFlag);
pBufferObject->bUseVehicleColours = bitFlag;
CopyFromBuf(buf, pBufferObject->m_fCollisionDamageMultiplier);
CopyFromBuf(buf, pBufferObject->m_nCollisionDamageEffect);
CopyFromBuf(buf, pBufferObject->m_nSpecialCollisionResponseCases);
CopyFromBuf(buf, pBufferObject->m_nEndOfLifeTime);
#ifndef COMPATIBLE_SAVES
CopyFromBuf(buf, (pBufferObject->GetAddressOfEntityProperties())[0]);
CopyFromBuf(buf, (pBufferObject->GetAddressOfEntityProperties())[1]);
#endif
if (GetObjectPool()->GetSlot(ref >> 8))
CPopulation::ConvertToDummyObject(GetObjectPool()->GetSlot(ref >> 8));
CObject* pObject = new(ref) CObject(mi, false);
pObject->GetMatrix() = pBufferObject->GetMatrix();
#ifdef COMPATIBLE_SAVES
pObject->LoadEntityFlags(buf);
#endif
pObject->m_fUprootLimit = pBufferObject->m_fUprootLimit;
pObject->m_objectMatrix = pBufferObject->m_objectMatrix;
pObject->ObjectCreatedBy = pBufferObject->ObjectCreatedBy;
pObject->bIsPickup = pBufferObject->bIsPickup;
pObject->bPickupObjWithMessage = pBufferObject->bPickupObjWithMessage;
pObject->bOutOfStock = pBufferObject->bOutOfStock;
pObject->bGlassCracked = pBufferObject->bGlassCracked;
pObject->bGlassBroken = pBufferObject->bGlassBroken;
pObject->bHasBeenDamaged = pBufferObject->bHasBeenDamaged;
pObject->bUseVehicleColours = pBufferObject->bUseVehicleColours;
pObject->m_fCollisionDamageMultiplier = pBufferObject->m_fCollisionDamageMultiplier;
pObject->m_nCollisionDamageEffect = pBufferObject->m_nCollisionDamageEffect;
pObject->m_nSpecialCollisionResponseCases = pBufferObject->m_nSpecialCollisionResponseCases;
pObject->m_nEndOfLifeTime = pBufferObject->m_nEndOfLifeTime;
#ifndef COMPATIBLE_SAVES
(pObject->GetAddressOfEntityProperties())[0] = (pBufferObject->GetAddressOfEntityProperties())[0];
(pObject->GetAddressOfEntityProperties())[1] = (pBufferObject->GetAddressOfEntityProperties())[1];
#endif
pObject->bHasCollided = false;
CWorld::Add(pObject);
delete[] obuf;
}
VALIDATESAVEBUF(size)
}
void CPools::SavePedPool(uint8* buf, uint32* size)
{
INITSAVEBUF
int nNumPeds = 0;
int nPoolSize = GetPedPool()->GetSize();
for (int i = 0; i < nPoolSize; i++) {
CPed* pPed = GetPedPool()->GetSlot(i);
if (!pPed)
continue;
#ifdef MISSION_REPLAY
if ((!pPed->bInVehicle || (pPed == CWorld::Players[CWorld::PlayerInFocus].m_pPed && IsQuickSave)) && pPed->m_nPedType == PEDTYPE_PLAYER1)
#else
if (!pPed->bInVehicle && pPed->m_nPedType == PEDTYPE_PLAYER1)
#endif
nNumPeds++;
}
*size = sizeof(int) + nNumPeds * (sizeof(uint32) + sizeof(int16) + sizeof(int) + CPlayerPed::nSaveStructSize +
sizeof(CWanted::MaximumWantedLevel) + sizeof(CWanted::nMaximumWantedLevel) + MAX_MODEL_NAME);
CopyToBuf(buf, nNumPeds);
for (int i = 0; i < nPoolSize; i++) {
CPed* pPed = GetPedPool()->GetSlot(i);
if (!pPed)
continue;
#ifdef MISSION_REPLAY
if ((!pPed->bInVehicle || (pPed == CWorld::Players[CWorld::PlayerInFocus].m_pPed && IsQuickSave)) && pPed->m_nPedType == PEDTYPE_PLAYER1) {
#else
if (!pPed->bInVehicle && pPed->m_nPedType == PEDTYPE_PLAYER1) {
#endif
CopyToBuf(buf, pPed->m_nPedType);
CopyToBuf(buf, pPed->m_modelIndex);
int32 ref = GetPedRef(pPed);
CopyToBuf(buf, ref);
#ifdef COMPATIBLE_SAVES
pPed->Save(buf);
#else
memcpy(buf, pPed, sizeof(CPlayerPed));
SkipSaveBuf(buf, sizeof(CPlayerPed));
#endif
CopyToBuf(buf, CWanted::MaximumWantedLevel);
CopyToBuf(buf, CWanted::nMaximumWantedLevel);
memcpy(buf, CModelInfo::GetModelInfo(pPed->GetModelIndex())->GetModelName(), MAX_MODEL_NAME);
SkipSaveBuf(buf, MAX_MODEL_NAME);
}
}
VALIDATESAVEBUF(*size);
#undef CopyToBuf
}
void CPools::LoadPedPool(uint8* buf, uint32 size)
{
INITSAVEBUF
int nPeds;
CopyFromBuf(buf, nPeds);
for (int i = 0; i < nPeds; i++) {
uint32 pedtype;
int16 model;
int ref;
CopyFromBuf(buf, pedtype);
CopyFromBuf(buf, model);
CopyFromBuf(buf, ref);
#ifdef COMPATIBLE_SAVES
CPed* pPed;
char name[MAX_MODEL_NAME];
// Unfortunate hack: player model is stored after ped structure.
// It could be avoided by just using "player" because in practice it is always true.
memcpy(name, buf + CPlayerPed::nSaveStructSize + 2 * sizeof(int32), MAX_MODEL_NAME);
CStreaming::RequestSpecialModel(model, name, STREAMFLAGS_DONT_REMOVE);
CStreaming::LoadAllRequestedModels(false);
if (pedtype == PEDTYPE_PLAYER1)
pPed = new(ref) CPlayerPed();
else
assert(0);
pPed->Load(buf);
if (pedtype == PEDTYPE_PLAYER1) {
CopyFromBuf(buf, CWanted::MaximumWantedLevel);
CopyFromBuf(buf, CWanted::nMaximumWantedLevel);
SkipSaveBuf(buf, MAX_MODEL_NAME);
}
if (pedtype == PEDTYPE_PLAYER1) {
pPed->m_wepAccuracy = 100;
CWorld::Players[0].m_pPed = (CPlayerPed*)pPed;
}
CWorld::Add(pPed);
#else
char* pbuf = new char[sizeof(CPlayerPed)];
CPlayerPed* pBufferPlayer = (CPlayerPed*)pbuf;
CPed* pPed;
char name[MAX_MODEL_NAME];
// the code implies that there was idea to load non-player ped
if (pedtype == PEDTYPE_PLAYER1) { // always true
memcpy(pbuf, buf, sizeof(CPlayerPed));
SkipSaveBuf(buf, sizeof(CPlayerPed));
CopyFromBuf(buf, CWanted::MaximumWantedLevel);
CopyFromBuf(buf, CWanted::nMaximumWantedLevel);
CopyFromBuf(buf, name);
}
CStreaming::RequestSpecialModel(model, name, STREAMFLAGS_DONT_REMOVE);
CStreaming::LoadAllRequestedModels(false);
if (pedtype == PEDTYPE_PLAYER1) {
CPlayerPed* pPlayerPed = new(ref) CPlayerPed();
for (int i = 0; i < ARRAY_SIZE(pPlayerPed->m_nTargettableObjects); i++)
pPlayerPed->m_nTargettableObjects[i] = pBufferPlayer->m_nTargettableObjects[i];
pPlayerPed->m_fMaxStamina = pBufferPlayer->m_fMaxStamina;
pPed = pPlayerPed;
}
pPed->SetPosition(pBufferPlayer->GetPosition());
pPed->m_fHealth = pBufferPlayer->m_fHealth;
pPed->m_fArmour = pBufferPlayer->m_fArmour;
pPed->CharCreatedBy = pBufferPlayer->CharCreatedBy;
pPed->m_currentWeapon = 0;
pPed->m_maxWeaponTypeAllowed = pBufferPlayer->m_maxWeaponTypeAllowed;
for (int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++)
pPed->m_weapons[i] = pBufferPlayer->m_weapons[i];
if (pedtype == PEDTYPE_PLAYER1) {
pPed->m_wepAccuracy = 100;
CWorld::Players[0].m_pPed = (CPlayerPed*)pPed;
}
CWorld::Add(pPed);
delete[] pbuf;
#endif
}
VALIDATESAVEBUF(size)
}
#undef CopyFromBuf
#undef CopyToBuf

61
src/core/Pools.h Normal file
View file

@ -0,0 +1,61 @@
#pragma once
#include "templates.h"
#include "Lists.h"
#include "Treadable.h"
#include "Object.h"
#include "CutsceneHead.h"
#include "PlayerPed.h"
#include "Automobile.h"
#include "DummyPed.h"
#include "AudioScriptObject.h"
typedef CPool<CPtrNode> CCPtrNodePool;
typedef CPool<CEntryInfoNode> CEntryInfoNodePool;
typedef CPool<CPed,CPlayerPed> CPedPool;
typedef CPool<CVehicle,CAutomobile> CVehiclePool;
typedef CPool<CBuilding> CBuildingPool;
typedef CPool<CTreadable> CTreadablePool;
typedef CPool<CObject, CCutsceneHead> CObjectPool;
typedef CPool<CDummy, CDummyPed> CDummyPool;
typedef CPool<cAudioScriptObject> CAudioScriptObjectPool;
class CPools
{
static CCPtrNodePool *ms_pPtrNodePool;
static CEntryInfoNodePool *ms_pEntryInfoNodePool;
static CPedPool *ms_pPedPool;
static CVehiclePool *ms_pVehiclePool;
static CBuildingPool *ms_pBuildingPool;
static CTreadablePool *ms_pTreadablePool;
static CObjectPool *ms_pObjectPool;
static CDummyPool *ms_pDummyPool;
static CAudioScriptObjectPool *ms_pAudioScriptObjectPool;
public:
static CCPtrNodePool *GetPtrNodePool(void) { return ms_pPtrNodePool; }
static CEntryInfoNodePool *GetEntryInfoNodePool(void) { return ms_pEntryInfoNodePool; }
static CPedPool *GetPedPool(void) { return ms_pPedPool; }
static CVehiclePool *GetVehiclePool(void) { return ms_pVehiclePool; }
static CBuildingPool *GetBuildingPool(void) { return ms_pBuildingPool; }
static CTreadablePool *GetTreadablePool(void) { return ms_pTreadablePool; }
static CObjectPool *GetObjectPool(void) { return ms_pObjectPool; }
static CDummyPool *GetDummyPool(void) { return ms_pDummyPool; }
static CAudioScriptObjectPool *GetAudioScriptObjectPool(void) { return ms_pAudioScriptObjectPool; }
static void Initialise(void);
static void ShutDown(void);
static int32 GetPedRef(CPed *ped);
static CPed *GetPed(int32 handle);
static int32 GetVehicleRef(CVehicle *vehicle);
static CVehicle *GetVehicle(int32 handle);
static int32 GetObjectRef(CObject *object);
static CObject *GetObject(int32 handle);
static void CheckPoolsEmpty();
static void MakeSureSlotInObjectPoolIsEmpty(int32 slot);
static void LoadObjectPool(uint8 *buf, uint32 size);
static void LoadPedPool(uint8 *buf, uint32 size);
static void LoadVehiclePool(uint8 *buf, uint32 size);
static void SaveObjectPool(uint8 *buf, uint32 *size);
static void SavePedPool(uint8 *buf, uint32 *size);
static void SaveVehiclePool(uint8 *buf, uint32 *size);
};

71
src/core/Profile.cpp Normal file
View file

@ -0,0 +1,71 @@
#include "common.h"
#include "Profile.h"
#ifndef MASTER
float CProfile::ms_afStartTime[NUM_PROFILES];
float CProfile::ms_afCumulativeTime[NUM_PROFILES];
float CProfile::ms_afEndTime[NUM_PROFILES];
float CProfile::ms_afMaxEndTime[NUM_PROFILES];
float CProfile::ms_afMaxCumulativeTime[NUM_PROFILES];
Const char *CProfile::ms_pProfileString[NUM_PROFILES];
RwRGBA CProfile::ms_aBarColours[NUM_PROFILES];
void CProfile::Initialise()
{
ms_afMaxEndTime[PROFILE_FRAME_RATE] = 0.0f;
ms_afMaxEndTime[PROFILE_PHYSICS] = 0.0f;
ms_afMaxEndTime[PROFILE_COLLISION] = 0.0f;
ms_afMaxEndTime[PROFILE_PED_AI] = 0.0f;
ms_afMaxEndTime[PROFILE_PROCESSING_TIME] = 0.0f;
ms_afMaxEndTime[PROFILE_RENDERING_TIME] = 0.0f;
ms_afMaxEndTime[PROFILE_TOTAL] = 0.0f;
ms_pProfileString[PROFILE_FRAME_RATE] = "Frame rate";
ms_pProfileString[PROFILE_PHYSICS] = "Physics";
ms_pProfileString[PROFILE_COLLISION] = "Collision";
ms_pProfileString[PROFILE_PED_AI] = "Ped AI";
ms_pProfileString[PROFILE_PROCESSING_TIME] = "Processing time";
ms_pProfileString[PROFILE_RENDERING_TIME] = "Rendering time";
ms_pProfileString[PROFILE_TOTAL] = "Total";
ms_afMaxCumulativeTime[PROFILE_FRAME_RATE] = 0.0f;
ms_afMaxCumulativeTime[PROFILE_PHYSICS] = 0.0f;
ms_afMaxCumulativeTime[PROFILE_COLLISION] = 0.0f;
ms_afMaxCumulativeTime[PROFILE_PED_AI] = 0.0f;
ms_afMaxCumulativeTime[PROFILE_PROCESSING_TIME] = 0.0f;
ms_afMaxCumulativeTime[PROFILE_RENDERING_TIME] = 0.0f;
ms_afMaxCumulativeTime[PROFILE_TOTAL] = 0.0f;
ms_aBarColours[PROFILE_PHYSICS] = { 0, 127, 255, 255 };
ms_aBarColours[PROFILE_COLLISION] = { 0, 255, 255, 255 };
ms_aBarColours[PROFILE_PED_AI] = { 255, 0, 0, 255 };
ms_aBarColours[PROFILE_PROCESSING_TIME] = { 0, 255, 0, 255 };
ms_aBarColours[PROFILE_RENDERING_TIME] = { 0, 0, 255, 255 };
ms_aBarColours[PROFILE_TOTAL] = { 255, 255, 255, 255 };
}
void CProfile::SuspendProfile(eProfile profile)
{
ms_afEndTime[profile] = -ms_afStartTime[profile];
ms_afCumulativeTime[profile] -= ms_afStartTime[profile];
}
void CProfile::ShowResults()
{
ms_afMaxEndTime[PROFILE_FRAME_RATE] = Max(ms_afMaxEndTime[PROFILE_FRAME_RATE], ms_afEndTime[PROFILE_FRAME_RATE]);
ms_afMaxEndTime[PROFILE_PHYSICS] = Max(ms_afMaxEndTime[PROFILE_PHYSICS], ms_afEndTime[PROFILE_PHYSICS]);
ms_afMaxEndTime[PROFILE_COLLISION] = Max(ms_afMaxEndTime[PROFILE_COLLISION], ms_afEndTime[PROFILE_COLLISION]);
ms_afMaxEndTime[PROFILE_PED_AI] = Max(ms_afMaxEndTime[PROFILE_PED_AI], ms_afEndTime[PROFILE_PED_AI]);
ms_afMaxEndTime[PROFILE_PROCESSING_TIME] = Max(ms_afMaxEndTime[PROFILE_PROCESSING_TIME], ms_afEndTime[PROFILE_PROCESSING_TIME]);
ms_afMaxEndTime[PROFILE_RENDERING_TIME] = Max(ms_afMaxEndTime[PROFILE_RENDERING_TIME], ms_afEndTime[PROFILE_RENDERING_TIME]);
ms_afMaxEndTime[PROFILE_TOTAL] = Max(ms_afMaxEndTime[PROFILE_TOTAL], ms_afEndTime[PROFILE_TOTAL]);
ms_afMaxCumulativeTime[PROFILE_FRAME_RATE] = Max(ms_afMaxCumulativeTime[PROFILE_FRAME_RATE], ms_afCumulativeTime[PROFILE_FRAME_RATE]);
ms_afMaxCumulativeTime[PROFILE_PHYSICS] = Max(ms_afMaxCumulativeTime[PROFILE_PHYSICS], ms_afCumulativeTime[PROFILE_PHYSICS]);
ms_afMaxCumulativeTime[PROFILE_COLLISION] = Max(ms_afMaxCumulativeTime[PROFILE_COLLISION], ms_afCumulativeTime[PROFILE_COLLISION]);
ms_afMaxCumulativeTime[PROFILE_PED_AI] = Max(ms_afMaxCumulativeTime[PROFILE_PED_AI], ms_afCumulativeTime[PROFILE_PED_AI]);
ms_afMaxCumulativeTime[PROFILE_PROCESSING_TIME] = Max(ms_afMaxCumulativeTime[PROFILE_PROCESSING_TIME], ms_afCumulativeTime[PROFILE_PROCESSING_TIME]);
ms_afMaxCumulativeTime[PROFILE_RENDERING_TIME] = Max(ms_afMaxCumulativeTime[PROFILE_RENDERING_TIME], ms_afCumulativeTime[PROFILE_RENDERING_TIME]);
ms_afMaxCumulativeTime[PROFILE_TOTAL] = Max(ms_afMaxCumulativeTime[PROFILE_TOTAL], ms_afCumulativeTime[PROFILE_TOTAL]);
}
#endif

28
src/core/Profile.h Normal file
View file

@ -0,0 +1,28 @@
#pragma once
enum eProfile
{
PROFILE_FRAME_RATE,
PROFILE_PHYSICS,
PROFILE_COLLISION,
PROFILE_PED_AI,
PROFILE_PROCESSING_TIME,
PROFILE_RENDERING_TIME,
PROFILE_TOTAL,
NUM_PROFILES,
};
class CProfile
{
static float ms_afStartTime[NUM_PROFILES];
static float ms_afCumulativeTime[NUM_PROFILES];
static float ms_afEndTime[NUM_PROFILES];
static float ms_afMaxEndTime[NUM_PROFILES];
static float ms_afMaxCumulativeTime[NUM_PROFILES];
static Const char *ms_pProfileString[NUM_PROFILES];
static RwRGBA ms_aBarColours[NUM_PROFILES];
public:
static void Initialise();
static void SuspendProfile(eProfile profile);
static void ShowResults();
};

1568
src/core/Radar.cpp Normal file

File diff suppressed because it is too large Load diff

201
src/core/Radar.h Normal file
View file

@ -0,0 +1,201 @@
#pragma once
#include "Sprite2d.h"
#include "Draw.h"
enum eBlipType
{
BLIP_NONE,
BLIP_CAR,
BLIP_CHAR,
BLIP_OBJECT,
BLIP_COORD,
BLIP_CONTACT_POINT
};
enum eBlipDisplay
{
BLIP_DISPLAY_NEITHER = 0,
BLIP_DISPLAY_MARKER_ONLY = 1,
BLIP_DISPLAY_BLIP_ONLY = 2,
BLIP_DISPLAY_BOTH = 3,
};
enum eRadarSprite
{
#ifdef MENU_MAP
RADAR_SPRITE_ENTITY_BLIP = -2,
RADAR_SPRITE_COORD_BLIP = -1,
#endif
RADAR_SPRITE_NONE = 0,
RADAR_SPRITE_ASUKA,
RADAR_SPRITE_BOMB,
RADAR_SPRITE_CAT,
RADAR_SPRITE_CENTRE,
RADAR_SPRITE_COPCAR,
RADAR_SPRITE_DON,
RADAR_SPRITE_EIGHT,
RADAR_SPRITE_EL,
RADAR_SPRITE_ICE,
RADAR_SPRITE_JOEY,
RADAR_SPRITE_KENJI,
RADAR_SPRITE_LIZ,
RADAR_SPRITE_LUIGI,
RADAR_SPRITE_NORTH,
RADAR_SPRITE_RAY,
RADAR_SPRITE_SAL,
RADAR_SPRITE_SAVE,
RADAR_SPRITE_SPRAY,
RADAR_SPRITE_TONY,
RADAR_SPRITE_WEAPON,
#ifdef MENU_MAP
RADAR_SPRITE_WAYPOINT,
#endif
RADAR_SPRITE_COUNT
};
enum
{
RADAR_TRACE_RED,
RADAR_TRACE_GREEN,
RADAR_TRACE_LIGHT_BLUE,
RADAR_TRACE_GRAY,
RADAR_TRACE_YELLOW,
RADAR_TRACE_MAGENTA,
RADAR_TRACE_CYAN
};
enum
{
BLIP_MODE_TRIANGULAR_UP = 0,
BLIP_MODE_TRIANGULAR_DOWN,
BLIP_MODE_SQUARE,
};
struct sRadarTrace
{
uint32 m_nColor;
uint32 m_eBlipType; // eBlipType
int32 m_nEntityHandle;
CVector2D m_vec2DPos;
CVector m_vecPos;
uint16 m_BlipIndex;
bool m_bDim;
bool m_bInUse;
float m_Radius;
int16 m_wScale;
uint16 m_eBlipDisplay; // eBlipDisplay
uint16 m_eRadarSprite; // eRadarSprite
};
VALIDATE_SIZE(sRadarTrace, 0x30);
// Values for screen space
#define RADAR_LEFT (40.0f)
#ifdef PS2_HUD
#define RADAR_BOTTOM (44.0f)
#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)
*/
#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)
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
{
public:
static float m_radarRange;
static sRadarTrace ms_RadarTrace[NUMRADARBLIPS];
static CSprite2d AsukaSprite;
static CSprite2d BombSprite;
static CSprite2d CatSprite;
static CSprite2d CentreSprite;
static CSprite2d CopcarSprite;
static CSprite2d DonSprite;
static CSprite2d EightSprite;
static CSprite2d ElSprite;
static CSprite2d IceSprite;
static CSprite2d JoeySprite;
static CSprite2d KenjiSprite;
static CSprite2d LizSprite;
static CSprite2d LuigiSprite;
static CSprite2d NorthSprite;
static CSprite2d RaySprite;
static CSprite2d SalSprite;
static CSprite2d SaveSprite;
static CSprite2d SpraySprite;
static CSprite2d TonySprite;
static CSprite2d WeaponSprite;
static CSprite2d *RadarSprites[RADAR_SPRITE_COUNT];
static float cachedCos;
static float cachedSin;
#ifdef MENU_MAP
static CSprite2d WaypointSprite;
static int TargetMarkerId;
static CVector TargetMarkerPos;
static void InitFrontEndMap();
static void DrawYouAreHereSprite(float, float);
static void ToggleTargetMarker(float, float);
#endif
static uint8 CalculateBlipAlpha(float dist);
static void ChangeBlipBrightness(int32 i, int32 bright);
static void ChangeBlipColour(int32 i, int32);
static void ChangeBlipDisplay(int32 i, eBlipDisplay display);
static void ChangeBlipScale(int32 i, int32 scale);
static void ClearBlip(int32 i);
static void ClearBlipForEntity(eBlipType type, int32 id);
static int ClipRadarPoly(CVector2D *out, const CVector2D *in);
static bool DisplayThisBlip(int32 i);
static void Draw3dMarkers();
static void DrawBlips();
static void DrawMap();
static void DrawRadarMap();
static void DrawRadarMask();
static void DrawRadarSection(int32 x, int32 y);
static void DrawRadarSprite(uint16 sprite, float x, float y, uint8 alpha);
static void DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha);
static int32 GetActualBlipArrayIndex(int32 i);
static int32 GetNewUniqueBlipIndex(int32 i);
static uint32 GetRadarTraceColour(uint32 color, bool bright);
static void Initialise();
static float LimitRadarPoint(CVector2D &point);
static void LoadAllRadarBlips(uint8 *buf, uint32 size);
static void LoadTextures();
static void RemoveRadarSections();
static void SaveAllRadarBlips(uint8*, uint32*);
static void SetBlipSprite(int32 i, int32 icon);
static int32 SetCoordBlip(eBlipType type, CVector pos, int32, eBlipDisplay);
static int32 SetEntityBlip(eBlipType type, int32, int32, eBlipDisplay);
static void SetRadarMarkerState(int32 i, bool flag);
static void ShowRadarMarker(CVector pos, uint32 color, float radius);
static void ShowRadarTrace(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha);
static void ShowRadarTraceWithHeight(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha, uint8 mode);
static void Shutdown();
static void StreamRadarSections(const CVector &posn);
static void StreamRadarSections(int32 x, int32 y);
static void TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y);
static void TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in);
static void TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in);
static void TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in);
// no in CRadar in the game:
static void CalculateCachedSinCos();
};

28
src/core/Range2D.cpp Normal file
View file

@ -0,0 +1,28 @@
#include "common.h"
#include "Range2D.h"
#include "General.h"
CRange2D::CRange2D(CVector2D _min, CVector2D _max) : min(_min), max(_max) {}
bool
CRange2D::IsInRange(CVector2D vec)
{
return min.x < vec.x && max.x > vec.x && min.y < vec.y && max.y > vec.y;
}
void
CRange2D::DebugShowRange(float, int)
{
}
CVector2D
CRange2D::GetRandomPointInRange()
{
int distX = Abs(max.x - min.x);
int distY = Abs(max.y - min.y);
float outX = CGeneral::GetRandomNumber() % distX + min.x;
float outY = CGeneral::GetRandomNumber() % distY + min.y;
return CVector2D(outX, outY);
}

11
src/core/Range2D.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
class CRange2D
{
CVector2D min, max;
public:
CRange2D(CVector2D _min, CVector2D _max);
bool IsInRange(CVector2D vec);
void DebugShowRange(float, int);
CVector2D GetRandomPointInRange();
};

30
src/core/Range3D.cpp Normal file
View file

@ -0,0 +1,30 @@
#include "common.h"
#include "Range3D.h"
#include "General.h"
CRange3D::CRange3D(CVector _min, CVector _max) : min(_min), max(_max) {}
bool
CRange3D::IsInRange(CVector vec)
{
return min.x < vec.x && max.x > vec.x && min.y < vec.y && max.y > vec.y && min.z < vec.z && max.z > vec.z;
}
void
CRange3D::DebugShowRange(float, int)
{
}
CVector
CRange3D::GetRandomPointInRange()
{
int distX = Abs(max.x - min.x);
int distY = Abs(max.y - min.y);
int distZ = Abs(max.z - min.z);
float outX = CGeneral::GetRandomNumber() % distX + min.x;
float outY = CGeneral::GetRandomNumber() % distY + min.y;
float outZ = CGeneral::GetRandomNumber() % distZ + min.z;
return CVector(outX, outY, outZ);
}

11
src/core/Range3D.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
class CRange3D
{
CVector min, max;
public:
CRange3D(CVector _min, CVector _max);
bool IsInRange(CVector vec);
void DebugShowRange(float, int);
CVector GetRandomPointInRange();
};

126
src/core/References.cpp Normal file
View file

@ -0,0 +1,126 @@
#include "common.h"
#include "World.h"
#include "Vehicle.h"
#include "PlayerPed.h"
#include "Pools.h"
#include "References.h"
CReference CReferences::aRefs[NUMREFERENCES];
CReference *CReferences::pEmptyList;
void
CReferences::Init(void)
{
int i;
pEmptyList = &aRefs[0];
for(i = 0; i < NUMREFERENCES; i++){
aRefs[i].pentity = nil;
aRefs[i].next = &aRefs[i+1];
}
aRefs[NUMREFERENCES-1].next = nil;
}
void
CEntity::RegisterReference(CEntity **pent)
{
if(IsBuilding())
return;
CReference *ref;
// check if already registered
for(ref = m_pFirstReference; ref; ref = ref->next)
if(ref->pentity == pent)
return;
// have to allocate new reference
ref = CReferences::pEmptyList;
if(ref){
CReferences::pEmptyList = ref->next;
ref->pentity = pent;
ref->next = m_pFirstReference;
m_pFirstReference = ref;
}
}
// Clear all references to this entity
void
CEntity::ResolveReferences(void)
{
CReference *ref;
// clear pointers to this entity
for(ref = m_pFirstReference; ref; ref = ref->next)
if(*ref->pentity == this)
*ref->pentity = nil;
// free list
if(m_pFirstReference){
for(ref = m_pFirstReference; ref->next; ref = ref->next)
;
ref->next = CReferences::pEmptyList;
CReferences::pEmptyList = m_pFirstReference;
m_pFirstReference = nil;
}
}
// Free all references that no longer point to this entity
void
CEntity::PruneReferences(void)
{
CReference *ref, *next, **lastnextp;
lastnextp = &m_pFirstReference;
for(ref = m_pFirstReference; ref; ref = next){
next = ref->next;
if(*ref->pentity == this)
lastnextp = &ref->next;
else{
*lastnextp = ref->next;
ref->next = CReferences::pEmptyList;
CReferences::pEmptyList = ref;
}
}
}
void
CReferences::RemoveReferencesToPlayer(void)
{
if(FindPlayerVehicle())
FindPlayerVehicle()->ResolveReferences();
#ifdef FIX_BUGS
if (FindPlayerPed()) {
CPlayerPed* pPlayerPed = FindPlayerPed();
FindPlayerPed()->ResolveReferences();
CWorld::Players[CWorld::PlayerInFocus].m_pPed = pPlayerPed;
pPlayerPed->RegisterReference((CEntity**)&CWorld::Players[CWorld::PlayerInFocus].m_pPed);
}
#else
if(FindPlayerPed())
FindPlayerPed()->ResolveReferences();
#endif
}
void
CReferences::PruneAllReferencesInWorld(void)
{
int i;
CEntity *e;
i = CPools::GetPedPool()->GetSize();
while(--i >= 0){
e = CPools::GetPedPool()->GetSlot(i);
if(e)
e->PruneReferences();
}
i = CPools::GetVehiclePool()->GetSize();
while(--i >= 0){
e = CPools::GetVehiclePool()->GetSlot(i);
if(e)
e->PruneReferences();
}
i = CPools::GetObjectPool()->GetSize();
while(--i >= 0){
e = CPools::GetObjectPool()->GetSlot(i);
if(e)
e->PruneReferences();
}
}

20
src/core/References.h Normal file
View file

@ -0,0 +1,20 @@
#pragma once
class CEntity;
struct CReference
{
CReference *next;
CEntity **pentity;
};
class CReferences
{
public:
static CReference aRefs[NUMREFERENCES];
static CReference *pEmptyList;
static void Init(void);
static void RemoveReferencesToPlayer(void);
static void PruneAllReferencesInWorld(void);
};

420
src/core/Stats.cpp Normal file
View file

@ -0,0 +1,420 @@
#include "common.h"
#include "Stats.h"
#include "Text.h"
#include "World.h"
int32 CStats::DaysPassed;
int32 CStats::HeadsPopped;
int32 CStats::CommercialPassed;
int32 CStats::IndustrialPassed;
int32 CStats::SuburbanPassed;
int32 CStats::NumberKillFrenziesPassed;
int32 CStats::PeopleKilledByOthers;
int32 CStats::HelisDestroyed;
int32 CStats::PedsKilledOfThisType[NUM_PEDTYPES];
int32 CStats::TimesDied;
int32 CStats::TimesArrested;
int32 CStats::KillsSinceLastCheckpoint;
float CStats::DistanceTravelledInVehicle;
float CStats::DistanceTravelledOnFoot;
int32 CStats::ProgressMade;
int32 CStats::TotalProgressInGame;
int32 CStats::CarsExploded;
int32 CStats::PeopleKilledByPlayer;
float CStats::MaximumJumpDistance;
float CStats::MaximumJumpHeight;
int32 CStats::MaximumJumpFlips;
int32 CStats::MaximumJumpSpins;
int32 CStats::BestStuntJump;
int32 CStats::NumberOfUniqueJumpsFound;
int32 CStats::TotalNumberOfUniqueJumps;
int32 CStats::PassengersDroppedOffWithTaxi;
int32 CStats::MoneyMadeWithTaxi;
int32 CStats::MissionsGiven;
int32 CStats::MissionsPassed;
char CStats::LastMissionPassedName[8];
int32 CStats::TotalLegitimateKills;
int32 CStats::ElBurroTime;
int32 CStats::Record4x4One;
int32 CStats::Record4x4Two;
int32 CStats::Record4x4Three;
int32 CStats::Record4x4Mayhem;
int32 CStats::LivesSavedWithAmbulance;
int32 CStats::CriminalsCaught;
int32 CStats::HighestLevelAmbulanceMission;
int32 CStats::FiresExtinguished;
int32 CStats::LongestFlightInDodo;
int32 CStats::TimeTakenDefuseMission;
int32 CStats::TotalNumberKillFrenzies;
int32 CStats::TotalNumberMissions;
int32 CStats::RoundsFiredByPlayer;
int32 CStats::KgsOfExplosivesUsed;
int32 CStats::InstantHitsFiredByPlayer;
int32 CStats::InstantHitsHitByPlayer;
int32 CStats::BestTimeBombDefusal;
int32 CStats::mmRain;
int32 CStats::CarsCrushed;
int32 CStats::FastestTimes[CStats::TOTAL_FASTEST_TIMES];
int32 CStats::HighestScores[CStats::TOTAL_HIGHEST_SCORES];
void CStats::Init()
{
PeopleKilledByOthers = 0;
PeopleKilledByPlayer = 0;
RoundsFiredByPlayer = 0;
CarsExploded = 0;
HelisDestroyed = 0;
ProgressMade = 0;
KgsOfExplosivesUsed = 0;
InstantHitsFiredByPlayer = 0;
InstantHitsHitByPlayer = 0;
CarsCrushed = 0;
HeadsPopped = 0;
TimesArrested = 0;
TimesDied = 0;
DaysPassed = 0;
NumberOfUniqueJumpsFound = 0;
mmRain = 0;
MaximumJumpFlips = 0;
MaximumJumpSpins = 0;
MaximumJumpDistance = 0;
MaximumJumpHeight = 0;
BestStuntJump = 0;
TotalNumberOfUniqueJumps = 0;
Record4x4One = 0;
LongestFlightInDodo = 0;
Record4x4Two = 0;
PassengersDroppedOffWithTaxi = 0;
Record4x4Three = 0;
MoneyMadeWithTaxi = 0;
Record4x4Mayhem = 0;
LivesSavedWithAmbulance = 0;
ElBurroTime = 0;
CriminalsCaught = 0;
MissionsGiven = 0;
HighestLevelAmbulanceMission = 0;
MissionsPassed = 0;
FiresExtinguished = 0;
DistanceTravelledOnFoot = 0;
TimeTakenDefuseMission = 0;
NumberKillFrenziesPassed = 0;
DistanceTravelledInVehicle = 0;
TotalNumberKillFrenzies = 0;
TotalNumberMissions = 0;
KillsSinceLastCheckpoint = 0;
TotalLegitimateKills = 0;
for (int i = 0; i < TOTAL_FASTEST_TIMES; i++)
FastestTimes[i] = 0;
for (int i = 0; i < TOTAL_HIGHEST_SCORES; i++)
HighestScores[i] = 0;
for (int i = 0; i < NUM_PEDTYPES; i++)
PedsKilledOfThisType[i] = 0;
IndustrialPassed = 0;
CommercialPassed = 0;
SuburbanPassed = 0;
}
void CStats::RegisterFastestTime(int32 index, int32 time)
{
assert(index >= 0 && index < TOTAL_FASTEST_TIMES);
if (FastestTimes[index] == 0)
FastestTimes[index] = time;
else
FastestTimes[index] = Min(FastestTimes[index], time);
}
void CStats::RegisterHighestScore(int32 index, int32 score)
{
assert(index >= 0 && index < TOTAL_HIGHEST_SCORES);
HighestScores[index] = Max(HighestScores[index], score);
}
void CStats::RegisterElBurroTime(int32 time)
{
ElBurroTime = (ElBurroTime && ElBurroTime < time) ? ElBurroTime : time;
}
void CStats::Register4x4OneTime(int32 time)
{
Record4x4One = (Record4x4One && Record4x4One < time) ? Record4x4One : time;
}
void CStats::Register4x4TwoTime(int32 time)
{
Record4x4Two = (Record4x4Two && Record4x4Two < time) ? Record4x4Two : time;
}
void CStats::Register4x4ThreeTime(int32 time)
{
Record4x4Three = (Record4x4Three && Record4x4Three < time) ? Record4x4Three : time;
}
void CStats::Register4x4MayhemTime(int32 time)
{
Record4x4Mayhem = (Record4x4Mayhem && Record4x4Mayhem < time) ? Record4x4Mayhem : time;
}
void CStats::AnotherLifeSavedWithAmbulance()
{
++LivesSavedWithAmbulance;
}
void CStats::AnotherCriminalCaught()
{
++CriminalsCaught;
}
void CStats::RegisterLevelAmbulanceMission(int32 level)
{
HighestLevelAmbulanceMission = Max(HighestLevelAmbulanceMission, level);
}
void CStats::AnotherFireExtinguished()
{
++FiresExtinguished;
}
void CStats::RegisterLongestFlightInDodo(int32 time)
{
LongestFlightInDodo = Max(LongestFlightInDodo, time);
}
void CStats::RegisterTimeTakenDefuseMission(int32 time)
{
TimeTakenDefuseMission = (TimeTakenDefuseMission && TimeTakenDefuseMission < time) ? TimeTakenDefuseMission : time;
}
void CStats::AnotherKillFrenzyPassed()
{
++NumberKillFrenziesPassed;
}
void CStats::SetTotalNumberKillFrenzies(int32 total)
{
TotalNumberKillFrenzies = total;
}
void CStats::SetTotalNumberMissions(int32 total)
{
TotalNumberMissions = total;
}
wchar *CStats::FindCriminalRatingString()
{
int rating = FindCriminalRatingNumber();
if (rating < 10) return TheText.Get("RATNG1");
if (rating < 25) return TheText.Get("RATNG2");
if (rating < 70) return TheText.Get("RATNG3");
if (rating < 150) return TheText.Get("RATNG4");
if (rating < 250) return TheText.Get("RATNG5");
if (rating < 450) return TheText.Get("RATNG6");
if (rating < 700) return TheText.Get("RATNG7");
if (rating < 1000) return TheText.Get("RATNG8");
if (rating < 1400) return TheText.Get("RATNG9");
if (rating < 1900) return TheText.Get("RATNG10");
if (rating < 2500) return TheText.Get("RATNG11");
if (rating < 3200) return TheText.Get("RATNG12");
if (rating < 4000) return TheText.Get("RATNG13");
if (rating < 5000) return TheText.Get("RATNG14");
return TheText.Get("RATNG15");
}
int32 CStats::FindCriminalRatingNumber()
{
int32 rating;
rating = FiresExtinguished + 10 * HighestLevelAmbulanceMission + CriminalsCaught + LivesSavedWithAmbulance
+ 30 * HelisDestroyed + TotalLegitimateKills - 3 * TimesArrested - 3 * TimesDied
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney / 5000;
if (rating <= 0) rating = 0;
if (InstantHitsFiredByPlayer > 100)
rating += (float)CStats::InstantHitsHitByPlayer / (float)CStats::InstantHitsFiredByPlayer * 500.0f;
if (TotalProgressInGame)
rating += (float)CStats::ProgressMade / (float)CStats::TotalProgressInGame * 1000.0f;
if (!IndustrialPassed && rating >= 3521)
rating = 3521;
if (!CommercialPassed && rating >= 4552)
rating = 4552;
return rating;
}
void CStats::SaveStats(uint8 *buf, uint32 *size)
{
CheckPointReachedSuccessfully();
uint8 *buf_start = buf;
*size = sizeof(PeopleKilledByPlayer) +
sizeof(PeopleKilledByOthers) +
sizeof(CarsExploded) +
sizeof(RoundsFiredByPlayer) +
sizeof(PedsKilledOfThisType) +
sizeof(HelisDestroyed) +
sizeof(ProgressMade) +
sizeof(TotalProgressInGame) +
sizeof(KgsOfExplosivesUsed) +
sizeof(InstantHitsFiredByPlayer) +
sizeof(InstantHitsHitByPlayer) +
sizeof(CarsCrushed) +
sizeof(HeadsPopped) +
sizeof(TimesArrested) +
sizeof(TimesDied) +
sizeof(DaysPassed) +
sizeof(mmRain) +
sizeof(MaximumJumpDistance) +
sizeof(MaximumJumpHeight) +
sizeof(MaximumJumpFlips) +
sizeof(MaximumJumpSpins) +
sizeof(BestStuntJump) +
sizeof(NumberOfUniqueJumpsFound) +
sizeof(TotalNumberOfUniqueJumps) +
sizeof(MissionsGiven) +
sizeof(MissionsPassed) +
sizeof(PassengersDroppedOffWithTaxi) +
sizeof(MoneyMadeWithTaxi) +
sizeof(IndustrialPassed) +
sizeof(CommercialPassed) +
sizeof(SuburbanPassed) +
sizeof(ElBurroTime) +
sizeof(DistanceTravelledOnFoot) +
sizeof(DistanceTravelledInVehicle) +
sizeof(Record4x4One) +
sizeof(Record4x4Two) +
sizeof(Record4x4Three) +
sizeof(Record4x4Mayhem) +
sizeof(LivesSavedWithAmbulance) +
sizeof(CriminalsCaught) +
sizeof(HighestLevelAmbulanceMission) +
sizeof(FiresExtinguished) +
sizeof(LongestFlightInDodo) +
sizeof(TimeTakenDefuseMission) +
sizeof(NumberKillFrenziesPassed) +
sizeof(TotalNumberKillFrenzies) +
sizeof(TotalNumberMissions) +
sizeof(FastestTimes) +
sizeof(HighestScores) +
sizeof(KillsSinceLastCheckpoint) +
sizeof(TotalLegitimateKills) +
sizeof(LastMissionPassedName);
#define CopyToBuf(buf, data) memcpy(buf, &data, sizeof(data)); buf += sizeof(data);
CopyToBuf(buf, PeopleKilledByPlayer);
CopyToBuf(buf, PeopleKilledByOthers);
CopyToBuf(buf, CarsExploded);
CopyToBuf(buf, RoundsFiredByPlayer);
CopyToBuf(buf, PedsKilledOfThisType);
CopyToBuf(buf, HelisDestroyed);
CopyToBuf(buf, ProgressMade);
CopyToBuf(buf, TotalProgressInGame);
CopyToBuf(buf, KgsOfExplosivesUsed);
CopyToBuf(buf, InstantHitsFiredByPlayer);
CopyToBuf(buf, InstantHitsHitByPlayer);
CopyToBuf(buf, CarsCrushed);
CopyToBuf(buf, HeadsPopped);
CopyToBuf(buf, TimesArrested);
CopyToBuf(buf, TimesDied);
CopyToBuf(buf, DaysPassed);
CopyToBuf(buf, mmRain);
CopyToBuf(buf, MaximumJumpDistance);
CopyToBuf(buf, MaximumJumpHeight);
CopyToBuf(buf, MaximumJumpFlips);
CopyToBuf(buf, MaximumJumpSpins);
CopyToBuf(buf, BestStuntJump);
CopyToBuf(buf, NumberOfUniqueJumpsFound);
CopyToBuf(buf, TotalNumberOfUniqueJumps);
CopyToBuf(buf, MissionsGiven);
CopyToBuf(buf, MissionsPassed);
CopyToBuf(buf, PassengersDroppedOffWithTaxi);
CopyToBuf(buf, MoneyMadeWithTaxi);
CopyToBuf(buf, IndustrialPassed);
CopyToBuf(buf, CommercialPassed);
CopyToBuf(buf, SuburbanPassed);
CopyToBuf(buf, ElBurroTime);
CopyToBuf(buf, DistanceTravelledOnFoot);
CopyToBuf(buf, DistanceTravelledInVehicle);
CopyToBuf(buf, Record4x4One);
CopyToBuf(buf, Record4x4Two);
CopyToBuf(buf, Record4x4Three);
CopyToBuf(buf, Record4x4Mayhem);
CopyToBuf(buf, LivesSavedWithAmbulance);
CopyToBuf(buf, CriminalsCaught);
CopyToBuf(buf, HighestLevelAmbulanceMission);
CopyToBuf(buf, FiresExtinguished);
CopyToBuf(buf, LongestFlightInDodo);
CopyToBuf(buf, TimeTakenDefuseMission);
CopyToBuf(buf, NumberKillFrenziesPassed);
CopyToBuf(buf, TotalNumberKillFrenzies);
CopyToBuf(buf, TotalNumberMissions);
CopyToBuf(buf, FastestTimes);
CopyToBuf(buf, HighestScores);
CopyToBuf(buf, KillsSinceLastCheckpoint);
CopyToBuf(buf, TotalLegitimateKills);
CopyToBuf(buf, LastMissionPassedName);
assert(buf - buf_start == *size);
#undef CopyToBuf
}
void CStats::LoadStats(uint8 *buf, uint32 size)
{
uint8* buf_start = buf;
#define CopyFromBuf(buf, data) memcpy(&data, buf, sizeof(data)); buf += sizeof(data);
CopyFromBuf(buf, PeopleKilledByPlayer);
CopyFromBuf(buf, PeopleKilledByOthers);
CopyFromBuf(buf, CarsExploded);
CopyFromBuf(buf, RoundsFiredByPlayer);
CopyFromBuf(buf, PedsKilledOfThisType);
CopyFromBuf(buf, HelisDestroyed);
CopyFromBuf(buf, ProgressMade);
CopyFromBuf(buf, TotalProgressInGame);
CopyFromBuf(buf, KgsOfExplosivesUsed);
CopyFromBuf(buf, InstantHitsFiredByPlayer);
CopyFromBuf(buf, InstantHitsHitByPlayer);
CopyFromBuf(buf, CarsCrushed);
CopyFromBuf(buf, HeadsPopped);
CopyFromBuf(buf, TimesArrested);
CopyFromBuf(buf, TimesDied);
CopyFromBuf(buf, DaysPassed);
CopyFromBuf(buf, mmRain);
CopyFromBuf(buf, MaximumJumpDistance);
CopyFromBuf(buf, MaximumJumpHeight);
CopyFromBuf(buf, MaximumJumpFlips);
CopyFromBuf(buf, MaximumJumpSpins);
CopyFromBuf(buf, BestStuntJump);
CopyFromBuf(buf, NumberOfUniqueJumpsFound);
CopyFromBuf(buf, TotalNumberOfUniqueJumps);
CopyFromBuf(buf, MissionsGiven);
CopyFromBuf(buf, MissionsPassed);
CopyFromBuf(buf, PassengersDroppedOffWithTaxi);
CopyFromBuf(buf, MoneyMadeWithTaxi);
CopyFromBuf(buf, IndustrialPassed);
CopyFromBuf(buf, CommercialPassed);
CopyFromBuf(buf, SuburbanPassed);
CopyFromBuf(buf, ElBurroTime);
CopyFromBuf(buf, DistanceTravelledOnFoot);
CopyFromBuf(buf, DistanceTravelledInVehicle);
CopyFromBuf(buf, Record4x4One);
CopyFromBuf(buf, Record4x4Two);
CopyFromBuf(buf, Record4x4Three);
CopyFromBuf(buf, Record4x4Mayhem);
CopyFromBuf(buf, LivesSavedWithAmbulance);
CopyFromBuf(buf, CriminalsCaught);
CopyFromBuf(buf, HighestLevelAmbulanceMission);
CopyFromBuf(buf, FiresExtinguished);
CopyFromBuf(buf, LongestFlightInDodo);
CopyFromBuf(buf, TimeTakenDefuseMission);
CopyFromBuf(buf, NumberKillFrenziesPassed);
CopyFromBuf(buf, TotalNumberKillFrenzies);
CopyFromBuf(buf, TotalNumberMissions);
CopyFromBuf(buf, FastestTimes);
CopyFromBuf(buf, HighestScores);
CopyFromBuf(buf, KillsSinceLastCheckpoint);
CopyFromBuf(buf, TotalLegitimateKills);
CopyFromBuf(buf, LastMissionPassedName);
assert(buf - buf_start == size);
#undef CopyFromBuf
}

90
src/core/Stats.h Normal file
View file

@ -0,0 +1,90 @@
#pragma once
#include "PedType.h"
class CStats
{
public:
enum {
TOTAL_FASTEST_TIMES = 16,
TOTAL_HIGHEST_SCORES = 16
};
static int32 DaysPassed;
static int32 HeadsPopped;
static int32 CommercialPassed;
static int32 IndustrialPassed;
static int32 SuburbanPassed;
static int32 NumberKillFrenziesPassed;
static int32 PeopleKilledByOthers;
static int32 HelisDestroyed;
static int32 PedsKilledOfThisType[NUM_PEDTYPES];
static int32 TimesDied;
static int32 TimesArrested;
static int32 KillsSinceLastCheckpoint;
static float DistanceTravelledInVehicle;
static float DistanceTravelledOnFoot;
static int32 CarsExploded;
static int32 PeopleKilledByPlayer;
static int32 ProgressMade;
static int32 TotalProgressInGame;
static float MaximumJumpDistance;
static float MaximumJumpHeight;
static int32 MaximumJumpFlips;
static int32 MaximumJumpSpins;
static int32 BestStuntJump;
static int32 NumberOfUniqueJumpsFound;
static int32 TotalNumberOfUniqueJumps;
static int32 PassengersDroppedOffWithTaxi;
static int32 MoneyMadeWithTaxi;
static int32 MissionsGiven;
static int32 MissionsPassed;
static char LastMissionPassedName[8];
static int32 TotalLegitimateKills;
static int32 ElBurroTime;
static int32 Record4x4One;
static int32 Record4x4Two;
static int32 Record4x4Three;
static int32 Record4x4Mayhem;
static int32 LivesSavedWithAmbulance;
static int32 CriminalsCaught;
static int32 HighestLevelAmbulanceMission;
static int32 FiresExtinguished;
static int32 LongestFlightInDodo;
static int32 TimeTakenDefuseMission;
static int32 TotalNumberKillFrenzies;
static int32 TotalNumberMissions;
static int32 RoundsFiredByPlayer;
static int32 KgsOfExplosivesUsed;
static int32 InstantHitsFiredByPlayer;
static int32 InstantHitsHitByPlayer;
static int32 BestTimeBombDefusal;
static int32 mmRain;
static int32 CarsCrushed;
static int32 FastestTimes[TOTAL_FASTEST_TIMES];
static int32 HighestScores[TOTAL_HIGHEST_SCORES];
public:
static void Init(void);
static void RegisterFastestTime(int32, int32);
static void RegisterHighestScore(int32, int32);
static void RegisterElBurroTime(int32);
static void Register4x4OneTime(int32);
static void Register4x4TwoTime(int32);
static void Register4x4ThreeTime(int32);
static void Register4x4MayhemTime(int32);
static void AnotherLifeSavedWithAmbulance();
static void AnotherCriminalCaught();
static void RegisterLevelAmbulanceMission(int32);
static void AnotherFireExtinguished();
static wchar *FindCriminalRatingString();
static void RegisterLongestFlightInDodo(int32);
static void RegisterTimeTakenDefuseMission(int32);
static void AnotherKillFrenzyPassed();
static void SetTotalNumberKillFrenzies(int32);
static void SetTotalNumberMissions(int32);
static void CheckPointReachedSuccessfully() { TotalLegitimateKills += KillsSinceLastCheckpoint; KillsSinceLastCheckpoint = 0; };
static void CheckPointReachedUnsuccessfully() { KillsSinceLastCheckpoint = 0; };
static int32 FindCriminalRatingNumber();
static void SaveStats(uint8 *buf, uint32 *size);
static void LoadStats(uint8 *buf, uint32 size);
};

2831
src/core/Streaming.cpp Normal file

File diff suppressed because it is too large Load diff

197
src/core/Streaming.h Normal file
View file

@ -0,0 +1,197 @@
#pragma once
#include "Game.h"
enum {
STREAM_OFFSET_TXD = MODELINFOSIZE,
NUMSTREAMINFO = STREAM_OFFSET_TXD+TXDSTORESIZE
};
enum StreamFlags
{
STREAMFLAGS_DONT_REMOVE = 0x01,
STREAMFLAGS_SCRIPTOWNED = 0x02,
STREAMFLAGS_DEPENDENCY = 0x04, // Is this right?
STREAMFLAGS_PRIORITY = 0x08,
STREAMFLAGS_NOFADE = 0x10,
STREAMFLAGS_CANT_REMOVE = STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_SCRIPTOWNED,
STREAMFLAGS_KEEP_IN_MEMORY = STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_SCRIPTOWNED|STREAMFLAGS_DEPENDENCY,
};
enum StreamLoadState
{
STREAMSTATE_NOTLOADED = 0,
STREAMSTATE_LOADED = 1,
STREAMSTATE_INQUEUE = 2,
STREAMSTATE_READING = 3, // channel is reading
STREAMSTATE_STARTED = 4, // first part loaded
};
enum ChannelState
{
CHANNELSTATE_IDLE = 0,
CHANNELSTATE_READING = 1,
CHANNELSTATE_STARTED = 2,
CHANNELSTATE_ERROR = 3,
};
class CStreamingInfo
{
public:
CStreamingInfo *m_next;
CStreamingInfo *m_prev;
uint8 m_loadState;
uint8 m_flags;
int16 m_nextID;
uint32 m_position;
uint32 m_size;
bool GetCdPosnAndSize(uint32 &posn, uint32 &size);
void SetCdPosnAndSize(uint32 posn, uint32 size);
void AddToList(CStreamingInfo *link);
void RemoveFromList(void);
uint32 GetCdSize(void) { return m_size; }
bool IsPriority(void) { return !!(m_flags & STREAMFLAGS_PRIORITY); }
};
struct CStreamingChannel
{
int32 streamIds[4];
int32 offsets[4];
int32 state;
int32 field24;
int32 position;
int32 size;
int32 numTries;
int32 status; // from CdStream
};
class CDirectory;
class CPtrList;
class CStreaming
{
public:
static bool ms_disableStreaming;
static bool ms_bLoadingBigModel;
static int32 ms_numModelsRequested;
static CStreamingInfo ms_aInfoForModel[NUMSTREAMINFO];
static CStreamingInfo ms_startLoadedList;
static CStreamingInfo ms_endLoadedList;
static CStreamingInfo ms_startRequestedList;
static CStreamingInfo ms_endRequestedList;
static int32 ms_oldSectorX;
static int32 ms_oldSectorY;
static int32 ms_streamingBufferSize;
#ifndef ONE_THREAD_PER_CHANNEL
static int8 *ms_pStreamingBuffer[2];
#else
static int8 *ms_pStreamingBuffer[4];
#endif
static size_t ms_memoryUsed;
static CStreamingChannel ms_channel[2];
static int32 ms_channelError;
static int32 ms_numVehiclesLoaded;
static int32 ms_vehiclesLoaded[MAXVEHICLESLOADED];
static int32 ms_lastVehicleDeleted;
static CDirectory *ms_pExtraObjectsDir;
static int32 ms_numPriorityRequests;
static bool ms_hasLoadedLODs;
static int32 ms_currentPedGrp;
static int32 ms_lastCullZone;
static uint16 ms_loadedGangs;
static uint16 ms_loadedGangCars;
static int32 ms_currentPedLoading;
static int32 ms_imageOffsets[NUMCDIMAGES];
static int32 ms_lastImageRead;
static int32 ms_imageSize;
static size_t ms_memoryAvailable;
static void Init(void);
static void Init2(void);
static void Shutdown(void);
static void Update(void);
static void LoadCdDirectory(void);
static void LoadCdDirectory(const char *dirname, int32 n);
static bool ConvertBufferToObject(int8 *buf, int32 streamId);
static bool FinishLoadingLargeFile(int8 *buf, int32 streamId);
static bool HasModelLoaded(int32 id) { return ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED; }
static bool HasTxdLoaded(int32 id) { return HasModelLoaded(id+STREAM_OFFSET_TXD); }
static bool CanRemoveModel(int32 id) { return (ms_aInfoForModel[id].m_flags & STREAMFLAGS_CANT_REMOVE) == 0; }
static bool CanRemoveTxd(int32 id) { return CanRemoveModel(id+STREAM_OFFSET_TXD); }
static void RequestModel(int32 model, int32 flags);
static void ReRequestModel(int32 model) { RequestModel(model, ms_aInfoForModel[model].m_flags); }
static void RequestTxd(int32 txd, int32 flags) { RequestModel(txd + STREAM_OFFSET_TXD, flags); }
static void ReRequestTxd(int32 txd) { ReRequestModel(txd + STREAM_OFFSET_TXD); }
static void RequestSubway(void);
static void RequestBigBuildings(eLevelName level);
static void RequestIslands(eLevelName level);
static void RequestSpecialModel(int32 modelId, const char *modelName, int32 flags);
static void RequestSpecialChar(int32 charId, const char *modelName, int32 flags);
static bool HasSpecialCharLoaded(int32 id);
static void SetMissionDoesntRequireSpecialChar(int32 id);
static void DecrementRef(int32 id);
static void RemoveModel(int32 id);
static void RemoveTxd(int32 id) { RemoveModel(id + STREAM_OFFSET_TXD); }
static void RemoveUnusedBuildings(eLevelName level);
static void RemoveBuildings(eLevelName level);
static void RemoveUnusedBigBuildings(eLevelName level);
static void RemoveIslandsNotUsed(eLevelName level);
static void RemoveBigBuildings(eLevelName level);
static bool RemoveLoadedVehicle(void);
static bool RemoveLeastUsedModel(void);
static void RemoveAllUnusedModels(void);
static void RemoveUnusedModelsInLoadedList(void);
static bool RemoveReferencedTxds(size_t mem); // originally signed
static int32 GetAvailableVehicleSlot(void);
static bool IsTxdUsedByRequestedModels(int32 txdId);
static bool AddToLoadedVehiclesList(int32 modelId);
static bool IsObjectInCdImage(int32 id);
static void HaveAllBigBuildingsLoaded(eLevelName level);
static void SetModelIsDeletable(int32 id);
static void SetModelTxdIsDeletable(int32 id);
static void SetMissionDoesntRequireModel(int32 id);
static void LoadInitialPeds(void);
static void LoadInitialVehicles(void);
static void StreamVehiclesAndPeds(void);
static void StreamZoneModels(const CVector &pos);
static void RemoveCurrentZonesModels(void);
static int32 GetCdImageOffset(int32 lastPosn);
static int32 GetNextFileOnCd(int32 position, bool priority);
static void RequestModelStream(int32 ch);
static bool ProcessLoadingChannel(int32 ch);
static void RetryLoadFile(int32 ch);
static void LoadRequestedModels(void);
static void LoadAllRequestedModels(bool priority);
static void FlushChannels(void);
static void FlushRequestList(void);
static void MakeSpaceFor(int32 size);
static void ImGonnaUseStreamingMemory(void);
static void IHaveUsedStreamingMemory(void);
static void UpdateMemoryUsed(void);
static void AddModelsToRequestList(const CVector &pos);
static void ProcessEntitiesInSectorList(CPtrList &list, float x, float y, float xmin, float ymin, float xmax, float ymax);
static void ProcessEntitiesInSectorList(CPtrList &list);
static void DeleteFarAwayRwObjects(const CVector &pos);
static void DeleteAllRwObjects(void);
static void DeleteRwObjectsAfterDeath(const CVector &pos);
static void DeleteRwObjectsBehindCamera(size_t mem); // originally signed
static void DeleteRwObjectsInSectorList(CPtrList &list);
static void DeleteRwObjectsInOverlapSectorList(CPtrList &list, int32 x, int32 y);
static bool DeleteRwObjectsBehindCameraInSectorList(CPtrList &list, size_t mem); // originally signed
static bool DeleteRwObjectsNotInFrustumInSectorList(CPtrList &list, size_t mem); // originally signed
static void LoadScene(const CVector &pos);
static void MemoryCardSave(uint8 *buffer, uint32 *length);
static void MemoryCardLoad(uint8 *buffer, uint32 length);
static void UpdateForAnimViewer(void);
static void PrintStreamingBufferState();
};

143
src/core/SurfaceTable.cpp Normal file
View file

@ -0,0 +1,143 @@
#include "common.h"
#include "main.h"
#include "FileMgr.h"
#include "Weather.h"
#include "Collision.h"
#include "SurfaceTable.h"
float CSurfaceTable::ms_aAdhesiveLimitTable[NUMADHESIVEGROUPS][NUMADHESIVEGROUPS];
void
CSurfaceTable::Initialise(Const char *filename)
{
int lineno, fieldno;
char *line;
char surfname[256];
float adhesiveLimit;
CFileMgr::SetDir("");
CFileMgr::LoadFile(filename, work_buff, sizeof(work_buff), "r");
line = (char*)work_buff;
for(lineno = 0; lineno < NUMADHESIVEGROUPS; lineno++){
// skip white space and comments
while(*line == ' ' || *line == '\t' || *line == '\n' || *line == '\r' || *line == ';'){
if(*line == ';'){
while(*line != '\n' && *line != '\r')
line++;
}else
line++;
}
sscanf(line, "%s", surfname);
// skip what we just read
while(!(*line == ' ' || *line == '\t' || *line == ','))
line++;
for(fieldno = 0; fieldno <= lineno; fieldno++){
// skip white space
while(*line == ' ' || *line == '\t' || *line == ',')
line++;
adhesiveLimit = 0.0f;
if(*line != '-')
sscanf(line, "%f", &adhesiveLimit);
// skip what we just read
while(!(*line == ' ' || *line == '\t' || *line == ',' || *line == '\n'))
line++;
ms_aAdhesiveLimitTable[lineno][fieldno] = adhesiveLimit;
ms_aAdhesiveLimitTable[fieldno][lineno] = adhesiveLimit;
}
}
}
int
CSurfaceTable::GetAdhesionGroup(uint8 surfaceType)
{
switch(surfaceType){
case SURFACE_DEFAULT: return ADHESIVE_ROAD;
case SURFACE_TARMAC: return ADHESIVE_ROAD;
case SURFACE_GRASS: return ADHESIVE_LOOSE;
case SURFACE_GRAVEL: return ADHESIVE_LOOSE;
case SURFACE_MUD_DRY: return ADHESIVE_HARD;
case SURFACE_PAVEMENT: return ADHESIVE_ROAD;
case SURFACE_CAR: return ADHESIVE_HARD;
case SURFACE_GLASS: return ADHESIVE_HARD;
case SURFACE_TRANSPARENT_CLOTH: return ADHESIVE_HARD;
case SURFACE_GARAGE_DOOR: return ADHESIVE_HARD;
case SURFACE_CAR_PANEL: return ADHESIVE_HARD;
case SURFACE_THICK_METAL_PLATE: return ADHESIVE_HARD;
case SURFACE_SCAFFOLD_POLE: return ADHESIVE_HARD;
case SURFACE_LAMP_POST: return ADHESIVE_HARD;
case SURFACE_FIRE_HYDRANT: return ADHESIVE_HARD;
case SURFACE_GIRDER: return ADHESIVE_HARD;
case SURFACE_METAL_CHAIN_FENCE: return ADHESIVE_HARD;
case SURFACE_PED: return ADHESIVE_RUBBER;
case SURFACE_SAND: return ADHESIVE_LOOSE;
case SURFACE_WATER: return ADHESIVE_WET;
case SURFACE_WOOD_CRATES: return ADHESIVE_ROAD;
case SURFACE_WOOD_BENCH: return ADHESIVE_ROAD;
case SURFACE_WOOD_SOLID: return ADHESIVE_ROAD;
case SURFACE_RUBBER: return ADHESIVE_RUBBER;
case SURFACE_PLASTIC: return ADHESIVE_HARD;
case SURFACE_HEDGE: return ADHESIVE_LOOSE;
case SURFACE_STEEP_CLIFF: return ADHESIVE_LOOSE;
case SURFACE_CONTAINER: return ADHESIVE_HARD;
case SURFACE_NEWS_VENDOR: return ADHESIVE_HARD;
case SURFACE_WHEELBASE: return ADHESIVE_RUBBER;
case SURFACE_CARDBOARDBOX: return ADHESIVE_LOOSE;
case SURFACE_TRANSPARENT_STONE: return ADHESIVE_HARD;
case SURFACE_METAL_GATE: return ADHESIVE_HARD;
default: return ADHESIVE_ROAD;
}
}
float
CSurfaceTable::GetWetMultiplier(uint8 surfaceType)
{
switch(surfaceType){
case SURFACE_DEFAULT:
case SURFACE_TARMAC:
case SURFACE_MUD_DRY:
case SURFACE_PAVEMENT:
case SURFACE_TRANSPARENT_CLOTH:
case SURFACE_WOOD_CRATES:
case SURFACE_WOOD_BENCH:
case SURFACE_WOOD_SOLID:
case SURFACE_HEDGE:
case SURFACE_CARDBOARDBOX:
case SURFACE_TRANSPARENT_STONE:
return 1.0f - CWeather::WetRoads*0.25f;
case SURFACE_GRASS:
case SURFACE_CAR:
case SURFACE_GLASS:
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_PED:
case SURFACE_RUBBER:
case SURFACE_PLASTIC:
case SURFACE_STEEP_CLIFF:
case SURFACE_CONTAINER:
case SURFACE_NEWS_VENDOR:
case SURFACE_WHEELBASE:
case SURFACE_METAL_GATE:
return 1.0f - CWeather::WetRoads*0.4f;
default:
return 1.0f;
}
}
float
CSurfaceTable::GetAdhesiveLimit(CColPoint &colpoint)
{
return ms_aAdhesiveLimitTable[GetAdhesionGroup(colpoint.surfaceB)][GetAdhesionGroup(colpoint.surfaceA)];
}

80
src/core/SurfaceTable.h Normal file
View file

@ -0,0 +1,80 @@
#pragma once
enum eSurfaceType
{
SURFACE_DEFAULT,
SURFACE_TARMAC,
SURFACE_GRASS,
SURFACE_GRAVEL,
SURFACE_MUD_DRY,
SURFACE_PAVEMENT,
SURFACE_CAR,
SURFACE_GLASS,
SURFACE_TRANSPARENT_CLOTH,
SURFACE_GARAGE_DOOR,
SURFACE_CAR_PANEL,
SURFACE_THICK_METAL_PLATE,
SURFACE_SCAFFOLD_POLE,
SURFACE_LAMP_POST,
SURFACE_FIRE_HYDRANT,
SURFACE_GIRDER,
SURFACE_METAL_CHAIN_FENCE,
SURFACE_PED,
SURFACE_SAND,
SURFACE_WATER,
SURFACE_WOOD_CRATES,
SURFACE_WOOD_BENCH,
SURFACE_WOOD_SOLID,
SURFACE_RUBBER,
SURFACE_PLASTIC,
SURFACE_HEDGE,
SURFACE_STEEP_CLIFF,
SURFACE_CONTAINER,
SURFACE_NEWS_VENDOR,
SURFACE_WHEELBASE,
SURFACE_CARDBOARDBOX,
SURFACE_TRANSPARENT_STONE,
SURFACE_METAL_GATE,
// These are illegal
SURFACE_SAND_BEACH,
SURFACE_CONCRETE_BEACH,
};
enum
{
ADHESIVE_RUBBER,
ADHESIVE_HARD,
ADHESIVE_ROAD,
ADHESIVE_LOOSE,
ADHESIVE_WET,
NUMADHESIVEGROUPS
};
struct CColPoint;
inline bool
IsSeeThrough(uint8 surfType)
{
switch(surfType)
case SURFACE_GLASS:
case SURFACE_TRANSPARENT_CLOTH:
#if defined(FIX_BUGS) || defined(GTA_PS2)
case SURFACE_METAL_CHAIN_FENCE:
case SURFACE_TRANSPARENT_STONE:
case SURFACE_SCAFFOLD_POLE:
#endif
return true;
return false;
}
class CSurfaceTable
{
static float ms_aAdhesiveLimitTable[NUMADHESIVEGROUPS][NUMADHESIVEGROUPS];
public:
static void Initialise(Const char *filename);
static int GetAdhesionGroup(uint8 surfaceType);
static float GetWetMultiplier(uint8 surfaceType);
static float GetAdhesiveLimit(CColPoint &colpoint);
};

5
src/core/TimeStep.cpp Normal file
View file

@ -0,0 +1,5 @@
#include "TimeStep.h"
float CTimeStep::ms_fTimeScale = 1.0f;
float CTimeStep::ms_fFramesPerUpdate = 1.0f;
float CTimeStep::ms_fTimeStep = 1.0f;

10
src/core/TimeStep.h Normal file
View file

@ -0,0 +1,10 @@
#pragma once
// Pretty sure this class is not used by the game
class CTimeStep
{
public:
static float ms_fTimeScale;
static float ms_fFramesPerUpdate;
static float ms_fTimeStep;
};

329
src/core/Timer.cpp Normal file
View file

@ -0,0 +1,329 @@
#define WITHWINDOWS
#include "common.h"
#include "crossplatform.h"
#include "DMAudio.h"
#include "Record.h"
#include "Timer.h"
uint32 CTimer::m_snTimeInMilliseconds;
uint32 CTimer::m_snTimeInMillisecondsPauseMode = 1;
uint32 CTimer::m_snTimeInMillisecondsNonClipped;
uint32 CTimer::m_snPreviousTimeInMilliseconds;
uint32 CTimer::m_FrameCounter;
float CTimer::ms_fTimeScale;
float CTimer::ms_fTimeStep;
float CTimer::ms_fTimeStepNonClipped;
bool CTimer::m_UserPause;
bool CTimer::m_CodePause;
#ifdef FIX_BUGS
uint32 CTimer::m_LogicalFrameCounter;
uint32 CTimer::m_LogicalFramesPassed;
#endif
uint32 _nCyclesPerMS = 1;
#ifdef _WIN32
LARGE_INTEGER _oldPerfCounter;
LARGE_INTEGER perfSuspendCounter;
#define RsTimerType uint32
#else
#define RsTimerType double
#endif
RsTimerType oldPcTimer;
RsTimerType suspendPcTimer;
uint32 suspendDepth;
void CTimer::Initialise(void)
{
debug("Initialising CTimer...\n");
ms_fTimeScale = 1.0f;
ms_fTimeStep = 1.0f;
suspendDepth = 0;
m_UserPause = false;
m_CodePause = false;
m_snTimeInMillisecondsNonClipped = 0;
m_snPreviousTimeInMilliseconds = 0;
m_snTimeInMilliseconds = 1;
#ifdef FIX_BUGS
m_LogicalFrameCounter = 0;
m_LogicalFramesPassed = 0;
#endif
#ifdef _WIN32
LARGE_INTEGER perfFreq;
if ( QueryPerformanceFrequency(&perfFreq) )
{
OutputDebugString("Performance counter available\n");
_nCyclesPerMS = uint32(perfFreq.QuadPart / 1000);
QueryPerformanceCounter(&_oldPerfCounter);
}
else
#endif
{
OutputDebugString("Performance counter not available, using millesecond timer\n");
_nCyclesPerMS = 0;
oldPcTimer = RsTimer();
}
m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds;
m_FrameCounter = 0;
DMAudio.ResetTimers(m_snPreviousTimeInMilliseconds);
debug("CTimer ready\n");
}
void CTimer::Shutdown(void)
{
;
}
#ifdef FIX_BUGS
void CTimer::Update(void)
{
static double frameTimeLogical = 0.0;
static double frameTimeFraction = 0.0;
static double frameTimeFractionScaled = 0.0;
double frameTime;
double dblUpdInMs;
m_snPreviousTimeInMilliseconds = m_snTimeInMilliseconds;
#ifdef _WIN32
if ( (double)_nCyclesPerMS != 0.0 )
{
LARGE_INTEGER pc;
QueryPerformanceCounter(&pc);
int32 updInCycles = (pc.LowPart - _oldPerfCounter.LowPart); // & 0x7FFFFFFF; pointless
_oldPerfCounter = pc;
// bugfix from VC
double updInCyclesScaled = GetIsPaused() ? updInCycles : updInCycles * ms_fTimeScale;
frameTime = updInCyclesScaled / (double)_nCyclesPerMS;
dblUpdInMs = (double)updInCycles / (double)_nCyclesPerMS;
}
else
#endif
{
RsTimerType timer = RsTimer();
RsTimerType updInMs = timer - oldPcTimer;
// bugfix from VC
frameTime = GetIsPaused() ? (double)updInMs : (double)updInMs * ms_fTimeScale;
oldPcTimer = timer;
dblUpdInMs = (double)updInMs;
}
// count frames as if we're running at 30 fps
m_LogicalFramesPassed = 0;
frameTimeLogical += dblUpdInMs;
while(frameTimeLogical >= 1000.0 / 30.0) {
frameTimeLogical -= 1000.0 / 30.0;
m_LogicalFramesPassed++;
}
m_LogicalFrameCounter += m_LogicalFramesPassed;
frameTimeFraction += dblUpdInMs;
frameTimeFractionScaled += frameTime;
m_snTimeInMillisecondsPauseMode += uint32(frameTimeFraction);
if ( GetIsPaused() )
ms_fTimeStep = 0.0f;
else
{
m_snTimeInMilliseconds += uint32(frameTimeFractionScaled);
m_snTimeInMillisecondsNonClipped += uint32(frameTimeFractionScaled);
ms_fTimeStep = frameTime / 1000.0f * 50.0f;
}
frameTimeFraction -= uint32(frameTimeFraction);
frameTimeFractionScaled -= uint32(frameTimeFractionScaled);
if ( ms_fTimeStep < 0.01f && !GetIsPaused() )
ms_fTimeStep = 0.01f;
ms_fTimeStepNonClipped = ms_fTimeStep;
if ( !CRecordDataForGame::IsPlayingBack() )
{
ms_fTimeStep = Min(3.0f, ms_fTimeStep);
if ( (m_snTimeInMilliseconds - m_snPreviousTimeInMilliseconds) > 60 )
m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 60;
}
if ( CRecordDataForChase::IsRecording() )
{
ms_fTimeStep = 1.0f;
m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 16;
}
m_FrameCounter++;
}
#else
void CTimer::Update(void)
{
m_snPreviousTimeInMilliseconds = m_snTimeInMilliseconds;
#ifdef _WIN32
if ( (double)_nCyclesPerMS != 0.0 )
{
LARGE_INTEGER pc;
QueryPerformanceCounter(&pc);
int32 updInCycles = (pc.LowPart - _oldPerfCounter.LowPart); // & 0x7FFFFFFF; pointless
_oldPerfCounter = pc;
float updInCyclesScaled = updInCycles * ms_fTimeScale;
double frameTime = updInCyclesScaled / (double)_nCyclesPerMS;
m_snTimeInMillisecondsPauseMode = m_snTimeInMillisecondsPauseMode + frameTime;
if ( GetIsPaused() )
ms_fTimeStep = 0.0f;
else
{
m_snTimeInMilliseconds = m_snTimeInMilliseconds + frameTime;
m_snTimeInMillisecondsNonClipped = m_snTimeInMillisecondsNonClipped + frameTime;
ms_fTimeStep = frameTime / 1000.0f * 50.0f;
}
}
else
#endif
{
RsTimerType timer = RsTimer();
RsTimerType updInMs = timer - oldPcTimer;
double frameTime = (double)updInMs * ms_fTimeScale;
oldPcTimer = timer;
m_snTimeInMillisecondsPauseMode = m_snTimeInMillisecondsPauseMode + frameTime;
if ( GetIsPaused() )
ms_fTimeStep = 0.0f;
else
{
m_snTimeInMilliseconds = m_snTimeInMilliseconds + frameTime;
m_snTimeInMillisecondsNonClipped = m_snTimeInMillisecondsNonClipped + frameTime;
ms_fTimeStep = frameTime / 1000.0f * 50.0f;
}
}
if ( ms_fTimeStep < 0.01f && !GetIsPaused() )
ms_fTimeStep = 0.01f;
ms_fTimeStepNonClipped = ms_fTimeStep;
if ( !CRecordDataForGame::IsPlayingBack() )
{
ms_fTimeStep = Min(3.0f, ms_fTimeStep);
if ( (m_snTimeInMilliseconds - m_snPreviousTimeInMilliseconds) > 60 )
m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 60;
}
if ( CRecordDataForChase::IsRecording() )
{
ms_fTimeStep = 1.0f;
m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 16;
}
m_FrameCounter++;
}
#endif
void CTimer::Suspend(void)
{
if ( ++suspendDepth > 1 )
return;
#ifdef _WIN32
if ( (double)_nCyclesPerMS != 0.0 )
QueryPerformanceCounter(&perfSuspendCounter);
else
#endif
suspendPcTimer = RsTimer();
}
void CTimer::Resume(void)
{
if ( --suspendDepth != 0 )
return;
#ifdef _WIN32
if ( (double)_nCyclesPerMS != 0.0 )
{
LARGE_INTEGER pc;
QueryPerformanceCounter(&pc);
_oldPerfCounter.LowPart += pc.LowPart - perfSuspendCounter.LowPart;
}
else
#endif
oldPcTimer += RsTimer() - suspendPcTimer;
}
uint32 CTimer::GetCyclesPerMillisecond(void)
{
#ifdef _WIN32
if (_nCyclesPerMS != 0)
return _nCyclesPerMS;
else
#endif
return 1;
}
uint32 CTimer::GetCurrentTimeInCycles(void)
{
#ifdef _WIN32
if ( _nCyclesPerMS != 0 )
{
LARGE_INTEGER pc;
QueryPerformanceCounter(&pc);
return (pc.LowPart - _oldPerfCounter.LowPart); // & 0x7FFFFFFF; pointless
}
else
#endif
return RsTimer() - oldPcTimer;
}
bool CTimer::GetIsSlowMotionActive(void)
{
return ms_fTimeScale < 1.0f;
}
void CTimer::Stop(void)
{
m_snPreviousTimeInMilliseconds = m_snTimeInMilliseconds;
}
void CTimer::StartUserPause(void)
{
m_UserPause = true;
}
void CTimer::EndUserPause(void)
{
m_UserPause = false;
}
uint32 CTimer::GetCyclesPerFrame()
{
return 20;
}

71
src/core/Timer.h Normal file
View file

@ -0,0 +1,71 @@
#pragma once
class CTimer
{
static uint32 m_snTimeInMilliseconds;
static uint32 m_snTimeInMillisecondsPauseMode;
static uint32 m_snTimeInMillisecondsNonClipped;
static uint32 m_snPreviousTimeInMilliseconds;
static uint32 m_FrameCounter;
static float ms_fTimeScale;
static float ms_fTimeStep;
static float ms_fTimeStepNonClipped;
#ifdef FIX_BUGS
static uint32 m_LogicalFrameCounter;
static uint32 m_LogicalFramesPassed;
#endif
public:
static bool m_UserPause;
static bool m_CodePause;
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 uint32 GetTimeStepInMilliseconds() { return ms_fTimeStep / 50.0f * 1000.0f; }
static const float &GetTimeStepNonClipped(void) { return ms_fTimeStepNonClipped; }
static float GetTimeStepNonClippedInSeconds(void) { return ms_fTimeStepNonClipped / 50.0f; }
static float GetTimeStepNonClippedInMilliseconds(void) { return ms_fTimeStepNonClipped / 50.0f * 1000.0f; }
static void SetTimeStepNonClipped(float ts) { ms_fTimeStepNonClipped = ts; }
static const uint32 &GetFrameCounter(void) { return m_FrameCounter; }
static void SetFrameCounter(uint32 fc) { m_FrameCounter = fc; }
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; }
static uint32 GetTimeInMillisecondsPauseMode(void) { return m_snTimeInMillisecondsPauseMode; }
static void SetTimeInMillisecondsPauseMode(uint32 t) { m_snTimeInMillisecondsPauseMode = t; }
static uint32 GetPreviousTimeInMilliseconds(void) { return m_snPreviousTimeInMilliseconds; }
static void SetPreviousTimeInMilliseconds(uint32 t) { m_snPreviousTimeInMilliseconds = t; }
static const float &GetTimeScale(void) { return ms_fTimeScale; }
static void SetTimeScale(float ts) { ms_fTimeScale = ts; }
static uint32 GetCyclesPerFrame();
static bool GetIsPaused() { return m_UserPause || m_CodePause; }
static bool GetIsUserPaused() { return m_UserPause; }
static bool GetIsCodePaused() { return m_CodePause; }
static void SetCodePause(bool pause) { m_CodePause = pause; }
static void Initialise(void);
static void Shutdown(void);
static void Update(void);
static void Suspend(void);
static void Resume(void);
static uint32 GetCyclesPerMillisecond(void);
static uint32 GetCurrentTimeInCycles(void);
static bool GetIsSlowMotionActive(void);
static void Stop(void);
static void StartUserPause(void);
static void EndUserPause(void);
friend bool GenericLoad(void);
friend bool GenericSave(int file);
friend class CMemoryCard;
#ifdef FIX_BUGS
static float GetDefaultTimeStep(void) { return 50.0f / 30.0f; }
static float GetTimeStepFix(void) { return GetTimeStep() / GetDefaultTimeStep(); }
static uint32 GetLogicalFrameCounter(void) { return m_LogicalFrameCounter; }
static uint32 GetLogicalFramesPassed(void) { return m_LogicalFramesPassed; }
#endif
};

127
src/core/User.cpp Normal file
View file

@ -0,0 +1,127 @@
#include "common.h"
#include "Hud.h"
#include "PlayerPed.h"
#include "Replay.h"
#include "Text.h"
#include "User.h"
#include "Vehicle.h"
#include "World.h"
#include "Zones.h"
CPlaceName CUserDisplay::PlaceName;
COnscreenTimer CUserDisplay::OnscnTimer;
CPager CUserDisplay::Pager;
CCurrentVehicle CUserDisplay::CurrentVehicle;
CPlaceName::CPlaceName()
{
Init();
}
void
CPlaceName::Init()
{
m_pZone = nil;
m_pZone2 = nil;
m_nAdditionalTimer = 0;
}
void
CPlaceName::Process()
{
CVector pos = CWorld::Players[CWorld::PlayerInFocus].GetPos();
CZone *navigZone = CTheZones::FindSmallestZonePositionType(&pos, ZONE_NAVIG);
CZone *defaultZone = CTheZones::FindSmallestZonePositionType(&pos, ZONE_DEFAULT);
if (navigZone == nil) m_pZone = nil;
if (defaultZone == nil) m_pZone2 = nil;
if (navigZone == m_pZone) {
if (defaultZone == m_pZone2 || m_pZone != nil) {
if (navigZone != nil || defaultZone != nil) {
if (m_nAdditionalTimer != 0)
m_nAdditionalTimer--;
} else {
m_nAdditionalTimer = 0;
m_pZone = nil;
m_pZone2 = nil;
}
} else {
m_pZone2 = defaultZone;
m_nAdditionalTimer = 250;
}
} else {
m_pZone = navigZone;
m_nAdditionalTimer = 250;
}
Display();
}
void
CPlaceName::Display()
{
wchar *text;
if (m_pZone != nil)
text = m_pZone->GetTranslatedName();
else if (m_pZone2 != nil)
text = m_pZone2->GetTranslatedName();
#ifdef FIX_BUGS
else
text = nil;
#endif
CHud::SetZoneName(text);
}
CCurrentVehicle::CCurrentVehicle()
{
Init();
}
void
CCurrentVehicle::Init()
{
m_pCurrentVehicle = nil;
}
void
CCurrentVehicle::Process()
{
if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->InVehicle())
m_pCurrentVehicle = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pMyVehicle;
else
m_pCurrentVehicle = nil;
Display();
}
void
CCurrentVehicle::Display()
{
wchar *text = nil;
if (m_pCurrentVehicle != nil)
text = TheText.Get(((CVehicleModelInfo*)CModelInfo::GetModelInfo(m_pCurrentVehicle->GetModelIndex()))->m_gameName);
CHud::SetVehicleName(text);
}
void
CUserDisplay::Init()
{
PlaceName.Init();
OnscnTimer.Init();
Pager.Init();
CurrentVehicle.Init();
}
void
CUserDisplay::Process()
{
#ifdef FIX_BUGS
if (CReplay::IsPlayingBack())
return;
#endif
PlaceName.Process();
OnscnTimer.Process();
Pager.Process();
CurrentVehicle.Process();
}

41
src/core/User.h Normal file
View file

@ -0,0 +1,41 @@
#pragma once
#include "Pager.h"
#include "OnscreenTimer.h"
class CZone;
class CVehicle;
class CPlaceName
{
CZone *m_pZone;
CZone *m_pZone2;
int16 m_nAdditionalTimer;
public:
CPlaceName();
void Init();
void Process();
void Display();
};
class CCurrentVehicle
{
CVehicle *m_pCurrentVehicle;
public:
CCurrentVehicle();
void Init();
void Process();
void Display();
};
class CUserDisplay
{
public:
static CPlaceName PlaceName;
static COnscreenTimer OnscnTimer;
static CPager Pager;
static CCurrentVehicle CurrentVehicle;
static void Init();
static void Process();
};

492
src/core/Wanted.cpp Normal file
View file

@ -0,0 +1,492 @@
#include "common.h"
#include "Pools.h"
#include "ModelIndices.h"
#include "Timer.h"
#include "World.h"
#include "ZoneCull.h"
#include "Darkel.h"
#include "DMAudio.h"
#include "CopPed.h"
#include "Wanted.h"
#include "General.h"
int32 CWanted::MaximumWantedLevel = 6;
int32 CWanted::nMaximumWantedLevel = 6400;
void
CWanted::Initialise()
{
m_nChaos = 0;
m_nLastUpdateTime = 0;
m_nLastWantedLevelChange = 0;
m_CurrentCops = 0;
m_MaxCops = 0;
m_MaximumLawEnforcerVehicles = 0;
m_RoadblockDensity = 0;
m_bIgnoredByCops = false;
m_bIgnoredByEveryone = false;
m_bSwatRequired = false;
m_bFbiRequired = false;
m_bArmyRequired = false;
m_fCrimeSensitivity = 1.0f;
m_nWantedLevel = 0;
m_CopsBeatingSuspect = 0;
for (int i = 0; i < ARRAY_SIZE(m_pCops); i++)
m_pCops[i] = nil;
ClearQdCrimes();
}
bool
CWanted::AreSwatRequired()
{
return m_nWantedLevel == 4 || m_bSwatRequired;
}
bool
CWanted::AreFbiRequired()
{
return m_nWantedLevel == 5 || m_bFbiRequired;
}
bool
CWanted::AreArmyRequired()
{
return m_nWantedLevel == 6 || m_bArmyRequired;
}
int32
CWanted::NumOfHelisRequired()
{
if (m_bIgnoredByCops || m_bIgnoredByEveryone)
return 0;
switch (m_nWantedLevel) {
case 3:
case 4:
return 1;
case 5:
case 6:
return 2;
default:
return 0;
}
}
void
CWanted::SetWantedLevel(int32 level)
{
if (level > MaximumWantedLevel)
level = MaximumWantedLevel;
ClearQdCrimes();
switch (level) {
case 0:
m_nChaos = 0;
break;
case 1:
m_nChaos = 60;
break;
case 2:
m_nChaos = 220;
break;
case 3:
m_nChaos = 420;
break;
case 4:
m_nChaos = 820;
break;
case 5:
m_nChaos = 1620;
break;
case 6:
m_nChaos = 3220;
break;
default:
break;
}
UpdateWantedLevel();
}
void
CWanted::SetWantedLevelNoDrop(int32 level)
{
if (level > m_nWantedLevel)
SetWantedLevel(level);
}
void
CWanted::SetMaximumWantedLevel(int32 level)
{
switch(level){
case 0:
nMaximumWantedLevel = 0;
MaximumWantedLevel = 0;
break;
case 1:
nMaximumWantedLevel = 120;
MaximumWantedLevel = 1;
break;
case 2:
nMaximumWantedLevel = 300;
MaximumWantedLevel = 2;
break;
case 3:
nMaximumWantedLevel = 600;
MaximumWantedLevel = 3;
break;
case 4:
nMaximumWantedLevel = 1200;
MaximumWantedLevel = 4;
break;
case 5:
nMaximumWantedLevel = 2400;
MaximumWantedLevel = 5;
break;
case 6:
nMaximumWantedLevel = 4800;
MaximumWantedLevel = 6;
break;
}
}
void
CWanted::RegisterCrime(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare)
{
AddCrimeToQ(type, id, coors, false, policeDoesntCare);
}
void
CWanted::RegisterCrime_Immediately(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare)
{
#if defined FIX_SIGNIFICANT_BUGS || defined PEDS_REPORT_CRIMES_ON_PHONE
if (!AddCrimeToQ(type, id, coors, true, policeDoesntCare))
#else
if (!AddCrimeToQ(type, id, coors, false, policeDoesntCare))
#endif
ReportCrimeNow(type, coors, policeDoesntCare);
}
void
CWanted::ClearQdCrimes()
{
for (int i = 0; i < 16; i++)
m_aCrimes[i].m_nType = CRIME_NONE;
}
// returns whether the crime had been reported already
bool
CWanted::AddCrimeToQ(eCrimeType type, int32 id, const CVector &coors, bool reported, bool policeDoesntCare)
{
int i;
for(i = 0; i < 16; i++)
if(m_aCrimes[i].m_nType == type && m_aCrimes[i].m_nId == id){
if(m_aCrimes[i].m_bReported)
return true;
if(reported)
m_aCrimes[i].m_bReported = reported;
return false;
}
for(i = 0; i < 16; i++)
if(m_aCrimes[i].m_nType == CRIME_NONE)
break;
if(i < 16){
m_aCrimes[i].m_nType = type;
m_aCrimes[i].m_nId = id;
m_aCrimes[i].m_vecPosn = coors;
m_aCrimes[i].m_nTime = CTimer::GetTimeInMilliseconds();
m_aCrimes[i].m_bReported = reported;
m_aCrimes[i].m_bPoliceDoesntCare = policeDoesntCare;
}
return false;
}
void
CWanted::ReportCrimeNow(eCrimeType type, const CVector &coors, bool policeDoesntCare)
{
float sensitivity, chaos;
int wantedLevelDrop;
if(CDarkel::FrenzyOnGoing())
sensitivity = m_fCrimeSensitivity*0.3f;
else
sensitivity = m_fCrimeSensitivity;
wantedLevelDrop = Min(CCullZones::GetWantedLevelDrop(), 100);
chaos = (1.0f - wantedLevelDrop/100.0f) * sensitivity;
if (policeDoesntCare)
chaos *= 0.333f;
switch(type){
case CRIME_POSSESSION_GUN:
#ifdef PEDS_REPORT_CRIMES_ON_PHONE
m_nChaos += 5.0f*chaos;
#endif
break;
case CRIME_HIT_PED:
m_nChaos += 5.0f*chaos;
break;
case CRIME_HIT_COP:
m_nChaos += 45.0f*chaos;
break;
case CRIME_SHOOT_PED:
m_nChaos += 30.0f*chaos;
break;
case CRIME_SHOOT_COP:
m_nChaos += 80.0f*chaos;
break;
case CRIME_STEAL_CAR:
m_nChaos += 15.0f*chaos;
break;
case CRIME_RUN_REDLIGHT:
m_nChaos += 10.0f*chaos;
break;
case CRIME_RECKLESS_DRIVING:
m_nChaos += 5.0f*chaos;
break;
case CRIME_SPEEDING:
m_nChaos += 5.0f*chaos;
break;
case CRIME_RUNOVER_PED:
m_nChaos += 18.0f*chaos;
break;
case CRIME_RUNOVER_COP:
m_nChaos += 80.0f*chaos;
break;
case CRIME_SHOOT_HELI:
m_nChaos += 400.0f*chaos;
break;
case CRIME_PED_BURNED:
m_nChaos += 20.0f*chaos;
break;
case CRIME_COP_BURNED:
m_nChaos += 80.0f*chaos;
break;
case CRIME_VEHICLE_BURNED:
m_nChaos += 20.0f*chaos;
break;
case CRIME_DESTROYED_CESSNA:
m_nChaos += 500.0f*chaos;
break;
default:
// Error("Undefined crime type, RegisterCrime, Crime.cpp"); // different file for some reason
Error("Undefined crime type, RegisterCrime, Wanted.cpp");
}
DMAudio.ReportCrime(type, coors);
UpdateWantedLevel();
}
void
CWanted::UpdateWantedLevel()
{
int32 CurrWantedLevel = m_nWantedLevel;
if (m_nChaos > nMaximumWantedLevel)
m_nChaos = nMaximumWantedLevel;
if (m_nChaos >= 0 && m_nChaos < 40) {
m_nWantedLevel = 0;
m_MaximumLawEnforcerVehicles = 0;
m_MaxCops = 0;
m_RoadblockDensity = 0;
}
else if (m_nChaos >= 40 && m_nChaos < 200) {
m_nWantedLevel = 1;
m_MaximumLawEnforcerVehicles = 1;
m_MaxCops = 1;
m_RoadblockDensity = 0;
}
else if (m_nChaos >= 200 && m_nChaos < 400) {
m_nWantedLevel = 2;
m_MaximumLawEnforcerVehicles = 2;
m_MaxCops = 3;
m_RoadblockDensity = 0;
}
else if (m_nChaos >= 400 && m_nChaos < 800) {
m_nWantedLevel = 3;
m_MaximumLawEnforcerVehicles = 2;
m_MaxCops = 4;
m_RoadblockDensity = 4;
}
else if (m_nChaos >= 800 && m_nChaos < 1600) {
m_nWantedLevel = 4;
m_MaximumLawEnforcerVehicles = 2;
m_MaxCops = 6;
m_RoadblockDensity = 8;
}
else if (m_nChaos >= 1600 && m_nChaos < 3200) {
m_nWantedLevel = 5;
m_MaximumLawEnforcerVehicles = 3;
m_MaxCops = 8;
m_RoadblockDensity = 10;
}
else if (m_nChaos >= 3200) {
m_nWantedLevel = 6;
m_MaximumLawEnforcerVehicles = 3;
m_MaxCops = 10;
m_RoadblockDensity = 12;
}
if (CurrWantedLevel != m_nWantedLevel)
m_nLastWantedLevelChange = CTimer::GetTimeInMilliseconds();
}
int32
CWanted::WorkOutPolicePresence(CVector posn, float radius)
{
int i;
CPed *ped;
CVehicle *vehicle;
int numPolice = 0;
i = CPools::GetPedPool()->GetSize();
while(--i >= 0){
ped = CPools::GetPedPool()->GetSlot(i);
if(ped &&
IsPolicePedModel(ped->GetModelIndex()) &&
(posn - ped->GetPosition()).Magnitude() < radius)
numPolice++;
}
i = CPools::GetVehiclePool()->GetSize();
while(--i >= 0){
vehicle = CPools::GetVehiclePool()->GetSlot(i);
if(vehicle &&
vehicle->bIsLawEnforcer &&
IsPoliceVehicleModel(vehicle->GetModelIndex()) &&
vehicle != FindPlayerVehicle() &&
vehicle->GetStatus() != STATUS_ABANDONED && vehicle->GetStatus() != STATUS_WRECKED &&
(posn - vehicle->GetPosition()).Magnitude() < radius)
numPolice++;
}
return numPolice;
}
void
CWanted::Update(void)
{
if (CTimer::GetTimeInMilliseconds() - m_nLastUpdateTime > 1000) {
if (m_nWantedLevel > 1) {
m_nLastUpdateTime = CTimer::GetTimeInMilliseconds();
} else {
float radius = 18.0f;
CVector playerPos = FindPlayerCoors();
if (WorkOutPolicePresence(playerPos, radius) == 0) {
m_nLastUpdateTime = CTimer::GetTimeInMilliseconds();
m_nChaos = Max(0, m_nChaos - 1);
UpdateWantedLevel();
}
}
UpdateCrimesQ();
bool orderMessedUp = false;
int currCopNum = 0;
bool foundEmptySlot = false;
for (int i = 0; i < ARRAY_SIZE(m_pCops); i++) {
if (m_pCops[i]) {
++currCopNum;
if (foundEmptySlot)
orderMessedUp = true;
} else {
foundEmptySlot = true;
}
}
if (currCopNum != m_CurrentCops) {
printf("CopPursuit total messed up: re-setting\n");
m_CurrentCops = currCopNum;
}
if (orderMessedUp) {
printf("CopPursuit pointer list messed up: re-sorting\n");
bool fixed = true;
for (int i = 0; i < ARRAY_SIZE(m_pCops); i++) {
if (!m_pCops[i]) {
for (int j = i; j < ARRAY_SIZE(m_pCops); j++) {
if (m_pCops[j]) {
m_pCops[i] = m_pCops[j];
m_pCops[j] = nil;
fixed = false;
break;
}
}
if (fixed)
break;
}
}
}
}
}
void
CWanted::ResetPolicePursuit(void)
{
for(int i = 0; i < ARRAY_SIZE(m_pCops); i++) {
CCopPed *cop = m_pCops[i];
if (!cop)
continue;
cop->m_bIsInPursuit = false;
cop->m_objective = OBJECTIVE_NONE;
cop->m_prevObjective = OBJECTIVE_NONE;
cop->m_nLastPedState = PED_NONE;
if (!cop->DyingOrDead()) {
cop->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f));
}
m_pCops[i] = nil;
}
m_CurrentCops = 0;
}
void
CWanted::Reset(void)
{
ResetPolicePursuit();
Initialise();
}
#ifdef PEDS_REPORT_CRIMES_ON_PHONE
bool
CrimeShouldBeReportedOnPhone(eCrimeType crime)
{
switch (crime) {
case CRIME_POSSESSION_GUN:
case CRIME_HIT_PED:
case CRIME_HIT_COP:
case CRIME_SHOOT_PED:
case CRIME_SHOOT_COP:
case CRIME_STEAL_CAR:
case CRIME_RECKLESS_DRIVING:
case CRIME_RUNOVER_PED:
case CRIME_RUNOVER_COP:
case CRIME_PED_BURNED:
case CRIME_COP_BURNED:
case CRIME_VEHICLE_BURNED:
return true;
default:
return false;
}
}
#endif
void
CWanted::UpdateCrimesQ(void)
{
for(int i = 0; i < ARRAY_SIZE(m_aCrimes); i++) {
CCrimeBeingQd &crime = m_aCrimes[i];
if (crime.m_nType != CRIME_NONE) {
#ifdef PEDS_REPORT_CRIMES_ON_PHONE
if (!CrimeShouldBeReportedOnPhone(crime.m_nType))
#endif
if (CTimer::GetTimeInMilliseconds() > crime.m_nTime + 500 && !crime.m_bReported) {
ReportCrimeNow(crime.m_nType, crime.m_vecPosn, crime.m_bPoliceDoesntCare);
crime.m_bReported = true;
}
if (CTimer::GetTimeInMilliseconds() > crime.m_nTime + 10000)
crime.m_nType = CRIME_NONE;
}
}
}

58
src/core/Wanted.h Normal file
View file

@ -0,0 +1,58 @@
#pragma once
#include "Crime.h"
class CEntity;
class CCopPed;
class CWanted
{
public:
int32 m_nChaos;
int32 m_nLastUpdateTime;
uint32 m_nLastWantedLevelChange;
float m_fCrimeSensitivity;
uint8 m_CurrentCops;
uint8 m_MaxCops;
uint8 m_MaximumLawEnforcerVehicles;
uint8 m_CopsBeatingSuspect;
int16 m_RoadblockDensity;
uint8 m_bIgnoredByCops : 1;
uint8 m_bIgnoredByEveryone : 1;
uint8 m_bSwatRequired : 1;
uint8 m_bFbiRequired : 1;
uint8 m_bArmyRequired : 1;
int32 m_nWantedLevel;
CCrimeBeingQd m_aCrimes[16];
CCopPed *m_pCops[10];
static int32 MaximumWantedLevel;
static int32 nMaximumWantedLevel;
public:
void Initialise();
bool AreSwatRequired();
bool AreFbiRequired();
bool AreArmyRequired();
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();
bool AddCrimeToQ(eCrimeType type, int32 id, const CVector &pos, bool reported, bool policeDoesntCare);
void ReportCrimeNow(eCrimeType type, const CVector &coors, bool policeDoesntCare);
void UpdateWantedLevel();
void Reset();
void ResetPolicePursuit();
void UpdateCrimesQ();
void Update();
bool IsIgnored(void) { return m_bIgnoredByCops || m_bIgnoredByEveryone; }
static int32 WorkOutPolicePresence(CVector posn, float radius);
static void SetMaximumWantedLevel(int32 level);
};
VALIDATE_SIZE(CWanted, 0x204);

2162
src/core/World.cpp Normal file

File diff suppressed because it is too large Load diff

155
src/core/World.h Normal file
View file

@ -0,0 +1,155 @@
#pragma once
#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. */
#define SECTOR_SIZE_X (40.0f)
#define SECTOR_SIZE_Y (40.0f)
#define NUMSECTORS_X (100)
#define NUMSECTORS_Y (100)
#define WORLD_SIZE_X (NUMSECTORS_X * SECTOR_SIZE_X)
#define WORLD_SIZE_Y (NUMSECTORS_Y * SECTOR_SIZE_Y)
#define WORLD_MIN_X (-2000.0f)
#define WORLD_MIN_Y (-2000.0f)
#define WORLD_MAX_X (WORLD_MIN_X + WORLD_SIZE_X)
#define WORLD_MAX_Y (WORLD_MIN_Y + WORLD_SIZE_Y)
#define MAP_Z_LOW_LIMIT -100.0f
enum
{
ENTITYLIST_BUILDINGS,
ENTITYLIST_BUILDINGS_OVERLAP,
ENTITYLIST_OBJECTS,
ENTITYLIST_OBJECTS_OVERLAP,
ENTITYLIST_VEHICLES,
ENTITYLIST_VEHICLES_OVERLAP,
ENTITYLIST_PEDS,
ENTITYLIST_PEDS_OVERLAP,
ENTITYLIST_DUMMIES,
ENTITYLIST_DUMMIES_OVERLAP,
NUMSECTORENTITYLISTS
};
class CSector
{
public:
CPtrList m_lists[NUMSECTORENTITYLISTS];
};
VALIDATE_SIZE(CSector, 0x28);
class CWorld
{
static CPtrList ms_bigBuildingsList[NUM_LEVELS];
static CPtrList ms_listMovingEntityPtrs;
static CSector ms_aSectors[NUMSECTORS_Y][NUMSECTORS_X];
static uint16 ms_nCurrentScanCode;
public:
static uint8 PlayerInFocus;
static CPlayerInfo Players[NUMPLAYERS];
static CEntity *pIgnoreEntity;
static bool bIncludeDeadPeds;
static bool bNoMoreCollisionTorque;
static bool bSecondShift;
static bool bForceProcessControl;
static bool bProcessCutsceneOnly;
static bool bDoingCarCollisions;
static bool bIncludeCarTyres;
static void Remove(CEntity *entity);
static void Add(CEntity *entity);
static CSector *GetSector(int x, int y) { return &ms_aSectors[y][x]; }
static CPtrList &GetBigBuildingList(eLevelName i) { return ms_bigBuildingsList[i]; }
static CPtrList &GetMovingEntityList(void) { return ms_listMovingEntityPtrs; }
static uint16 GetCurrentScanCode(void) { return ms_nCurrentScanCode; }
static void AdvanceCurrentScanCode(void){
if(++CWorld::ms_nCurrentScanCode == 0){
CWorld::ClearScanCodes();
CWorld::ms_nCurrentScanCode = 1;
}
}
static void ClearScanCodes(void);
static void ClearExcitingStuffFromArea(const CVector &pos, float radius, bool bRemoveProjectilesAndTidyUpShadows);
static bool CameraToIgnoreThisObject(CEntity *ent);
static bool ProcessLineOfSight(const CVector &point1, const CVector &point2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
static bool ProcessLineOfSightSector(CSector &sector, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
static bool ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
static bool ProcessVerticalLine(const CVector &point1, float z2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly);
static bool ProcessVerticalLineSector(CSector &sector, const CColLine &line, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly);
static bool ProcessVerticalLineSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, CStoredCollPoly *poly);
static bool GetIsLineOfSightClear(const CVector &point1, const CVector &point2, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
static bool GetIsLineOfSightSectorClear(CSector &sector, const CColLine &line, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
static bool GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
static CEntity *TestSphereAgainstWorld(CVector centre, float radius, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects);
static CEntity *TestSphereAgainstSectorList(CPtrList&, CVector, float, CEntity*, bool);
static void FindObjectsInRangeSectorList(CPtrList &list, Const CVector &centre, float radius, bool ignoreZ, int16 *numObjects, int16 lastObject, CEntity **objects);
static void FindObjectsInRange(Const CVector &centre, float radius, bool ignoreZ, int16 *numObjects, int16 lastObject, CEntity **objects, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies);
static void FindObjectsOfTypeInRangeSectorList(uint32 modelId, CPtrList& list, const CVector& position, float radius, bool bCheck2DOnly, int16* nEntitiesFound, int16 maxEntitiesToFind, CEntity** aEntities);
static void FindObjectsOfTypeInRange(uint32 modelId, const CVector& position, float radius, bool bCheck2DOnly, int16* nEntitiesFound, int16 maxEntitiesToFind, CEntity** aEntities, bool bBuildings, bool bVehicles, bool bPeds, bool bObjects, bool bDummies);
static float FindGroundZForCoord(float x, float y);
static float FindGroundZFor3DCoord(float x, float y, float z, bool *found);
static float FindRoofZFor3DCoord(float x, float y, float z, bool *found);
static void RemoveReferencesToDeletedObject(CEntity*);
static void FindObjectsKindaColliding(const CVector& position, float radius, bool bCheck2DOnly, int16* nCollidingEntities, int16 maxEntitiesToFind, CEntity** aEntities, bool bBuildings, bool bVehicles, bool bPeds, bool bObjects, bool bDummies);
static void FindObjectsKindaCollidingSectorList(CPtrList& list, const CVector& position, float radius, bool bCheck2DOnly, int16* nCollidingEntities, int16 maxEntitiesToFind, CEntity** aEntities);
static void FindObjectsIntersectingCube(const CVector& vecStartPos, const CVector& vecEndPos, int16* nIntersecting, int16 maxEntitiesToFind, CEntity** aEntities, bool bBuildings, bool bVehicles, bool bPeds, bool bObjects, bool bDummies);
static void FindObjectsIntersectingCubeSectorList(CPtrList& list, const CVector& vecStartPos, const CVector& vecEndPos, int16* nIntersecting, int16 maxEntitiesToFind, CEntity** aEntities);
static void FindObjectsIntersectingAngledCollisionBox(const CColBox &, const CMatrix &, const CVector &, float, float, float, float, int16*, int16, CEntity **, bool, bool, bool, bool, bool);
static void FindObjectsIntersectingAngledCollisionBoxSectorList(CPtrList& list, const CColBox& boundingBox, const CMatrix& matrix, const CVector& position, int16* nEntitiesFound, int16 maxEntitiesToFind, CEntity** aEntities);
static void FindMissionEntitiesIntersectingCube(const CVector& vecStartPos, const CVector& vecEndPos, int16* nIntersecting, int16 maxEntitiesToFind, CEntity** aEntities, bool bVehicles, bool bPeds, bool bObjects);
static void FindMissionEntitiesIntersectingCubeSectorList(CPtrList& list, const CVector& vecStartPos, const CVector& vecEndPos, int16* nIntersecting, int16 maxEntitiesToFind, CEntity** aEntities, bool bIsVehicleList, bool bIsPedList);
static void ClearCarsFromArea(float x1, float y1, float z1, float x2, float y2, float z2);
static void ClearPedsFromArea(float x1, float y1, float z1, float x2, float y2, float z2);
static void CallOffChaseForArea(float x1, float y1, float x2, float y2);
static void CallOffChaseForAreaSectorListVehicles(CPtrList& list, float x1, float y1, float x2, float y2, float fStartX, float fStartY, float fEndX, float fEndY);
static void CallOffChaseForAreaSectorListPeds(CPtrList& list, float x1, float y1, float x2, float y2);
static float GetSectorX(float f) { return ((f - WORLD_MIN_X)/SECTOR_SIZE_X); }
static float GetSectorY(float f) { return ((f - WORLD_MIN_Y)/SECTOR_SIZE_Y); }
static int GetSectorIndexX(float f) { return (int)GetSectorX(f); }
static int GetSectorIndexY(float f) { return (int)GetSectorY(f); }
static float GetWorldX(int x) { return x*SECTOR_SIZE_X + WORLD_MIN_X; }
static float GetWorldY(int y) { return y*SECTOR_SIZE_Y + WORLD_MIN_Y; }
static void RemoveEntityInsteadOfProcessingIt(CEntity* ent);
static void RemoveFallenPeds();
static void RemoveFallenCars();
static void StopAllLawEnforcersInTheirTracks();
static void SetAllCarsCanBeDamaged(bool);
static void ExtinguishAllCarFiresInArea(CVector, float);
static void SetCarsOnFire(float x, float y, float z, float radius, CEntity* reason);
static void SetPedsOnFire(float x, float y, float z, float radius, CEntity* reason);
static void Initialise();
static void AddParticles();
static void ShutDown();
static void ClearForRestart(void);
static void RepositionCertainDynamicObjects();
static void RepositionOneObject(CEntity* pEntity);
static void RemoveStaticObjects();
static void Process();
static void TriggerExplosion(const CVector& position, float fRadius, float fPower, CEntity* pCreator, bool bProcessVehicleBombTimer);
static void TriggerExplosionSectorList(CPtrList& list, const CVector& position, float fRadius, float fPower, CEntity* pCreator, bool bProcessVehicleBombTimer);
static void UseDetonator(CEntity *pEntity);
};
extern CColPoint gaTempSphereColPoints[MAX_COLLISION_POINTS];

1589
src/core/ZoneCull.cpp Normal file

File diff suppressed because it is too large Load diff

137
src/core/ZoneCull.h Normal file
View file

@ -0,0 +1,137 @@
class CEntity;
class CCullZone
{
public:
CVector position;
float minx;
float maxx;
float miny;
float maxy;
float minz;
float maxz;
int32 m_indexStart;
int16 m_groupIndexCount[3]; // only useful during resolution stage
int16 m_numBuildings;
int16 m_numTreadablesPlus10m;
int16 m_numTreadables;
void DoStuffLeavingZone(void);
static void DoStuffLeavingZone_OneBuilding(uint16 i);
static void DoStuffLeavingZone_OneTreadableBoth(uint16 i);
void DoStuffEnteringZone(void);
static void DoStuffEnteringZone_OneBuilding(uint16 i);
static void DoStuffEnteringZone_OneTreadablePlus10m(uint16 i);
static void DoStuffEnteringZone_OneTreadable(uint16 i);
static bool TestLine(CVector vec1, CVector vec2);
static bool DoThoroughLineTest(CVector vec1, CVector vec2, CEntity *testEntity);
float CalcDistToCullZoneSquared(float x, float y);
float CalcDistToCullZone(float x, float y) { return Sqrt(CalcDistToCullZoneSquared(x, y)); };
bool IsEntityCloseEnoughToZone(CEntity* entity, bool checkLevel);
bool PointFallsWithinZone(CVector pos, float radius);
bool TestEntityVisibilityFromCullZone(CEntity *entity, float extraDist, CEntity *LODentity);
void FindTestPoints();
void GetGroupStartAndSize(int32 groupid, int32 &start, int32 &size) {
switch (groupid) {
case 0:
default:
// buildings
start = m_indexStart;
size = m_groupIndexCount[0];
break;
case 1:
// treadables + 10m
start = m_groupIndexCount[0] + m_indexStart;
size = m_groupIndexCount[1];
break;
case 2:
// treadables
start = m_groupIndexCount[0] + m_groupIndexCount[1] + m_indexStart;
size = m_groupIndexCount[2];
break;
}
}
};
enum eZoneAttribs
{
ATTRZONE_CAMCLOSEIN = 1,
ATTRZONE_STAIRS = 2,
ATTRZONE_1STPERSON = 4,
ATTRZONE_NORAIN = 8,
ATTRZONE_NOPOLICE = 0x10,
ATTRZONE_NOTCULLZONE = 0x20,
ATTRZONE_DOINEEDCOLLISION = 0x40,
ATTRZONE_SUBWAYVISIBLE = 0x80,
};
struct CAttributeZone
{
float minx;
float maxx;
float miny;
float maxy;
float minz;
float maxz;
int16 attributes;
int16 wantedLevel;
};
class CCullZones
{
public:
static int32 NumCullZones;
static CCullZone aZones[NUMCULLZONES];
static int32 NumAttributeZones;
static CAttributeZone aAttributeZones[NUMATTRIBZONES];
static uint16 aIndices[NUMZONEINDICES];
static int16 aPointersToBigBuildingsForBuildings[NUMBUILDINGS];
static int16 aPointersToBigBuildingsForTreadables[NUMTREADABLES];
static int32 CurrentWantedLevelDrop_Player;
static int32 CurrentFlags_Camera;
static int32 CurrentFlags_Player;
static int32 OldCullZone;
static int32 EntityIndicesUsed;
static bool bCurrentSubwayIsInvisible;
static bool bCullZonesDisabled;
static void Init(void);
static void ResolveVisibilities(void);
static void Update(void);
static void ForceCullZoneCoors(CVector coors);
static int32 FindCullZoneForCoors(CVector coors);
static int32 FindAttributesForCoors(CVector coors, int32 *wantedLevel);
static CAttributeZone *FindZoneWithStairsAttributeForPlayer(void);
static void MarkSubwayAsInvisible(bool visible);
static void AddCullZone(CVector const &position,
float minx, float maxx,
float miny, float maxy,
float minz, float maxz,
uint16 flag, int16 wantedLevel);
static bool CamCloseInForPlayer(void) { return (CurrentFlags_Player & ATTRZONE_CAMCLOSEIN) != 0; }
static bool CamStairsForPlayer(void) { return (CurrentFlags_Player & ATTRZONE_STAIRS) != 0; }
static bool Cam1stPersonForPlayer(void) { return (CurrentFlags_Player & ATTRZONE_1STPERSON) != 0; }
static bool NoPolice(void) { return (CurrentFlags_Player & ATTRZONE_NOPOLICE) != 0; }
static bool DoINeedToLoadCollision(void) { return (CurrentFlags_Player & ATTRZONE_DOINEEDCOLLISION) != 0; }
static bool PlayerNoRain(void) { return (CurrentFlags_Player & ATTRZONE_NORAIN) != 0; }
static bool CamNoRain(void) { return (CurrentFlags_Camera & ATTRZONE_NORAIN) != 0; }
static int32 GetWantedLevelDrop(void) { return CurrentWantedLevelDrop_Player; }
static void BuildListForBigBuildings();
static void DoVisibilityTestCullZone(int zoneId, bool doIt);
static bool DoWeHaveMoreThanXOccurencesOfSet(int32 count, uint16 *set);
static void CompressIndicesArray();
static bool PickRandomSetForGroup(int32 zone, int32 group, uint16 *set);
static void ReplaceSetForAllGroups(uint16 *set, uint16 setid);
static void TidyUpAndMergeLists(uint16 *extraIndices, int32 numExtraIndices);
// debug
static bool LoadTempFile(void);
static void SaveTempFile(void);
};

821
src/core/Zones.cpp Normal file
View file

@ -0,0 +1,821 @@
#include "common.h"
#include <ctype.h>
#include "Zones.h"
#include "Clock.h"
#include "Text.h"
#include "World.h"
#include "Timer.h"
#include "SaveBuf.h"
#ifdef COMPATIBLE_SAVES
#define ZONEARRAY_SAVE_SIZE 0xAF0
#define MAPZONEARRAY_SAVE_SIZE 0x578
#else
#define ZONEARRAY_SAVE_SIZE sizeof(ZoneArray)
#define MAPZONEARRAY_SAVE_SIZE sizeof(MapZoneArray)
#endif
eLevelName CTheZones::m_CurrLevel;
CZone *CTheZones::m_pPlayersZone;
int16 CTheZones::FindIndex;
uint16 CTheZones::NumberOfAudioZones;
int16 CTheZones::AudioZoneArray[NUMAUDIOZONES];
uint16 CTheZones::TotalNumberOfMapZones;
uint16 CTheZones::TotalNumberOfZones;
CZone CTheZones::ZoneArray[NUMZONES];
CZone CTheZones::MapZoneArray[NUMMAPZONES];
uint16 CTheZones::TotalNumberOfZoneInfos;
CZoneInfo CTheZones::ZoneInfoArray[2*NUMZONES];
#define SWAPF(a, b) { float t; t = a; a = b; b = t; }
inline bool IsNormalZone(int type) { return type == ZONE_DEFAULT || type == ZONE_NAVIG || type == ZONE_INFO; }
static void
CheckZoneInfo(CZoneInfo *info)
{
assert(info->carThreshold[0] >= 0);
assert(info->carThreshold[0] <= info->carThreshold[1]);
assert(info->carThreshold[1] <= info->carThreshold[2]);
assert(info->carThreshold[2] <= info->carThreshold[3]);
assert(info->carThreshold[3] <= info->carThreshold[4]);
assert(info->carThreshold[4] <= info->carThreshold[5]);
assert(info->carThreshold[5] <= info->copThreshold);
assert(info->copThreshold <= info->gangThreshold[0]);
assert(info->gangThreshold[0] <= info->gangThreshold[1]);
assert(info->gangThreshold[1] <= info->gangThreshold[2]);
assert(info->gangThreshold[2] <= info->gangThreshold[3]);
assert(info->gangThreshold[3] <= info->gangThreshold[4]);
assert(info->gangThreshold[4] <= info->gangThreshold[5]);
assert(info->gangThreshold[5] <= info->gangThreshold[6]);
assert(info->gangThreshold[6] <= info->gangThreshold[7]);
assert(info->gangThreshold[7] <= info->gangThreshold[8]);
}
wchar*
CZone::GetTranslatedName(void)
{
return TheText.Get(name);
}
void
CTheZones::Init(void)
{
int i;
for(i = 0; i < NUMAUDIOZONES; i++)
AudioZoneArray[i] = -1;
NumberOfAudioZones = 0;
for(i = 0; i < NUMZONES; i++)
memset(&ZoneArray[i], 0, sizeof(CZone));
CZoneInfo *zonei;
int x = 1000/6;
for(i = 0; i < 2*NUMZONES; i++){
zonei = &ZoneInfoArray[i];
zonei->carDensity = 10;
zonei->carThreshold[0] = x;
zonei->carThreshold[1] = zonei->carThreshold[0] + x;
zonei->carThreshold[2] = zonei->carThreshold[1] + x;
zonei->carThreshold[3] = zonei->carThreshold[2] + x;
zonei->carThreshold[4] = zonei->carThreshold[3];
zonei->carThreshold[5] = zonei->carThreshold[4];
zonei->copThreshold = zonei->carThreshold[5] + x;
zonei->gangThreshold[0] = zonei->copThreshold;
zonei->gangThreshold[1] = zonei->gangThreshold[0];
zonei->gangThreshold[2] = zonei->gangThreshold[1];
zonei->gangThreshold[3] = zonei->gangThreshold[2];
zonei->gangThreshold[4] = zonei->gangThreshold[3];
zonei->gangThreshold[5] = zonei->gangThreshold[4];
zonei->gangThreshold[6] = zonei->gangThreshold[5];
zonei->gangThreshold[7] = zonei->gangThreshold[6];
zonei->gangThreshold[8] = zonei->gangThreshold[7];
CheckZoneInfo(zonei);
}
TotalNumberOfZoneInfos = 1; // why 1?
TotalNumberOfZones = 1;
m_CurrLevel = LEVEL_GENERIC;
m_pPlayersZone = &ZoneArray[0];
strcpy(ZoneArray[0].name, "CITYZON");
ZoneArray[0].minx = -4000.0f;
ZoneArray[0].miny = -4000.0f;
ZoneArray[0].minz = -500.0f;
ZoneArray[0].maxx = 4000.0f;
ZoneArray[0].maxy = 4000.0f;
ZoneArray[0].maxz = 500.0f;
ZoneArray[0].level = LEVEL_GENERIC;
for(i = 0; i < NUMMAPZONES; i++){
memset(&MapZoneArray[i], 0, sizeof(CZone));
MapZoneArray[i].type = ZONE_MAPZONE;
}
TotalNumberOfMapZones = 1;
strcpy(MapZoneArray[0].name, "THEMAP");
MapZoneArray[0].minx = -4000.0f;
MapZoneArray[0].miny = -4000.0f;
MapZoneArray[0].minz = -500.0f;
MapZoneArray[0].maxx = 4000.0f;
MapZoneArray[0].maxy = 4000.0f;
MapZoneArray[0].maxz = 500.0f;
MapZoneArray[0].level = LEVEL_GENERIC;
}
void
CTheZones::Update(void)
{
#ifdef SQUEEZE_PERFORMANCE
if (CTimer::GetFrameCounter() % 5 != 0)
return;
#endif
CVector pos;
pos = FindPlayerCoors();
m_pPlayersZone = FindSmallestZonePosition(&pos);
m_CurrLevel = GetLevelFromPosition(&pos);
}
void
CTheZones::CreateZone(char *name, eZoneType type,
float minx, float miny, float minz,
float maxx, float maxy, float maxz,
eLevelName level)
{
char *p;
char tmpname[8];
if(minx > maxx) SWAPF(minx, maxx);
if(miny > maxy) SWAPF(miny, maxy);
if(minz > maxz) SWAPF(minz, maxz);
// make upper case
for(p = name; *p; p++) if(islower(*p)) *p = toupper(*p);
// add zone
strncpy(tmpname, name, 7);
tmpname[7] = '\0';
strcpy(ZoneArray[TotalNumberOfZones].name, tmpname);
ZoneArray[TotalNumberOfZones].type = type;
ZoneArray[TotalNumberOfZones].minx = minx;
ZoneArray[TotalNumberOfZones].miny = miny;
ZoneArray[TotalNumberOfZones].minz = minz;
ZoneArray[TotalNumberOfZones].maxx = maxx;
ZoneArray[TotalNumberOfZones].maxy = maxy;
ZoneArray[TotalNumberOfZones].maxz = maxz;
ZoneArray[TotalNumberOfZones].level = level;
if(IsNormalZone(type)){
ZoneArray[TotalNumberOfZones].zoneinfoDay = TotalNumberOfZoneInfos++;
ZoneArray[TotalNumberOfZones].zoneinfoNight = TotalNumberOfZoneInfos++;
}
TotalNumberOfZones++;
}
void
CTheZones::CreateMapZone(char *name, eZoneType type,
float minx, float miny, float minz,
float maxx, float maxy, float maxz,
eLevelName level)
{
CZone *zone;
char *p;
if(minx > maxx) SWAPF(minx, maxx);
if(miny > maxy) SWAPF(miny, maxy);
if(minz > maxz) SWAPF(minz, maxz);
// make upper case
for(p = name; *p; p++) if(islower(*p)) *p = toupper(*p);
// add zone
zone = &MapZoneArray[TotalNumberOfMapZones++];
strncpy(zone->name, name, 7);
zone->name[7] = '\0';
zone->type = type;
zone->minx = minx;
zone->miny = miny;
zone->minz = minz;
zone->maxx = maxx;
zone->maxy = maxy;
zone->maxz = maxz;
zone->level = level;
}
void
CTheZones::PostZoneCreation(void)
{
int i;
for(i = 1; i < TotalNumberOfZones; i++)
InsertZoneIntoZoneHierarchy(&ZoneArray[i]);
InitialiseAudioZoneArray();
}
void
CTheZones::InsertZoneIntoZoneHierarchy(CZone *zone)
{
zone->child = nil;
zone->parent = nil;
zone->next = nil;
InsertZoneIntoZoneHierRecursive(zone, &ZoneArray[0]);
}
bool
CTheZones::InsertZoneIntoZoneHierRecursive(CZone *inner, CZone *outer)
{
int n;
CZone *child, *next, *insert;
// return false if inner was not inserted into outer
if(outer == nil ||
!ZoneIsEntirelyContainedWithinOtherZone(inner, outer))
return false;
// try to insert inner into children of outer
for(child = outer->child; child; child = child->next)
if(InsertZoneIntoZoneHierRecursive(inner, child))
return true;
// insert inner as child of outer
// count number of outer's children contained within inner
n = 0;
for(child = outer->child; child; child = child->next)
if(ZoneIsEntirelyContainedWithinOtherZone(child, inner))
n++;
inner->next = outer->child;
inner->parent = outer;
outer->child = inner;
// move children from outer to inner
if(n){
insert = inner;
for(child = inner->next; child; child = next){
next = child->next;
if(ZoneIsEntirelyContainedWithinOtherZone(child,inner)){
insert->next = child->next;
child->parent = inner;
child->next = inner->child;
inner->child = child;
}else
insert = child;
}
}
return true;
}
bool
CTheZones::ZoneIsEntirelyContainedWithinOtherZone(CZone *inner, CZone *outer)
{
char tmp[100];
if(inner->minx < outer->minx ||
inner->maxx > outer->maxx ||
inner->miny < outer->miny ||
inner->maxy > outer->maxy ||
inner->minz < outer->minz ||
inner->maxz > outer->maxz){
CVector vmin(inner->minx, inner->miny, inner->minz);
if(PointLiesWithinZone(&vmin, outer))
sprintf(tmp, "Overlapping zones %s and %s\n",
inner->name, outer->name);
CVector vmax(inner->maxx, inner->maxy, inner->maxz);
if(PointLiesWithinZone(&vmax, outer))
sprintf(tmp, "Overlapping zones %s and %s\n",
inner->name, outer->name);
return false;
}
return true;
}
bool
CTheZones::PointLiesWithinZone(const CVector *v, CZone *zone)
{
return zone->minx <= v->x && v->x <= zone->maxx &&
zone->miny <= v->y && v->y <= zone->maxy &&
zone->minz <= v->z && v->z <= zone->maxz;
}
eLevelName
CTheZones::GetLevelFromPosition(CVector const *v)
{
int i;
// char tmp[116];
// if(!PointLiesWithinZone(v, &MapZoneArray[0]))
// sprintf(tmp, "x = %.3f y= %.3f z = %.3f\n", v.x, v.y, v.z);
for(i = 1; i < TotalNumberOfMapZones; i++)
if(PointLiesWithinZone(v, &MapZoneArray[i]))
return MapZoneArray[i].level;
return MapZoneArray[0].level;
}
CZone*
CTheZones::FindSmallestZonePosition(const CVector *v)
{
CZone *best = &ZoneArray[0];
// zone to test next
CZone *zone = ZoneArray[0].child;
while(zone)
// if in zone, descent into children
if(PointLiesWithinZone(v, zone)){
best = zone;
zone = zone->child;
// otherwise try next zone
}else
zone = zone->next;
return best;
}
CZone*
CTheZones::FindSmallestZonePositionType(const CVector *v, eZoneType type)
{
CZone *best = nil;
if(ZoneArray[0].type == type)
best = &ZoneArray[0];
// zone to test next
CZone *zone = ZoneArray[0].child;
while(zone)
// if in zone, descent into children
if(PointLiesWithinZone(v, zone)){
if(zone->type == type)
best = zone;
zone = zone->child;
// otherwise try next zone
}else
zone = zone->next;
return best;
}
CZone*
CTheZones::FindSmallestZonePositionILN(const CVector *v)
{
CZone *best = nil;
if(IsNormalZone(ZoneArray[0].type))
best = &ZoneArray[0];
// zone to test next
CZone *zone = ZoneArray[0].child;
while(zone)
// if in zone, descent into children
if(PointLiesWithinZone(v, zone)){
if(IsNormalZone(zone->type))
best = zone;
zone = zone->child;
// otherwise try next zone
}else
zone = zone->next;
return best;
}
int16
CTheZones::FindZoneByLabelAndReturnIndex(Const char *name)
{
char str[8];
memset(str, 0, 8);
strncpy(str, name, 8);
for(FindIndex = 0; FindIndex < TotalNumberOfZones; FindIndex++)
if(strcmp(GetZone(FindIndex)->name, name) == 0)
return FindIndex;
return -1;
}
CZoneInfo*
CTheZones::GetZoneInfo(const CVector *v, uint8 day)
{
CZone *zone;
zone = FindSmallestZonePositionILN(v);
if(zone == nil)
return &ZoneInfoArray[0];
return &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight];
}
void
CTheZones::GetZoneInfoForTimeOfDay(const CVector *pos, CZoneInfo *info)
{
CZoneInfo *day, *night;
float d, n;
day = GetZoneInfo(pos, 1);
night = GetZoneInfo(pos, 0);
if(CClock::GetIsTimeInRange(8, 19))
*info = *day;
else if(CClock::GetIsTimeInRange(22, 5))
*info = *night;
else{
if(CClock::GetIsTimeInRange(19, 22)){
n = (CClock::GetHours() - 19) / 3.0f;
assert(n >= 0.0f && n <= 1.0f);
d = 1.0f - n;
}else{
d = (CClock::GetHours() - 5) / 3.0f;
assert(d >= 0.0f && d <= 1.0f);
n = 1.0f - d;
}
info->carDensity = day->carDensity * d + night->carDensity * n;
info->carThreshold[0] = day->carThreshold[0] * d + night->carThreshold[0] * n;
info->carThreshold[1] = day->carThreshold[1] * d + night->carThreshold[1] * n;
info->carThreshold[2] = day->carThreshold[2] * d + night->carThreshold[2] * n;
info->carThreshold[3] = day->carThreshold[3] * d + night->carThreshold[3] * n;
info->carThreshold[4] = day->carThreshold[4] * d + night->carThreshold[4] * n;
info->carThreshold[5] = day->carThreshold[5] * d + night->carThreshold[5] * n;
info->copThreshold = day->copThreshold * d + night->copThreshold * n;
info->gangThreshold[0] = day->gangThreshold[0] * d + night->gangThreshold[0] * n;
info->gangThreshold[1] = day->gangThreshold[1] * d + night->gangThreshold[1] * n;
info->gangThreshold[2] = day->gangThreshold[2] * d + night->gangThreshold[2] * n;
info->gangThreshold[3] = day->gangThreshold[3] * d + night->gangThreshold[3] * n;
info->gangThreshold[4] = day->gangThreshold[4] * d + night->gangThreshold[4] * n;
info->gangThreshold[5] = day->gangThreshold[5] * d + night->gangThreshold[5] * n;
info->gangThreshold[6] = day->gangThreshold[6] * d + night->gangThreshold[6] * n;
info->gangThreshold[7] = day->gangThreshold[7] * d + night->gangThreshold[7] * n;
info->gangThreshold[8] = day->gangThreshold[8] * d + night->gangThreshold[8] * n;
info->pedDensity = day->pedDensity * d + night->pedDensity * n;
info->copDensity = day->copDensity * d + night->copDensity * n;
info->gangDensity[0] = day->gangDensity[0] * d + night->gangDensity[0] * n;
info->gangDensity[1] = day->gangDensity[1] * d + night->gangDensity[1] * n;
info->gangDensity[2] = day->gangDensity[2] * d + night->gangDensity[2] * n;
info->gangDensity[3] = day->gangDensity[3] * d + night->gangDensity[3] * n;
info->gangDensity[4] = day->gangDensity[4] * d + night->gangDensity[4] * n;
info->gangDensity[5] = day->gangDensity[5] * d + night->gangDensity[5] * n;
info->gangDensity[6] = day->gangDensity[6] * d + night->gangDensity[6] * n;
info->gangDensity[7] = day->gangDensity[7] * d + night->gangDensity[7] * n;
info->gangDensity[8] = day->gangDensity[8] * d + night->gangDensity[8] * n;
}
if(CClock::GetIsTimeInRange(5, 19))
info->pedGroup = day->pedGroup;
else
info->pedGroup = night->pedGroup;
CheckZoneInfo(info);
}
void
CTheZones::SetZoneCarInfo(uint16 zoneid, uint8 day, int16 carDensity,
int16 gang0Num, int16 gang1Num, int16 gang2Num,
int16 gang3Num, int16 gang4Num, int16 gang5Num,
int16 gang6Num, int16 gang7Num, int16 gang8Num,
int16 copNum,
int16 car0Num, int16 car1Num, int16 car2Num,
int16 car3Num, int16 car4Num, int16 car5Num)
{
CZone *zone;
CZoneInfo *info;
zone = GetZone(zoneid);
info = &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight];
CheckZoneInfo(info);
if(carDensity != -1) info->carDensity = carDensity;
int16 oldCar1Num = info->carThreshold[1] - info->carThreshold[0];
int16 oldCar2Num = info->carThreshold[2] - info->carThreshold[1];
int16 oldCar3Num = info->carThreshold[3] - info->carThreshold[2];
int16 oldCar4Num = info->carThreshold[4] - info->carThreshold[3];
int16 oldCar5Num = info->carThreshold[5] - info->carThreshold[4];
int16 oldCopNum = info->copThreshold - info->carThreshold[5];
int16 oldGang0Num = info->gangThreshold[0] - info->copThreshold;
int16 oldGang1Num = info->gangThreshold[1] - info->gangThreshold[0];
int16 oldGang2Num = info->gangThreshold[2] - info->gangThreshold[1];
int16 oldGang3Num = info->gangThreshold[3] - info->gangThreshold[2];
int16 oldGang4Num = info->gangThreshold[4] - info->gangThreshold[3];
int16 oldGang5Num = info->gangThreshold[5] - info->gangThreshold[4];
int16 oldGang6Num = info->gangThreshold[6] - info->gangThreshold[5];
int16 oldGang7Num = info->gangThreshold[7] - info->gangThreshold[6];
int16 oldGang8Num = info->gangThreshold[8] - info->gangThreshold[7];
if(car0Num != -1) info->carThreshold[0] = car0Num;
if(car1Num != -1) info->carThreshold[1] = info->carThreshold[0] + car1Num;
else info->carThreshold[1] = info->carThreshold[0] + oldCar1Num;
if(car2Num != -1) info->carThreshold[2] = info->carThreshold[1] + car2Num;
else info->carThreshold[2] = info->carThreshold[1] + oldCar2Num;
if(car3Num != -1) info->carThreshold[3] = info->carThreshold[2] + car3Num;
else info->carThreshold[3] = info->carThreshold[2] + oldCar3Num;
if(car4Num != -1) info->carThreshold[4] = info->carThreshold[3] + car4Num;
else info->carThreshold[4] = info->carThreshold[3] + oldCar4Num;
if(car5Num != -1) info->carThreshold[5] = info->carThreshold[4] + car5Num;
else info->carThreshold[5] = info->carThreshold[4] + oldCar5Num;
if(copNum != -1) info->copThreshold = info->carThreshold[5] + copNum;
else info->copThreshold = info->carThreshold[5] + oldCopNum;
if(gang0Num != -1) info->gangThreshold[0] = info->copThreshold + gang0Num;
else info->gangThreshold[0] = info->copThreshold + oldGang0Num;
if(gang1Num != -1) info->gangThreshold[1] = info->gangThreshold[0] + gang1Num;
else info->gangThreshold[1] = info->gangThreshold[0] + oldGang1Num;
if(gang2Num != -1) info->gangThreshold[2] = info->gangThreshold[1] + gang2Num;
else info->gangThreshold[2] = info->gangThreshold[1] + oldGang2Num;
if(gang3Num != -1) info->gangThreshold[3] = info->gangThreshold[2] + gang3Num;
else info->gangThreshold[3] = info->gangThreshold[2] + oldGang3Num;
if(gang4Num != -1) info->gangThreshold[4] = info->gangThreshold[3] + gang4Num;
else info->gangThreshold[4] = info->gangThreshold[3] + oldGang4Num;
if(gang5Num != -1) info->gangThreshold[5] = info->gangThreshold[4] + gang5Num;
else info->gangThreshold[5] = info->gangThreshold[4] + oldGang5Num;
if(gang6Num != -1) info->gangThreshold[6] = info->gangThreshold[5] + gang6Num;
else info->gangThreshold[6] = info->gangThreshold[5] + oldGang6Num;
if(gang7Num != -1) info->gangThreshold[7] = info->gangThreshold[6] + gang7Num;
else info->gangThreshold[7] = info->gangThreshold[6] + oldGang7Num;
if(gang8Num != -1) info->gangThreshold[8] = info->gangThreshold[7] + gang8Num;
else info->gangThreshold[8] = info->gangThreshold[7] + oldGang8Num;
CheckZoneInfo(info);
}
void
CTheZones::SetZonePedInfo(uint16 zoneid, uint8 day, int16 pedDensity,
int16 gang0Density, int16 gang1Density, int16 gang2Density, int16 gang3Density,
int16 gang4Density, int16 gang5Density, int16 gang6Density, int16 gang7Density,
int16 gang8Density, int16 copDensity)
{
CZone *zone;
CZoneInfo *info;
zone = GetZone(zoneid);
info = &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight];
if(pedDensity != -1) info->pedDensity = pedDensity;
if(copDensity != -1) info->copDensity = copDensity;
if(gang0Density != -1) info->gangDensity[0] = gang0Density;
if(gang1Density != -1) info->gangDensity[1] = gang1Density;
if(gang2Density != -1) info->gangDensity[2] = gang2Density;
if(gang3Density != -1) info->gangDensity[3] = gang3Density;
if(gang4Density != -1) info->gangDensity[4] = gang4Density;
if(gang5Density != -1) info->gangDensity[5] = gang5Density;
if(gang6Density != -1) info->gangDensity[6] = gang6Density;
if(gang7Density != -1) info->gangDensity[7] = gang7Density;
if(gang8Density != -1) info->gangDensity[8] = gang8Density;
}
void
CTheZones::SetCarDensity(uint16 zoneid, uint8 day, uint16 cardensity)
{
CZone *zone;
zone = GetZone(zoneid);
if(IsNormalZone(zone->type))
ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].carDensity = cardensity;
}
void
CTheZones::SetPedDensity(uint16 zoneid, uint8 day, uint16 peddensity)
{
CZone *zone;
zone = GetZone(zoneid);
if(IsNormalZone(zone->type))
ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].pedDensity = peddensity;
}
void
CTheZones::SetPedGroup(uint16 zoneid, uint8 day, uint16 pedgroup)
{
CZone *zone;
zone = GetZone(zoneid);
if(IsNormalZone(zone->type))
ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].pedGroup = pedgroup;
}
int16
CTheZones::FindAudioZone(CVector *pos)
{
int i;
for(i = 0; i < NumberOfAudioZones; i++)
if(PointLiesWithinZone(pos, GetAudioZone(i)))
return i;
return -1;
}
eLevelName
CTheZones::FindZoneForPoint(const CVector &pos)
{
if(PointLiesWithinZone(&pos, GetZone(FindZoneByLabelAndReturnIndex("IND_ZON"))))
return LEVEL_INDUSTRIAL;
if(PointLiesWithinZone(&pos, GetZone(FindZoneByLabelAndReturnIndex("COM_ZON"))))
return LEVEL_COMMERCIAL;
if(PointLiesWithinZone(&pos, GetZone(FindZoneByLabelAndReturnIndex("SUB_ZON"))))
return LEVEL_SUBURBAN;
return LEVEL_GENERIC;
}
void
CTheZones::AddZoneToAudioZoneArray(CZone *zone)
{
int i, z;
if(zone->type != ZONE_DEFAULT)
return;
/* This is a bit stupid */
z = -1;
for(i = 0; i < NUMZONES; i++)
if(&ZoneArray[i] == zone)
z = i;
AudioZoneArray[NumberOfAudioZones++] = z;
}
void
CTheZones::InitialiseAudioZoneArray(void)
{
bool gonext;
CZone *zone;
gonext = false;
zone = &ZoneArray[0];
// Go deep first,
// set gonext when backing up a level to visit the next child
while(zone)
if(gonext){
AddZoneToAudioZoneArray(zone);
if(zone->next){
gonext = false;
zone = zone->next;
}else
zone = zone->parent;
}else if(zone->child)
zone = zone->child;
else{
AddZoneToAudioZoneArray(zone);
if(zone->next)
zone = zone->next;
else{
gonext = true;
zone = zone->parent;
}
}
}
#ifdef COMPATIBLE_SAVES
static inline void
SaveOneZone(CZone &zone, uint8 *&buffer)
{
memcpy(buffer, zone.name, sizeof(zone.name));
SkipSaveBuf(buffer, sizeof(zone.name));
WriteSaveBuf(buffer, zone.minx);
WriteSaveBuf(buffer, zone.miny);
WriteSaveBuf(buffer, zone.minz);
WriteSaveBuf(buffer, zone.maxx);
WriteSaveBuf(buffer, zone.maxy);
WriteSaveBuf(buffer, zone.maxz);
WriteSaveBuf(buffer, zone.type);
WriteSaveBuf(buffer, zone.level);
WriteSaveBuf(buffer, zone.zoneinfoDay);
WriteSaveBuf(buffer, zone.zoneinfoNight);
WriteSaveBuf(buffer, (int32)CTheZones::GetIndexForZonePointer(zone.child));
WriteSaveBuf(buffer, (int32)CTheZones::GetIndexForZonePointer(zone.parent));
WriteSaveBuf(buffer, (int32)CTheZones::GetIndexForZonePointer(zone.next));
}
#endif
void
CTheZones::SaveAllZones(uint8 *buffer, uint32 *size)
{
INITSAVEBUF
int i;
*size = SAVE_HEADER_SIZE
+ sizeof(int32) // GetIndexForZonePointer
+ sizeof(m_CurrLevel) + sizeof(FindIndex)
+ sizeof(int16) // padding
+ ZONEARRAY_SAVE_SIZE + sizeof(ZoneInfoArray)
+ sizeof(TotalNumberOfZones) + sizeof(TotalNumberOfZoneInfos)
+ MAPZONEARRAY_SAVE_SIZE + sizeof(AudioZoneArray)
+ sizeof(TotalNumberOfMapZones) + sizeof(NumberOfAudioZones);
WriteSaveHeader(buffer, 'Z', 'N', 'S', '\0', *size - SAVE_HEADER_SIZE);
WriteSaveBuf(buffer, (int32)GetIndexForZonePointer(m_pPlayersZone));
WriteSaveBuf(buffer, m_CurrLevel);
WriteSaveBuf(buffer, FindIndex);
WriteSaveBuf(buffer, (int16)0); // padding
for(i = 0; i < ARRAY_SIZE(ZoneArray); i++){
#ifdef COMPATIBLE_SAVES
SaveOneZone(ZoneArray[i], buffer);
#else
CZone *zone = WriteSaveBuf(buffer, ZoneArray[i]);
zone->child = (CZone*)GetIndexForZonePointer(ZoneArray[i].child);
zone->parent = (CZone*)GetIndexForZonePointer(ZoneArray[i].parent);
zone->next = (CZone*)GetIndexForZonePointer(ZoneArray[i].next);
#endif
}
for(i = 0; i < ARRAY_SIZE(ZoneInfoArray); i++)
WriteSaveBuf(buffer, ZoneInfoArray[i]);
WriteSaveBuf(buffer, TotalNumberOfZones);
WriteSaveBuf(buffer, TotalNumberOfZoneInfos);
for(i = 0; i < ARRAY_SIZE(MapZoneArray); i++) {
#ifndef COMPATIBLE_SAVES
CZone* zone = WriteSaveBuf(buffer, MapZoneArray[i]);
#endif
/*
The call of GetIndexForZonePointer is wrong, as it is
meant for a different array, but the game doesn't brake
if those fields are nil. Let's make sure they are.
*/
assert(MapZoneArray[i].child == nil);
assert(MapZoneArray[i].parent == nil);
assert(MapZoneArray[i].next == nil);
#ifndef COMPATIBLE_SAVES
zone->child = (CZone*)GetIndexForZonePointer(MapZoneArray[i].child);
zone->parent = (CZone*)GetIndexForZonePointer(MapZoneArray[i].parent);
zone->next = (CZone*)GetIndexForZonePointer(MapZoneArray[i].next);
#else
SaveOneZone(MapZoneArray[i], buffer);
#endif
}
for(i = 0; i < ARRAY_SIZE(AudioZoneArray); i++)
WriteSaveBuf(buffer, AudioZoneArray[i]);
WriteSaveBuf(buffer, TotalNumberOfMapZones);
WriteSaveBuf(buffer, NumberOfAudioZones);
VALIDATESAVEBUF(*size)
}
#ifdef COMPATIBLE_SAVES
static inline void
LoadOneZone(CZone &zone, uint8 *&buffer)
{
memcpy(zone.name, buffer, sizeof(zone.name));
SkipSaveBuf(buffer, sizeof(zone.name));
ReadSaveBuf(&zone.minx, buffer);
ReadSaveBuf(&zone.miny, buffer);
ReadSaveBuf(&zone.minz, buffer);
ReadSaveBuf(&zone.maxx, buffer);
ReadSaveBuf(&zone.maxy, buffer);
ReadSaveBuf(&zone.maxz, buffer);
ReadSaveBuf(&zone.type, buffer);
ReadSaveBuf(&zone.level, buffer);
ReadSaveBuf(&zone.zoneinfoDay, buffer);
ReadSaveBuf(&zone.zoneinfoNight, buffer);
int32 tmp;
ReadSaveBuf(&tmp, buffer);
zone.child = CTheZones::GetPointerForZoneIndex(tmp);
ReadSaveBuf(&tmp, buffer);
zone.parent = CTheZones::GetPointerForZoneIndex(tmp);
ReadSaveBuf(&tmp, buffer);
zone.next = CTheZones::GetPointerForZoneIndex(tmp);
}
#endif
void
CTheZones::LoadAllZones(uint8 *buffer, uint32 size)
{
INITSAVEBUF
int32 i;
CheckSaveHeader(buffer, 'Z', 'N', 'S', '\0', size - SAVE_HEADER_SIZE);
ReadSaveBuf(&i, buffer);
m_pPlayersZone = GetPointerForZoneIndex(i);
ReadSaveBuf(&m_CurrLevel, buffer);
ReadSaveBuf(&FindIndex, buffer);
SkipSaveBuf(buffer, 2);
for(i = 0; i < ARRAY_SIZE(ZoneArray); i++){
#ifdef COMPATIBLE_SAVES
LoadOneZone(ZoneArray[i], buffer);
#else
ReadSaveBuf(&ZoneArray[i], buffer);
ZoneArray[i].child = GetPointerForZoneIndex((uintptr)ZoneArray[i].child);
ZoneArray[i].parent = GetPointerForZoneIndex((uintptr)ZoneArray[i].parent);
ZoneArray[i].next = GetPointerForZoneIndex((uintptr)ZoneArray[i].next);
#endif
}
for(i = 0; i < ARRAY_SIZE(ZoneInfoArray); i++)
ReadSaveBuf(&ZoneInfoArray[i], buffer);
ReadSaveBuf(&TotalNumberOfZones, buffer);
ReadSaveBuf(&TotalNumberOfZoneInfos, buffer);
for(i = 0; i < ARRAY_SIZE(MapZoneArray); i++){
#ifdef COMPATIBLE_SAVES
LoadOneZone(MapZoneArray[i], buffer);
#else
ReadSaveBuf(&MapZoneArray[i], buffer);
/*
The call of GetPointerForZoneIndex is wrong, as it is
meant for a different array, but the game doesn't brake
if save data stored is -1.
*/
MapZoneArray[i].child = GetPointerForZoneIndex((uintptr)MapZoneArray[i].child);
MapZoneArray[i].parent = GetPointerForZoneIndex((uintptr)MapZoneArray[i].parent);
MapZoneArray[i].next = GetPointerForZoneIndex((uintptr)MapZoneArray[i].next);
#endif
assert(MapZoneArray[i].child == nil);
assert(MapZoneArray[i].parent == nil);
assert(MapZoneArray[i].next == nil);
}
for(i = 0; i < ARRAY_SIZE(AudioZoneArray); i++)
ReadSaveBuf(&AudioZoneArray[i], buffer);
ReadSaveBuf(&TotalNumberOfMapZones, buffer);
ReadSaveBuf(&NumberOfAudioZones, buffer);
VALIDATESAVEBUF(size)
}

114
src/core/Zones.h Normal file
View file

@ -0,0 +1,114 @@
#pragma once
#include "Game.h"
#include "Gangs.h"
enum eZoneType
{
ZONE_DEFAULT,
ZONE_NAVIG,
ZONE_INFO,
ZONE_MAPZONE,
};
class CZone
{
public:
char name[8];
float minx;
float miny;
float minz;
float maxx;
float maxy;
float maxz;
eZoneType type;
eLevelName level;
int16 zoneinfoDay;
int16 zoneinfoNight;
CZone *child;
CZone *parent;
CZone *next;
wchar *GetTranslatedName(void);
};
class CZoneInfo
{
public:
// Car data
int16 carDensity;
int16 carThreshold[6];
int16 copThreshold;
int16 gangThreshold[NUM_GANGS];
// Ped data
uint16 pedDensity;
uint16 copDensity;
uint16 gangDensity[NUM_GANGS];
uint16 pedGroup;
};
class CTheZones
{
static CZone *m_pPlayersZone;
static int16 FindIndex;
static uint16 NumberOfAudioZones;
static int16 AudioZoneArray[NUMAUDIOZONES];
static uint16 TotalNumberOfMapZones;
static uint16 TotalNumberOfZones;
static CZone ZoneArray[NUMZONES];
static CZone MapZoneArray[NUMMAPZONES];
static uint16 TotalNumberOfZoneInfos;
static CZoneInfo ZoneInfoArray[2*NUMZONES];
public:
static eLevelName m_CurrLevel;
static void Init(void);
static void Update(void);
static void CreateZone(char *name, eZoneType type,
float minx, float miny, float minz,
float maxx, float maxy, float maxz,
eLevelName level);
static void CreateMapZone(char *name, eZoneType type,
float minx, float miny, float minz,
float maxx, float maxy, float maxz,
eLevelName level);
static CZone *GetZone(uint16 i) { return &ZoneArray[i]; }
static CZone *GetAudioZone(uint16 i) { return &ZoneArray[AudioZoneArray[i]]; }
static void PostZoneCreation(void);
static void InsertZoneIntoZoneHierarchy(CZone *zone);
static bool InsertZoneIntoZoneHierRecursive(CZone *z1, CZone *z2);
static bool ZoneIsEntirelyContainedWithinOtherZone(CZone *z1, CZone *z2);
static bool PointLiesWithinZone(const CVector *v, CZone *zone);
static eLevelName GetLevelFromPosition(const CVector *v);
static CZone *FindSmallestZonePosition(const CVector *v);
static CZone *FindSmallestZonePositionType(const CVector *v, eZoneType type);
static CZone *FindSmallestZonePositionILN(const CVector *v);
static int16 FindZoneByLabelAndReturnIndex(Const char *name);
static CZoneInfo *GetZoneInfo(const CVector *v, uint8 day);
static void GetZoneInfoForTimeOfDay(const CVector *pos, CZoneInfo *info);
static void SetZoneCarInfo(uint16 zoneid, uint8 day, int16 carDensity,
int16 gang0Num, int16 gang1Num, int16 gang2Num,
int16 gang3Num, int16 gang4Num, int16 gang5Num,
int16 gang6Num, int16 gang7Num, int16 gang8Num,
int16 copNum,
int16 car0Num, int16 car1Num, int16 car2Num,
int16 car3Num, int16 car4Num, int16 car5Num);
static void SetZonePedInfo(uint16 zoneid, uint8 day, int16 pedDensity,
int16 gang0Density, int16 gang1Density, int16 gang2Density, int16 gang3Density,
int16 gang4Density, int16 gang5Density, int16 gang6Density, int16 gang7Density,
int16 gang8Density, int16 copDensity);
static void SetCarDensity(uint16 zoneid, uint8 day, uint16 cardensity);
static void SetPedDensity(uint16 zoneid, uint8 day, uint16 peddensity);
static void SetPedGroup(uint16 zoneid, uint8 day, uint16 pedgroup);
static int16 FindAudioZone(CVector *pos);
static eLevelName FindZoneForPoint(const CVector &pos);
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);
static void LoadAllZones(uint8 *buffer, uint32 length);
};

401
src/core/common.h Normal file
View file

@ -0,0 +1,401 @@
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#define _USE_MATH_DEFINES
#pragma warning(disable: 4244) // int to float
#pragma warning(disable: 4800) // int to bool
#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
#ifdef __SWITCH__
#include <switch.h>
#endif
#include <stdint.h>
#include <string.h>
#include <math.h>
#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
#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 <windows.h>
#endif
#ifdef WITHD3D
#ifdef LIBRW
#define WITH_D3D // librw includes d3d9 itself via this right now
#else
#ifndef USE_D3D9
#include <d3d8.h>
#else
#include <d3d9.h>
#endif
#endif
#endif
#ifdef WITHDINPUT
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#endif
#include <rwcore.h>
#include <rpworld.h>
// gotta put this somewhere
#ifdef LIBRW
#define STREAMPOS(str) ((str)->tell())
#define STREAMFILE(str) (((rw::StreamFile*)(str))->file)
#define HIERNODEINFO(hier) ((hier)->nodeInfo)
#define HIERNODEID(hier, i) ((hier)->nodeInfo[i].id)
#define HANIMFRAME(anim, i) ((RwUInt8*)(anim)->keyframes + (i)*(anim)->interpInfo->animKeyFrameSize)
#else
#define RWHALFPIXEL // always d3d
#define STREAMPOS(str) ((str)->Type.memory.position)
#define STREAMFILE(str) ((str)->Type.file.fpFile)
#define HIERNODEINFO(hier) ((hier)->pNodeInfo)
#define HIERNODEID(hier, i) ((hier)->pNodeInfo[i].nodeID)
#define HANIMFRAME(anim, i) ((RwUInt8*)(anim)->pFrames + (i)*(anim)->interpInfo->keyFrameSize)
#define RpHAnimStdInterpFrame RpHAnimStdKeyFrame
#endif
#ifdef RWHALFPIXEL
#define HALFPX (0.5f)
#else
#define HALFPX (0.0f)
#endif
#define rwVENDORID_ROCKSTAR 0x0253F2
#define Max(a,b) ((a) > (b) ? (a) : (b))
#define Min(a,b) ((a) < (b) ? (a) : (b))
// Use this to add const that wasn't there in the original code
#define Const const
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;
typedef int64_t int64;
// hardcode ucs-2
typedef uint16_t wchar;
typedef uint8 bool8;
typedef uint16 bool16;
typedef uint32 bool32;
#if defined(_MSC_VER) || defined (__MWERKS__)
typedef ptrdiff_t ssize_t;
#endif
#ifndef nil
#define nil NULL
#endif
#include "config.h"
#ifdef PED_SKIN
#include <rphanim.h>
#include <rpskin.h>
#endif
#ifdef __GNUC__
#define TYPEALIGN(n) __attribute__ ((aligned (n)))
#else
#ifdef _MSC_VER
#define TYPEALIGN(n) __declspec(align(n))
#else
#define TYPEALIGN(n) // unknown compiler...ignore
#endif
#endif
#define ALIGNPTR(p) (void*)((((uintptr)(void*)p) + sizeof(void*)-1) & ~(sizeof(void*)-1))
// PDP-10 like byte functions
#define MASK(p, s) (((1<<(s))-1) << (p))
inline uint32 dpb(uint32 b, uint32 p, uint32 s, uint32 w)
{
uint32 m = MASK(p,s);
return (w & ~m) | ((b<<p) & m);
}
inline uint32 ldb(uint32 p, uint32 s, uint32 w)
{
return w>>p & (1<<s)-1;
}
#include "skeleton.h"
#include "Draw.h"
#if defined(PROPER_SCALING) || defined(PS2_HUD)
#ifdef FORCE_PC_SCALING
#define DEFAULT_SCREEN_WIDTH (640)
#define DEFAULT_SCREEN_HEIGHT (448)
#else
#define DEFAULT_SCREEN_WIDTH (640)
#define DEFAULT_SCREEN_HEIGHT (480)
#endif
#elif defined(GTA_PS2)
#define DEFAULT_SCREEN_WIDTH (640)
#define DEFAULT_SCREEN_HEIGHT (480)
#else //elif defined(GTA_PC)
#define DEFAULT_SCREEN_WIDTH (640)
#define DEFAULT_SCREEN_HEIGHT (448)
#endif
#define DEFAULT_ASPECT_RATIO (4.0f/3.0f)
#define DEFAULT_VIEWWINDOW (0.7f)
// game uses maximumWidth/Height, but this probably won't work
// with RW windowed mode
#ifdef GTA_PS2
#ifdef GTA_PAL
#define SCREEN_WIDTH ((float)640)
#define SCREEN_HEIGHT ((float)512)
#else
#define SCREEN_WIDTH ((float)640)
#define SCREEN_HEIGHT ((float)448)
#endif
#else
#define SCREEN_WIDTH ((float)RsGlobal.width)
#define SCREEN_HEIGHT ((float)RsGlobal.height)
#endif
#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)))
// This scales from PS2 pixel coordinates to the real resolution
#define SCREEN_STRETCH_X(a) ((a) * (float) SCREEN_WIDTH / DEFAULT_SCREEN_WIDTH)
#define SCREEN_STRETCH_Y(a) ((a) * (float) SCREEN_HEIGHT / DEFAULT_SCREEN_HEIGHT)
#define SCREEN_STRETCH_FROM_RIGHT(a) (SCREEN_WIDTH - SCREEN_STRETCH_X(a))
#define SCREEN_STRETCH_FROM_BOTTOM(a) (SCREEN_HEIGHT - SCREEN_STRETCH_Y(a))
// This scales from PS2 pixel coordinates while optionally maintaining the aspect ratio
#define SCREEN_SCALE_X(a) SCREEN_SCALE_AR(SCREEN_STRETCH_X(a))
#define SCREEN_SCALE_Y(a) SCREEN_STRETCH_Y(a)
#define SCREEN_SCALE_FROM_RIGHT(a) (SCREEN_WIDTH - SCREEN_SCALE_X(a))
#define SCREEN_SCALE_FROM_BOTTOM(a) (SCREEN_HEIGHT - SCREEN_SCALE_Y(a))
#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)
#endif
#include "maths.h"
#include "Vector.h"
#ifdef GTA_PS2
#include "VuVector.h"
#define CVUVECTOR CVuVector
#else
#define CVUVECTOR CVector
#endif
#include "Vector2D.h"
#include "Matrix.h"
#include "Rect.h"
class CRGBA
{
public:
union
{
uint32 color32;
struct { uint8 r, g, b, a; };
struct { uint8 red, green, blue, alpha; };
#ifdef RWCORE_H
struct { RwRGBA rwRGBA; };
#endif
};
CRGBA(void) { }
CRGBA(uint8 r, uint8 g, uint8 b, uint8 a) : r(r), g(g), b(b), a(a) { }
bool operator ==(const CRGBA &right)
{
return this->r == right.r && this->g == right.g && this->b == right.b && this->a == right.a;
}
bool operator !=(const CRGBA &right)
{
return !(*this == right);
}
CRGBA &operator =(const CRGBA &right)
{
this->r = right.r;
this->g = right.g;
this->b = right.b;
this->a = right.a;
return *this;
}
#ifdef RWCORE_H
operator RwRGBA &(void) {
return rwRGBA;
}
operator RwRGBA *(void) {
return &rwRGBA;
}
operator RwRGBA (void) const {
return rwRGBA;
}
CRGBA &operator =(const RwRGBA &right)
{
this->r = right.red;
this->g = right.green;
this->b = right.blue;
this->a = right.alpha;
return *this;
}
#endif
};
#if (defined(_MSC_VER))
extern int strcasecmp(const char *str1, const char *str2);
#endif
extern wchar *AllocUnicode(const char*src);
#define Clamp(v, low, high) ((v)<(low) ? (low) : (v)>(high) ? (high) : (v))
#define Clamp2(v, center, radius) ((v) > (center) ? Min(v, center + radius) : Max(v, center - radius))
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)
#define DEGTORAD(x) ((x) * PI / 180.0f)
#define RADTODEG(x) ((x) * 180.0f / PI)
#ifdef USE_PS2_RAND
#define MYRAND_MAX 65535
#else
#define MYRAND_MAX 32767
#endif
int myrand(void);
void mysrand(unsigned int seed);
void re3_debug(const char *format, ...);
void re3_trace(const char *filename, unsigned int lineno, const char *func, const char *format, ...);
void re3_assert(const char *expr, const char *filename, unsigned int lineno, const char *func);
void re3_usererror(const char *format, ...);
#define DEBUGBREAK() __debugbreak();
// Switch to enable development messages.
#if 1
#define DEV(f, ...)
#else
#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 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) (_Expression)
#endif
#define ASSERT assert
#ifdef __MWERKS__
#define static_assert(bool_constexpr, message)
#endif
#define _TODO(x)
#define _TODOCONST(x) (x)
#ifdef CHECK_STRUCT_SIZES
template<int s, int t> struct check_size {
static_assert(s == t, "Invalid structure size");
};
#define VALIDATE_SIZE(struc, size) check_size<sizeof(struc), size> struc ## Check
#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 PERCENT(x, p) ((float(x) * (float(p) / 100.0f)))
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
#define BIT(num) (1<<(num))
#define ABS(a) (((a) < 0) ? (-(a)) : (a))
#define norm(value, min, max) (((value) < (min)) ? 0 : (((value) > (max)) ? 1 : (((value) - (min)) / ((max) - (min)))))
#define lerp(norm, min, max) ( (norm) * ((max) - (min)) + (min) )
#define STRINGIFY(x) #x
#define STR(x) STRINGIFY(x)
#define CONCAT_(x,y) x##y
#define CONCAT(x,y) CONCAT_(x,y)

498
src/core/config.h Normal file
View file

@ -0,0 +1,498 @@
#pragma once
// disables (most) stuff that wasn't in original gta3.exe
#ifdef __MWERKS__
#define VANILLA_DEFINES
#endif
enum Config {
NUMPLAYERS = 1, // 4 on PS2
NUMCDIMAGES = 12, // gta3.img duplicates (not used on PC)
MAX_CDIMAGES = 8, // additional cdimages
MAX_CDCHANNELS = 5,
MODELINFOSIZE = 5500, // 3150 on PS2
#ifdef VANILLA_DEFINES
TXDSTORESIZE = 850,
#else
TXDSTORESIZE = 1024, // for Xbox map
#endif
EXTRADIRSIZE = 128,
CUTSCENEDIRSIZE = 512,
SIMPLEMODELSIZE = 5000, // 2910 on PS2
MLOMODELSIZE = 1,
MLOINSTANCESIZE = 1,
TIMEMODELSIZE = 30,
CLUMPMODELSIZE = 5,
PEDMODELSIZE = 90,
VEHICLEMODELSIZE = 120, // 70 on PS2
XTRACOMPSMODELSIZE = 2,
TWODFXSIZE = 2000, // 1210 on PS2
MAXVEHICLESLOADED = 50, // 70 on mobile
NUMOBJECTINFO = 168, // object.dat
// Pool sizes
NUMPTRNODES = 30000, // 26000 on PS2
NUMENTRYINFOS = 5400, // 3200 on PS2
NUMPEDS = 140, // 90 on PS2
NUMVEHICLES = 110, // 70 on PS2
NUMBUILDINGS = 5500, // 4915 on PS2
NUMTREADABLES = 1214,
NUMOBJECTS = 450,
NUMDUMMIES = 2802, // 2368 on PS2
NUMAUDIOSCRIPTOBJECTS = 256,
NUMCUTSCENEOBJECTS = 50,
NUMANIMBLOCKS = 2,
NUMANIMATIONS = 250,
NUMTEMPOBJECTS = 30,
// Path data
NUM_PATHNODES = 4930,
NUM_CARPATHLINKS = 2076,
NUM_MAPOBJECTS = 1250,
NUM_PATHCONNECTIONS = 10260,
// Link list lengths
NUMALPHALIST = 20,
NUMALPHAENTITYLIST = 150,
NUMCOLCACHELINKS = 200,
NUMREFERENCES = 800,
// Zones
NUMAUDIOZONES = 36,
NUMZONES = 50,
NUMMAPZONES = 25,
// Cull zones
NUMCULLZONES = 512,
NUMATTRIBZONES = 288,
NUMZONEINDICES = 55000,
PATHNODESIZE = 4500,
NUMWEATHERS = 4,
NUMHOURS = 24,
NUMEXTRADIRECTIONALS = 4,
NUMANTENNAS = 8,
NUMCORONAS = 56,
NUMPOINTLIGHTS = 32,
NUM3DMARKERS = 32,
NUMBRIGHTLIGHTS = 32,
NUMSHINYTEXTS = 32,
NUMMONEYMESSAGES = 16,
NUMPICKUPMESSAGES = 16,
NUMBULLETTRACES = 16,
NUMMBLURSTREAKS = 4,
NUMSKIDMARKS = 32,
NUMONSCREENTIMERENTRIES = 1,
NUMRADARBLIPS = 32,
NUMGENERALPICKUPS = 320,
NUMSCRIPTEDPICKUPS = 16,
NUMPICKUPS = NUMGENERALPICKUPS + NUMSCRIPTEDPICKUPS,
NUMCOLLECTEDPICKUPS = 20,
NUMPACMANPICKUPS = 256,
NUMEVENTS = 64,
NUM_CARGENS = 160,
NUM_PATH_NODES_IN_AUTOPILOT = 8,
NUM_ACCIDENTS = 20,
NUM_FIRES = 40,
NUM_GARAGES = 32,
NUM_PROJECTILES = 32,
NUM_GLASSPANES = 45,
NUM_GLASSENTITIES = 32,
NUM_WATERCANNONS = 3,
NUMPEDROUTES = 200,
NUMPHONES = 50,
NUMPEDGROUPS = 31,
NUMMODELSPERPEDGROUP = 8,
NUMSHOTINFOS = 100,
NUMROADBLOCKS = 600,
NUMVISIBLEENTITIES = 2000,
NUMINVISIBLEENTITIES = 150,
NUM_AUDIOENTITY_EVENTS = 4,
NUM_PED_COMMENTS_SLOTS = 20,
NUM_SOUND_QUEUES = 2,
NUM_AUDIOENTITIES = 200,
NUM_SCRIPT_MAX_ENTITIES = 40,
NUM_GARAGE_STORED_CARS = 6,
NUM_CRANES = 8,
NUM_EXPLOSIONS = 48,
};
// We don't expect to compile for PS2 or Xbox
// but it might be interesting for documentation purposes
#define GTA_PC
//#define GTA_PS2
//#define GTA_XBOX
// Version defines
#define GTA3_PS2_140 300
#define GTA3_PS2_160 301
#define GTA3_PC_10 310
#define GTA3_PC_11 311
#define GTA3_PC_STEAM 312
// TODO? maybe something for xbox or android?
#define GTA_VERSION GTA3_PC_11
// Enable configuration for handheld console ports
#if defined(__SWITCH__) || defined(PSP2)
#define GTA_HANDHELD
#endif
#if defined GTA_PS2
# define GTA_PS2_STUFF
# define RANDOMSPLASH
# define USE_CUSTOM_ALLOCATOR
# define VU_COLLISION
# define ANIM_COMPRESSION
# define PS2_MENU
#elif defined GTA_PC
# define EXTERNAL_3D_SOUND
# define AUDIO_REFLECTIONS
# ifndef GTA_HANDHELD
# define PC_PLAYER_CONTROLS // mouse player/cam mode
# endif
# define GTA_REPLAY
# define GTA_SCENE_EDIT
# define PC_MENU
#elif defined GTA_XBOX
#endif
// This is enabled for all released games.
// any debug stuff that isn't left in any game is not in FINAL
//#define FINAL
// This is enabled for all released games except mobile
// any debug stuff that is only left in mobile, is not in MASTER
//#define MASTER
// once and for all:
// pc: FINAL & MASTER
// mobile: FINAL
// MASTER builds must be FINAL
#ifdef MASTER
#define FINAL
#endif
// these are placed here to work with VANILLA_DEFINES for compatibility
#define NO_CDCHECK // skip audio CD check
#define DEFAULT_NATIVE_RESOLUTION // Set default video mode to your native resolution (fixes Windows 10 launch)
#ifdef VANILLA_DEFINES
#if !defined(_WIN32) || defined(__LP64__) || defined(_WIN64)
#error Vanilla can only be built for win-x86
#endif
#define FINAL
#define MASTER
//#define USE_MY_DOCUMENTS
#define THIS_IS_STUPID
#define PC_PARTICLE
#define DONT_FIX_REPLAY_BUGS
#define USE_TXD_CDIMAGE // generate and load textures from txd.img
//#define USE_TEXTURE_POOL // not possible because R* used custom RW33
#else
// This enables things from the PS2 version on PC
#define GTA_PS2_STUFF
// quality of life fixes that should also be in FINAL
#define NASTY_GAME // nasty game for all languages
// those infamous texts
#define DRAW_GAME_VERSION_TEXT
#ifdef DRAW_GAME_VERSION_TEXT
// unlike R* development builds, ours has runtime switch on debug menu & .ini, and disabled as default.
// If you disable this then game will fetch version from peds.col, as R* did while in development.
//#define USE_OUR_VERSIONING // enabled from buildfiles by default
#endif
//#define DRAW_MENU_VERSION_TEXT
// Memory allocation and compression
// #define USE_CUSTOM_ALLOCATOR // use CMemoryHeap for allocation. use with care, not finished yet
//#define COMPRESSED_COL_VECTORS // use compressed vectors for collision vertices
//#define ANIM_COMPRESSION // only keep most recently used anims uncompressed
#if defined GTA_PC && defined GTA_PS2_STUFF
# define USE_PS2_RAND
# define RANDOMSPLASH // use random splash as on PS2
# define PS2_MATFX
#endif
#ifdef VU_COLLISION
#define COMPRESSED_COL_VECTORS // currently need compressed vectors in this code
#endif
#ifdef MASTER
// only in master builds
#undef DRAW_GAME_VERSION_TEXT
#else
// not in master builds
#define VALIDATE_SAVE_SIZE
#define DEBUGMENU
#endif
#ifdef FINAL
// in all games
# define USE_MY_DOCUMENTS // use my documents directory for user files
#else
// not in any game
# define CHATTYSPLASH // print what the game is loading
# define TIMEBARS // print debug timers
#endif
#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, and keeps saves compatible between platforms, needs to be enabled on 64bit builds!
#define FIX_INCOMPATIBLE_SAVES // try to fix incompatible saves, requires COMPATIBLE_SAVES
#define LOAD_INI_SETTINGS // as the name suggests. fundamental for CUSTOM_FRONTEND_OPTIONS
#define NO_MOVIES // add option to disable intro videos
#define EXTENDED_OFFSCREEN_DESPAWN_RANGE // Use onscreen despawn range for offscreen peds and vehicles to avoid them despawning in the distance when you look
// away
#if defined(__LP64__) || defined(_WIN64)
#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 __MINGW32__
#undef ASCII_STRCMP
#endif
// Just debug menu entries
#ifdef DEBUGMENU
#define MISSION_SWITCHER // from debug menu
#endif
// Rendering/display
//#define EXTRA_MODEL_FLAGS // from mobile to optimize rendering
//# 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
#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
#ifdef DISABLE_LOADING_SCREEN
// enable the PC splash
#undef RANDOMSPLASH
#endif
#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)
#define EXTENDED_PIPELINES // custom render pipelines (includes Neo)
#define SCREEN_DROPLETS // neo water droplets
#define NEW_RENDERER // leeds-like world rendering, needs librw
#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
// Particle
//#define PC_PARTICLE
//#define PS2_ALTERNATIVE_CARSPLASH // unused on PS2
// Pad
#if !defined(RW_GL3) && defined(_WIN32)
#define XINPUT
#endif
#if defined XINPUT || (defined RW_GL3 && !defined LIBRW_SDL2 && !defined GTA_HANDHELD)
#define DETECT_JOYSTICK_MENU // Then we'll expect user to enter Controller->Detect joysticks if his joystick isn't detected at the start.
#endif
#define DETECT_PAD_INPUT_SWITCH // Adds automatic switch of pad related stuff between controller and kb/m
#define KANGAROO_CHEAT
#define ALLCARSHELI_CHEAT
#define ALT_DODO_CHEAT
#define REGISTER_START_BUTTON
#define BIND_VEHICLE_FIREWEAPON // Adds ability to rebind fire key for 'in vehicle' controls
#define BUTTON_ICONS // use textures to show controller buttons
// Hud, frontend and radar
//#define PS2_HUD
#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
#ifndef PC_MENU
# define PS2_MENU
//# define PS2_MENU_USEALLPAGEICONS
#else
# if defined(XINPUT) || defined(GTA_HANDHELD)
# define GAMEPAD_MENU // Add gamepad menu
# endif
# define SCROLLABLE_STATS_PAGE // only draggable by mouse atm
# define TRIANGLE_BACK_BUTTON
//# define CIRCLE_BACK_BUTTON
//# define PS2_LIKE_MENU // An effort to recreate PS2 menu, cycling through tabs, different bg etc.
//# define PS2_SAVE_DIALOG // PS2 style save dialog with transparent black box
# define CUSTOM_FRONTEND_OPTIONS
# ifdef CUSTOM_FRONTEND_OPTIONS
# define MENU_MAP // VC-like menu map. Won't appear if you don't have our menu.txd
# define GRAPHICS_MENU_OPTIONS // otherwise Display settings will be scrollable
# define NO_ISLAND_LOADING // disable loadscreen between islands via loading all island data at once, consumes more memory and CPU
# define CUTSCENE_BORDERS_SWITCH
# define MULTISAMPLING // adds MSAA option
# define INVERT_LOOK_FOR_PAD // add bInvertLook4Pad from VC
# define PED_CAR_DENSITY_SLIDERS
# endif
#endif
// Script
#define USE_DEBUG_SCRIPT_LOADER // Loads main.scm by default. Hold R for main_freeroam.scm and D for main_d.scm
#define USE_MEASUREMENTS_IN_METERS // makes game use meters instead of feet in script
#define USE_PRECISE_MEASUREMENT_CONVERTION // makes game convert feet to meeters more precisely
#ifdef PC_MENU
# define MISSION_REPLAY // mobile feature
#endif
//#define SIMPLIER_MISSIONS // apply simplifications from mobile
#define USE_ADVANCED_SCRIPT_DEBUG_OUTPUT
#define SCRIPT_LOG_FILE_LEVEL 0 // 0 == no log, 1 == overwrite every frame, 2 == full log
#if SCRIPT_LOG_FILE_LEVEL == 0
#undef USE_ADVANCED_SCRIPT_DEBUG_OUTPUT
#endif
#ifndef USE_ADVANCED_SCRIPT_DEBUG_OUTPUT
#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!)
// Vehicles
#define EXPLODING_AIRTRAIN // can blow up jumbo jet with rocket launcher
//#define REMOVE_TREADABLE_PATHFIND
// Pickups
//#define MONEY_MESSAGES
#define CAMERA_PICKUP
// Peds
#define PED_SKIN // support for skinned geometry on peds, requires COMPATIBLE_SAVES
#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 CANCELLABLE_CAR_ENTER
//#define PEDS_REPORT_CRIMES_ON_PHONE // requires COMPATIBLE_SAVES
// Camera
//#define PS2_CAM_TRANSITION // old way of transitioning between cam modes
#define IMPROVED_CAMERA // Better Debug cam, and maybe more in the future
#define FREE_CAM // Rotating cam
// Audio
#define EXTERNAL_3D_SOUND // use external engine to simulate 3d audio spatialization. OpenAL would not work without it (because it works in a 3d space
// originally and making it work in 2d only requires more resource). Will not work on PS2
#define AUDIO_REFLECTIONS // Enable audio reflections. Disabled on mobile, didn't exist yet on PS2.
#define RADIO_SCROLL_TO_PREV_STATION
#define AUDIO_CACHE
#define PS2_AUDIO_CHANNELS // increases the maximum number of audio channels to PS2 value of 44 (PC has 28 originally)
#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
#define PAUSE_RADIO_IN_FRONTEND // pause radio when game is paused
#define ATTACH_RELEASING_SOUNDS_TO_ENTITIES // sounds would follow ped and vehicles coordinates if not being queued otherwise
#define USE_TIME_SCALE_FOR_AUDIO // slow down/speed up sounds according to the speed of the game
#define MULTITHREADED_AUDIO // for streams. requires C++11 or later
#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
// Streaming
#if !defined(_WIN32) && !defined(__SWITCH__)
//#define ONE_THREAD_PER_CHANNEL // Don't use if you're not on SSD/Flash - also not utilized too much right now(see commented LoadAllRequestedModels in Streaming.cpp)
#define FLUSHABLE_STREAMING // Make it possible to interrupt reading when processing file isn't needed anymore.
#endif
#define BIG_IMG // Not complete - allows to read larger img files
//#define SQUEEZE_PERFORMANCE
#ifdef SQUEEZE_PERFORMANCE
#undef PS2_ALPHA_TEST
#undef NO_ISLAND_LOADING
#undef PS2_AUDIO_CHANNELS
#undef EXTENDED_OFFSCREEN_DESPAWN_RANGE
#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
// if these defines are enabled saves are not vanilla compatible without COMPATIBLE_SAVES
#ifndef COMPATIBLE_SAVES
#undef PED_SKIN
#undef PEDS_REPORT_CRIMES_ON_PHONE
#endif
#ifdef GTA_HANDHELD
#define IGNORE_MOUSE_KEYBOARD // ignore mouse & keyboard input
#endif
#ifdef __SWITCH__
#define USE_UNNAMED_SEM // named semaphores are unsupported on the switch
#endif
#endif // VANILLA_DEFINES
#if defined(AUDIO_OAL) && !defined(EXTERNAL_3D_SOUND)
#error AUDIO_OAL cannot work without EXTERNAL_3D_SOUND
#endif
#if defined(GTA_PS2) && defined(EXTERNAL_3D_SOUND)
#error EXTERNAL_3D_SOUND cannot work on PS2
#endif
#if defined(AUDIO_REFLECTIONS) && GTA_VERSION < GTA3_PC_10
#error AUDIO_REFLECTIONS cannot work with versions below GTA3_PC_10
#endif

2493
src/core/main.cpp Normal file

File diff suppressed because it is too large Load diff

76
src/core/main.h Normal file
View file

@ -0,0 +1,76 @@
#pragma once
#ifndef FINAL
// defined in RwHelpder.cpp
void PushRendergroup(const char *name);
void PopRendergroup(void);
#define PUSH_RENDERGROUP(str) PushRendergroup(str)
#define POP_RENDERGROUP() PopRendergroup()
#else
#define PUSH_RENDERGROUP(str)
#define POP_RENDERGROUP()
#endif
struct GlobalScene
{
RpWorld *world;
RwCamera *camera;
};
extern GlobalScene Scene;
extern uint8 work_buff[55000];
extern char gString[256];
extern char gString2[512];
extern wchar gUString[256];
extern wchar gUString2[256];
extern bool gbPrintShite;
extern bool gbModelViewer;
#ifdef TIMEBARS
extern bool gbShowTimebars;
#else
#define gbShowTimebars false
#endif
#ifndef FINAL
extern bool gbPrintMemoryUsage;
#endif
class CSprite2d;
bool DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
bool DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
void DoRWStuffEndOfFrame(void);
void PreAllocateRwObjects(void);
void InitialiseGame(void);
void LoadingScreen(const char *str1, const char *str2, const char *splashscreen);
void LoadingIslandScreen(const char *levelName);
CSprite2d *LoadSplash(const char *name);
void DestroySplashScreen(void);
Const char *GetLevelSplashScreen(int level);
Const char *GetRandomSplashScreen(void);
void LittleTest(void);
void ValidateVersion();
void ResetLoadingScreenBar(void);
#ifndef MASTER
void TheModelViewer(void);
#endif
#ifdef LOAD_INI_SETTINGS
bool LoadINISettings();
void SaveINISettings();
void LoadINIControllerSettings();
void SaveINIControllerSettings();
#endif
#ifdef NEW_RENDERER
extern bool gbNewRenderer;
bool FredIsInFirstPersonCam(void);
#endif
#ifdef DRAW_GAME_VERSION_TEXT
extern bool gbDrawVersionText;
#endif
#ifdef NO_MOVIES
extern bool gbNoMovies;
#endif

119
src/core/obrstr.cpp Normal file
View file

@ -0,0 +1,119 @@
#include "common.h"
#include "Debug.h"
#include "obrstr.h"
char obrstr[128];
char obrstr2[128];
void ObrInt(int32 n1)
{
IntToStr(n1, obrstr);
CDebug::DebugAddText(obrstr);
}
void ObrInt2(int32 n1, int32 n2)
{
IntToStr(n1, obrstr);
strcat(obrstr, " ");
IntToStr(n2, obrstr2);
strcat(obrstr, obrstr2);
CDebug::DebugAddText(obrstr);
}
void ObrInt3(int32 n1, int32 n2, int32 n3)
{
IntToStr(n1, obrstr);
strcat(obrstr, " ");
IntToStr(n2, obrstr2);
strcat(obrstr, obrstr2);
strcat(obrstr, " ");
IntToStr(n3, obrstr2);
strcat(obrstr, obrstr2);
CDebug::DebugAddText(obrstr);
}
void ObrInt4(int32 n1, int32 n2, int32 n3, int32 n4)
{
IntToStr(n1, obrstr);
strcat(obrstr, " ");
IntToStr(n2, obrstr2);
strcat(obrstr, obrstr2);
strcat(obrstr, " ");
IntToStr(n3, obrstr2);
strcat(obrstr, obrstr2);
strcat(obrstr, " ");
IntToStr(n4, obrstr2);
strcat(obrstr, obrstr2);
CDebug::DebugAddText(obrstr);
}
void ObrInt5(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5)
{
IntToStr(n1, obrstr);
strcat(obrstr, " ");
IntToStr(n2, obrstr2);
strcat(obrstr, obrstr2);
strcat(obrstr, " ");
IntToStr(n3, obrstr2);
strcat(obrstr, obrstr2);
strcat(obrstr, " ");
IntToStr(n4, obrstr2);
strcat(obrstr, obrstr2);
strcat(obrstr, " ");
IntToStr(n5, obrstr2);
strcat(obrstr, obrstr2);
CDebug::DebugAddText(obrstr);
}
void ObrInt6(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6)
{
IntToStr(n1, obrstr);
strcat(obrstr, " ");
IntToStr(n2, obrstr2);
strcat(obrstr, obrstr2);
strcat(obrstr, " ");
IntToStr(n3, obrstr2);
strcat(obrstr, obrstr2);
strcat(obrstr, " ");
IntToStr(n4, obrstr2);
strcat(obrstr, obrstr2);
strcat(obrstr, " ");
IntToStr(n5, obrstr2);
strcat(obrstr, obrstr2);
strcat(obrstr, " ");
IntToStr(n6, obrstr2);
strcat(obrstr, obrstr2);
CDebug::DebugAddText(obrstr);
}
void IntToStr(int32 inNum, char *outStr)
{
bool isNeg = inNum < 0;
if (isNeg) {
inNum = -inNum;
*outStr = '-';
}
int16 digits = 1;
if (inNum > 9) {
int32 _inNum = inNum;
do {
digits++;
_inNum /= 10;
} while (_inNum > 9);
}
int32 strSize = digits;
if (isNeg)
strSize++;
char *pStr = &outStr[strSize];
int32 i = 0;
do {
*(pStr-- - 1) = (inNum % 10) + '0';
inNum /= 10;
} while (++i < strSize);
outStr[strSize] = '\0';
}

9
src/core/obrstr.h Normal file
View file

@ -0,0 +1,9 @@
#pragma once
void ObrInt(int32 n1);
void ObrInt2(int32 n1, int32 n2);
void ObrInt3(int32 n1, int32 n2, int32 n3);
void ObrInt4(int32 n1, int32 n2, int32 n3, int32 n4);
void ObrInt5(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5);
void ObrInt6(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6);
void IntToStr(int32 inNum, char *outStr);

1233
src/core/re3.cpp Normal file

File diff suppressed because it is too large Load diff

269
src/core/templates.h Normal file
View file

@ -0,0 +1,269 @@
#pragma once
template<typename T, int32 n>
class CStore
{
public:
int32 allocPtr;
T store[n];
T *Alloc(void){
if(allocPtr >= n){
printf("Size of this thing:%d needs increasing\n", n);
assert(0);
}
return &store[allocPtr++];
}
void Clear(void){
allocPtr = 0;
}
int32 GetIndex(T *item){
assert(item >= &store[0]);
assert(item < &store[n]);
return item - store;
}
T *GetItem(int32 index){
assert(index >= 0);
assert(index < n);
return &store[index];
}
};
#define POOLFLAG_ID 0x7f
#define POOLFLAG_ISFREE 0x80
template<typename T, typename U = T>
class CPool
{
U *m_entries;
uint8 *m_flags;
int32 m_size;
int32 m_allocPtr;
public:
CPool(int32 size){
m_entries = (U*)new uint8[sizeof(U)*size];
m_flags = new uint8[size];
m_size = size;
m_allocPtr = 0;
for(int i = 0; i < size; i++){
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[] m_flags;
m_entries = nil;
m_flags = nil;
m_size = 0;
m_allocPtr = 0;
}
}
int32 GetSize(void) const { return m_size; }
T *New(void){
bool wrapped = false;
do
#ifdef FIX_BUGS
if (++m_allocPtr >= m_size) {
m_allocPtr = 0;
if (wrapped)
return nil;
wrapped = true;
}
#else
if(++m_allocPtr == m_size){
if(wrapped)
return nil;
wrapped = true;
m_allocPtr = 0;
}
#endif
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){
T *entry = (T*)&m_entries[handle>>8];
SetNotFreeAt(handle);
return entry;
}
void SetNotFreeAt(int32 handle){
int idx = handle>>8;
SetIsFree(idx, false);
SetId(idx, handle & POOLFLAG_ID);
for(m_allocPtr = 0; m_allocPtr < m_size; m_allocPtr++)
if(GetIsFree(m_allocPtr))
return;
}
void Delete(T *entry){
int i = GetJustIndex(entry);
SetIsFree(i, true);
if(i < m_allocPtr)
m_allocPtr = i;
}
T *GetSlot(int 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] == (handle & 0xFF) ?
(T*)&m_entries[handle >> 8] : nil;
}
int32 GetIndex(T *entry){
int i = GetJustIndex_NoFreeAssert(entry);
return m_flags[i] + (i<<8);
}
int32 GetJustIndex(T *entry){
int index = GetJustIndex_NoFreeAssert(entry);
assert(!GetIsFree(index));
return index;
}
int32 GetJustIndex_NoFreeAssert(T* entry){
int index = ((U*)entry - m_entries);
assert((U*)entry == (U*)&m_entries[index]); // cast is unsafe - check required
return index;
}
int32 GetNoOfUsedSpaces(void) const{
int i;
int n = 0;
for(i = 0; i < m_size; i++)
if(!GetIsFree(i))
n++;
return n;
}
void ClearStorage(uint8 *&flags, U *&entries){
delete[] flags;
delete[] (uint8*)entries;
flags = nil;
entries = nil;
}
uint32 GetMaxEntrySize() const { return sizeof(U); }
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, m_size);
m_allocPtr = 0;
ClearStorage(flags, entries);
debug("CopyBack:%d (/%d)\n", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */
}
void Store(uint8 *&flags, U *&entries){
flags = (uint8*)new uint8[sizeof(uint8)*m_size];
entries = (U*)new uint8[sizeof(U)*m_size];
memcpy(flags, m_flags, sizeof(uint8)*m_size);
memcpy(entries, m_entries, sizeof(U)*m_size);
debug("Stored:%d (/%d)\n", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */
}
};
template<typename T>
class CLink
{
public:
T item;
CLink<T> *prev;
CLink<T> *next;
void Insert(CLink<T> *link){
link->next = this->next;
this->next->prev = link;
link->prev = this;
this->next = link;
}
void Remove(void){
this->prev->next = this->next;
this->next->prev = this->prev;
}
};
template<typename T>
class CLinkList
{
public:
CLink<T> head, tail;
CLink<T> freeHead, freeTail;
CLink<T> *links;
void Init(int n){
links = new CLink<T>[n];
head.next = &tail;
tail.prev = &head;
freeHead.next = &freeTail;
freeTail.prev = &freeHead;
while(n--)
freeHead.Insert(&links[n]);
}
void Shutdown(void){
delete[] links;
links = nil;
}
void Clear(void){
while(head.next != &tail)
Remove(head.next);
}
CLink<T> *Insert(T const &item){
CLink<T> *node = freeHead.next;
if(node == &freeTail)
return nil;
node->item = item;
node->Remove(); // remove from free list
head.Insert(node);
return node;
}
CLink<T> *InsertSorted(T const &item){
CLink<T> *sort;
for(sort = head.next; sort != &tail; sort = sort->next)
if(sort->item.sort >= item.sort)
break;
CLink<T> *node = freeHead.next;
if(node == &freeTail)
return nil;
node->item = item;
node->Remove(); // remove from free list
sort->prev->Insert(node);
return node;
}
void Remove(CLink<T> *link){
link->Remove(); // remove from list
freeHead.Insert(link); // insert into free list
}
int32 Count(void){
int n = 0;
CLink<T> *lnk;
for(lnk = head.next; lnk != &tail; lnk = lnk->next)
n++;
return n;
}
};

121
src/core/timebars.cpp Normal file
View file

@ -0,0 +1,121 @@
#include "common.h"
#ifndef MASTER
#include "Font.h"
#include "Frontend.h"
#include "Timer.h"
#include "Text.h"
#define MAX_TIMERS (50)
#define MAX_MS_COLLECTED (40)
// enables frame time output
#define FRAMETIME
struct sTimeBar
{
char name[20];
float startTime;
float endTime;
int32 unk;
};
struct
{
sTimeBar Timers[MAX_TIMERS];
uint32 count;
} TimerBar;
float MaxTimes[MAX_TIMERS];
float MaxFrameTime;
uint32 curMS;
uint32 msCollected[MAX_MS_COLLECTED];
#ifdef FRAMETIME
float FrameInitTime;
#endif
void tbInit()
{
TimerBar.count = 0;
uint32 i = CTimer::GetFrameCounter() & 0x7F;
if (i == 0) {
do
MaxTimes[i++] = 0.0f;
while (i != MAX_TIMERS);
#ifdef FRAMETIME
MaxFrameTime = 0.0f;
#endif
}
#ifdef FRAMETIME
FrameInitTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
#endif
}
void tbStartTimer(int32 unk, Const char *name)
{
strcpy(TimerBar.Timers[TimerBar.count].name, name);
TimerBar.Timers[TimerBar.count].unk = unk;
TimerBar.Timers[TimerBar.count].startTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
TimerBar.count++;
}
void tbEndTimer(Const char* name)
{
uint32 n = 1500;
for (uint32 i = 0; i < TimerBar.count; i++) {
if (strcmp(name, TimerBar.Timers[i].name) == 0)
n = i;
}
assert(n != 1500);
TimerBar.Timers[n].endTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
}
float Diag_GetFPS()
{
return 39000.0f / (msCollected[(curMS - 1) % MAX_MS_COLLECTED] - msCollected[curMS % MAX_MS_COLLECTED]);
}
void tbDisplay()
{
char temp[200];
wchar wtemp[200];
#ifdef FRAMETIME
float FrameEndTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
#endif
msCollected[(curMS++) % MAX_MS_COLLECTED] = RsTimer();
CFont::SetBackgroundOff();
CFont::SetBackgroundColor(CRGBA(0, 0, 0, 128));
CFont::SetScale(0.48f, 1.12f);
CFont::SetCentreOff();
CFont::SetJustifyOff();
CFont::SetWrapx(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH));
CFont::SetRightJustifyOff();
CFont::SetPropOn();
CFont::SetFontStyle(FONT_BANK);
sprintf(temp, "FPS: %.2f", Diag_GetFPS());
AsciiToUnicode(temp, wtemp);
CFont::SetColor(CRGBA(255, 255, 255, 255));
if (!CMenuManager::m_PrefsMarketing || !CMenuManager::m_PrefsDisableTutorials) {
CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * (4.0f / DEFAULT_SCREEN_HEIGHT), wtemp);
#ifndef FINAL
// Timers output (my own implementation)
for (uint32 i = 0; i < TimerBar.count; i++) {
MaxTimes[i] = Max(MaxTimes[i], TimerBar.Timers[i].endTime - TimerBar.Timers[i].startTime);
sprintf(temp, "%s: %.2f", &TimerBar.Timers[i].name[0], MaxTimes[i]);
AsciiToUnicode(temp, wtemp);
CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * ((8.0f * (i + 2)) / DEFAULT_SCREEN_HEIGHT), wtemp);
}
#ifdef FRAMETIME
MaxFrameTime = Max(MaxFrameTime, FrameEndTime - FrameInitTime);
sprintf(temp, "Frame Time: %.2f", MaxFrameTime);
AsciiToUnicode(temp, wtemp);
CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * ((8.0f * (TimerBar.count + 4)) / DEFAULT_SCREEN_HEIGHT), wtemp);
#endif // FRAMETIME
#endif // !FINAL
}
}
#endif // !MASTER

13
src/core/timebars.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#ifdef TIMEBARS
void tbInit();
void tbStartTimer(int32, Const char*);
void tbEndTimer(Const char*);
void tbDisplay();
#else
#define tbInit()
#define tbStartTimer(a, b)
#define tbEndTimer(a)
#define tbDisplay()
#endif