This commit is contained in:
_AG
2019-07-07 15:16:54 +02:00
159 changed files with 390 additions and 188 deletions

1310
src/core/Camera.cpp Normal file

File diff suppressed because it is too large Load Diff

477
src/core/Camera.h Normal file
View File

@ -0,0 +1,477 @@
#pragma once
#include "Placeable.h"
class CEntity;
class CPed;
class CAutomobile;
#define NUMBER_OF_VECTORS_FOR_AVERAGE 2
struct CCam
{
enum
{
MODE_TOPDOWN1 = 1,
MODE_TOPDOWN2,
MODE_BEHINDCAR,
MODE_FOLLOWPED,
MODE_AIMING,
MODE_DEBUG,
MODE_SNIPER,
MODE_ROCKET,
MODE_MODELVIEW,
MODE_BILL,
MODE_SYPHON,
MODE_CIRCLE,
MODE_CHEESYZOOM,
MODE_WHEELCAM,
MODE_FIXED,
MODE_FIRSTPERSON,
MODE_FLYBY,
MODE_CAMONASTRING,
MODE_REACTIONCAM,
MODE_FOLLOWPEDWITHBINDING,
MODE_CHRISWITHBINDINGPLUSROTATION,
MODE_BEHINDBOAT,
MODE_PLAYERFALLENWATER,
MODE_CAMONTRAINROOF,
MODE_CAMRUNNINGSIDETRAIN,
MODE_BLOODONTHETRACKS,
MODE_IMTHEPASSENGERWOOWOO,
MODE_SYPHONCRIMINFRONT,
MODE_PEDSDEADBABY,
MODE_CUSHYPILLOWSARSE,
MODE_LOOKATCARS,
MODE_ARRESTCAMONE,
MODE_ARRESTCAMTWO,
MODE_M16FIRSTPERSON_34,
MODE_SPECIALFIXEDFORSYPHON,
MODE_FIGHT,
MODE_TOPDOWNPED,
MODE_SNIPER_RUN_AROUND,
MODE_ROCKET_RUN_AROUND,
MODE_FIRSTPERSONPEDONPC_40,
MODE_FIRSTPERSONPEDONPC_41,
MODE_FIRSTPERSONPEDONPC_42,
MODE_EDITOR,
MODE_M16FIRSTPERSON_44
};
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; // 32
bool LookingRight;
bool ResetStatics; //for interpolation type stuff to work
bool Rotating;
int16 Mode; // CameraMode
uint32 m_uiFinishTime; // 52
int m_iDoCollisionChecksOnFrameNum;
int m_iDoCollisionCheckEveryNumOfFrames;
int m_iFrameNumWereAt; // 64
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_fUnknownZOffSet;
float m_fAmountFractionObscured;
float m_fAlphaSpeedOverOneFrame; // 100
float m_fBetaSpeedOverOneFrame;
float m_fBufferedTargetBeta;
float m_fBufferedTargetOrientation;
float m_fBufferedTargetOrientationSpeed;
float m_fCamBufferedHeight;
float m_fCamBufferedHeightSpeed;
float m_fCloseInPedHeightOffset;
float m_fCloseInPedHeightOffsetSpeed; // 132
float m_fCloseInCarHeightOffset;
float m_fCloseInCarHeightOffsetSpeed;
float m_fDimensionOfHighestNearCar;
float m_fDistanceBeforeChanges;
float m_fFovSpeedOverOneFrame;
float m_fMinDistAwayFromCamWhenInterPolating;
float m_fPedBetweenCameraHeightOffset;
float m_fPlayerInFrontSyphonAngleOffSet; // 164
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; // 200
float m_fInitialPlayerOrientation; //used for first person
float Alpha;
float AlphaSpeed;
float FOV;
float FOVSpeed;
float Beta;
float BetaSpeed;
float Distance; // 232
float DistanceSpeed;
float CA_MIN_DISTANCE;
float CA_MAX_DISTANCE;
float SpeedVar;
// ped onfoot zoom distance
float m_fTargetZoomGroundOne;
float m_fTargetZoomGroundTwo; // 256
float m_fTargetZoomGroundThree;
// ped onfoot alpha angle offset
float m_fTargetZoomOneZExtra;
float m_fTargetZoomTwoZExtra;
float m_fTargetZoomThreeZExtra;
float m_fTargetZoomZCloseIn;
float m_fMinRealGroundDist;
float m_fTargetCloseInDist;
CVector m_cvecTargetCoorsForFudgeInter; // 360
CVector m_cvecCamFixedModeVector; // 372
CVector m_cvecCamFixedModeSource; // 384
CVector m_cvecCamFixedModeUpOffSet; // 396
CVector m_vecLastAboveWaterCamPosition; //408 //helper for when the player has gone under the water
CVector m_vecBufferedPlayerBodyOffset; // 420
// The three vectors that determine this camera for this frame
CVector Front; // 432 // 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;
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);
bool Using3rdPersonMouseCam();
bool GetWeaponFirstPersonOn();
void Process_Debug(float *vec, float a, float b, float c);
void Process_FollowPed(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);
};
static_assert(sizeof(CCam) == 0x1A4, "CCam: wrong size");
static_assert(offsetof(CCam, Alpha) == 0xA8, "CCam: error");
static_assert(offsetof(CCam, Front) == 0x140, "CCam: error");
struct CCamPathSplines
{
float m_arr_PathData[800];
};
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: figure out
FADE_0,
FADE_1, // mid fade
FADE_2,
FADE_OUT = 0,
FADE_IN,
};
enum
{
MBLUR_NONE,
MBLUR_SNIPER,
MBLUR_NORMAL,
MBLUR_INTRO1, // green camera
MBLUR_INTRO2, // unused
MBLUR_INTRO3, // bank scene
MBLUR_INTRO4, // jail break scene
MBLUR_INTRO5, // explosion
MBLUR_INTRO6, // player shot
MBLUR_UNUSED, // pinkish
};
struct CCamera : public CPlaceable
{
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_bJustJumpedOutOf1stPersonBecauseOfTarget;
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;
// where are those?
//bool m_bVehicleSuspenHigh;
//bool m_bEnable1rstPersonCamCntrlsScript;
//bool m_bAllow1rstPersonWeaponsCamera;
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;
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;
float CarZoomIndicator;
float CarZoomValue;
float CarZoomValueSmooth;
float DistanceToWater;
float FOVDuringInter;
float LODDistMultiplier;
float GenerationDistMultiplier;
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;
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;
float PedZoomIndicator;
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];
void *pToGarageWeAreIn;
void *pToGarageWeAreInForHackAvoidFirstPerson;
CQueuedMode m_PlayerMode;
CQueuedMode PlayerWeaponMode;
CVector m_PreviousCameraPosition;
CVector m_RealPreviousCameraPosition;
CVector m_cvecAimingTargetCoors;
CVector m_vecFixedModeVector;
// one of those has to go
CVector m_vecFixedModeSource;
CVector m_vecFixedModeUpOffSet;
// CVector m_vecCutSceneOffset;
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;
CVector m_vecClearGeometryVec;
CVector m_vecGameCamPos;
CVector SourceDuringInter;
CVector TargetDuringInter;
CVector UpDuringInter;
RwCamera *m_pRwCamera;
CEntity *pTargetEntity;
CCamPathSplines m_arrPathArray[4];
CTrainCamNode m_arrTrainCamNode[800];
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_fFractionInterToStopMovingTarget;
float m_fFractionInterToStopCatchUpTarget;
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;
CMatrix &GetCameraMatrix(void) { return m_cameraMatrix; }
CVector &GetGameCamPosition(void) { return m_vecGameCamPos; }
bool IsPointVisible(const CVector &center, const CMatrix *mat);
bool IsSphereVisible(const CVector &center, float radius, const CMatrix *mat);
bool IsBoxVisible(RwV3d *box, const CMatrix *mat);
int GetLookDirection(void);
void Fade(float timeout, int16 direction);
int GetScreenFadeStatus(void);
void ProcessFade(void);
void ProcessMusicFade(void);
void SetFadeColour(uint8 r, uint8 g, uint8 b);
void SetMotionBlur(int r, int g, int b, int a, int type);
void SetMotionBlurAlpha(int a);
void RenderMotionBlur(void);
void ClearPlayerWeaponMode();
void CalculateDerivedValues(void);
void DrawBordersForWideScreen(void);
void Restore(void);
void SetWidescreenOff(void);
void dtor(void) { this->CCamera::~CCamera(); }
};
static_assert(offsetof(CCamera, m_WideScreenOn) == 0x70, "CCamera: error");
static_assert(offsetof(CCamera, WorldViewerBeingUsed) == 0x75, "CCamera: error");
static_assert(offsetof(CCamera, m_uiNumberOfTrainCamNodes) == 0x84, "CCamera: error");
static_assert(offsetof(CCamera, m_uiTransitionState) == 0x89, "CCamera: error");
static_assert(offsetof(CCamera, m_uiTimeTransitionStart) == 0x94, "CCamera: error");
static_assert(offsetof(CCamera, m_BlurBlue) == 0x9C, "CCamera: error");
static_assert(offsetof(CCamera, Cams) == 0x1A4, "CCamera: error");
static_assert(sizeof(CCamera) == 0xE9D8, "CCamera: wrong size");
extern CCamera &TheCamera;

529
src/core/CdStream.cpp Normal file
View File

@ -0,0 +1,529 @@
#include <windows.h>
#include "common.h"
#include "patcher.h"
#include "CdStream.h"
#include "rwcore.h"
#include "RwHelper.h"
#define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", __VA_ARGS__)
#define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", __VA_ARGS__)
struct CdReadInfo
{
uint32 nSectorOffset;
uint32 nSectorsToRead;
void *pBuffer;
char field_C;
bool bLocked;
bool bInUse;
char _pad0;
int32 nStatus;
HANDLE hSemaphore;
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;
DWORD _gCdStreamThreadId;
CdReadInfo *gpReadInfo;
Queue gChannelRequestQ;
int32 lastPosnRead;
BOOL _gbCdStreamOverlapped;
BOOL _gbCdStreamAsync;
DWORD _gdwCdStreamFlags;
void
CdStreamInitThread(void)
{
SetLastError(0);
if ( gNumChannels > 0 )
{
for ( int32 i = 0; i < gNumChannels; i++ )
{
gpReadInfo[i].hSemaphore = CreateSemaphore(nil, 0, 2, nil);
if ( gpReadInfo[i].hSemaphore == nil )
{
CDTRACE("failed to create sync semaphore");
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 );
gCdStreamSema = CreateSemaphore(nil, 0, 5, "CdStream");
if ( gCdStreamSema == nil )
{
CDTRACE("failed to create stream semaphore");
ASSERT(0);
return;
}
_gCdStreamThread = CreateThread(nil, 64*1024/*64KB*/, CdStreamThread, nil, CREATE_SUSPENDED, &_gCdStreamThreadId);
if ( _gCdStreamThread == nil )
{
CDTRACE("failed to create streaming thread");
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;
if ( BytesPerSector <= CDSTREAM_SECTOR_SIZE )
{
_gdwCdStreamFlags |= FILE_FLAG_NO_BUFFERING;
debug("Using no buffered loading for streaming\n");
}
_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 );
CDDEBUG("read info %p", 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].hSemaphore);
}
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->bInUse )
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;
}
SetFilePointer(hImage, _GET_OFFSET(offset) * CDSTREAM_SECTOR_SIZE, nil, FILE_BEGIN);
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->bInUse )
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;
}
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->hSemaphore != nil );
WaitForSingleObject(pChannel->hSemaphore, INFINITE);
}
pChannel->bInUse = false;
return pChannel->nStatus;
}
DWORD NumberOfBytesTransferred;
if ( _gbCdStreamOverlapped && pChannel->hFile )
{
ASSERT(pChannel->hFile != nil );
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->bInUse = 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;
}
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->hSemaphore != nil );
ReleaseSemaphore(pChannel->hSemaphore, 1, NULL);
}
pChannel->bInUse = 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;
}
STARTPATCHES
InjectHook(0x405B50, CdStreamInitThread, PATCH_JUMP);
InjectHook(0x405C80, CdStreamInit, PATCH_JUMP);
//InjectHook(0x405DB0, debug, PATCH_JUMP);
InjectHook(0x405DC0, GetGTA3ImgSize, PATCH_JUMP);
InjectHook(0x405DD0, CdStreamShutdown, PATCH_JUMP);
InjectHook(0x405E40, CdStreamRead, PATCH_JUMP);
InjectHook(0x405F90, CdStreamGetStatus, PATCH_JUMP);
InjectHook(0x406000, CdStreamGetLastPosn, PATCH_JUMP);
InjectHook(0x406010, CdStreamSync, PATCH_JUMP);
InjectHook(0x4060B0, AddToQueue, PATCH_JUMP);
InjectHook(0x4060F0, GetFirstInQueue, PATCH_JUMP);
InjectHook(0x406110, RemoveFirstInQueue, PATCH_JUMP);
InjectHook(0x406140, CdStreamThread, PATCH_JUMP);
InjectHook(0x406270, CdStreamAddImage, PATCH_JUMP);
InjectHook(0x4062E0, CdStreamGetImageName, PATCH_JUMP);
InjectHook(0x406300, CdStreamRemoveImages, PATCH_JUMP);
InjectHook(0x406370, CdStreamGetNumImages, PATCH_JUMP);
ENDPATCHES

46
src/core/CdStream.h Normal file
View File

@ -0,0 +1,46 @@
#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);
DWORD WINAPI CdStreamThread(LPVOID lpThreadParameter);
bool CdStreamAddImage(char const *path);
char *CdStreamGetImageName(int32 cd);
void CdStreamRemoveImages(void);
int32 CdStreamGetNumImages(void);

131
src/core/Clock.cpp Normal file
View File

@ -0,0 +1,131 @@
#include "common.h"
#include "patcher.h"
#include "Timer.h"
#include "Pad.h"
#include "Clock.h"
#include "Stats.h"
_TODO("gbFastTime");
bool &gbFastTime = *(bool*)0x95CDBB;
uint8 &CClock::ms_nGameClockHours = *(uint8*)0x95CDA6;
uint8 &CClock::ms_nGameClockMinutes = *(uint8*)0x95CDC8;
uint16 &CClock::ms_nGameClockSeconds = *(uint16*)0x95CC7C;
uint8 &CClock::ms_Stored_nGameClockHours = *(uint8*)0x95CD7B;
uint8 &CClock::ms_Stored_nGameClockMinutes = *(uint8*)0x95CD9B;
uint16 &CClock::ms_Stored_nGameClockSeconds = *(uint16*)0x95CC9C;
uint32 &CClock::ms_nMillisecondsPerGameMinute = *(uint32*)0x8F2C64;
int32 &CClock::ms_nLastClockTick = *(int32*)0x9430E4;
bool &CClock::ms_bClockHasBeenStored = *(bool*)0x95CD82;
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;
}
STARTPATCHES
InjectHook(0x473370, CClock::Initialise, PATCH_JUMP);
InjectHook(0x473460, CClock::Update, PATCH_JUMP);
InjectHook(0x4733C0, CClock::SetGameClock, PATCH_JUMP);
InjectHook(0x4733F0, CClock::GetGameClockMinutesUntil, PATCH_JUMP);
InjectHook(0x473420, CClock::GetIsTimeInRange, PATCH_JUMP);
InjectHook(0x473540, CClock::StoreClock, PATCH_JUMP);
InjectHook(0x473570, CClock::RestoreClock, PATCH_JUMP);
ENDPATCHES

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

@ -0,0 +1,31 @@
#pragma once
class CClock
{
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 int32 &ms_nLastClockTick;
static bool &ms_bClockHasBeenStored;
public:
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; }
};

1887
src/core/Collision.cpp Normal file

File diff suppressed because it is too large Load Diff

157
src/core/Collision.h Normal file
View File

@ -0,0 +1,157 @@
#pragma once
#include "templates.h"
#include "Game.h" // for eLevelName
struct CColSphere
{
CVector center;
float radius;
uint8 surface;
uint8 piece;
void Set(float radius, const CVector &center, uint8 surf, uint8 piece);
void Set(float radius, const CVector &center) { this->center = center; this->radius = radius; }
};
struct CColBox
{
CVector min;
CVector max;
uint8 surface;
uint8 piece;
void Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece);
CVector GetSize(void) { return max - min; }
};
struct CColLine
{
CVector p0;
int pad0;
CVector p1;
int pad1;
CColLine(void) { };
CColLine(const CVector &p0, const CVector &p1) { this->p0 = p0; this->p1 = p1; };
void Set(const CVector &p0, const CVector &p1);
CColLine *ctor(CVector *p0, CVector *p1) { return ::new (this) CColLine(*p0, *p1); }
};
struct CColTriangle
{
uint16 a;
uint16 b;
uint16 c;
uint8 surface;
void Set(const CVector *v, int a, int b, int c, uint8 surf, uint8 piece);
};
struct CColTrianglePlane
{
CVector normal;
float dist;
uint8 dir;
void Set(const CVector *v, CColTriangle &tri);
void GetNormal(CVector &n) const { n = normal; }
float CalcPoint(const CVector &v) const { return DotProduct(normal, v) - dist; };
};
struct CColPoint
{
CVector point;
int pad1;
// the surface normal on the surface of point
CVector normal;
int pad2;
uint8 surfaceA;
uint8 pieceA;
uint8 surfaceB;
uint8 pieceB;
float depth;
};
struct CStoredCollPoly
{
CVector verts[3];
bool valid;
};
struct CColModel
{
CColSphere boundingSphere;
CColBox boundingBox;
short numSpheres;
short numLines;
short numBoxes;
short numTriangles;
int level;
bool ownsCollisionVolumes;
CColSphere *spheres;
CColLine *lines;
CColBox *boxes;
CVector *vertices;
CColTriangle *triangles;
CColTrianglePlane *trianglePlanes;
CColModel(void);
~CColModel(void);
void RemoveCollisionVolumes(void);
void CalculateTrianglePlanes(void);
void RemoveTrianglePlanes(void);
CLink<CColModel*> *GetLinkPtr(void);
void SetLinkPtr(CLink<CColModel*>*);
void GetTrianglePoint(CVector &v, int i) const;
CColModel *ctor(void) { return ::new (this) CColModel(); }
void dtor(void) { this->CColModel::~CColModel(); }
CColModel& operator=(const CColModel& other);
};
class CCollision
{
public:
static eLevelName &ms_collisionInMemory;
static CLinkList<CColModel*> &ms_colModelCache;
static void Init(void);
static void Shutdown(void);
static void Update(void);
static void LoadCollisionWhenINeedIt(bool changeLevel);
static void SortOutCollisionAfterLoad(void);
static void LoadCollisionScreen(eLevelName level);
static void DrawColModel(const CMatrix &mat, const CColModel &colModel);
static void DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id);
static void CalculateTrianglePlanes(CColModel *model);
// all these return true if there's a collision
static bool TestSphereSphere(const CColSphere &s1, const CColSphere &s2);
static bool TestSphereBox(const CColSphere &sph, const CColBox &box);
static bool TestLineBox(const CColLine &line, const CColBox &box);
static bool TestVerticalLineBox(const CColLine &line, const CColBox &box);
static bool TestLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane);
static bool TestLineSphere(const CColLine &line, const CColSphere &sph);
static bool TestSphereTriangle(const CColSphere &sphere, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane);
static bool TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough);
static bool ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq);
static bool ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq);
static bool ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist);
static bool ProcessVerticalLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist, CStoredCollPoly *poly);
static bool ProcessLineTriangle(const CColLine &line , const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist);
static bool ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist);
static bool ProcessSphereTriangle(const CColSphere &sph, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq);
static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough);
static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly);
static int32 ProcessColModels(const CMatrix &matrix1, CColModel &model1, const CMatrix &matrix2, CColModel &model2, CColPoint *point1, CColPoint *point2, float *linedists);
// TODO:
// CCollision::IsStoredPolyStillValidVerticalLine
static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point);
static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest);
};

View File

@ -0,0 +1,57 @@
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#include "common.h"
#include "patcher.h"
#include "ControllerConfig.h"
#include "Pad.h"
#include "FileMgr.h"
CControllerConfigManager &ControlsManager = *(CControllerConfigManager*)0x8F43A4;
WRAPPER void CControllerConfigManager::UpdateJoyButtonState(int padnumber) { EAXJMP(0x58F5B0); }
WRAPPER void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonDown(int button, int padnumber) { EAXJMP(0x58C5E0); }
WRAPPER void CControllerConfigManager::AffectControllerStateOn_ButtonDown(int button, eControllerType type) { EAXJMP(0x58C730); }
WRAPPER void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonUp(int button, int padnumber) { EAXJMP(0x58CE80); }
WRAPPER void CControllerConfigManager::AffectControllerStateOn_ButtonUp(int button, int padnumber) { EAXJMP(0x58CFD0); }
WRAPPER void CControllerConfigManager::MakeControllerActionsBlank() { EAXJMP(0x58B7A0); }
WRAPPER void CControllerConfigManager::InitDefaultControlConfiguration() { EAXJMP(0x58B930); }
WRAPPER void CControllerConfigManager::InitDefaultControlConfigMouse(CMouseControllerState const &mousestate) { EAXJMP(0x58BD00); }
WRAPPER int32 CControllerConfigManager::GetJoyButtonJustDown() { EAXJMP(0x58B7D0); }
WRAPPER void CControllerConfigManager::InitDefaultControlConfigJoyPad(unsigned int buttons) { EAXJMP(0x58BD90); }
WRAPPER void CControllerConfigManager::ClearSimButtonPressCheckers() { EAXJMP(0x58D220); }
WRAPPER void CControllerConfigManager::AffectPadFromKeyBoard() { EAXJMP(0x58D0C0); }
WRAPPER void CControllerConfigManager::AffectPadFromMouse() { EAXJMP(0x58D1A0); }
void CControllerConfigManager::LoadSettings(int32 file)
{
bool bValid = true;
if ( file )
{
char buff[29];
CFileMgr::Read(file, buff, sizeof(buff));
if ( !strncmp(buff, "THIS FILE IS NOT VALID YET", sizeof(buff) - 3) )
bValid = false;
else
CFileMgr::Seek(file, 0, 0);
}
if ( bValid )
{
ControlsManager.MakeControllerActionsBlank();
for ( int i = 0; i < 4; i++ )
{
for ( int j = 0; j < 41; j++ )
{
CFileMgr::Read(file, (char *)&ControlsManager.m_aSettings[j][i], sizeof(tControllerConfigBind));
}
}
}
}
WRAPPER void CControllerConfigManager::SaveSettings(int32 file)
{
EAXJMP(0x58B800);
}

View File

@ -0,0 +1,58 @@
#pragma once
// based on x-gtasa
enum eControllerType
{
KEYBOARD,
OPTIONAL_EXTRA,
MOUSE,
JOYSTICK,
};
class CMouseControllerState;
class CControllerConfigManager
{
public:
struct tControllerConfigBind
{
RsKeyCodes m_Key;
int32 m_ContSetOrder;
};
bool field_0;
char _pad0[3];
DIJOYSTATE2 m_OldState;
DIJOYSTATE2 m_NewState;
wchar m_aActionNames[41][40];
bool m_aButtonStates[17];
char _pad1[3];
tControllerConfigBind m_aSettings[41][4];
uint8 m_aSimCheckers[4][4];
bool m_bMouseAssociated;
char _pad2[3];
void UpdateJoyButtonState(int padnumber);
void UpdateJoyInConfigMenus_ButtonDown(int button, int padnumber);
void AffectControllerStateOn_ButtonDown(int button, eControllerType type);
void UpdateJoyInConfigMenus_ButtonUp(int button, int padnumber);
void AffectControllerStateOn_ButtonUp(int button, int padnumber);
int32 GetJoyButtonJustDown();
void LoadSettings(int32 file);
void SaveSettings(int32 file);
void MakeControllerActionsBlank();
void InitDefaultControlConfiguration();
void InitDefaultControlConfigMouse(CMouseControllerState const &mousestate);
void InitDefaultControlConfigJoyPad(unsigned int buttons);
void ClearSimButtonPressCheckers();
void AffectPadFromKeyBoard();
void AffectPadFromMouse();
};
VALIDATE_SIZE(CControllerConfigManager, 0x143C);
extern CControllerConfigManager &ControlsManager;

7
src/core/CutsceneMgr.cpp Normal file
View File

@ -0,0 +1,7 @@
#include "common.h"
#include "patcher.h"
#include "CutsceneMgr.h"
bool &CCutsceneMgr::ms_running = *(bool*)0x95CCF5;
bool &CCutsceneMgr::ms_cutsceneProcessing = *(bool*)0x95CD9F;
CDirectory *&CCutsceneMgr::ms_pCutsceneDir = *(CDirectory**)0x8F5F88;

15
src/core/CutsceneMgr.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
class CDirectory;
class CCutsceneMgr
{
static bool &ms_running;
static bool &ms_cutsceneProcessing;
public:
static CDirectory *&ms_pCutsceneDir;
static bool IsRunning(void) { return ms_running; }
static bool IsCutsceneProcessing(void) { return ms_cutsceneProcessing; }
};

65
src/core/Directory.cpp Normal file
View File

@ -0,0 +1,65 @@
#include "common.h"
#include "patcher.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, 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);
entries[numEntries++] = dirinfo;
}
bool
CDirectory::FindItem(const char *name, uint32 &offset, uint32 &size)
{
int i;
for(i = 0; i < numEntries; i++)
if(strcmpi(entries[i].name, name) == 0){
offset = entries[i].offset;
size = entries[i].size;
return true;
}
return false;
}
STARTPATCHES
InjectHook(0x473630, &CDirectory::ReadDirFile, PATCH_JUMP);
InjectHook(0x473690, &CDirectory::WriteDirFile, PATCH_JUMP);
InjectHook(0x473600, &CDirectory::AddItem, PATCH_JUMP);
InjectHook(0x4736E0, &CDirectory::FindItem, PATCH_JUMP);
ENDPATCHES

22
src/core/Directory.h Normal file
View File

@ -0,0 +1,22 @@
#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);
bool FindItem(const char *name, uint32 &offset, uint32 &size);
};

1182
src/core/FileLoader.cpp Normal file

File diff suppressed because it is too large Load Diff

42
src/core/FileLoader.h Normal file
View File

@ -0,0 +1,42 @@
#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, 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 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);
};

300
src/core/FileMgr.cpp Normal file
View File

@ -0,0 +1,300 @@
#define _CRT_SECURE_NO_WARNINGS
#include <fcntl.h>
#include <direct.h>
#include "common.h"
#include "patcher.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];
/* 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 = fopen(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 int
myfread(void *buf, size_t elt, size_t n, int fd)
{
if(myfiles[fd].isText){
char *p;
size_t i;
int c;
n *= elt;
p = (char*)buf;
for(i = 0; i < n; i++){
c = myfgetc(fd);
if(c == EOF)
break;
*p++ = c;
}
return i / elt;
}
return fread(buf, elt, n, myfiles[fd].file);
}
static int
myfwrite(void *buf, size_t elt, size_t n, int fd)
{
if(myfiles[fd].isText){
char *p;
size_t i;
int c;
n *= elt;
p = (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 = (char*)0x5F18F8;
char *CFileMgr::ms_dirName = (char*)0x713CA8;
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, "\\");
}
chdir(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, "\\");
}
chdir(ms_dirName);
}
void
CFileMgr::SetDirMyDocuments(void)
{
SetDir(""); // better start at the root if user directory is relative
chdir(_psGetUserFilesFolder());
}
int
CFileMgr::LoadFile(const char *file, uint8 *buf, int unused, const char *mode)
{
int fd;
int n, len;
fd = myfopen(file, mode);
if(fd == 0)
return 0;
len = 0;
do{
n = myfread(buf + len, 1, 0x4000, fd);
if(n < 0)
return -1;
len += n;
}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");
}
int
CFileMgr::Read(int fd, char *buf, int len)
{
return myfread(buf, 1, len, fd);
}
int
CFileMgr::Write(int fd, char *buf, int len)
{
return myfwrite(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);
}
STARTPATCHES
InjectHook(0x478F80, CFileMgr::Initialise, PATCH_JUMP);
InjectHook(0x478FB0, CFileMgr::ChangeDir, PATCH_JUMP);
InjectHook(0x479020, CFileMgr::SetDir, PATCH_JUMP);
InjectHook(0x479080, CFileMgr::SetDirMyDocuments, PATCH_JUMP);
InjectHook(0x479090, CFileMgr::LoadFile, PATCH_JUMP);
InjectHook(0x479100, CFileMgr::OpenFile, PATCH_JUMP);
InjectHook(0x479120, CFileMgr::OpenFileForWriting, PATCH_JUMP);
InjectHook(0x479140, CFileMgr::Read, PATCH_JUMP);
InjectHook(0x479160, CFileMgr::Write, PATCH_JUMP);
InjectHook(0x479180, CFileMgr::Seek, PATCH_JUMP);
InjectHook(0x4791D0, CFileMgr::ReadLine, PATCH_JUMP);
InjectHook(0x479200, CFileMgr::CloseFile, PATCH_JUMP);
InjectHook(0x479210, CFileMgr::GetErrorReadWrite, PATCH_JUMP);
ENDPATCHES

21
src/core/FileMgr.h Normal file
View File

@ -0,0 +1,21 @@
#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 int LoadFile(const char *file, uint8 *buf, int unused, const char *mode);
static int OpenFile(const char *file, const char *mode);
static int OpenFileForWriting(const char *file);
static int Read(int fd, char *buf, int len);
static int Write(int fd, char *buf, int 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);
};

5
src/core/Fire.cpp Normal file
View File

@ -0,0 +1,5 @@
#include "common.h"
#include "patcher.h"
#include "Fire.h"
WRAPPER void CFire::Extinguish(void) { EAXJMP(0x479D40); }

23
src/core/Fire.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include "common.h"
#include "Entity.h"
class CFire
{
char m_bIsOngoing;
char m_bExists;
char m_bPropogationFlag;
char m_bAudioSet;
CVector m_vecPos;
CEntity *m_pEntity;
CEntity *m_pSource;
int m_nExtinguishTime;
int m_nStartTime;
int field_20;
int field_24;
int field_28;
float field_2C;
public:
void Extinguish(void);
};

2353
src/core/Frontend.cpp Normal file

File diff suppressed because it is too large Load Diff

512
src/core/Frontend.h Normal file
View File

@ -0,0 +1,512 @@
#pragma
#include "Sprite2d.h"
#define MENUHEADER_POS_X 35.0f
#define MENUHEADER_POS_Y 93.0f
#define MENUHEADER_WIDTH 0.84f
#define MENUHEADER_HEIGHT 1.6f
#define MENUACTION_POS_X 20.0f
#define MENUACTION_POS_Y 37.5f
#define MENUACTION_WIDTH 0.675f
#define MENUACTION_HEIGHT 0.81f
#define MENUCOLUMN_POS_X MENUHEADER_POS_X + 16.0f
#define MENUCOLUMN_MAX_Y 149.0f
#define MENUCOLUMN_MID_Y 100.0f
#define MENUCOLUMN_MIN_Y 110.0f
#define MENUCOLUMN_PAUSE_Y 25.0f
#define MENUCOLUMN_START_Y 9.0f
#define MENUCOLUMN_FEDS 139.0f
#define MENUCOLUMN_SAVE_X 121.0f
#define MENUCOLUMN_SAVE_Y 111.0f
#define MENUCOLUMN_SPACING_MAX 24.0f
#define MENUCOLUMN_SPACING_MIN 20.0f
#define MENUSELECT_BOX_MAX 20.5f
#define MENUSELECT_BOX_MIN 17.0f
#ifndef ASPECT_RATIO_SCALE
#define MENURADIO_ICON_X 31.5f
#else
#define MENURADIO_ICON_X -262.0f
#endif
#define MENURADIO_ICON_Y 29.5f
#define MENURADIO_ICON_W 60.0f
#define MENURADIO_ICON_H 60.0f
#define MENUDROP_COLOR_A 150
#define MENUDROP_COLOR_SIZE -1
#define MENUSLIDER_X 306.0f
#define buf(a) (char*)(a)
enum eLanguages
{
LANGUAGE_AMERICAN,
LANGUAGE_FRENCH,
LANGUAGE_GERMAN,
LANGUAGE_ITALIAN,
LANGUAGE_SPANISH,
};
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,
};
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,
};
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
};
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_GRAPHICS_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_13 = 13,
MENUPAGE_LOADING_IN_PROGRESS = 14,
MENUPAGE_DELETING_IN_PROGRESS = 15,
MENUPAGE_16 = 16,
MENUPAGE_DELETE_FAILED = 17,
MENUPAGE_DEBUG_MENU = 18,
MENUPAGE_MEMORY_CARD_1 = 19,
MENUPAGE_MEMORY_CARD_2 = 20,
MENUPAGE_MULTIPLAYER_MAIN = 21,
MENUPAGE_SAVE_FAILED_1 = 22,
MENUPAGE_SAVE_FAILED_2 = 23,
MENUPAGE_SAVE = 24,
MENUPAGE_NO_MEMORY_CARD = 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_57 = 57,
MENUPAGE_58 = 58,
MENUPAGES
};
enum eMenuAction
{
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_UPDATESAVE,
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_UPDATEMEMCARDSAVE,
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_REDEFCTRL,
MENUACTION_UNK73,
MENUACTION_INITMP,
MENUACTION_MP_PLAYERCOLOR,
MENUACTION_MP_PLAYERNAME,
MENUACTION_MP_GAMENAME,
MENUACTION_GETKEY,
MENUACTION_SHOWHEADBOB,
MENUACTION_UNK80,
MENUACTION_INVVERT,
MENUACTION_CANCLEGAME,
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_DONTCANCLE,
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,
};
enum eCheckHover
{
ACTIVATE_OPTION = 2,
IGNORE_OPTION = 42,
};
enum eMenuColumns
{
MENUCOLUMN_LEFT,
MENUCOLUMN_CENTER,
MENUCOLUMN_RIGHT,
MENUCOLUMNS,
};
enum eMenuRow
{
MENUROW_NONE = -1,
MENUROW_0,
MENUROW_1,
MENUROW_2,
MENUROW_3,
MENUROW_4,
MENUROW_5,
MENUROW_6,
MENUROW_7,
MENUROW_8,
MENUROW_9,
MENUROW_10,
MENUROW_11,
MENUROW_12,
MENUROW_13,
MENUROW_14,
MENUROW_15,
MENUROW_16,
MENUROW_17,
MENUROWS,
};
struct tSkinInfo
{
int field_0;
char skinName[256];
char currSkinName[256];
char date[256];
int field_304;
};
struct CMenuScreen
{
char m_ScreenName[8];
int32 unk;
int32 m_PreviousPage[2]; // eMenuScreen
int32 m_ParentEntry[2]; // eMenuRow
struct CMenuEntry
{
int32 m_Action; // eMenuAction
char m_EntryName[8];
int32 m_SaveSlot; // eSaveSlot
int32 m_TargetMenu; // eMenuScreen
} m_aEntries[MENUROWS];
};
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;
char field_112;
char field_113;
bool m_bStartGameLoading;
bool m_bFirstTime;
bool m_bGameNotLoaded;
int32 m_nMousePosX;
int32 m_nMousePosY;
int32 m_nMouseTempPosX;
int32 m_nMouseTempPosY;
bool m_bShowMouse;
tSkinInfo field_12C;
tSkinInfo *m_pSelectedSkin;
tSkinInfo *field_438;
float field_43C;
int field_440;
int m_nSkinsTotal;
char _unk0[4];
int field_44C;
bool m_bSkinsFound;
bool m_bQuitGameNoCD;
char field_452;
bool m_bSaveMenuActive;
bool m_bLoadingSavedGame;
char field_455;
char field_456;
bool m_bSpritesLoaded;
CSprite2d m_aFrontEndSprites[28];
CSprite2d m_aMenuSprites[20];
int field_518;
int m_nMenuFadeAlpha;
char field_520;
char field_521;
char field_522;
char field_523;
char field_524;
int m_CurrCntrlAction;
char _unk1[4];
int field_530;
char field_534;
char field_535;
int8 field_536;
int m_nHelperTextAlpha;
int m_nMouseOldPosX;
int m_nMouseOldPosY;
int m_nHoverOption;
int m_nCurrScreen;
int m_nCurrOption;
int m_nPrevOption;
int m_nPrevScreen;
int field_558;
int m_nCurrSaveSlot;
int m_nScreenChangeDelayTimer;
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 int8 &m_ControlMethod;
static int8 &m_PrefsDMA;
static int8 &m_PrefsLanguage;
static int8 &m_bDisableMouseSteering;
static int32 &m_PrefsBrightness;
static float &m_PrefsLOD;
static int8 &m_bFrontEnd_ReloadObrTxtGxt;
static int32 &m_PrefsMusicVolume;
static int32 &m_PrefsSfxVolume;
static uint8 *m_PrefsSkinFile;
static bool &m_bStartUpFrontEndRequested;
static bool &m_bShutDownFrontEndRequested;
static bool &m_PrefsAllowNastyGame;
public:
void BuildStatLine(char *, void *, uint16, void *);
static void CentreMousePointer();
void CheckCodesForControls(int, int);
bool CheckHover(int x1, int x2, int y1, int y2);
void CheckSliderMovement(int);
int CostructStatLine(int);
void DisplayHelperText();
float DisplaySlider(float, float, float, float, float, float);
void DoSettingsBeforeStartingAGame();
void Draw();
void DrawControllerBound(int, int, int, uint8);
void DrawControllerScreenExtraText(int, int, int);
void DrawControllerSetupScreen();
void DrawFrontEnd();
void DrawFrontEndNormal();
void DrawPlayerSetupScreen();
int FadeIn(int alpha);
void FilterOutColorMarkersFromString(uint16, CRGBA &);
int GetStartOptionsCntrlConfigScreens();
static void InitialiseChangedLanguageSettings();
void LoadAllTextures();
void LoadSettings();
static void MessageScreen(char *);
static 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();
static float StretchX(float);
static float StretchY(float);
void SwitchMenuOnAndOff();
void UnloadTextures();
void WaitForUserCD();
// New content:
uint8 GetNumberOfMenuOptions();
void SwitchToNewScreen(int8 screen);
void SetDefaultPreferences(int8 screen);
};
static_assert(sizeof(CMenuManager) == 0x564, "CMenuManager: error");
extern CMenuManager &FrontEndMenuManager;

23
src/core/Game.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "common.h"
#include "patcher.h"
#include "Game.h"
eLevelName &CGame::currLevel = *(eLevelName*)0x941514;
bool &CGame::bDemoMode = *(bool*)0x5F4DD0;
bool &CGame::nastyGame = *(bool*)0x5F4DD4;
bool &CGame::frenchGame = *(bool*)0x95CDCB;
bool &CGame::germanGame = *(bool*)0x95CD1E;
bool &CGame::noProstitutes = *(bool*)0x95CDCF;
bool &CGame::playingIntro = *(bool*)0x95CDC2;
char *CGame::aDatFile = (char*)0x773A48;
WRAPPER void CGame::Initialise(const char *datFile) { EAXJMP(0x48BED0); }
WRAPPER void CGame::Process(void) { EAXJMP(0x48C850); }
WRAPPER bool CGame::InitialiseOnceBeforeRW(void) { EAXJMP(0x48BB80); }
WRAPPER bool CGame::InitialiseRenderWare(void) { EAXJMP(0x48BBA0); }
WRAPPER void CGame::ShutdownRenderWare(void) { EAXJMP(0x48BCB0); }
WRAPPER void CGame::FinalShutdown(void) { EAXJMP(0x48BEC0); }
WRAPPER void CGame::ShutDown(void) { EAXJMP(0x48C3A0); }
WRAPPER void CGame::ShutDownForRestart(void) { EAXJMP(0x48C6B0); }
WRAPPER void CGame::InitialiseWhenRestarting(void) { EAXJMP(0x48C740); }
WRAPPER bool CGame::InitialiseOnceAfterRW(void) { EAXJMP(0x48BD50); }

37
src/core/Game.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
enum eLevelName
{
LEVEL_NONE = 0,
LEVEL_INDUSTRIAL,
LEVEL_COMMERCIAL,
LEVEL_SUBURBAN
};
class CGame
{
public:
static eLevelName &currLevel;
static bool &bDemoMode;
static bool &nastyGame;
static bool &frenchGame;
static bool &germanGame;
static bool &noProstitutes;
static bool &playingIntro;
static char *aDatFile; //[32];
static void Initialise(const char *datFile);
static bool InitialiseOnceBeforeRW(void);
static bool InitialiseRenderWare(void);
static bool InitialiseOnceAfterRW(void);
static void InitialiseWhenRestarting(void);
static void ShutDown(void);
static void ShutdownRenderWare(void);
static void FinalShutdown(void);
static void ShutDownForRestart(void);
static void Process(void);
// NB: these do something on PS2
static void TidyUpMemory(bool, bool) {}
static void DrasticTidyUpMemory(void) {}
};

91
src/core/General.h Normal file
View File

@ -0,0 +1,91 @@
#pragma once
class CGeneral
{
public:
static float GetATanOfXY(float x, float y){
if(x == 0.0f && y == 0.0f)
return 0.0f;
float xabs = fabs(x);
float yabs = fabs(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 LimitRadianAngle(float angle)
{
float result;
if (angle < -25.0f)
result = -25.0f;
else if (angle > 25.0f)
result = 25.0f;
else
result = angle;
while (result >= PI) {
result -= 2 * PI;
}
while (result < -PI) {
result += 2 * PI;
}
return result;
}
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);
}
}
// not too sure about all these...
static uint16 GetRandomNumber(void)
{ return myrand() & MYRAND_MAX; }
// 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)); }
};

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);
}
}
};

380
src/core/MenuScreens.h Normal file
View File

@ -0,0 +1,380 @@
#pragma once
const CMenuScreen aScreens[] = {
// MENUPAGE_NONE = 0
{ "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, },
// MENUPAGE_STATS = 1
{ "FET_STA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_5, MENUROW_2,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_NEW_GAME = 2
{ "FET_SGA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_0, MENUROW_1,
MENUACTION_CHANGEMENU, "FES_SNG", SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD,
MENUACTION_CHANGEMENU, "GMLOAD", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT,
MENUACTION_CHANGEMENU, "FES_DGA", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_BRIEFS = 3
{ "FET_BRE", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_6, MENUROW_3,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENU_CONTROLLER_SETTINGS = 4
{ "FET_CON", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_0, MENUROW_0,
},
// MENUPAGE_SOUND_SETTINGS = 5
{ "FET_AUD", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_1, MENUROW_1,
MENUACTION_MUSICVOLUME, "FEA_MUS", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
MENUACTION_SFXVOLUME, "FEA_SFX", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
MENUACTION_AUDIOHW, "FEA_3DH", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
MENUACTION_SPEAKERCONF, "FEA_SPK", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
MENUACTION_DYNAMICACOUSTIC, "FET_DAM", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
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_SOUND_SETTINGS,
},
// MENUPAGE_GRAPHICS_SETTINGS = 6
{ "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_2, MENUROW_2,
MENUACTION_BRIGHTNESS, "FED_BRI", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
MENUACTION_DRAWDIST, "FEM_LOD", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
//MENUACTION_FRAMESYNC, "FEM_VSC", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
MENUACTION_FRAMELIMIT, "FEM_FRM", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
MENUACTION_TRAILS, "FED_TRA", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
MENUACTION_SUBTITLES, "FED_SUB", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
MENUACTION_WIDESCREEN, "FED_WIS", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
MENUACTION_SCREENRES, "FED_RES", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
MENUACTION_RESTOREDEF, "FET_DEF", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_LANGUAGE_SETTINGS = 7
{ "FET_LAN", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_3, MENUROW_3,
MENUACTION_LANG_ENG, "FEL_ENG", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_LANG_FRE, "FEL_FRE", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_LANG_GER, "FEL_GER", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_LANG_ITA, "FEL_ITA", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_LANG_SPA, "FEL_SPA", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_CHOOSE_LOAD_SLOT = 8
{ "FET_LG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_1, MENUROW_1,
MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
MENUACTION_CHECKSAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL3", SAVESLOT_3, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL4", SAVESLOT_4, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL5", SAVESLOT_5, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL6", SAVESLOT_6, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL7", SAVESLOT_7, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL8", SAVESLOT_8, MENUPAGE_LOAD_SLOT_CONFIRM,
},
// MENUPAGE_CHOOSE_DELETE_SLOT = 9
{ "FET_DG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_2, MENUROW_2,
MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
MENUACTION_CHECKSAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL3", SAVESLOT_3, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL4", SAVESLOT_4, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL5", SAVESLOT_5, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL6", SAVESLOT_6, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL7", SAVESLOT_7, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL8", SAVESLOT_8, MENUPAGE_DELETE_SLOT_CONFIRM,
},
// MENUPAGE_NEW_GAME_RELOAD = 10
{ "FET_NG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_0, MENUROW_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_NONE,
},
// MENUPAGE_LOAD_SLOT_CONFIRM = 11
{ "FET_LG", MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUROW_0, MENUROW_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", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_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_13 = 13
{ "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_LOADING_IN_PROGRESS = 14
{ "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
MENUACTION_LABEL, "FED_LDW", SAVESLOT_NONE, MENUPAGE_LOAD_SLOT_CONFIRM,
},
// MENUPAGE_DELETING_IN_PROGRESS = 15
{ "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
MENUACTION_LABEL, "FEDL_WR", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_16 = 16
{ "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
MENUACTION_LABEL, "FES_LOE", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_DELETE_FAILED = 17
{ "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_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", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_MEMORY_CARD_1 = 19
{ "FEM_MCM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_MEMORY_CARD_2 = 20
{ "FEM_MC2", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_MULTIPLAYER_MAIN = 21
{ "FET_MP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_SAVE_FAILED_1 = 22
{ "MCDNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_SAVE_FAILED_2 = 23
{ "MCGNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_SAVE = 24
{ "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
MENUACTION_LABEL, "FES_SCG", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_UPDATESAVE, "GMSAVE", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
MENUACTION_UPDATEMEMCARDSAVE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_NO_MEMORY_CARD = 25
{ "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_CHOOSE_SAVE_SLOT = 26
{ "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
MENUACTION_UPDATEMEMCARDSAVE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_UPDATESAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_UPDATESAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_UPDATESAVE, "FEM_SL3", SAVESLOT_3, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_UPDATESAVE, "FEM_SL4", SAVESLOT_4, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_UPDATESAVE, "FEM_SL5", SAVESLOT_5, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_UPDATESAVE, "FEM_SL6", SAVESLOT_6, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_UPDATESAVE, "FEM_SL7", SAVESLOT_7, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_UPDATESAVE, "FEM_SL8", SAVESLOT_8, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
},
// MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27
{ "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_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", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_MULTIPLAYER_CONNECTION = 29
{ "FET_CON", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_MULTIPLAYER_FIND_GAME = 30
{ "FET_FG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_MULTIPLAYER_MODE = 31
{ "FET_GT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_MULTIPLAYER_CREATE = 32
{ "FET_HG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_MULTIPLAYER_START = 33
{ "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_SKIN_SELECT_OLD = 34
{ "FET_PS", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_CONTROLLER_PC = 35
{ "FET_CTL", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_0, MENUROW_0,
MENUACTION_CTRLMETHOD, "FET_CME", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
MENUACTION_CHANGEMENU, "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", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_0, MENUROW_0,
},
// MENUPAGE_CONTROLLER_PC_OLD2 = 37
{ "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_CONTROLLER_PC_OLD3 = 38
{ "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_CONTROLLER_PC_OLD4 = 39
{ "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_CONTROLLER_DEBUG = 40
{ "FEC_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_OPTIONS = 41
{ "FET_OPT", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_1, MENUROW_4,
MENUACTION_CHANGEMENU, "FET_CTL", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
MENUACTION_CHANGEMENU, "FET_AUD", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
MENUACTION_CHANGEMENU, "FET_DIS", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
MENUACTION_CHANGEMENU, "FET_LAN", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS,
//MENUACTION_CHANGEMENU, "FET_PSU", SAVESLOT_NONE, MENUPAGE_SKIN_SELECT,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_EXIT = 42
{ "FET_QG", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_2, MENUROW_5,
MENUACTION_LABEL, "FEQ_SRE", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CANCLEGAME, "FEM_YES", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_SAVING_IN_PROGRESS = 43
{ "", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
MENUACTION_LABEL, "FES_WAR", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_SAVE_SUCCESSFUL = 44
{ "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
MENUACTION_LABEL, "FES_SSC", SAVESLOT_LABEL, MENUPAGE_NONE,
MENUACTION_UPDATEMEMCARDSAVE, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
},
// MENUPAGE_DELETING = 45
{ "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0,
MENUACTION_LABEL, "FED_DLW", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_DELETE_SUCCESS = 46
{ "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_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", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_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", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
MENUACTION_LABEL, "FEC_SVU", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_LOAD_FAILED_2 = 49
{ "FET_LG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_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", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_START_MENU = 51
{ "FEM_MM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_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", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_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", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_SKIN_SELECT = 54
{ "FET_PSU", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_4, MENUROW_4,
//MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN,
},
// MENUPAGE_KEYBOARD_CONTROLS = 55
{ "FET_STI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_1, MENUROW_1,
//MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
},
// MENUPAGE_MOUSE_CONTROLS = 56
{ "FET_MTI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_2, MENUROW_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_57 = 57
{ "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
// MENUPAGE_58 = 58
{ "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
},
};

15
src/core/Messages.cpp Normal file
View File

@ -0,0 +1,15 @@
#include "common.h"
#include "patcher.h"
#include "Messages.h"
WRAPPER void CMessages::Display(void) { EAXJMP(0x529800); }
WRAPPER void CMessages::ClearAllMessagesDisplayedByGame(void) { EAXJMP(0x52B670); }
WRAPPER int CMessages::WideStringCopy(wchar* dst, wchar* src, unsigned short size) { EAXJMP(0x5294B0); }
WRAPPER char CMessages::WideStringCompare(wchar* str1, wchar* str2, unsigned short size) { EAXJMP(0x529510); }
WRAPPER void CMessages::InsertNumberInString(wchar* src, int n1, int n2, int n3, int n4, int n5, int n6, wchar* dst) { EAXJMP(0x52A1A0); }
WRAPPER void CMessages::InsertPlayerControlKeysInString(wchar* src) { EAXJMP(0x52A490); }
WRAPPER int CMessages::GetWideStringLength(wchar* src) { EAXJMP(0x529490); }
tPreviousBrief *CMessages::PreviousBriefs = (tPreviousBrief *)0x713C08;
tMessage *CMessages::BriefMessages = (tMessage *)0x8786E0;
tBigMessage *CMessages::BIGMessages = (tBigMessage *)0x773628;

44
src/core/Messages.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
struct tMessage
{
wchar *m_pText;
uint16 m_nFlag;
private:
int8 _pad6[2];
public:
uint32 m_nTime;
uint32 m_nStartTime;
int32 m_nNumber[6];
wchar *m_pString;
};
struct tBigMessage
{
tMessage m_Current;
tMessage m_Stack[3];
};
struct tPreviousBrief
{
wchar *m_pText;
int32 m_nNumber[6];
wchar *m_pString;
};
class CMessages
{
public:
static tPreviousBrief *PreviousBriefs;
static tMessage *BriefMessages;
static tBigMessage *BIGMessages;
public:
static void Display(void);
static void ClearAllMessagesDisplayedByGame(void);
static int WideStringCopy(wchar* dst, wchar* src, unsigned short size);
static char WideStringCompare(wchar* str1, wchar* str2, unsigned short size);
static void InsertNumberInString(wchar* src, int n1, int n2, int n3, int n4, int n5, int n6, wchar* dst);
static void InsertPlayerControlKeysInString(wchar* src);
static int GetWideStringLength(wchar *src);
};

77
src/core/NodeName.cpp Normal file
View File

@ -0,0 +1,77 @@
#include "common.h"
#include "patcher.h"
#include "NodeName.h"
static int32 &gPluginOffset = *(int32*)0x64C610;
enum
{
ID_NODENAME = MAKECHUNKID(rwVENDORID_ROCKSTAR, 0xFE),
};
#define NODENAMEEXT(o) (RWPLUGINOFFSET(char, o, gPluginOffset))
void*
NodeNameConstructor(void *object, RwInt32 offsetInObject, RwInt32 sizeInObject)
{
if(gPluginOffset > 0)
NODENAMEEXT(object)[0] = '\0';
return object;
}
void*
NodeNameDestructor(void *object, RwInt32 offsetInObject, RwInt32 sizeInObject)
{
return object;
}
void*
NodeNameCopy(void *dstObject, const void *srcObject, RwInt32 offsetInObject, RwInt32 sizeInObject)
{
strncpy(NODENAMEEXT(dstObject), NODENAMEEXT(srcObject), 23);
return nil;
}
RwStream*
NodeNameStreamRead(RwStream *stream, RwInt32 binaryLength, void *object, RwInt32 offsetInObject, RwInt32 sizeInObject)
{
RwStreamRead(stream, NODENAMEEXT(object), binaryLength);
NODENAMEEXT(object)[binaryLength] = '\0';
return stream;
}
RwStream*
NodeNameStreamWrite(RwStream *stream, RwInt32 binaryLength, const void *object, RwInt32 offsetInObject, RwInt32 sizeInObject)
{
RwStreamWrite(stream, NODENAMEEXT(object), binaryLength);
return stream;
}
RwInt32
NodeNameStreamGetSize(const void *object, RwInt32 offsetInObject, RwInt32 sizeInObject)
{
// game checks for null pointer on node name extension but that really happen
return rwstrlen(NODENAMEEXT(object));
}
bool
NodeNamePluginAttach(void)
{
gPluginOffset = RwFrameRegisterPlugin(24, ID_NODENAME,
NodeNameConstructor,
NodeNameDestructor,
NodeNameCopy);
RwFrameRegisterPluginStream(ID_NODENAME,
NodeNameStreamRead,
NodeNameStreamWrite,
NodeNameStreamGetSize);
return gPluginOffset != -1;
}
char*
GetFrameNodeName(RwFrame *frame)
{
if(gPluginOffset < 0)
return nil;
return NODENAMEEXT(frame);
}

4
src/core/NodeName.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
bool NodeNamePluginAttach(void);
char *GetFrameNodeName(RwFrame *frame);

20
src/core/PCSave.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "common.h"
#include "patcher.h"
#include "Frontend.h"
#include "PCSave.h"
WRAPPER void C_PcSave::SetSaveDirectory(const char *path) { EAXJMP(0x591EA0); }
WRAPPER int8 C_PcSave::PopulateSlotInfo() { EAXJMP(0x592090); }
WRAPPER int8 C_PcSave::DeleteSlot(int) { EAXJMP(0x5922F0); }
WRAPPER int8 C_PcSave::SaveSlot(int) { EAXJMP(0x591EC0); }
WRAPPER int8 CheckSlotDataValid(int) { EAXJMP(0x591A40); }
WRAPPER wchar *GetNameOfSavedGame(int counter) { EAXJMP(0x591B60); }
WRAPPER wchar *GetSavedGameDateAndTime(int counter) { EAXJMP(0x591B50); }
C_PcSave PcSaveHelper = *(C_PcSave*)0x8E2C60;
int *Slots = (int*)0x728040;
int *SlotFileName = (int*)0x6F07C8;
int *SlotSaveDate = (int*)0x72B858;

21
src/core/PCSave.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
class C_PcSave
{
public:
int32 m_nHelper;
static void SetSaveDirectory(const char *path);
int8 PopulateSlotInfo();
int8 DeleteSlot(int);
int8 SaveSlot(int);
};
extern int8 CheckSlotDataValid(int);
extern wchar *GetNameOfSavedGame(int counter);
extern wchar *GetSavedGameDateAndTime(int counter);
extern C_PcSave PcSaveHelper;
extern int *Slots;
extern int *SlotFileName;
extern int *SlotSaveDate;

2091
src/core/Pad.cpp Normal file

File diff suppressed because it is too large Load Diff

367
src/core/Pad.h Normal file
View File

@ -0,0 +1,367 @@
#pragma once
// same as RW skeleton
/*
enum Key
{
// ascii...
KEY_ESC = 128,
KEY_F1 = 129,
KEY_F2 = 130,
KEY_F3 = 131,
KEY_F4 = 132,
KEY_F5 = 133,
KEY_F6 = 134,
KEY_F7 = 135,
KEY_F8 = 136,
KEY_F9 = 137,
KEY_F10 = 138,
KEY_F11 = 139,
KEY_F12 = 140,
KEY_INS = 141,
KEY_DEL = 142,
KEY_HOME = 143,
KEY_END = 144,
KEY_PGUP = 145,
KEY_PGDN = 146,
KEY_UP = 147,
KEY_DOWN = 148,
KEY_LEFT = 149,
KEY_RIGHT = 150,
// some stuff ommitted
KEY_BACKSP = 168,
KEY_TAB = 169,
KEY_CAPSLK = 170,
KEY_ENTER = 171,
KEY_LSHIFT = 172,
KEY_RSHIFT = 173,
KEY_LCTRL = 174,
KEY_RCTRL = 175,
KEY_LALT = 176,
KEY_RALT = 177,
KEY_NULL, // unused
KEY_NUMKEYS
};
*/
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; };
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:
CControllerState NewState;
CControllerState OldState;
CControllerState PCTempKeyState;
CControllerState PCTempJoyState;
CControllerState PCTempMouseState;
// straight out of my IDB
int16 Phase;
int16 Mode;
int16 ShakeDur;
uint8 ShakeFreq;
int8 bHornHistory[5];
uint8 iCurrHornHistory;
bool DisablePlayerControls;
int8 bApplyBrakes;
char _unk[12]; //int32 unk[3];
char _pad0[3];
int32 LastTimeTouched;
int32 AverageWeapon;
int32 AverageEntries;
CPad() { }
~CPad() { }
static bool &bDisplayNoControllerMessage;
static bool &bObsoleteControllerMessage;
static bool &m_bMapPadOneToPadTwo;
static CKeyboardState &OldKeyState;
static CKeyboardState &NewKeyState;
static CKeyboardState &TempKeyState;
static char KeyBoardCheatString[18];
static CMouseControllerState &OldMouseControllerState;
static CMouseControllerState &NewMouseControllerState;
static CMouseControllerState &PCTempMouseControllerState;
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);
void AddToPCCheatString(char c);
static void UpdatePads(void);
void ProcessPCSpecificStuff(void);
void Update(int16 unk);
static void DoCheats(void);
void DoCheats(int16 unk);
static void StopPadsShaking(void);
void StopShaking(int16 unk);
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);
// mouse
bool GetLeftMouseJustDown() { return !!(NewMouseControllerState.LMB && !OldMouseControllerState.LMB); }
// 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); } // GetEnterJustDown
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 GetEnterJustDown() { 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); }
// 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); }
int32 GetLeftShoulder1(void) { return NewState.LeftShoulder1; }
int32 GetLeftShoulder2(void) { return NewState.LeftShoulder2; }
int32 GetRightShoulder1(void) { return NewState.RightShoulder1; }
int32 GetRightShoulder2(void) { return NewState.RightShoulder2; }
};
VALIDATE_SIZE(CPad, 0xFC);
#define IsButtonJustDown(pad, btn) \
(!(pad)->OldState.btn && (pad)->NewState.btn)
void LittleTest(void);

72
src/core/Placeable.cpp Normal file
View File

@ -0,0 +1,72 @@
#include "common.h"
#include "Placeable.h"
#include "patcher.h"
CPlaceable::CPlaceable(void)
{
m_matrix.SetScale(1.0f);
}
CPlaceable::~CPlaceable(void) { }
void
CPlaceable::SetHeading(float angle)
{
CVector pos = GetPosition();
m_matrix.SetRotateZ(angle);
GetPosition() += 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;
}
STARTPATCHES
InjectHook(0x49F9A0, &CPlaceable::ctor, PATCH_JUMP);
InjectHook(0x49F9E0, &CPlaceable::dtor, PATCH_JUMP);
InjectHook(0x49FA00, &CPlaceable::SetHeading, PATCH_JUMP);
InjectHook(0x49FA50, (bool (CPlaceable::*)(float, float, float, float))&CPlaceable::IsWithinArea, PATCH_JUMP);
InjectHook(0x49FAF0, (bool (CPlaceable::*)(float, float, float, float, float, float))&CPlaceable::IsWithinArea, PATCH_JUMP);
ENDPATCHES

26
src/core/Placeable.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
class CPlaceable
{
public:
// disable allocation
static void *operator new(size_t) = delete;
CMatrix m_matrix;
CPlaceable(void);
virtual ~CPlaceable(void);
CVector &GetPosition(void) { return *m_matrix.GetPosition(); }
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 SetTransform(RwMatrix *m) { m_matrix = CMatrix(m, false); }
void SetHeading(float angle);
bool IsWithinArea(float x1, float y1, float x2, float y2);
bool IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2);
CPlaceable *ctor(void) { return ::new (this) CPlaceable(); }
void dtor(void) { this->CPlaceable::~CPlaceable(); }
};
static_assert(sizeof(CPlaceable) == 0x4C, "CPlaceable: error");

5
src/core/PlayerInfo.cpp Normal file
View File

@ -0,0 +1,5 @@
#include "common.h"
#include "patcher.h"
#include "PlayerInfo.h"
WRAPPER void CPlayerInfo::MakePlayerSafe(bool) { EAXJMP(0x4A1400); }

72
src/core/PlayerInfo.h Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include "Collision.h"
enum eWastedBustedState
{
WBSTATE_PLAYING,
WBSTATE_WASTED,
WBSTATE_BUSTED,
WBSTATE_FAILED_CRITICAL_MISSION,
};
class CVehicle;
class CPlayerPed;
class CCivilianPed;
class CPlayerInfo
{
public:
CPlayerPed *m_pPed;
CVehicle *m_pRemoteVehicle;
CColModel m_ColModel;
CVehicle *m_pVehicleEx;
char m_aPlayerName[70];
int32 m_nMoney;
int32 m_nVisibleMoney;
int32 m_nCollectedPackages;
int32 m_nTotalPackages;
int32 field_188;
int32 m_nSwitchTaxiTime;
bool m_bSwitchTaxi;
int8 field_197;
int8 field_198;
int8 field_199;
int32 m_nNextSexFrequencyUpdateTime;
int32 m_nNextSexMoneyUpdateTime;
int32 m_nSexFrequency;
CCivilianPed *m_pHooker;
int8 m_WBState; // eWastedBustedState
int8 field_217;
int8 field_218;
int8 field_219;
int32 m_nWBTime;
bool m_bInRemoteMode;
int8 field_225;
int8 field_226;
int8 field_227;
int32 m_nTimeLostRemoteCar;
int32 m_nTimeLastHealthLoss;
int32 m_nTimeLastArmourLoss;
int32 field_240;
int32 m_nUpsideDownCounter;
int32 field_248;
int16 m_nTrafficMultiplier;
int8 field_254;
int8 field_255;
float m_fRoadDensity;
int32 m_nPreviousTimeRewardedForExplosion;
int32 m_nExplosionsSinceLastReward;
int32 field_268;
int32 field_272;
bool m_bInfiniteSprint;
bool m_bFastReload;
bool m_bGetOutOfJailFree;
bool m_bGetOutOfHospitalFree;
uint8 m_aSkinName[32];
RwTexture *m_pSkinTexture;
void MakePlayerSafe(bool);
};
static_assert(sizeof(CPlayerInfo) == 0x13C, "CPlayerInfo: error");

5
src/core/PlayerSkin.cpp Normal file
View File

@ -0,0 +1,5 @@
#include "common.h"
#include "patcher.h"
#include "PlayerSkin.h"
WRAPPER void CPlayerSkin::BeginFrontEndSkinEdit() { EAXJMP(0x59BC70); }

7
src/core/PlayerSkin.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
class CPlayerSkin
{
public:
static void BeginFrontEndSkinEdit();
};

25
src/core/Pools.cpp Normal file
View File

@ -0,0 +1,25 @@
#include "common.h"
#include "Pools.h"
CCPtrNodePool *&CPools::ms_pPtrNodePool = *(CCPtrNodePool**)0x943044;
CEntryInfoNodePool *&CPools::ms_pEntryInfoNodePool = *(CEntryInfoNodePool**)0x941448;
CPedPool *&CPools::ms_pPedPool = *(CPedPool**)0x8F2C60;
CVehiclePool *&CPools::ms_pVehiclePool = *(CVehiclePool**)0x9430DC;
CBuildingPool *&CPools::ms_pBuildingPool = *(CBuildingPool**)0x8F2C04;
CTreadablePool *&CPools::ms_pTreadablePool = *(CTreadablePool**)0x8F2568;
CObjectPool *&CPools::ms_pObjectPool = *(CObjectPool**)0x880E28;
CDummyPool *&CPools::ms_pDummyPool = *(CDummyPool**)0x8F2C18;
void
CPools::Initialise(void)
{
// TODO: unused right now
ms_pPtrNodePool = new CCPtrNodePool(NUMPTRNODES);
ms_pEntryInfoNodePool = new CEntryInfoNodePool(NUMENTRYINFOS);
ms_pPedPool = new CPedPool(NUMPEDS);
ms_pVehiclePool = new CVehiclePool(NUMVEHICLES);
ms_pBuildingPool = new CBuildingPool(NUMBUILDINGS);
ms_pTreadablePool = new CTreadablePool(NUMTREADABLES);
ms_pObjectPool = new CObjectPool(NUMOBJECTS);
ms_pDummyPool = new CDummyPool(NUMDUMMIES);
}

43
src/core/Pools.h Normal file
View File

@ -0,0 +1,43 @@
#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"
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;
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;
// 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 void Initialise(void);
};

1117
src/core/Radar.cpp Normal file

File diff suppressed because it is too large Load Diff

146
src/core/Radar.h Normal file
View File

@ -0,0 +1,146 @@
#pragma once
#include "Sprite2d.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
{
RADAR_SPRITE_NONE = 0,
RADAR_SPRITE_ASUKA = 1,
RADAR_SPRITE_BOMB = 2,
RADAR_SPRITE_CAT = 3,
RADAR_SPRITE_CENTRE = 4,
RADAR_SPRITE_COPCAR = 5,
RADAR_SPRITE_DON = 6,
RADAR_SPRITE_EIGHT = 7,
RADAR_SPRITE_EL = 8,
RADAR_SPRITE_ICE = 9,
RADAR_SPRITE_JOEY = 10,
RADAR_SPRITE_KENJI = 11,
RADAR_SPRITE_LIZ = 12,
RADAR_SPRITE_LUIGI = 13,
RADAR_SPRITE_NORTH = 14,
RADAR_SPRITE_RAY = 15,
RADAR_SPRITE_SAL = 16,
RADAR_SPRITE_SAVE = 17,
RADAR_SPRITE_SPRAY = 18,
RADAR_SPRITE_TONY = 19,
RADAR_SPRITE_WEAPON = 20,
RADAR_SPRITE_COUNT = 21,
};
struct CBlip
{
int32 m_nColor;
int16 m_eBlipType; // eBlipType
int32 m_nEntityHandle;
CVector2D m_vec2DPos;
CVector m_vecPos;
int16 m_BlipIndex;
bool m_bDim;
bool m_bInUse;
float m_Radius;
int16 m_wScale;
int16 m_eBlipDisplay; // eBlipDisplay
int16 m_IconID; // eRadarSprite
};
static_assert(sizeof(CBlip) == 0x30, "CBlip: error");
// Values for screen space
#define RADAR_LEFT (40.0f)
#define RADAR_BOTTOM (47.0f)
#define RADAR_WIDTH (94.0f)
#define RADAR_HEIGHT (76.0f)
class CRadar
{
public:
static float &m_RadarRange;
static CBlip *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[21];
public:
static int CalculateBlipAlpha(float dist);
static void ChangeBlipBrightness(int32 i, int32 bright);
static void ChangeBlipColour(int32 i);
static void ChangeBlipDisplay(int32 i, int16 flag);
static void ChangeBlipScale(int32 i, int16 scale);
static void ClearBlip(int32 i);
static void ClearBlipForEntity(int16 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(int32 sprite, float x, float y, int32 alpha);
static void DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha);
static int32 GetActualBlipArray(int32 i);
static int32 GetNewUniqueBlipIndex(int32 i);
static int32 GetRadarTraceColour(int32 color, bool bright);
static void Initialise();
static float LimitRadarPoint(CVector2D &point);
static void LoadAllRadarBlips(int32);
static void LoadTextures();
static void RemoveRadarSections();
static void RemoveMapSection(int32 x, int32 y);
static void RequestMapSection(int32 x, int32 y);
static void SaveAllRadarBlips(int32);
static void SetBlipSprite(int32 i, int32 icon);
static int SetCoordBlip(int32 type, CVector pos, int32 flag);
static int SetEntityBlip(int32 type, CVector pos, int32 color, int32 flag);
static void SetRadarMarkerState(int32 i, int32 flag);
static void ShowRadarMarker(CVector pos, int16 color, float radius);
static void ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha);
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 GetTextureCorners(int32 x, int32 y, CVector2D *out);
static void ClipRadarTileCoords(int32 &x, int32 &y);
static bool IsPointInsideRadar(const CVector2D &);
static int LineRadarBoxCollision(CVector2D &, const CVector2D &, const CVector2D &);
};

65
src/core/References.cpp Normal file
View File

@ -0,0 +1,65 @@
#include "common.h"
#include "patcher.h"
#include "World.h"
#include "Vehicle.h"
#include "PlayerPed.h"
#include "Pools.h"
#include "References.h"
CReference *CReferences::aRefs = (CReference*)0x70BBE0; //[NUMREFERENCES];
CReference *&CReferences::pEmptyList = *(CReference**)0x8F1AF8;
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
CReferences::RemoveReferencesToPlayer(void)
{
if(FindPlayerVehicle())
FindPlayerVehicle()->ResolveReferences();
if(FindPlayerPed())
FindPlayerPed()->ResolveReferences();
}
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();
}
}
STARTPATCHES
InjectHook(0x4A7350, CReferences::Init, PATCH_JUMP);
InjectHook(0x4A7570, CReferences::RemoveReferencesToPlayer, PATCH_JUMP);
InjectHook(0x4A75A0, CReferences::PruneAllReferencesInWorld, PATCH_JUMP);
ENDPATCHES

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);
};

230
src/core/RwClumpRead.cpp Normal file
View File

@ -0,0 +1,230 @@
#include "common.h"
#include "patcher.h"
struct rpGeometryList
{
RpGeometry **geometries;
int32 numGeoms;
};
struct rpAtomicBinary
{
RwInt32 frameIndex;
RwInt32 geomIndex;
RwInt32 flags;
RwInt32 unused;
};
static int32 numberGeometrys;
static int32 streamPosition;
static rpGeometryList gGeomList;
static rwFrameList gFrameList;
static RpClumpChunkInfo gClumpInfo;
rpGeometryList*
GeometryListStreamRead1(RwStream *stream, rpGeometryList *geomlist)
{
int i;
RwUInt32 size, version;
RwInt32 numGeoms;
numberGeometrys = 0;
if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
return nil;
assert(size == 4);
if(RwStreamRead(stream, &numGeoms, 4) != 4)
return nil;
numberGeometrys = numGeoms/2;
geomlist->numGeoms = numGeoms;
if(geomlist->numGeoms > 0){
geomlist->geometries = (RpGeometry**)RwMalloc(geomlist->numGeoms * sizeof(RpGeometry*));
if(geomlist->geometries == nil)
return nil;
memset(geomlist->geometries, 0, geomlist->numGeoms * sizeof(RpGeometry*));
}else
geomlist->geometries = nil;
for(i = 0; i < numberGeometrys; i++){
if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version))
return nil;
geomlist->geometries[i] = RpGeometryStreamRead(stream);
if(geomlist->geometries[i] == nil)
return nil;
}
return geomlist;
}
rpGeometryList*
GeometryListStreamRead2(RwStream *stream, rpGeometryList *geomlist)
{
int i;
RwUInt32 version;
for(i = numberGeometrys; i < geomlist->numGeoms; i++){
if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version))
return nil;
geomlist->geometries[i] = RpGeometryStreamRead(stream);
if(geomlist->geometries[i] == nil)
return nil;
}
return geomlist;
}
void
GeometryListDeinitialize(rpGeometryList *geomlist)
{
int i;
for(i = 0; i < geomlist->numGeoms; i++)
if(geomlist->geometries[i])
RpGeometryDestroy(geomlist->geometries[i]);
if(geomlist->numGeoms){
RwFree(geomlist->geometries);
geomlist->numGeoms = 0;
}
}
RpAtomic*
ClumpAtomicStreamRead(RwStream *stream, rwFrameList *frmList, rpGeometryList *geomList)
{
RwUInt32 size, version;
rpAtomicBinary a;
RpAtomic *atomic;
numberGeometrys = 0;
if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
return nil;
assert(size <= sizeof(rpAtomicBinary));
if(RwStreamRead(stream, &a, size) != size)
return nil;
atomic = RpAtomicCreate();
if(atomic == nil)
return nil;
RpAtomicSetFlags(atomic, a.flags);
if(frmList->numFrames){
assert(a.frameIndex < frmList->numFrames);
RpAtomicSetFrame(atomic, frmList->frames[a.frameIndex]);
}
if(geomList->numGeoms){
assert(a.geomIndex < geomList->numGeoms);
RpAtomicSetGeometry(atomic, geomList->geometries[a.geomIndex], 0);
}else{
RpGeometry *geom;
if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version)){
RpAtomicDestroy(atomic);
return nil;
}
geom = RpGeometryStreamRead(stream);
if(geom == nil){
RpAtomicDestroy(atomic);
return nil;
}
RpAtomicSetGeometry(atomic, geom, 0);
RpGeometryDestroy(geom);
}
return atomic;
}
bool
RpClumpGtaStreamRead1(RwStream *stream)
{
RwUInt32 size, version;
if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
return false;
if(version >= 0x33000){
assert(size == 12);
if(RwStreamRead(stream, &gClumpInfo, 12) != 12)
return false;
}else{
assert(size == 4);
if(RwStreamRead(stream, &gClumpInfo, 4) != 4)
return false;
}
if(!RwStreamFindChunk(stream, rwID_FRAMELIST, nil, &version))
return false;
if(_rwFrameListStreamRead(stream, &gFrameList) == nil)
return false;
if(!RwStreamFindChunk(stream, rwID_GEOMETRYLIST, nil, &version)){
rwFrameListDeinitialize(&gFrameList);
return false;
}
if(GeometryListStreamRead1(stream, &gGeomList) == nil){
rwFrameListDeinitialize(&gFrameList);
return false;
}
streamPosition = stream->Type.memory.position;
return true;
}
RpClump*
RpClumpGtaStreamRead2(RwStream *stream)
{
int i;
RwUInt32 version;
RpAtomic *atomic;
RpClump *clump;
clump = RpClumpCreate();
if(clump == nil)
return nil;
RwStreamSkip(stream, streamPosition - stream->Type.memory.position);
if(GeometryListStreamRead2(stream, &gGeomList) == nil){
GeometryListDeinitialize(&gGeomList);
rwFrameListDeinitialize(&gFrameList);
RpClumpDestroy(clump);
return nil;
}
RpClumpSetFrame(clump, gFrameList.frames[0]);
for(i = 0; i < gClumpInfo.numAtomics; i++){
if(!RwStreamFindChunk(stream, rwID_ATOMIC, nil, &version)){
GeometryListDeinitialize(&gGeomList);
rwFrameListDeinitialize(&gFrameList);
RpClumpDestroy(clump);
return nil;
}
atomic = ClumpAtomicStreamRead(stream, &gFrameList, &gGeomList);
if(atomic == nil){
GeometryListDeinitialize(&gGeomList);
rwFrameListDeinitialize(&gFrameList);
RpClumpDestroy(clump);
return nil;
}
RpClumpAddAtomic(clump, atomic);
}
GeometryListDeinitialize(&gGeomList);
rwFrameListDeinitialize(&gFrameList);
return clump;
}
void
RpClumpGtaCancelStream(void)
{
GeometryListDeinitialize(&gGeomList);
rwFrameListDeinitialize(&gFrameList);
gFrameList.numFrames = 0;
}
STARTPATCHES
InjectHook(0x526060, RpClumpGtaStreamRead1, PATCH_JUMP);
InjectHook(0x526180, RpClumpGtaStreamRead2, PATCH_JUMP);
InjectHook(0x5262D0, RpClumpGtaCancelStream, PATCH_JUMP);
ENDPATCHES

356
src/core/RwHelper.cpp Normal file
View File

@ -0,0 +1,356 @@
#define WITHD3D
#include "common.h"
#include "patcher.h"
#include "Timecycle.h"
#include "skeleton.h"
void *
RwMallocAlign(RwUInt32 size, RwUInt32 align)
{
void *mem = (void *)malloc(size + align);
ASSERT(mem != nil);
void *addr = (void *)((((RwUInt32)mem) + align) & ~(align - 1));
ASSERT(addr != nil);
*(((void **)addr) - 1) = mem;
return addr;
}
void
RwFreeAlign(void *mem)
{
ASSERT(mem != nil);
void *addr = *(((void **)mem) - 1);
ASSERT(addr != nil);
free(addr);
}
void
DefinedState(void)
{
RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSWRAP);
RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEGOURAUD);
RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATEALPHAPRIMITIVEBUFFER, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEBORDERCOLOR, (void*)RWRGBALONG(0, 0, 0, 255));
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEFOGCOLOR,
(void*)RWRGBALONG(CTimeCycle::GetFogRed(), CTimeCycle::GetFogGreen(), CTimeCycle::GetFogBlue(), 255));
RwRenderStateSet(rwRENDERSTATEFOGTYPE, (void*)rwFOGTYPELINEAR);
RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE);
// D3D stuff
RwD3D8SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
RwD3D8SetRenderState(D3DRS_ALPHAREF, 2);
}
RwFrame*
GetFirstFrameCallback(RwFrame *child, void *data)
{
*(RwFrame**)data = child;
return nil;
}
RwFrame*
GetFirstChild(RwFrame *frame)
{
RwFrame *child;
child = nil;
RwFrameForAllChildren(frame, GetFirstFrameCallback, &child);
return child;
}
RwObject*
GetFirstObjectCallback(RwObject *object, void *data)
{
*(RwObject**)data = object;
return nil;
}
RwObject*
GetFirstObject(RwFrame *frame)
{
RwObject *obj;
obj = nil;
RwFrameForAllObjects(frame, GetFirstObjectCallback, &obj);
return obj;
}
RpAtomic*
GetFirstAtomicCallback(RpAtomic *atm, void *data)
{
*(RpAtomic**)data = atm;
return nil;
}
RpAtomic*
GetFirstAtomic(RpClump *clump)
{
RpAtomic *atm;
atm = nil;
RpClumpForAllAtomics(clump, GetFirstAtomicCallback, &atm);
return atm;
}
RwTexture*
GetFirstTextureCallback(RwTexture *tex, void *data)
{
*(RwTexture**)data = tex;
return nil;
}
RwTexture*
GetFirstTexture(RwTexDictionary *txd)
{
RwTexture *tex;
tex = nil;
RwTexDictionaryForAllTextures(txd, GetFirstTextureCallback, &tex);
return tex;
}
void
CameraSize(RwCamera * camera, RwRect * rect,
RwReal viewWindow, RwReal aspectRatio)
{
if (camera)
{
RwVideoMode videoMode;
RwRect r;
RwRect origSize = { 0, 0, 0, 0 }; // FIX just to make the compier happy
RwV2d vw;
RwEngineGetVideoModeInfo(&videoMode,
RwEngineGetCurrentVideoMode());
origSize.w = RwRasterGetWidth(RwCameraGetRaster(camera));
origSize.h = RwRasterGetHeight(RwCameraGetRaster(camera));
if (!rect)
{
if (videoMode.flags & rwVIDEOMODEEXCLUSIVE)
{
/* For full screen applications, resizing the camera just doesn't
* make sense, use the video mode size.
*/
r.x = r.y = 0;
r.w = videoMode.width;
r.h = videoMode.height;
rect = &r;
}
else
{
/*
rect not specified - reuse current values
*/
r.w = RwRasterGetWidth(RwCameraGetRaster(camera));
r.h = RwRasterGetHeight(RwCameraGetRaster(camera));
r.x = r.y = 0;
rect = &r;
}
}
if (( origSize.w != rect->w ) && ( origSize.h != rect->h ))
{
RwRaster *raster;
RwRaster *zRaster;
/*
* Destroy rasters...
*/
raster = RwCameraGetRaster(camera);
if( raster )
{
RwRasterDestroy(raster);
}
zRaster = RwCameraGetZRaster(camera);
if( zRaster )
{
RwRasterDestroy(zRaster);
}
/*
* Create new rasters...
*/
raster = RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPECAMERA);
zRaster = RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPEZBUFFER);
if( raster && zRaster )
{
RwCameraSetRaster(camera, raster);
RwCameraSetZRaster(camera, zRaster);
}
else
{
if( raster )
{
RwRasterDestroy(raster);
}
if( zRaster )
{
RwRasterDestroy(zRaster);
}
rect->x = origSize.x;
rect->y = origSize.y;
rect->w = origSize.w;
rect->h = origSize.h;
/*
* Use default values...
*/
raster =
RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPECAMERA);
zRaster =
RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPEZBUFFER);
RwCameraSetRaster(camera, raster);
RwCameraSetZRaster(camera, zRaster);
}
}
/* Figure out the view window */
if (videoMode.flags & rwVIDEOMODEEXCLUSIVE)
{
/* derive ratio from aspect ratio */
vw.x = viewWindow;
vw.y = viewWindow / aspectRatio;
}
else
{
/* derive from pixel ratios */
if (rect->w > rect->h)
{
vw.x = viewWindow;
vw.y = (rect->h * viewWindow) / rect->w;
}
else
{
vw.x = (rect->w * viewWindow) / rect->h;
vw.y = viewWindow;
}
}
RwCameraSetViewWindow(camera, &vw);
RsGlobal.width = rect->w;
RsGlobal.height = rect->h;
}
return;
}
void
CameraDestroy(RwCamera *camera)
{
RwRaster *raster, *tmpRaster;
RwFrame *frame;
if (camera)
{
frame = RwCameraGetFrame(camera);
if (frame)
{
RwFrameDestroy(frame);
}
raster = RwCameraGetRaster(camera);
if (raster)
{
tmpRaster = RwRasterGetParent(raster);
RwRasterDestroy(raster);
if ((tmpRaster != nil) && (tmpRaster != raster))
{
RwRasterDestroy(tmpRaster);
}
}
raster = RwCameraGetZRaster(camera);
if (raster)
{
tmpRaster = RwRasterGetParent(raster);
RwRasterDestroy(raster);
if ((tmpRaster != nil) && (tmpRaster != raster))
{
RwRasterDestroy(tmpRaster);
}
}
RwCameraDestroy(camera);
}
return;
}
RwCamera *
CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer)
{
RwCamera *camera;
camera = RwCameraCreate();
if (camera)
{
RwCameraSetFrame(camera, RwFrameCreate());
RwCameraSetRaster(camera,
RwRasterCreate(0, 0, 0, rwRASTERTYPECAMERA));
if (zBuffer)
{
RwCameraSetZRaster(camera,
RwRasterCreate(0, 0, 0,
rwRASTERTYPEZBUFFER));
}
/* now check that everything is valid */
if (RwCameraGetFrame(camera) &&
RwCameraGetRaster(camera) &&
RwRasterGetParent(RwCameraGetRaster(camera)) &&
(!zBuffer || (RwCameraGetZRaster(camera) &&
RwRasterGetParent(RwCameraGetZRaster
(camera)))))
{
/* everything OK */
return (camera);
}
}
/* if we're here then an error must have occurred so clean up */
CameraDestroy(camera);
return (nil);
}
STARTPATCHES
//InjectHook(0x526450, GetFirstObjectCallback, PATCH_JUMP);
InjectHook(0x526460, GetFirstObject, PATCH_JUMP);
InjectHook(0x527170, CameraSize, PATCH_JUMP);
InjectHook(0x527340, CameraDestroy, PATCH_JUMP);
InjectHook(0x5273B0, CameraCreate, PATCH_JUMP);
ENDPATCHES

27
src/core/RwHelper.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
void *RwMallocAlign(RwUInt32 size, RwUInt32 align);
void RwFreeAlign(void *mem);
void DefinedState(void);
RwFrame *GetFirstChild(RwFrame *frame);
RwObject *GetFirstObject(RwFrame *frame);
RpAtomic *GetFirstAtomic(RpClump *clump);
RwTexture *GetFirstTexture(RwTexDictionary *txd);
RwTexDictionary *RwTexDictionaryGtaStreamRead(RwStream *stream);
RwTexDictionary *RwTexDictionaryGtaStreamRead1(RwStream *stream);
RwTexDictionary *RwTexDictionaryGtaStreamRead2(RwStream *stream, RwTexDictionary *texDict);
bool RpClumpGtaStreamRead1(RwStream *stream);
RpClump *RpClumpGtaStreamRead2(RwStream *stream);
void RpClumpGtaCancelStream(void);
void CameraSize(RwCamera *camera,
RwRect *rect,
RwReal viewWindow,
RwReal aspectRatio);
void CameraDestroy(RwCamera *camera);
RwCamera *CameraCreate(RwInt32 width,
RwInt32 height,
RwBool zBuffer);

212
src/core/RwMatFX.cpp Normal file
View File

@ -0,0 +1,212 @@
#define WITHD3D
#include "common.h"
#include "patcher.h"
struct MatFXNothing { int pad[5]; int effect; };
struct MatFXBump
{
RwFrame *bumpFrame;
RwTexture *bumpedTex;
RwTexture *bumpTex;
float negBumpCoefficient;
int pad;
int effect;
};
struct MatFXEnv
{
RwFrame *envFrame;
RwTexture *envTex;
float envCoeff;
int envFBalpha;
int pad;
int effect;
};
struct MatFXDual
{
RwTexture *dualTex;
RwInt32 srcBlend;
RwInt32 dstBlend;
};
struct MatFX
{
union {
MatFXNothing n;
MatFXBump b;
MatFXEnv e;
MatFXDual d;
} fx[2];
int effects;
};
int &MatFXMaterialDataOffset = *(int*)0x66188C;
int &MatFXAtomicDataOffset = *(int*)0x66189C;
#ifdef PS2_MATFX
void
_rpMatFXD3D8AtomicMatFXDefaultRender(RxD3D8InstanceData *inst, int flags, RwTexture *texture)
{
if(flags & (rpGEOMETRYTEXTURED|rpGEOMETRYTEXTURED2) && texture)
RwD3D8SetTexture(texture, 0);
else
RwD3D8SetTexture(nil, 0);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(inst->vertexAlpha || inst->material->color.alpha != 0xFF));
RwD3D8SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, inst->vertexAlpha != 0);
RwD3D8SetPixelShader(0);
RwD3D8SetVertexShader(inst->vertexShader);
RwD3D8SetStreamSource(0, inst->vertexBuffer, inst->stride);
if(inst->indexBuffer){
RwD3D8SetIndices(inst->indexBuffer, inst->baseIndex);
RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices);
}else
RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices);
}
// map [-1; -1] -> [0; 1], flip V
static RwMatrix scalenormal = {
{ 0.5f, 0.0f, 0.0f }, 0,
{ 0.0f, -0.5f, 0.0f }, 0,
{ 0.0f, 0.0f, 1.0f }, 0,
{ 0.5f, 0.5f, 0.0f }, 0,
};
// flipped U for PS2
static RwMatrix scalenormal_flipU = {
{ -0.5f, 0.0f, 0.0f }, 0,
{ 0.0f, -0.5f, 0.0f }, 0,
{ 0.0f, 0.0f, 1.0f }, 0,
{ 0.5f, 0.5f, 0.0f }, 0,
};
void
ApplyEnvMapTextureMatrix(RwTexture *tex, int n, RwFrame *frame)
{
RwD3D8SetTexture(tex, n);
RwD3D8SetTextureStageState(n, D3DRS_ALPHAREF, 2);
RwD3D8SetTextureStageState(n, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL);
if(frame){
RwMatrix *envframemat = RwMatrixCreate();
RwMatrix *tmpmat = RwMatrixCreate();
RwMatrix *envmat = RwMatrixCreate();
RwMatrixInvert(envframemat, RwFrameGetLTM(frame));
// PS2
// can this be simplified?
*tmpmat = *RwFrameGetLTM(RwCameraGetFrame((RwCamera*)RWSRCGLOBAL(curCamera)));
RwV3dNegate(&tmpmat->right, &tmpmat->right);
tmpmat->flags = 0;
tmpmat->pos.x = 0.0f;
tmpmat->pos.y = 0.0f;
tmpmat->pos.z = 0.0f;
RwMatrixMultiply(envmat, tmpmat, envframemat);
*tmpmat = *envmat;
// important because envframemat can have a translation that we don't like
tmpmat->pos.x = 0.0f;
tmpmat->pos.y = 0.0f;
tmpmat->pos.z = 0.0f;
// for some reason we flip in U as well
RwMatrixMultiply(envmat, tmpmat, &scalenormal_flipU);
RwD3D8SetTransform(D3DTS_TEXTURE0+n, envmat);
RwMatrixDestroy(envmat);
RwMatrixDestroy(tmpmat);
RwMatrixDestroy(envframemat);
}else
RwD3D8SetTransform(D3DTS_TEXTURE0+n, &scalenormal);
}
void
_rpMatFXD3D8AtomicMatFXEnvRender_ps2(RxD3D8InstanceData *inst, int flags, int sel, RwTexture *texture, RwTexture *envMap)
{
MatFX *matfx = *RWPLUGINOFFSET(MatFX*, inst->material, MatFXMaterialDataOffset);
MatFXEnv *env = &matfx->fx[sel].e;
uint8 intens = (uint8)(env->envCoeff*255.0f);
if(intens == 0 || envMap == nil){
if(sel == 0)
_rpMatFXD3D8AtomicMatFXDefaultRender(inst, flags, texture);
return;
}
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(inst->vertexAlpha || inst->material->color.alpha != 0xFF));
if(flags & (rpGEOMETRYTEXTURED|rpGEOMETRYTEXTURED2) && texture)
RwD3D8SetTexture(texture, 0);
else
RwD3D8SetTexture(nil, 0);
RwD3D8SetVertexShader(inst->vertexShader);
RwD3D8SetStreamSource(0, inst->vertexBuffer, inst->stride);
RwD3D8SetIndices(inst->indexBuffer, inst->baseIndex);
if(inst->indexBuffer)
RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices);
else
RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices);
// Effect pass
ApplyEnvMapTextureMatrix(envMap, 0, env->envFrame);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwUInt32 src, dst, lighting, zwrite, fog, fogcol;
RwRenderStateGet(rwRENDERSTATESRCBLEND, &src);
RwRenderStateGet(rwRENDERSTATEDESTBLEND, &dst);
// This is of course not using framebuffer alpha,
// but if the diffuse texture had no alpha, the result should actually be rather the same
if(env->envFBalpha)
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
else
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
RwD3D8GetRenderState(D3DRS_LIGHTING, &lighting);
RwD3D8GetRenderState(D3DRS_ZWRITEENABLE, &zwrite);
RwD3D8GetRenderState(D3DRS_FOGENABLE, &fog);
RwD3D8SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
if(fog){
RwD3D8GetRenderState(D3DRS_FOGCOLOR, &fogcol);
RwD3D8SetRenderState(D3DRS_FOGCOLOR, 0);
}
D3DCOLOR texfactor = D3DCOLOR_RGBA(intens, intens, intens, intens);
RwD3D8SetRenderState(D3DRS_TEXTUREFACTOR, texfactor);
RwD3D8SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
RwD3D8SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
RwD3D8SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_TFACTOR);
// alpha unused
//RwD3D8SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
//RwD3D8SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
//RwD3D8SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_TFACTOR);
if(inst->indexBuffer)
RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices);
else
RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices);
// Reset states
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)src);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)dst);
RwD3D8SetRenderState(D3DRS_LIGHTING, lighting);
RwD3D8SetRenderState(D3DRS_ZWRITEENABLE, zwrite);
if(fog)
RwD3D8SetRenderState(D3DRS_FOGCOLOR, fogcol);
RwD3D8SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
RwD3D8SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
RwD3D8SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, 0);
RwD3D8SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
}
STARTPATCHES
InjectHook(0x5CF6C0, _rpMatFXD3D8AtomicMatFXEnvRender_ps2, PATCH_JUMP);
ENDPATCHES
#endif

126
src/core/RwTexRead.cpp Normal file
View File

@ -0,0 +1,126 @@
#include "common.h"
#include "patcher.h"
RwTexture*
RwTextureGtaStreamRead(RwStream *stream)
{
RwUInt32 size, version;
RwTexture *tex;
if(!RwStreamFindChunk(stream, rwID_TEXTURENATIVE, &size, &version))
return nil;
// TODO: unused timing
if(!RWSRCGLOBAL(stdFunc[rwSTANDARDNATIVETEXTUREREAD](stream, &tex, size)))
return nil;
return tex;
}
RwTexture*
destroyTexture(RwTexture *texture, void *data)
{
RwTextureDestroy(texture);
return texture;
}
RwTexDictionary*
RwTexDictionaryGtaStreamRead(RwStream *stream)
{
RwUInt32 size, version;
RwInt32 numTextures;
RwTexDictionary *texDict;
RwTexture *tex;
if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
return nil;
assert(size == 4);
if(RwStreamRead(stream, &numTextures, size) != size)
return nil;
texDict = RwTexDictionaryCreate();
if(texDict == nil)
return nil;
while(numTextures--){
tex = RwTextureGtaStreamRead(stream);
if(tex == nil){
RwTexDictionaryForAllTextures(texDict, destroyTexture, nil);
RwTexDictionaryDestroy(texDict);
return nil;
}
RwTexDictionaryAddTexture(texDict, tex);
}
return texDict;
}
static int32 numberTextures = -1;
static int32 streamPosition;
RwTexDictionary*
RwTexDictionaryGtaStreamRead1(RwStream *stream)
{
RwUInt32 size, version;
RwInt32 numTextures;
RwTexDictionary *texDict;
RwTexture *tex;
numberTextures = 0;
if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
return nil;
assert(size == 4);
if(RwStreamRead(stream, &numTextures, size) != size)
return nil;
texDict = RwTexDictionaryCreate();
if(texDict == nil)
return nil;
numberTextures = numTextures/2;
while(numTextures > numberTextures){
numTextures--;
tex = RwTextureGtaStreamRead(stream);
if(tex == nil){
RwTexDictionaryForAllTextures(texDict, destroyTexture, nil);
RwTexDictionaryDestroy(texDict);
return nil;
}
RwTexDictionaryAddTexture(texDict, tex);
}
numberTextures = numTextures;
streamPosition = stream->Type.memory.position;
return texDict;
}
RwTexDictionary*
RwTexDictionaryGtaStreamRead2(RwStream *stream, RwTexDictionary *texDict)
{
RwTexture *tex;
RwStreamSkip(stream, streamPosition - stream->Type.memory.position);
while(numberTextures--){
tex = RwTextureGtaStreamRead(stream);
if(tex == nil){
RwTexDictionaryForAllTextures(texDict, destroyTexture, nil);
RwTexDictionaryDestroy(texDict);
return nil;
}
RwTexDictionaryAddTexture(texDict, tex);
}
return texDict;
}
STARTPATCHES
InjectHook(0x592380, RwTextureGtaStreamRead, PATCH_JUMP);
InjectHook(0x5924A0, RwTexDictionaryGtaStreamRead, PATCH_JUMP);
InjectHook(0x592550, RwTexDictionaryGtaStreamRead1, PATCH_JUMP);
InjectHook(0x592650, RwTexDictionaryGtaStreamRead2, PATCH_JUMP);
ENDPATCHES

13
src/core/Stats.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "common.h"
#include "Stats.h"
int32 &CStats::DaysPassed = *(int32*)0x8F2BB8;
int32 &CStats::HeadShots = *(int32*)0x8F647C;
bool& CStats::CommercialPassed = *(bool*)0x8F4334;
int32 &CStats::NumberKillFrenziesPassed = *(int32*)0x8E287C;
int32 &CStats::PeopleKilledByOthers = *(int32*)0x8E2C50;
void CStats::AnotherKillFrenzyPassed()
{
++NumberKillFrenziesPassed;
}

14
src/core/Stats.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
class CStats
{
public:
static int32 &DaysPassed;
static int32 &HeadShots;
static bool& CommercialPassed;
static int32 &NumberKillFrenziesPassed;
static int32 &PeopleKilledByOthers;
public:
static void AnotherKillFrenzyPassed();
};

2509
src/core/Streaming.cpp Normal file

File diff suppressed because it is too large Load Diff

188
src/core/Streaming.h Normal file
View File

@ -0,0 +1,188 @@
#pragma once
#include "Game.h"
enum {
STREAM_OFFSET_MODEL = 0,
STREAM_OFFSET_TXD = STREAM_OFFSET_MODEL+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,
// TODO: this isn't named well, maybe CANT_REMOVE?
STREAMFLAGS_NOT_IN_LIST = 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;
enum eLevelName;
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;
static int8 **ms_pStreamingBuffer; //[2]
static int32 &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 uint32 &ms_memoryAvailable;
static void Init(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 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(int32 mem);
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(int32 mem);
static void DeleteRwObjectsInSectorList(CPtrList &list);
static void DeleteRwObjectsInOverlapSectorList(CPtrList &list, int32 x, int32 y);
static bool DeleteRwObjectsBehindCameraInSectorList(CPtrList &list, int32 mem);
static bool DeleteRwObjectsNotInFrustumInSectorList(CPtrList &list, int32 mem);
static void LoadScene(const CVector &pos);
static void MemoryCardSave(uint8 *buffer, uint32 *length);
static void MemoryCardLoad(uint8 *buffer, uint32 length);
};

150
src/core/SurfaceTable.cpp Normal file
View File

@ -0,0 +1,150 @@
#include "common.h"
#include "patcher.h"
#include "main.h"
#include "FileMgr.h"
#include "Weather.h"
#include "Collision.h"
#include "SurfaceTable.h"
float (*CSurfaceTable::ms_aAdhesiveLimitTable)[NUMADHESIVEGROUPS] = (float (*)[NUMADHESIVEGROUPS])0x8E29D4;
void
CSurfaceTable::Initialise(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_0: return ADHESIVE_ROAD;
case SURFACE_1: return ADHESIVE_ROAD;
case SURFACE_2: return ADHESIVE_LOOSE;
case SURFACE_3: return ADHESIVE_LOOSE;
case SURFACE_4: return ADHESIVE_HARD;
case SURFACE_5: return ADHESIVE_ROAD;
case SURFACE_6: return ADHESIVE_HARD;
case SURFACE_7: return ADHESIVE_HARD;
case SURFACE_8: return ADHESIVE_HARD;
case SURFACE_9: return ADHESIVE_HARD;
case SURFACE_10: return ADHESIVE_HARD;
case SURFACE_11: return ADHESIVE_HARD;
case SURFACE_12: return ADHESIVE_HARD;
case SURFACE_13: return ADHESIVE_HARD;
case SURFACE_14: return ADHESIVE_HARD;
case SURFACE_15: return ADHESIVE_HARD;
case SURFACE_16: return ADHESIVE_HARD;
case SURFACE_17: return ADHESIVE_RUBBER;
case SURFACE_18: return ADHESIVE_LOOSE;
case SURFACE_19: return ADHESIVE_WET;
case SURFACE_20: return ADHESIVE_ROAD;
case SURFACE_21: return ADHESIVE_ROAD;
case SURFACE_22: return ADHESIVE_ROAD;
case SURFACE_23: return ADHESIVE_RUBBER;
case SURFACE_24: return ADHESIVE_HARD;
case SURFACE_25: return ADHESIVE_LOOSE;
case SURFACE_26: return ADHESIVE_LOOSE;
case SURFACE_27: return ADHESIVE_HARD;
case SURFACE_28: return ADHESIVE_HARD;
case SURFACE_29: return ADHESIVE_RUBBER;
case SURFACE_30: return ADHESIVE_LOOSE;
case SURFACE_31: return ADHESIVE_HARD;
case SURFACE_32: return ADHESIVE_HARD;
default: return ADHESIVE_ROAD;
}
}
float
CSurfaceTable::GetWetMultiplier(uint8 surfaceType)
{
switch(surfaceType){
case SURFACE_0:
case SURFACE_1:
case SURFACE_4:
case SURFACE_5:
case SURFACE_8:
case SURFACE_20:
case SURFACE_21:
case SURFACE_22:
case SURFACE_25:
case SURFACE_30:
case SURFACE_31:
return 1.0f - CWeather::WetRoads*0.25f;
case SURFACE_2:
case SURFACE_6:
case SURFACE_7:
case SURFACE_9:
case SURFACE_10:
case SURFACE_11:
case SURFACE_12:
case SURFACE_13:
case SURFACE_14:
case SURFACE_15:
case SURFACE_16:
case SURFACE_17:
case SURFACE_23:
case SURFACE_24:
case SURFACE_26:
case SURFACE_27:
case SURFACE_28:
case SURFACE_29:
case SURFACE_32:
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)];
}
STARTPATCHES
InjectHook(0x4AB8F0, CSurfaceTable::Initialise, PATCH_JUMP);
InjectHook(0x4ABA60, CSurfaceTable::GetAdhesionGroup, PATCH_JUMP);
InjectHook(0x4ABAA0, CSurfaceTable::GetWetMultiplier, PATCH_JUMP);
InjectHook(0x4ABA30, CSurfaceTable::GetAdhesiveLimit, PATCH_JUMP);
ENDPATCHES

106
src/core/SurfaceTable.h Normal file
View File

@ -0,0 +1,106 @@
#pragma once
enum
{
SURFACE_0,
SURFACE_1,
SURFACE_2,
SURFACE_3,
SURFACE_4,
SURFACE_5,
SURFACE_6,
SURFACE_7,
SURFACE_8,
SURFACE_9,
SURFACE_10,
SURFACE_11,
SURFACE_12,
SURFACE_13,
SURFACE_14,
SURFACE_15,
SURFACE_16,
SURFACE_17,
SURFACE_18,
SURFACE_19,
SURFACE_20,
SURFACE_21,
SURFACE_22,
SURFACE_23,
SURFACE_24,
SURFACE_25,
SURFACE_26,
SURFACE_27,
SURFACE_28,
SURFACE_29,
SURFACE_30,
SURFACE_31,
SURFACE_32,
NUMSURFACETYPES
};
// From nick
// TODO: check and use this
enum eSurfaceType
{
SURFACE_DEFAULT,
SURFACE_TARMAC,
SURFACE_GRASS,
SURFACE_DIRT,
SURFACE_DIRTTRACK,
SURFACE_PAVEMENT,
SURFACE_METAL6,
SURFACE_GLASS,
SURFACE_SCAFFOLD,
SURFACE_METAL_DOOR, // garage door
SURFACE_BILLBOARD,
SURFACE_STEEL, //?
SURFACE_METAL_POLE, // ?
SURFACE_STREET_LIGHT,
SURFACE_METAL14,
SURFACE_METAL15,
SURFACE_METAL_FENCE,
SURFACE_FLESH,
SURFACE_SAND,
SURFACE_PUDDLE,
SURFACE_WOOD,
SURFACE_WOOD_BOX,
SURFACE_WOOD_PLANK,
SURFACE_TIRE,
SURFACE_HARD24,
SURFACE_HEDGE,
SURFACE_STONE,
SURFACE_METAL27,
SURFACE_METAL28,
SURFACE_RUBBER29,
SURFACE_LOOSE30,
SURFACE_BOLLARD,
SURFACE_GATE,
SURFACE_SAND33,
SURFACE_ROAD34,
};
enum
{
ADHESIVE_RUBBER,
ADHESIVE_HARD,
ADHESIVE_ROAD,
ADHESIVE_LOOSE,
ADHESIVE_WET,
NUMADHESIVEGROUPS
};
struct CColPoint;
class CSurfaceTable
{
// static float ms_aAdhesiveLimitTable[NUMADHESIVEGROUPS][NUMADHESIVEGROUPS];
static float (*ms_aAdhesiveLimitTable)[NUMADHESIVEGROUPS];
public:
static void Initialise(char *filename);
static int GetAdhesionGroup(uint8 surfaceType);
static float GetWetMultiplier(uint8 surfaceType);
static float GetAdhesiveLimit(CColPoint &colpoint);
};

View File

@ -0,0 +1,17 @@
#include "common.h"
#include "patcher.h"
#include "TempColModels.h"
CColModel &CTempColModels::ms_colModelPed1 = *(CColModel*)0x726CB0;
CColModel &CTempColModels::ms_colModelPed2 = *(CColModel*)0x726D08;
CColModel &CTempColModels::ms_colModelBBox = *(CColModel*)0x727FE0;
CColModel &CTempColModels::ms_colModelBumper1 = *(CColModel*)0x86BE88;
CColModel &CTempColModels::ms_colModelWheel1 = *(CColModel*)0x878C40;
CColModel &CTempColModels::ms_colModelPanel1 = *(CColModel*)0x87BDD8;
CColModel &CTempColModels::ms_colModelBodyPart2 = *(CColModel*)0x87BE30;
CColModel &CTempColModels::ms_colModelBodyPart1 = *(CColModel*)0x87BE88;
CColModel &CTempColModels::ms_colModelCutObj = *(CColModel*)0x87C960;
CColModel &CTempColModels::ms_colModelPedGroundHit = *(CColModel*)0x880480;
CColModel &CTempColModels::ms_colModelBoot1 = *(CColModel*)0x880670;
CColModel &CTempColModels::ms_colModelDoor1 = *(CColModel*)0x880850;
CColModel &CTempColModels::ms_colModelBonnet1 = *(CColModel*)0x8808A8;

21
src/core/TempColModels.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include "Collision.h"
class CTempColModels
{
public:
static CColModel &ms_colModelPed1;
static CColModel &ms_colModelPed2;
static CColModel &ms_colModelBBox;
static CColModel &ms_colModelBumper1;
static CColModel &ms_colModelWheel1;
static CColModel &ms_colModelPanel1;
static CColModel &ms_colModelBodyPart2;
static CColModel &ms_colModelBodyPart1;
static CColModel &ms_colModelCutObj;
static CColModel &ms_colModelPedGroundHit;
static CColModel &ms_colModelBoot1;
static CColModel &ms_colModelDoor1;
static CColModel &ms_colModelBonnet1;
};

232
src/core/Text.cpp Normal file
View File

@ -0,0 +1,232 @@
#include "common.h"
#include "patcher.h"
#include "FileMgr.h"
#include "Frontend.h"
#include "Messages.h"
#include "Text.h"
static wchar WideErrorString[25];
CText &TheText = *(CText*)0x941520;
CText::CText(void)
{
keyArray.entries = nil;
keyArray.numEntries = 0;
data.chars = nil;
data.numChars = 0;
encoding = 101;
memset(WideErrorString, 0, sizeof(WideErrorString));
}
CText::~CText(void)
{
data.Unload();
keyArray.Unload();
}
void
CText::Load(void)
{
uint8 *filedata;
char filename[32], type[4];
int length;
int offset, sectlen;
Unload();
filedata = new uint8[0x40000];
CFileMgr::SetDir("TEXT");
switch(CMenuManager::m_PrefsLanguage){
case LANGUAGE_AMERICAN:
sprintf(filename, "AMERICAN.GXT");
break;
case LANGUAGE_FRENCH:
sprintf(filename, "FRENCH.GXT");
break;
case LANGUAGE_GERMAN:
sprintf(filename, "GERMAN.GXT");
break;
case LANGUAGE_ITALIAN:
sprintf(filename, "ITALIAN.GXT");
break;
case LANGUAGE_SPANISH:
sprintf(filename, "SPANISH.GXT");
break;
}
length = CFileMgr::LoadFile(filename, filedata, 0x40000, "rb");
CFileMgr::SetDir("");
offset = 0;
while(offset < length){
type[0] = filedata[offset++];
type[1] = filedata[offset++];
type[2] = filedata[offset++];
type[3] = filedata[offset++];
sectlen = (int)filedata[offset+3]<<24 | (int)filedata[offset+2]<<16 |
(int)filedata[offset+1]<<8 | (int)filedata[offset+0];
offset += 4;
if(sectlen != 0){
if(strncmp(type, "TKEY", 4) == 0)
keyArray.Load(sectlen, filedata, &offset);
else if(strncmp(type, "TDAT", 4) == 0)
data.Load(sectlen, filedata, &offset);
else
offset += sectlen;
}
}
keyArray.Update(data.chars);
delete[] filedata;
}
void
CText::Unload(void)
{
CMessages::ClearAllMessagesDisplayedByGame();
data.Unload();
keyArray.Unload();
}
wchar*
CText::Get(const char *key)
{
return keyArray.Search(key);
}
wchar
CText::GetUpperCase(wchar c)
{
// TODO: do this depending on encoding
if(islower(c))
return toupper(c);
return c;
}
void
CText::UpperCase(wchar *s)
{
while(*s){
*s = GetUpperCase(*s);
s++;
}
}
void
CKeyArray::Load(uint32 length, uint8 *data, int *offset)
{
uint32 i;
uint8 *rawbytes;
numEntries = length / sizeof(CKeyEntry);
entries = new CKeyEntry[numEntries];
rawbytes = (uint8*)entries;
for(i = 0; i < length; i++)
rawbytes[i] = data[(*offset)++];
}
void
CKeyArray::Unload(void)
{
delete[] entries;
entries = nil;
numEntries = 0;
}
void
CKeyArray::Update(wchar *chars)
{
int i;
for(i = 0; i < numEntries; i++)
entries[i].value = (wchar*)((uint8*)chars + (uintptr)entries[i].value);
}
CKeyEntry*
CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high)
{
int mid;
int diff;
if(low > high)
return nil;
mid = (low + high)/2;
diff = strcmp(key, entries[mid].key);
if(diff == 0)
return &entries[mid];
if(diff < 0)
return BinarySearch(key, entries, low, mid-1);
if(diff > 0)
return BinarySearch(key, entries, mid+1, high);
return nil;
}
wchar*
CKeyArray::Search(const char *key)
{
CKeyEntry *found;
char errstr[25];
int i;
found = BinarySearch(key, entries, 0, numEntries-1);
if(found)
return found->value;
sprintf(errstr, "%s missing", key);
for(i = 0; i < 25; i++)
WideErrorString[i] = errstr[i];
return WideErrorString;
}
void
CData::Load(uint32 length, uint8 *data, int *offset)
{
uint32 i;
uint8 *rawbytes;
numChars = length / sizeof(wchar);
chars = new wchar[numChars];
rawbytes = (uint8*)chars;
for(i = 0; i < length; i++)
rawbytes[i] = data[(*offset)++];
}
void
CData::Unload(void)
{
delete[] chars;
chars = nil;
numChars = 0;
}
void
AsciiToUnicode(const char *src, uint16 *dst)
{
while((*dst++ = *src++) != '\0');
}
void
TextCopy(wchar *dst, const wchar *src)
{
while((*dst++ = *src++) != '\0');
}
STARTPATCHES
InjectHook(0x52C3C0, &CText::Load, PATCH_JUMP);
InjectHook(0x52C580, &CText::Unload, PATCH_JUMP);
InjectHook(0x52C5A0, &CText::Get, PATCH_JUMP);
InjectHook(0x52BE70, &CKeyArray::Load, PATCH_JUMP);
InjectHook(0x52BF60, &CKeyArray::Unload, PATCH_JUMP);
InjectHook(0x52BF80, &CKeyArray::Update, PATCH_JUMP);
InjectHook(0x52C060, &CKeyArray::BinarySearch, PATCH_JUMP);
InjectHook(0x52BFB0, &CKeyArray::Search, PATCH_JUMP);
InjectHook(0x52C120, &CData::Load, PATCH_JUMP);
InjectHook(0x52C200, &CData::Unload, PATCH_JUMP);
ENDPATCHES

52
src/core/Text.h Normal file
View File

@ -0,0 +1,52 @@
#pragma once
void AsciiToUnicode(const char *src, wchar *dst);
void TextCopy(wchar *dst, const wchar *src);
struct CKeyEntry
{
wchar *value;
char key[8];
};
// If this fails, CKeyArray::Load will have to be fixed
static_assert(sizeof(CKeyEntry) == 12, "CKeyEntry: error");
class CKeyArray
{
public:
CKeyEntry *entries;
int numEntries;
void Load(uint32 length, uint8 *data, int *offset);
void Unload(void);
void Update(wchar *chars);
CKeyEntry *BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high);
wchar *Search(const char *key);
};
class CData
{
public:
wchar *chars;
int numChars;
void Load(uint32 length, uint8 *data, int *offset);
void Unload(void);
};
class CText
{
CKeyArray keyArray;
CData data;
int8 encoding;
public:
CText(void);
~CText(void);
void Load(void);
void Unload(void);
wchar *Get(const char *key);
wchar GetUpperCase(wchar c);
void UpperCase(wchar *s);
};
extern CText &TheText;

235
src/core/Timer.cpp Normal file
View File

@ -0,0 +1,235 @@
#include <windows.h>
#include "common.h"
#include "patcher.h"
#include "DMAudio.h"
#include "Record.h"
#include "Timer.h"
uint32 &CTimer::m_snTimeInMilliseconds = *(uint32*)0x885B48;
uint32 &CTimer::m_snTimeInMillisecondsPauseMode = *(uint32*)0x5F7614;
uint32 &CTimer::m_snTimeInMillisecondsNonClipped = *(uint32*)0x9412E8;
uint32 &CTimer::m_snPreviousTimeInMilliseconds = *(uint32*)0x8F29E4;
uint32 &CTimer::m_FrameCounter = *(uint32*)0x9412EC;
float &CTimer::ms_fTimeScale = *(float*)0x8F2C20;
float &CTimer::ms_fTimeStep = *(float*)0x8E2CB4;
float &CTimer::ms_fTimeStepNonClipped = *(float*)0x8E2C4C;
bool &CTimer::m_UserPause = *(bool*)0x95CD7C;
bool &CTimer::m_CodePause = *(bool*)0x95CDB1;
//UInt32 oldPcTimer;
uint32 &oldPcTimer = *(uint32*)0x9434F4;
//UInt32 suspendPcTimer;
uint32 &suspendPcTimer = *(uint32*)0x62A308;
//UInt32 _nCyclesPerMS = 1;
uint32 &_nCyclesPerMS = *(uint32*)0x5F7610;
//LARGE_INTEGER _oldPerfCounter;
LARGE_INTEGER &_oldPerfCounter = *(LARGE_INTEGER*)0x62A310;
//LARGE_INTEGER perfSuspendCounter;
LARGE_INTEGER &perfSuspendCounter = *(LARGE_INTEGER*)0x62A318;
//UInt32 suspendDepth;
uint32 &suspendDepth = *(uint32*)0x62A320;
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;
LARGE_INTEGER perfFreq;
if ( QueryPerformanceFrequency(&perfFreq) )
{
OutputDebugString("Performance counter available\n");
_nCyclesPerMS = uint32(perfFreq.QuadPart / 1000);
QueryPerformanceCounter(&_oldPerfCounter);
}
else
{
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)
{
;
}
#if 1
WRAPPER void CTimer::Update(void) { EAXJMP(0x4ACF70); }
#else
void CTimer::Update(void)
{
m_snPreviousTimeInMilliseconds = m_snTimeInMilliseconds;
if ( (double)_nCyclesPerMS != 0.0 )
{
LARGE_INTEGER pc;
QueryPerformanceCounter(&pc);
int32 updInCycles = (pc.LowPart - _oldPerfCounter.LowPart) & 0x7FFFFFFF;
_oldPerfCounter = pc;
double updInCyclesScaled = (double)updInCycles * ms_fTimeScale;
double upd = updInCyclesScaled / (double)_nCyclesPerMS;
m_snTimeInMillisecondsPauseMode = (Int64)(m_snTimeInMillisecondsPauseMode + upd);
if ( GetIsPaused() )
ms_fTimeStep = 0.0f;
else
{
m_snTimeInMilliseconds = (Int64)(m_snTimeInMilliseconds + upd);
m_snTimeInMillisecondsNonClipped = (Int64)(m_snTimeInMillisecondsNonClipped + upd);
ms_fTimeStep = updInCyclesScaled / (double)_nCyclesPerMS / 20.0;
}
}
else
{
uint32 timer = RsTimer();
uint32 updInMs = timer - oldPcTimer;
double upd = (double)updInMs * ms_fTimeScale;
oldPcTimer = timer;
m_snTimeInMillisecondsPauseMode = (Int64)(m_snTimeInMillisecondsPauseMode + upd);
if ( GetIsPaused() )
ms_fTimeStep = 0.0f;
else
{
m_snTimeInMilliseconds = (Int64)(m_snTimeInMilliseconds + upd);
m_snTimeInMillisecondsNonClipped = (Int64)(m_snTimeInMillisecondsNonClipped + upd);
ms_fTimeStep = upd / 1000.0f * 50.0f;
}
}
if ( ms_fTimeStep < 0.01f && !GetIsPaused() )
ms_fTimeStep = 0.01f;
ms_fTimeStepNonClipped = ms_fTimeStep;
if ( CRecordDataForGame::RecordingState != RECORDSTATE_2 )
{
ms_fTimeStep = min(3.0f, ms_fTimeStep);
if ( (m_snTimeInMilliseconds - m_snPreviousTimeInMilliseconds) > 60 )
m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 60;
}
if ( CRecordDataForChase::Status == RECORDSTATE_1 )
{
ms_fTimeStep = 1.0f;
m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 16;
}
m_FrameCounter++;
}
#endif
void CTimer::Suspend(void)
{
if ( ++suspendDepth > 1 )
return;
if ( (double)_nCyclesPerMS != 0.0 )
QueryPerformanceCounter(&perfSuspendCounter);
else
suspendPcTimer = RsTimer();
}
void CTimer::Resume(void)
{
if ( --suspendDepth != 0 )
return;
if ( (double)_nCyclesPerMS != 0.0 )
{
LARGE_INTEGER pc;
QueryPerformanceCounter(&pc);
_oldPerfCounter.LowPart += pc.LowPart - perfSuspendCounter.LowPart;
}
else
oldPcTimer += RsTimer() - suspendPcTimer;
}
uint32 CTimer::GetCyclesPerMillisecond(void)
{
if (_nCyclesPerMS != 0)
return _nCyclesPerMS;
else
return 1;
}
uint32 CTimer::GetCurrentTimeInCycles(void)
{
if ( _nCyclesPerMS != 0 )
{
LARGE_INTEGER pc;
QueryPerformanceCounter(&pc);
return (pc.LowPart - _oldPerfCounter.LowPart) & 0x7FFFFFFF;
}
else
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;
}
#if 0
STARTPATCHES
InjectHook(0x4ACE60, CTimer::Initialise, PATCH_JUMP);
InjectHook(0x4ACF60, CTimer::Shutdown, PATCH_JUMP);
InjectHook(0x4ACF70, CTimer::Update, PATCH_JUMP);
InjectHook(0x4AD310, CTimer::Suspend, PATCH_JUMP);
InjectHook(0x4AD370, CTimer::Resume, PATCH_JUMP);
InjectHook(0x4AD3F0, CTimer::GetCyclesPerMillisecond, PATCH_JUMP);
InjectHook(0x4AD410, CTimer::GetCurrentTimeInCycles, PATCH_JUMP);
InjectHook(0x4AD450, CTimer::GetIsSlowMotionActive, PATCH_JUMP);
InjectHook(0x4AD480, CTimer::Stop, PATCH_JUMP);
InjectHook(0x4AD490, CTimer::StartUserPause, PATCH_JUMP);
InjectHook(0x4AD4A0, CTimer::EndUserPause, PATCH_JUMP);
ENDPATCHES
#endif

51
src/core/Timer.h Normal file
View File

@ -0,0 +1,51 @@
#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;
static bool &m_UserPause;
static bool &m_CodePause;
public:
static float GetTimeStep(void) { return ms_fTimeStep; }
static void SetTimeStep(float ts) { ms_fTimeStep = ts; }
static float GetTimeStepInSeconds() { return ms_fTimeStep / 50.0f; }
static float GetTimeStepInMilliseconds() { return ms_fTimeStep / 50.0f * 1000.0f; }
static float GetTimeStepNonClipped(void) { return ms_fTimeStepNonClipped; }
static float GetTimeStepNonClippedInSeconds(void) { return ms_fTimeStepNonClipped / 50.0f; }
static void SetTimeStepNonClipped(float ts) { ms_fTimeStepNonClipped = ts; }
static uint32 GetFrameCounter(void) { return m_FrameCounter; }
static void SetFrameCounter(uint32 fc) { m_FrameCounter = fc; }
static 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 float GetTimeScale(void) { return ms_fTimeScale; }
static void SetTimeScale(float ts) { ms_fTimeScale = ts; }
static bool GetIsPaused() { return m_UserPause || m_CodePause; }
static bool GetIsUserPaused() { return m_UserPause; }
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);
};

208
src/core/TxdStore.cpp Normal file
View File

@ -0,0 +1,208 @@
#include "common.h"
#include "patcher.h"
#include "templates.h"
#include "Streaming.h"
#include "RwHelper.h"
#include "TxdStore.h"
CPool<TxdDef,TxdDef> *&CTxdStore::ms_pTxdPool = *(CPool<TxdDef,TxdDef>**)0x8F5FB8;
RwTexDictionary *&CTxdStore::ms_pStoredTxd = *(RwTexDictionary**)0x9405BC;
void
CTxdStore::Initialize(void)
{
if(ms_pTxdPool == nil)
ms_pTxdPool = new CPool<TxdDef,TxdDef>(TXDSTORESIZE);
}
void
CTxdStore::Shutdown(void)
{
if(ms_pTxdPool)
delete ms_pTxdPool;
}
void
CTxdStore::GameShutdown(void)
{
int i;
for(i = 0; i < TXDSTORESIZE; i++){
TxdDef *def = GetSlot(i);
if(def && GetNumRefs(i) == 0)
RemoveTxdSlot(i);
}
}
int
CTxdStore::AddTxdSlot(const char *name)
{
TxdDef *def = ms_pTxdPool->New();
assert(def);
def->texDict = nil;
def->refCount = 0;
strcpy(def->name, name);
return ms_pTxdPool->GetJustIndex(def);
}
void
CTxdStore::RemoveTxdSlot(int slot)
{
TxdDef *def = GetSlot(slot);
if(def->texDict)
RwTexDictionaryDestroy(def->texDict);
ms_pTxdPool->Delete(def);
}
int
CTxdStore::FindTxdSlot(const char *name)
{
char *defname;
int size = ms_pTxdPool->GetSize();
for(int i = 0; i < size; i++){
defname = GetTxdName(i);
if(defname && _strcmpi(defname, name) == 0)
return i;
}
return -1;
}
char*
CTxdStore::GetTxdName(int slot)
{
TxdDef *def = GetSlot(slot);
return def ? def->name : nil;
}
void
CTxdStore::PushCurrentTxd(void)
{
ms_pStoredTxd = RwTexDictionaryGetCurrent();
}
void
CTxdStore::PopCurrentTxd(void)
{
RwTexDictionarySetCurrent(ms_pStoredTxd);
ms_pStoredTxd = nil;
}
void
CTxdStore::SetCurrentTxd(int slot)
{
TxdDef *def = GetSlot(slot);
if(def)
RwTexDictionarySetCurrent(def->texDict);
}
void
CTxdStore::Create(int slot)
{
GetSlot(slot)->texDict = RwTexDictionaryCreate();
}
int
CTxdStore::GetNumRefs(int slot)
{
return GetSlot(slot)->refCount;
}
void
CTxdStore::AddRef(int slot)
{
GetSlot(slot)->refCount++;
}
void
CTxdStore::RemoveRef(int slot)
{
if(--GetSlot(slot)->refCount <= 0)
CStreaming::RemoveModel(slot + STREAM_OFFSET_TXD);
}
void
CTxdStore::RemoveRefWithoutDelete(int slot)
{
GetSlot(slot)->refCount--;
}
bool
CTxdStore::LoadTxd(int slot, RwStream *stream)
{
TxdDef *def = GetSlot(slot);
if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, nil, nil)){
def->texDict = RwTexDictionaryGtaStreamRead(stream);
return def->texDict != nil;
}
printf("Failed to load TXD\n");
return false;
}
bool
CTxdStore::LoadTxd(int slot, const char *filename)
{
RwStream *stream;
bool ret;
ret = false;
_rwD3D8TexDictionaryEnableRasterFormatConversion(true);
do
stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename);
while(stream == nil);
ret = LoadTxd(slot, stream);
RwStreamClose(stream, nil);
return ret;
}
bool
CTxdStore::StartLoadTxd(int slot, RwStream *stream)
{
TxdDef *def = GetSlot(slot);
if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, nil, nil)){
def->texDict = RwTexDictionaryGtaStreamRead1(stream);
return def->texDict != nil;
}else{
printf("Failed to load TXD\n");
return false;
}
}
bool
CTxdStore::FinishLoadTxd(int slot, RwStream *stream)
{
TxdDef *def = GetSlot(slot);
def->texDict = RwTexDictionaryGtaStreamRead2(stream, def->texDict);
return def->texDict != nil;
}
void
CTxdStore::RemoveTxd(int slot)
{
TxdDef *def = GetSlot(slot);
if(def->texDict)
RwTexDictionaryDestroy(def->texDict);
def->texDict = nil;
}
STARTPATCHES
InjectHook(0x527440, CTxdStore::Initialize, PATCH_JUMP);
InjectHook(0x527470, CTxdStore::Shutdown, PATCH_JUMP);
InjectHook(0x527490, CTxdStore::GameShutdown, PATCH_JUMP);
InjectHook(0x5274E0, CTxdStore::AddTxdSlot, PATCH_JUMP);
InjectHook(0x5275D0, CTxdStore::FindTxdSlot, PATCH_JUMP);
InjectHook(0x527590, CTxdStore::GetTxdName, PATCH_JUMP);
InjectHook(0x527900, CTxdStore::PushCurrentTxd, PATCH_JUMP);
InjectHook(0x527910, CTxdStore::PopCurrentTxd, PATCH_JUMP);
InjectHook(0x5278C0, CTxdStore::SetCurrentTxd, PATCH_JUMP);
InjectHook(0x527830, CTxdStore::Create, PATCH_JUMP);
InjectHook(0x527A00, CTxdStore::GetNumRefs, PATCH_JUMP);
InjectHook(0x527930, CTxdStore::AddRef, PATCH_JUMP);
InjectHook(0x527970, CTxdStore::RemoveRef, PATCH_JUMP);
InjectHook(0x5279C0, CTxdStore::RemoveRefWithoutDelete, PATCH_JUMP);
InjectHook(0x527700, (bool (*)(int, RwStream*))CTxdStore::LoadTxd, PATCH_JUMP);
InjectHook(0x5276B0, (bool (*)(int, const char*))CTxdStore::LoadTxd, PATCH_JUMP);
InjectHook(0x527770, CTxdStore::StartLoadTxd, PATCH_JUMP);
InjectHook(0x5277E0, CTxdStore::FinishLoadTxd, PATCH_JUMP);
InjectHook(0x527870, CTxdStore::RemoveTxd, PATCH_JUMP);
ENDPATCHES

44
src/core/TxdStore.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include "templates.h"
struct TxdDef {
RwTexDictionary *texDict;
int refCount;
char name[20];
};
class CTxdStore
{
static CPool<TxdDef,TxdDef> *&ms_pTxdPool;
static RwTexDictionary *&ms_pStoredTxd;
public:
static void Initialize(void);
static void Shutdown(void);
static void GameShutdown(void);
static int AddTxdSlot(const char *name);
static void RemoveTxdSlot(int slot);
static int FindTxdSlot(const char *name);
static char *GetTxdName(int slot);
static void PushCurrentTxd(void);
static void PopCurrentTxd(void);
static void SetCurrentTxd(int slot);
static void Create(int slot);
static int GetNumRefs(int slot);
static void AddRef(int slot);
static void RemoveRef(int slot);
static void RemoveRefWithoutDelete(int slot);
static bool LoadTxd(int slot, RwStream *stream);
static bool LoadTxd(int slot, const char *filename);
static bool StartLoadTxd(int slot, RwStream *stream);
static bool FinishLoadTxd(int slot, RwStream *stream);
static void RemoveTxd(int slot);
static TxdDef *GetSlot(int slot) {
assert(slot >= 0);
assert(ms_pTxdPool);
assert(slot < ms_pTxdPool->GetSize());
return ms_pTxdPool->GetSlot(slot);
}
static bool isTxdLoaded(int slot);
};

176
src/core/User.cpp Normal file
View File

@ -0,0 +1,176 @@
#include "common.h"
#include "patcher.h"
#include "DMAudio.h"
#include "Hud.h"
#include "Replay.h"
#include "Timer.h"
#include "Script.h"
#include "User.h"
CPlaceName& CUserDisplay::PlaceName = *(CPlaceName*)0x8F29BC;
COnscreenTimer& CUserDisplay::OnscnTimer = *(COnscreenTimer*)0x862238;
CPager& CUserDisplay::Pager = *(CPager*)0x8F2744;
CCurrentVehicle& CUserDisplay::CurrentVehicle = *(CCurrentVehicle*)0x8F5FE8;
void COnscreenTimer::Init() {
m_bDisabled = false;
for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) {
m_sEntries[i].m_nTimerOffset = 0;
m_sEntries[i].m_nCounterOffset = 0;
for(uint32 j = 0; j < 10; j++) {
m_sEntries[i].m_aTimerText[j] = 0;
m_sEntries[i].m_aCounterText[j] = 0;
}
m_sEntries[i].m_nType = 0;
m_sEntries[i].m_bTimerProcessed = 0;
m_sEntries[i].m_bCounterProcessed = 0;
}
}
void COnscreenTimer::Process() {
if(!CReplay::IsPlayingBack() && !m_bDisabled) {
for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) {
m_sEntries[i].Process();
}
}
}
void COnscreenTimer::ProcessForDisplay() {
if(CHud::m_Wants_To_Draw_Hud) {
m_bProcessed = false;
for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) {
if(m_sEntries[i].ProcessForDisplay()) {
m_bProcessed = true;
}
}
}
}
void COnscreenTimer::ClearCounter(uint32 offset) {
for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) {
if(offset == m_sEntries[i].m_nCounterOffset) {
m_sEntries[i].m_nCounterOffset = 0;
m_sEntries[i].m_aCounterText[0] = 0;
m_sEntries[i].m_nType = 0;
m_sEntries[i].m_bCounterProcessed = 0;
}
}
}
void COnscreenTimer::ClearClock(uint32 offset) {
for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) {
if(offset == m_sEntries[i].m_nTimerOffset) {
m_sEntries[i].m_nTimerOffset = 0;
m_sEntries[i].m_aTimerText[0] = 0;
m_sEntries[i].m_bTimerProcessed = 0;
}
}
}
void COnscreenTimer::AddCounter(uint32 offset, uint16 type, char* text) {
uint32 i = 0;
for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) {
if(m_sEntries[i].m_nCounterOffset == 0) {
break;
}
return;
}
m_sEntries[i].m_nCounterOffset = offset;
if(text) {
strncpy(m_sEntries[i].m_aCounterText, text, 10);
} else {
m_sEntries[i].m_aCounterText[0] = 0;
}
m_sEntries[i].m_nType = type;
}
void COnscreenTimer::AddClock(uint32 offset, char* text) {
uint32 i = 0;
for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) {
if(m_sEntries[i].m_nTimerOffset == 0) {
break;
}
return;
}
m_sEntries[i].m_nTimerOffset = offset;
if(text) {
strncpy(m_sEntries[i].m_aTimerText, text, 10);
} else {
m_sEntries[i].m_aTimerText[0] = 0;
}
}
void COnscreenTimerEntry::Process() {
if(m_nTimerOffset == 0) {
return;
}
uint32* timerPtr = (uint32*)&CTheScripts::ScriptSpace[m_nTimerOffset];
uint32 oldTime = *timerPtr;
int32 newTime = int32(oldTime - uint32(20.0f * CTimer::GetTimeStep()));
if(newTime < 0) {
*timerPtr = 0;
m_bTimerProcessed = 0;
m_nTimerOffset = 0;
m_aTimerText[0] = 0;
} else {
*timerPtr = (uint32)newTime;
uint32 oldTimeSeconds = oldTime / 1000;
if(oldTimeSeconds <= 11 && newTime / 1000 != oldTimeSeconds) {
// TODO: use an enum here
DMAudio.PlayFrontEndSound(0x93, newTime / 1000);
}
}
}
bool COnscreenTimerEntry::ProcessForDisplay() {
m_bTimerProcessed = false;
m_bCounterProcessed = false;
if(m_nTimerOffset == 0 && m_nCounterOffset == 0) {
return false;
}
if(m_nTimerOffset != 0) {
m_bTimerProcessed = true;
ProcessForDisplayTimer();
}
if(m_nCounterOffset != 0) {
m_bCounterProcessed = true;
ProcessForDisplayCounter();
}
return true;
}
int COnscreenTimerEntry::ProcessForDisplayTimer() {
uint32 time = *(uint32*)&CTheScripts::ScriptSpace[m_nTimerOffset];
return sprintf(m_bTimerBuffer, "%02d:%02d", time / 1000 / 60,
time / 1000 % 60);
}
int COnscreenTimerEntry::ProcessForDisplayCounter() {
uint32 counter = *(uint32*)&CTheScripts::ScriptSpace[m_nCounterOffset];
return sprintf(m_bCounterBuffer, "%d", counter);
}
STARTPATCHES
InjectHook(0x429160, &COnscreenTimerEntry::Process, PATCH_JUMP);
InjectHook(0x429110, &COnscreenTimerEntry::ProcessForDisplay, PATCH_JUMP);
InjectHook(0x429080, &COnscreenTimerEntry::ProcessForDisplayTimer, PATCH_JUMP);
InjectHook(0x4290F0, &COnscreenTimerEntry::ProcessForDisplayCounter, PATCH_JUMP);
InjectHook(0x429220, &COnscreenTimer::Init, PATCH_JUMP);
InjectHook(0x429320, &COnscreenTimer::Process, PATCH_JUMP);
InjectHook(0x4292E0, &COnscreenTimer::ProcessForDisplay, PATCH_JUMP);
InjectHook(0x429450, &COnscreenTimer::ClearCounter, PATCH_JUMP);
InjectHook(0x429410, &COnscreenTimer::ClearClock, PATCH_JUMP);
InjectHook(0x4293B0, &COnscreenTimer::AddCounter, PATCH_JUMP);
InjectHook(0x429350, &COnscreenTimer::AddClock, PATCH_JUMP);
ENDPATCHES

64
src/core/User.h Normal file
View File

@ -0,0 +1,64 @@
#pragma once
class COnscreenTimerEntry
{
public:
uint32 m_nTimerOffset;
uint32 m_nCounterOffset;
char m_aTimerText[10];
char m_aCounterText[10];
uint16 m_nType;
char m_bCounterBuffer[42];
char m_bTimerBuffer[42];
bool m_bTimerProcessed;
bool m_bCounterProcessed;
void Process();
bool ProcessForDisplay();
int ProcessForDisplayTimer();
int ProcessForDisplayCounter();
};
static_assert(sizeof(COnscreenTimerEntry) == 0x74, "COnscreenTimerEntry: error");
class COnscreenTimer
{
public:
COnscreenTimerEntry m_sEntries[NUMONSCREENTIMERENTRIES];
bool m_bProcessed;
bool m_bDisabled;
void Init();
void Process();
void ProcessForDisplay();
void ClearCounter(uint32 offset);
void ClearClock(uint32 offset);
void AddCounter(uint32 offset, uint16 type, char* text);
void AddClock(uint32 offset, char* text);
};
static_assert(sizeof(COnscreenTimer) == 0x78, "COnscreenTimer: error");
class CPlaceName
{
};
class CCurrentVehicle
{
};
class CPager
{
};
class CUserDisplay
{
public:
static CPlaceName &PlaceName;
static COnscreenTimer &OnscnTimer;
static CPager &Pager;
static CCurrentVehicle &CurrentVehicle;
};

129
src/core/Wanted.cpp Normal file
View File

@ -0,0 +1,129 @@
#include "common.h"
#include "patcher.h"
#include "Wanted.h"
int32 &CWanted::MaximumWantedLevel = *(int32*)0x5F7714;
bool CWanted::AreSwatRequired()
{
return m_nWantedLevel >= 4;
}
bool CWanted::AreFbiRequired()
{
return m_nWantedLevel >= 5;
}
bool CWanted::AreArmyRequired()
{
return m_nWantedLevel >= 6;
}
int CWanted::NumOfHelisRequired()
{
if (m_IsIgnoredByCops)
return 0;
// Return value is number of helicopters, no need to name them.
switch (m_nWantedLevel) {
case WANTEDLEVEL_3:
case WANTEDLEVEL_4:
return 1;
case WANTEDLEVEL_5:
case WANTEDLEVEL_6:
return 2;
default:
return 0;
};
}
void CWanted::SetWantedLevel(int32 level)
{
ClearQdCrimes();
switch (level) {
case NOTWANTED:
m_nChaos = 0;
break;
case WANTEDLEVEL_1:
m_nChaos = 60;
break;
case WANTEDLEVEL_2:
m_nChaos = 220;
break;
case WANTEDLEVEL_3:
m_nChaos = 420;
break;
case WANTEDLEVEL_4:
m_nChaos = 820;
break;
case WANTEDLEVEL_5:
m_nChaos = 1620;
break;
case WANTEDLEVEL_6:
m_nChaos = 3220;
break;
default:
if (level > MaximumWantedLevel)
m_nChaos = MaximumWantedLevel;
break;
}
UpdateWantedLevel();
}
void CWanted::ClearQdCrimes()
{
for (int i = 0; i < 16; i++) {
m_sCrimes[i].m_eCrimeType = CRIME_NONE;
};
}
void CWanted::UpdateWantedLevel()
{
int32 CurrWantedLevel = m_nWantedLevel;
if (m_nChaos >= 0 && m_nChaos < 40) {
m_nWantedLevel = NOTWANTED;
m_MaximumLawEnforcerVehicles = 0;
m_MaxCops = 0;
m_RoadblockDensity = 0;
}
else if (m_nChaos >= 40 && m_nChaos < 200) {
m_nWantedLevel = WANTEDLEVEL_1;
m_MaximumLawEnforcerVehicles = 1;
m_MaxCops = 1;
m_RoadblockDensity = 0;
}
else if (m_nChaos >= 200 && m_nChaos < 400) {
m_nWantedLevel = WANTEDLEVEL_2;
m_MaximumLawEnforcerVehicles = 2;
m_MaxCops = 3;
m_RoadblockDensity = 0;
}
else if (m_nChaos >= 400 && m_nChaos < 800) {
m_nWantedLevel = WANTEDLEVEL_3;
m_MaximumLawEnforcerVehicles = 2;
m_MaxCops = 4;
m_RoadblockDensity = 4;
}
else if (m_nChaos >= 800 && m_nChaos < 1600) {
m_nWantedLevel = WANTEDLEVEL_4;
m_MaximumLawEnforcerVehicles = 2;
m_MaxCops = 6;
m_RoadblockDensity = 8;
}
else if (m_nChaos >= 1600 && m_nChaos < 3200) {
m_nWantedLevel = WANTEDLEVEL_5;
m_MaximumLawEnforcerVehicles = 3;
m_MaxCops = 8;
m_RoadblockDensity = 10;
}
else if (m_nChaos >= 3200) {
m_nWantedLevel = WANTEDLEVEL_6;
m_MaximumLawEnforcerVehicles = 3;
m_MaxCops = 10;
m_RoadblockDensity = 12;
}
if (CurrWantedLevel != m_nWantedLevel)
m_nLastWantedLevelChange = CTimer::GetTimeInMilliseconds();
}

49
src/core/Wanted.h Normal file
View File

@ -0,0 +1,49 @@
#pragma once
#include "Entity.h"
#include "math/Vector.h"
#include "CopPed.h"
enum eWantedLevel {
NOTWANTED,
WANTEDLEVEL_1,
WANTEDLEVEL_2,
WANTEDLEVEL_3,
WANTEDLEVEL_4,
WANTEDLEVEL_5,
WANTEDLEVEL_6,
};
class CWanted
{
public:
int32 m_nChaos;
int32 m_nLastUpdateTime;
int32 m_nLastWantedLevelChange;
float m_fCrimeSensitivity;
uint8 m_CurrentCops;
uint8 m_MaxCops;
uint8 m_MaximumLawEnforcerVehicles;
int8 field_19;
int16 m_RoadblockDensity;
uint8 m_IsIgnoredByCops : 1;
uint8 m_IsIgnoredByEveryOne : 1;
uint8 m_IsSwatRequired : 1;
uint8 m_IsFbiRequired : 1;
uint8 m_IdArmyRequired : 1;
int8 field_23;
int32 m_nWantedLevel;
CCrime m_sCrimes[16];
CCopPed *m_pCops[10];
static int32 &MaximumWantedLevel;
public:
bool AreSwatRequired();
bool AreFbiRequired();
bool AreArmyRequired();
int NumOfHelisRequired();
void SetWantedLevel(int32);
void ClearQdCrimes();
void UpdateWantedLevel();
};
static_assert(sizeof(CWanted) == 0x204, "CWanted: error");

718
src/core/World.cpp Normal file
View File

@ -0,0 +1,718 @@
#include "common.h"
#include "patcher.h"
#include "Entity.h"
#include "Ped.h"
#include "PlayerPed.h"
#include "Vehicle.h"
#include "Object.h"
#include "Camera.h"
#include "DMAudio.h"
#include "CarCtrl.h"
#include "Garages.h"
#include "TempColModels.h"
#include "World.h"
CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60;
CPtrList &CWorld::ms_listMovingEntityPtrs = *(CPtrList*)0x8F433C;
CSector (*CWorld::ms_aSectors)[NUMSECTORS_X] = (CSector (*)[NUMSECTORS_Y])0x665608;
uint16 &CWorld::ms_nCurrentScanCode = *(uint16*)0x95CC64;
uint8 &CWorld::PlayerInFocus = *(uint8 *)0x95CD61;
CPlayerInfo *CWorld::Players = (CPlayerInfo *)0x9412F0;
bool &CWorld::bNoMoreCollisionTorque = *(bool*)0x95CDCC;
CEntity *&CWorld::pIgnoreEntity = *(CEntity**)0x8F6494;
bool &CWorld::bIncludeDeadPeds = *(bool*)0x95CD8F;
bool &CWorld::bSecondShift = *(bool*)0x95CD54;
bool &CWorld::bForceProcessControl = *(bool*)0x95CD6C;
bool &CWorld::bProcessCutsceneOnly = *(bool*)0x95CD8B;
void
CWorld::Add(CEntity *ent)
{
if(ent->IsVehicle() || ent->IsPed())
DMAudio.SetEntityStatus(((CPhysical*)ent)->m_audioEntityId, true);
if(ent->bIsBIGBuilding)
ms_bigBuildingsList[ent->m_level].InsertItem(ent);
else
ent->Add();
if(ent->IsBuilding() || ent->IsDummy())
return;
if(!ent->bIsStatic)
((CPhysical*)ent)->AddToMovingList();
}
void
CWorld::Remove(CEntity *ent)
{
if(ent->IsVehicle() || ent->IsPed())
DMAudio.SetEntityStatus(((CPhysical*)ent)->m_audioEntityId, false);
if(ent->bIsBIGBuilding)
ms_bigBuildingsList[ent->m_level].RemoveItem(ent);
else
ent->Remove();
if(ent->IsBuilding() || ent->IsDummy())
return;
if(!ent->bIsStatic)
((CPhysical*)ent)->RemoveFromMovingList();
}
void
CWorld::ClearScanCodes(void)
{
CPtrNode *node;
for(int i = 0; i < NUMSECTORS_Y; i++)
for(int j = 0; j < NUMSECTORS_X; j++){
CSector *s = &ms_aSectors[i][j];
for(node = s->m_lists[ENTITYLIST_BUILDINGS].first; node; node = node->next)
((CEntity*)node->item)->m_scanCode = 0;
for(node = s->m_lists[ENTITYLIST_VEHICLES].first; node; node = node->next)
((CEntity*)node->item)->m_scanCode = 0;
for(node = s->m_lists[ENTITYLIST_PEDS].first; node; node = node->next)
((CEntity*)node->item)->m_scanCode = 0;
for(node = s->m_lists[ENTITYLIST_OBJECTS].first; node; node = node->next)
((CEntity*)node->item)->m_scanCode = 0;
for(node = s->m_lists[ENTITYLIST_DUMMIES].first; node; node = node->next)
((CEntity*)node->item)->m_scanCode = 0;
}
}
bool
CWorld::CameraToIgnoreThisObject(CEntity *ent)
{
if(CGarages::IsModelIndexADoor(ent->GetModelIndex()))
return false;
return ((CObject*)ent)->m_bCameraToAvoidThisObject != 1;
}
bool
CWorld::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)
{
int x, xstart, xend;
int y, ystart, yend;
int y1, y2;
float dist;
AdvanceCurrentScanCode();
entity = nil;
dist = 1.0f;
xstart = GetSectorIndexX(point1.x);
ystart = GetSectorIndexX(point1.y);
xend = GetSectorIndexX(point2.x);
yend = GetSectorIndexX(point2.y);
#define LOSARGS CColLine(point1, point2), point, dist, entity, checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, ignoreSomeObjects
if(xstart == xend && ystart == yend){
// Only one sector
return ProcessLineOfSightSector(*GetSector(xstart, ystart), LOSARGS);
}else if(xstart == xend){
// Only step in y
if(ystart < yend)
for(y = ystart; y <= yend; y++)
ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS);
else
for(y = ystart; y >= yend; y--)
ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS);
return dist < 1.0f;
}else if(ystart == yend){
// Only step in x
if(xstart < xend)
for(x = xstart; x <= xend; x++)
ProcessLineOfSightSector(*GetSector(x, ystart), LOSARGS);
else
for(x = xstart; x >= xend; x--)
ProcessLineOfSightSector(*GetSector(x, ystart), LOSARGS);
return dist < 1.0f;
}else{
if(point1.x < point2.x){
// Step from left to right
float m = (point2.y - point1.y) / (point2.x - point1.x);
y1 = ystart;
y2 = GetSectorIndexY((GetWorldX(xstart+1) - point1.x)*m + point1.y);
if(y1 < y2)
for(y = y1; y <= y2; y++)
ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS);
else
for(y = y1; y >= y2; y--)
ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS);
for(x = xstart+1; x < xend; x++){
y1 = y2;
y2 = GetSectorIndexY((GetWorldX(x+1) - point1.x)*m + point1.y);
if(y1 < y2)
for(y = y1; y <= y2; y++)
ProcessLineOfSightSector(*GetSector(x, y), LOSARGS);
else
for(y = y1; y >= y2; y--)
ProcessLineOfSightSector(*GetSector(x, y), LOSARGS);
}
y1 = y2;
y2 = yend;
if(y1 < y2)
for(y = y1; y <= y2; y++)
ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS);
else
for(y = y1; y >= y2; y--)
ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS);
}else{
// Step from right to left
float m = (point2.y - point1.y) / (point2.x - point1.x);
y1 = ystart;
y2 = GetSectorIndexY((GetWorldX(xstart) - point1.x)*m + point1.y);
if(y1 < y2)
for(y = y1; y <= y2; y++)
ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS);
else
for(y = y1; y >= y2; y--)
ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS);
for(x = xstart-1; x > xend; x--){
y1 = y2;
y2 = GetSectorIndexY((GetWorldX(x) - point1.x)*m + point1.y);
if(y1 < y2)
for(y = y1; y <= y2; y++)
ProcessLineOfSightSector(*GetSector(x, y), LOSARGS);
else
for(y = y1; y >= y2; y--)
ProcessLineOfSightSector(*GetSector(x, y), LOSARGS);
}
y1 = y2;
y2 = yend;
if(y1 < y2)
for(y = y1; y <= y2; y++)
ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS);
else
for(y = y1; y >= y2; y--)
ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS);
}
return dist < 1.0f;
}
#undef LOSARGS
}
bool
CWorld::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)
{
float mindist = dist;
bool deadPeds = !!bIncludeDeadPeds;
bIncludeDeadPeds = false;
if(checkBuildings){
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_BUILDINGS], line, point, mindist, entity, ignoreSeeThrough);
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_BUILDINGS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough);
}
if(checkVehicles){
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_VEHICLES], line, point, mindist, entity, ignoreSeeThrough);
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_VEHICLES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough);
}
if(checkPeds){
if(deadPeds)
bIncludeDeadPeds = true;
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_PEDS], line, point, mindist, entity, ignoreSeeThrough);
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_PEDS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough);
bIncludeDeadPeds = false;
}
if(checkObjects){
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_OBJECTS], line, point, mindist, entity, ignoreSeeThrough, ignoreSomeObjects);
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_OBJECTS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, ignoreSomeObjects);
}
if(checkDummies){
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_DUMMIES], line, point, mindist, entity, ignoreSeeThrough);
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_DUMMIES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough);
}
bIncludeDeadPeds = deadPeds;
if(mindist < dist){
dist = mindist;
return true;
}else
return false;
}
bool
CWorld::ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, bool ignoreSomeObjects)
{
bool deadPeds = false;
float mindist = dist;
CPtrNode *node;
CEntity *e;
CColModel *colmodel;
if(list.first && bIncludeDeadPeds && ((CEntity*)list.first->item)->IsPed())
deadPeds = true;
for(node = list.first; node; node = node->next){
e = (CEntity*)node->item;
if(e->m_scanCode != GetCurrentScanCode() &&
e != pIgnoreEntity &&
(e->bUsesCollision || deadPeds) &&
!(ignoreSomeObjects && CameraToIgnoreThisObject(e))){
colmodel = nil;
e->m_scanCode = GetCurrentScanCode();
if(e->IsPed()){
if(e->bUsesCollision ||
deadPeds && ((CPed*)e)->m_nPedState == PED_DEAD){
if(((CPed*)e)->UseGroundColModel())
colmodel = &CTempColModels::ms_colModelPedGroundHit;
else
colmodel = ((CPedModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex()))->GetHitColModel();
}else
colmodel = nil;
}else if(e->bUsesCollision)
colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel();
if(colmodel &&
CCollision::ProcessLineOfSight(line, e->GetMatrix(), *colmodel, point, dist, ignoreSeeThrough))
entity = e;
}
}
if(mindist < dist){
dist = mindist;
return true;
}else
return false;
}
bool
CWorld::ProcessVerticalLine(const CVector &point1, float z2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly)
{
AdvanceCurrentScanCode();
CVector point2(point1.x, point1.y, z2);
return CWorld::ProcessVerticalLineSector(*GetSector(GetSectorIndexX(point1.x), GetSectorIndexX(point1.y)),
CColLine(point1, point2), point, entity,
checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, poly);
}
bool
CWorld::ProcessVerticalLineSector(CSector &sector, const CColLine &line, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly)
{
float mindist = 1.0f;
if(checkBuildings){
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_BUILDINGS], line, point, mindist, entity, ignoreSeeThrough, poly);
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_BUILDINGS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly);
}
if(checkVehicles){
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_VEHICLES], line, point, mindist, entity, ignoreSeeThrough, poly);
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_VEHICLES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly);
}
if(checkPeds){
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_PEDS], line, point, mindist, entity, ignoreSeeThrough, poly);
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_PEDS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly);
}
if(checkObjects){
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_OBJECTS], line, point, mindist, entity, ignoreSeeThrough, poly);
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_OBJECTS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly);
}
if(checkDummies){
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_DUMMIES], line, point, mindist, entity, ignoreSeeThrough, poly);
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_DUMMIES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly);
}
return mindist < 1.0f;
}
bool
CWorld::ProcessVerticalLineSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, CStoredCollPoly *poly)
{
float mindist = dist;
CPtrNode *node;
CEntity *e;
CColModel *colmodel;
for(node = list.first; node; node = node->next){
e = (CEntity*)node->item;
if(e->m_scanCode != GetCurrentScanCode() &&
e->bUsesCollision){
e->m_scanCode = GetCurrentScanCode();
colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel();
if(CCollision::ProcessVerticalLine(line, e->GetMatrix(), *colmodel, point, dist, ignoreSeeThrough, poly))
entity = e;
}
}
if(mindist < dist){
dist = mindist;
return true;
}else
return false;
}
bool
CWorld::GetIsLineOfSightClear(const CVector &point1, const CVector &point2, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects)
{
int x, xstart, xend;
int y, ystart, yend;
int y1, y2;
AdvanceCurrentScanCode();
xstart = GetSectorIndexX(point1.x);
ystart = GetSectorIndexX(point1.y);
xend = GetSectorIndexX(point2.x);
yend = GetSectorIndexX(point2.y);
#define LOSARGS CColLine(point1, point2), checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, ignoreSomeObjects
if(xstart == xend && ystart == yend){
// Only one sector
return GetIsLineOfSightSectorClear(*GetSector(xstart, ystart), LOSARGS);
}else if(xstart == xend){
// Only step in y
if(ystart < yend){
for(y = ystart; y <= yend; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS))
return false;
}else{
for(y = ystart; y >= yend; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS))
return false;
}
}else if(ystart == yend){
// Only step in x
if(xstart < xend){
for(x = xstart; x <= xend; x++)
if(!GetIsLineOfSightSectorClear(*GetSector(x, ystart), LOSARGS))
return false;
}else{
for(x = xstart; x >= xend; x--)
if(!GetIsLineOfSightSectorClear(*GetSector(x, ystart), LOSARGS))
return false;
}
}else{
if(point1.x < point2.x){
// Step from left to right
float m = (point2.y - point1.y) / (point2.x - point1.x);
y1 = ystart;
y2 = GetSectorIndexY((GetWorldX(xstart+1) - point1.x)*m + point1.y);
if(y1 < y2){
for(y = y1; y <= y2; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS))
return false;
}else{
for(y = y1; y >= y2; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS))
return false;
}
for(x = xstart+1; x < xend; x++){
y1 = y2;
y2 = GetSectorIndexY((GetWorldX(x+1) - point1.x)*m + point1.y);
if(y1 < y2){
for(y = y1; y <= y2; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS))
return false;
}else{
for(y = y1; y >= y2; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS))
return false;
}
}
y1 = y2;
y2 = yend;
if(y1 < y2){
for(y = y1; y <= y2; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS))
return false;
}else{
for(y = y1; y >= y2; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS))
return false;
}
}else{
// Step from right to left
float m = (point2.y - point1.y) / (point2.x - point1.x);
y1 = ystart;
y2 = GetSectorIndexY((GetWorldX(xstart) - point1.x)*m + point1.y);
if(y1 < y2){
for(y = y1; y <= y2; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS))
return false;
}else{
for(y = y1; y >= y2; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS))
return false;
}
for(x = xstart-1; x > xend; x--){
y1 = y2;
y2 = GetSectorIndexY((GetWorldX(x) - point1.x)*m + point1.y);
if(y1 < y2){
for(y = y1; y <= y2; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS))
return false;
}else{
for(y = y1; y >= y2; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS))
return false;
}
}
y1 = y2;
y2 = yend;
if(y1 < y2){
for(y = y1; y <= y2; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS))
return false;
}else{
for(y = y1; y >= y2; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS))
return false;
}
}
}
return true;
#undef LOSARGS
}
bool
CWorld::GetIsLineOfSightSectorClear(CSector &sector, const CColLine &line, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects)
{
if(checkBuildings){
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_BUILDINGS], line, ignoreSeeThrough))
return false;
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_BUILDINGS_OVERLAP], line, ignoreSeeThrough))
return false;
}
if(checkVehicles){
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_VEHICLES], line, ignoreSeeThrough))
return false;
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_VEHICLES_OVERLAP], line, ignoreSeeThrough))
return false;
}
if(checkPeds){
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_PEDS], line, ignoreSeeThrough))
return false;
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_PEDS_OVERLAP], line, ignoreSeeThrough))
return false;
}
if(checkObjects){
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_OBJECTS], line, ignoreSeeThrough, ignoreSomeObjects))
return false;
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_OBJECTS_OVERLAP], line, ignoreSeeThrough, ignoreSomeObjects))
return false;
}
if(checkDummies){
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_DUMMIES], line, ignoreSeeThrough))
return false;
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_DUMMIES_OVERLAP], line, ignoreSeeThrough))
return false;
}
return true;
}
bool
CWorld::GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bool ignoreSeeThrough, bool ignoreSomeObjects)
{
CPtrNode *node;
CEntity *e;
CColModel *colmodel;
for(node = list.first; node; node = node->next){
e = (CEntity*)node->item;
if(e->m_scanCode != GetCurrentScanCode() &&
e->bUsesCollision){
e->m_scanCode = GetCurrentScanCode();
if(e != pIgnoreEntity &&
!(ignoreSomeObjects && CameraToIgnoreThisObject(e))){
colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel();
if(CCollision::TestLineOfSight(line, e->GetMatrix(), *colmodel, ignoreSeeThrough))
return false;
}
}
}
return true;
}
float
CWorld::FindGroundZForCoord(float x, float y)
{
CColPoint point;
CEntity *ent;
if(ProcessVerticalLine(CVector(x, y, 1000.0f), -1000.0f, point, ent, true, false, false, false, true, false, nil))
return point.point.z;
else
return 20.0f;
}
float
CWorld::FindGroundZFor3DCoord(float x, float y, float z, bool *found)
{
CColPoint point;
CEntity *ent;
if(ProcessVerticalLine(CVector(x, y, z), -1000.0f, point, ent, true, false, false, false, false, false, nil)){
if(found)
*found = true;
return point.point.z;
}else{
if(found)
*found = false;
return 0.0f;
}
}
float
CWorld::FindRoofZFor3DCoord(float x, float y, float z, bool *found)
{
CColPoint point;
CEntity *ent;
if(ProcessVerticalLine(CVector(x, y, z), 1000.0f, point, ent, true, false, false, false, true, false, nil)){
if(found)
*found = true;
return point.point.z;
}else{
if(found == nil)
printf("THERE IS NO MAP BELOW THE FOLLOWING COORS:%f %f %f. (FindGroundZFor3DCoord)\n", x, y, z);
if(found)
*found = false;
return 20.0f;
}
}
CPlayerPed*
FindPlayerPed(void)
{
return CWorld::Players[CWorld::PlayerInFocus].m_pPed;
}
CVehicle*
FindPlayerVehicle(void)
{
CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
if(ped->bInVehicle && ped->m_pMyVehicle)
return ped->m_pMyVehicle;
else
return nil;
}
CVehicle*
FindPlayerTrain(void)
{
if(FindPlayerVehicle() && FindPlayerVehicle()->IsTrain())
return FindPlayerVehicle();
else
return nil;
}
CEntity*
FindPlayerEntity(void)
{
CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
if(ped->bInVehicle && ped->m_pMyVehicle)
return ped->m_pMyVehicle;
else
return ped;
}
CVector
FindPlayerCoors(void)
{
CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
if(ped->bInVehicle && ped->m_pMyVehicle)
return ped->m_pMyVehicle->GetPosition();
else
return ped->GetPosition();
}
CVector&
FindPlayerSpeed(void)
{
CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
if(ped->bInVehicle && ped->m_pMyVehicle)
return ped->m_pMyVehicle->m_vecMoveSpeed;
else
return ped->m_vecMoveSpeed;
}
CVector&
FindPlayerCentreOfWorld(int32 player)
{
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();
}
CVector&
FindPlayerCentreOfWorld_NoSniperShift(void)
{
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 CWorld::Players[CWorld::PlayerInFocus].m_pPed->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 CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetForward().Heading();
}
STARTPATCHES
InjectHook(0x4AE930, CWorld::Add, PATCH_JUMP);
InjectHook(0x4AE9D0, CWorld::Remove, PATCH_JUMP);
InjectHook(0x4B1F60, CWorld::ClearScanCodes, PATCH_JUMP);
InjectHook(0x4AF970, CWorld::ProcessLineOfSight, PATCH_JUMP);
InjectHook(0x4B0A80, CWorld::ProcessLineOfSightSector, PATCH_JUMP);
InjectHook(0x4B0C70, CWorld::ProcessLineOfSightSectorList, PATCH_JUMP);
InjectHook(0x4B0DE0, CWorld::ProcessVerticalLine, PATCH_JUMP);
InjectHook(0x4B0EF0, CWorld::ProcessVerticalLineSector, PATCH_JUMP);
InjectHook(0x4B1090, CWorld::ProcessVerticalLineSectorList, PATCH_JUMP);
InjectHook(0x4AEAA0, CWorld::GetIsLineOfSightClear, PATCH_JUMP);
InjectHook(0x4B2000, CWorld::GetIsLineOfSightSectorClear, PATCH_JUMP);
InjectHook(0x4B2160, CWorld::GetIsLineOfSightSectorListClear, PATCH_JUMP);
InjectHook(0x4B3A80, CWorld::FindGroundZForCoord, PATCH_JUMP);
InjectHook(0x4B3AE0, CWorld::FindGroundZFor3DCoord, PATCH_JUMP);
InjectHook(0x4B3B50, CWorld::FindRoofZFor3DCoord, PATCH_JUMP);
ENDPATCHES

119
src/core/World.h Normal file
View File

@ -0,0 +1,119 @@
#pragma once
#include "Game.h"
#include "Lists.h"
#include "PlayerInfo.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)
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];
};
static_assert(sizeof(CSector) == 0x28, "CSector: error");
class CEntity;
struct CColPoint;
struct CColLine;
struct CStoredCollPoly;
class CWorld
{
static CPtrList *ms_bigBuildingsList; // [4];
static CPtrList &ms_listMovingEntityPtrs;
static CSector (*ms_aSectors)[NUMSECTORS_X]; // [NUMSECTORS_Y][NUMSECTORS_X];
static uint16 &ms_nCurrentScanCode;
public:
static uint8 &PlayerInFocus;
static CPlayerInfo *Players;
static CEntity *&pIgnoreEntity;
static bool &bIncludeDeadPeds;
static bool &bNoMoreCollisionTorque;
static bool &bSecondShift;
static bool &bForceProcessControl;
static bool &bProcessCutsceneOnly;
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 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 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 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; }
};
class CPlayerPed;
class CVehicle;
CPlayerPed *FindPlayerPed(void);
CVehicle *FindPlayerVehicle(void);
CVehicle *FindPlayerTrain(void);
CEntity *FindPlayerEntity(void);
CVector FindPlayerCoors(void);
CVector &FindPlayerSpeed(void);
CVector &FindPlayerCentreOfWorld(int32 player);
CVector &FindPlayerCentreOfWorld_NoSniperShift(void);
float FindPlayerHeading(void);

370
src/core/ZoneCull.cpp Normal file
View File

@ -0,0 +1,370 @@
#include "common.h"
#include "patcher.h"
#include "Building.h"
#include "Treadable.h"
#include "Train.h"
#include "Pools.h"
#include "Timer.h"
#include "Camera.h"
#include "World.h"
#include "FileMgr.h"
#include "ZoneCull.h"
int32 &CCullZones::NumCullZones = *(int*)0x8F2564;
CCullZone *CCullZones::aZones = (CCullZone*)0x864750; // [NUMCULLZONES];
int32 &CCullZones::NumAttributeZones = *(int*)0x8E29D0;
CAttributeZone *CCullZones::aAttributeZones = (CAttributeZone*)0x709C60; // [NUMATTRIBZONES];
uint16 *CCullZones::aIndices = (uint16*)0x847330; // [NUMZONEINDICES];
int16 *CCullZones::aPointersToBigBuildingsForBuildings = (int16*)0x86C9D0; // [NUMBUILDINGS];
int16 *CCullZones::aPointersToBigBuildingsForTreadables = (int16*)0x8F1B8C; // [NUMTREADABLES];
int32 &CCullZones::CurrentWantedLevelDrop_Player = *(int32*)0x880DA8;
int32 &CCullZones::CurrentFlags_Camera = *(int32*)0x940718;
int32 &CCullZones::CurrentFlags_Player = *(int32*)0x9415F0;
int32 &CCullZones::OldCullZone = *(int32*)0x8E2C90;
int32 &CCullZones::EntityIndicesUsed = *(int32*)0x8F2508;
bool &CCullZones::bCurrentSubwayIsInvisible = *(bool*)0x95CDA5;
bool &CCullZones::bCullZonesDisabled = *(bool*)0x95CD4A;
void
CCullZones::Init(void)
{
int i;
NumAttributeZones = 0;
NumCullZones = 0;
CurrentWantedLevelDrop_Player = 0;
CurrentFlags_Camera = 0;
CurrentFlags_Player = 0;
OldCullZone = -1;
EntityIndicesUsed = 0;
bCurrentSubwayIsInvisible = false;
for(i = 0; i < NUMBUILDINGS; i++)
aPointersToBigBuildingsForBuildings[i] = -1;
for(i = 0; i < NUMTREADABLES; i++)
aPointersToBigBuildingsForTreadables[i] = -1;
}
void
CCullZones::ResolveVisibilities(void)
{
int fd;
CFileMgr::SetDir("");
fd = CFileMgr::OpenFile("DATA\\cullzone.dat", "rb");
if(fd > 0){
CFileMgr::Read(fd, (char*)&NumCullZones, 4);
CFileMgr::Read(fd, (char*)aZones, NUMCULLZONES*sizeof(CCullZone));
CFileMgr::Read(fd, (char*)&NumAttributeZones, 4);
CFileMgr::Read(fd, (char*)aAttributeZones, NUMATTRIBZONES*sizeof(CAttributeZone));
CFileMgr::Read(fd, (char*)aIndices, NUMZONEINDICES*2);
CFileMgr::Read(fd, (char*)aPointersToBigBuildingsForBuildings, NUMBUILDINGS*2);
CFileMgr::Read(fd, (char*)aPointersToBigBuildingsForTreadables, NUMTREADABLES*2);
CFileMgr::CloseFile(fd);
}else{
// TODO: implement code from mobile to generate data here
}
}
void
CCullZones::Update(void)
{
bool invisible;
if(bCullZonesDisabled)
return;
switch(CTimer::GetFrameCounter() & 7){
case 0:
case 4:
/* Update Cull zone */
ForceCullZoneCoors(TheCamera.GetGameCamPosition());
break;
case 2:
/* Update camera attributes */
CurrentFlags_Camera = FindAttributesForCoors(TheCamera.GetGameCamPosition(), nil);
invisible = (CurrentFlags_Camera & ATTRZONE_SUBWAYVISIBLE) == 0;
if(invisible != bCurrentSubwayIsInvisible){
MarkSubwayAsInvisible(!invisible);
bCurrentSubwayIsInvisible = invisible;
}
break;
case 6:
/* Update player attributes */
CurrentFlags_Player = FindAttributesForCoors(FindPlayerCoors(),
&CurrentWantedLevelDrop_Player);
break;
}
}
void
CCullZones::ForceCullZoneCoors(CVector coors)
{
int32 z;
z = FindCullZoneForCoors(coors);
if(z != OldCullZone){
if(OldCullZone >= 0)
aZones[OldCullZone].DoStuffLeavingZone();
if(z >= 0)
aZones[z].DoStuffEnteringZone();
OldCullZone = z;
}
}
int32
CCullZones::FindCullZoneForCoors(CVector coors)
{
int i;
for(i = 0; i < NumCullZones; i++)
if(coors.x >= aZones[i].minx && coors.x <= aZones[i].maxx &&
coors.y >= aZones[i].miny && coors.y <= aZones[i].maxy &&
coors.z >= aZones[i].minz && coors.z <= aZones[i].maxz)
return i;
return -1;
}
int32
CCullZones::FindAttributesForCoors(CVector coors, int32 *wantedLevel)
{
int i;
int32 attribs;
attribs = 0;
for(i = 0; i < NumAttributeZones; i++)
if(coors.x >= aAttributeZones[i].minx && coors.x <= aAttributeZones[i].maxx &&
coors.y >= aAttributeZones[i].miny && coors.y <= aAttributeZones[i].maxy &&
coors.z >= aAttributeZones[i].minz && coors.z <= aAttributeZones[i].maxz){
attribs |= aAttributeZones[i].attributes;
if(wantedLevel && *wantedLevel <= aAttributeZones[i].wantedLevel)
*wantedLevel = aAttributeZones[i].wantedLevel;
}
return attribs;
}
CAttributeZone*
CCullZones::FindZoneWithStairsAttributeForPlayer(void)
{
int i;
CVector coors;
coors = FindPlayerCoors();
for(i = 0; i < NumAttributeZones; i++)
if(aAttributeZones[i].attributes & ATTRZONE_STAIRS &&
coors.x >= aAttributeZones[i].minx && coors.x <= aAttributeZones[i].maxx &&
coors.y >= aAttributeZones[i].miny && coors.y <= aAttributeZones[i].maxy &&
coors.z >= aAttributeZones[i].minz && coors.z <= aAttributeZones[i].maxz)
return &aAttributeZones[i];
return nil;
}
void
CCullZones::MarkSubwayAsInvisible(bool visible)
{
int i, n;
CEntity *e;
CVehicle *v;
n = CPools::GetBuildingPool()->GetSize();
for(i = 0; i < n; i++){
e = CPools::GetBuildingPool()->GetSlot(i);
if(e && e->bIsSubway)
e->bIsVisible = visible;
}
n = CPools::GetTreadablePool()->GetSize();
for(i = 0; i < n; i++){
e = CPools::GetTreadablePool()->GetSlot(i);
if(e && e->bIsSubway)
e->bIsVisible = visible;
}
n = CPools::GetVehiclePool()->GetSize();
for(i = 0; i < n; i++){
v = CPools::GetVehiclePool()->GetSlot(i);
if(v && v->IsTrain() && ((CTrain*)v)->m_trackId != 0)
v->bIsVisible = visible;
}
}
void
CCullZones::AddCullZone(CVector const &position,
float minx, float maxx,
float miny, float maxy,
float minz, float maxz,
uint16 flag, int16 wantedLevel)
{
CCullZone *cull;
CAttributeZone *attrib;
CVector v;
if((flag & ATTRZONE_NOTCULLZONE) == 0){
cull = &aZones[NumCullZones++];
v = position;
// WTF is this?
if((v-CVector(1032.14f, -624.255f, 24.93f)).Magnitude() < 1.0f)
v = CVector(1061.7f, -613.0f, 19.0f);
if((v-CVector(1029.48f, -495.757f, 21.98f)).Magnitude() < 1.0f)
v = CVector(1061.4f, -506.0f, 18.5f);
cull->position.x = clamp(v.x, minx, maxx);
cull->position.y = clamp(v.y, miny, maxy);
cull->position.z = clamp(v.z, minz, maxz);
cull->minx = minx;
cull->maxx = maxx;
cull->miny = miny;
cull->maxy = maxy;
cull->minz = minz;
cull->maxz = maxz;
cull->unk2 = 0;
cull->unk3 = 0;
cull->unk4 = 0;
cull->m_indexStart = 0;
}
if(flag & ~ATTRZONE_NOTCULLZONE){
attrib = &aAttributeZones[NumAttributeZones++];
attrib->minx = minx;
attrib->maxx = maxx;
attrib->miny = miny;
attrib->maxy = maxy;
attrib->minz = minz;
attrib->maxz = maxz;
attrib->attributes = flag;
attrib->wantedLevel = wantedLevel;
}
}
void
CCullZone::DoStuffLeavingZone(void)
{
int i;
for(i = 0; i < m_numBuildings; i++)
DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[m_indexStart + i]);
for(; i < m_numBuildings + m_numTreadablesPlus10m + m_numTreadables ; i++)
DoStuffLeavingZone_OneTreadableBoth(CCullZones::aIndices[m_indexStart + i]);
}
void
CCullZone::DoStuffLeavingZone_OneBuilding(uint16 i)
{
int16 bb;
int j;
if(i < 6000){
CPools::GetBuildingPool()->GetSlot(i)->bZoneCulled = false;
bb = CCullZones::aPointersToBigBuildingsForBuildings[i];
if(bb != -1)
CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = false;
}else{
i -= 6000;
for(j = 0; j < 3; j++)
DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]);
}
}
void
CCullZone::DoStuffLeavingZone_OneTreadableBoth(uint16 i)
{
int16 bb;
int j;
if(i < 6000){
CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = false;
CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled2 = false;
bb = CCullZones::aPointersToBigBuildingsForTreadables[i];
if(bb != -1)
CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = false;
}else{
i -= 6000;
for(j = 0; j < 3; j++)
DoStuffLeavingZone_OneTreadableBoth(CCullZones::aIndices[i+j]);
}
}
void
CCullZone::DoStuffEnteringZone(void)
{
int i;
for(i = 0; i < m_numBuildings; i++)
DoStuffEnteringZone_OneBuilding(CCullZones::aIndices[m_indexStart + i]);
for(; i < m_numBuildings + m_numTreadablesPlus10m; i++)
DoStuffEnteringZone_OneTreadablePlus10m(CCullZones::aIndices[m_indexStart + i]);
for(; i < m_numBuildings + m_numTreadablesPlus10m + m_numTreadables; i++)
DoStuffEnteringZone_OneTreadable(CCullZones::aIndices[m_indexStart + i]);
}
void
CCullZone::DoStuffEnteringZone_OneBuilding(uint16 i)
{
int16 bb;
int j;
if(i < 6000){
CPools::GetBuildingPool()->GetSlot(i)->bZoneCulled = true;
bb = CCullZones::aPointersToBigBuildingsForBuildings[i];
if(bb != -1)
CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true;
}else{
i -= 6000;
for(j = 0; j < 3; j++)
DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]);
}
}
void
CCullZone::DoStuffEnteringZone_OneTreadablePlus10m(uint16 i)
{
int16 bb;
int j;
if(i < 6000){
CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = true;;
CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled2 = true;;
bb = CCullZones::aPointersToBigBuildingsForTreadables[i];
if(bb != -1)
CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true;
}else{
i -= 6000;
for(j = 0; j < 3; j++)
DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]);
}
}
void
CCullZone::DoStuffEnteringZone_OneTreadable(uint16 i)
{
int16 bb;
int j;
if(i < 6000){
CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = true;;
bb = CCullZones::aPointersToBigBuildingsForTreadables[i];
if(bb != -1)
CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true;
}else{
i -= 6000;
for(j = 0; j < 3; j++)
DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]);
}
}
STARTPATCHES
InjectHook(0x524BC0, &CCullZones::Init, PATCH_JUMP);
InjectHook(0x524EC0, &CCullZones::ResolveVisibilities, PATCH_JUMP);
InjectHook(0x524F80, &CCullZones::Update, PATCH_JUMP);
InjectHook(0x525370, &CCullZones::AddCullZone, PATCH_JUMP);
InjectHook(0x5250D0, &CCullZones::ForceCullZoneCoors, PATCH_JUMP);
InjectHook(0x525130, &CCullZones::FindCullZoneForCoors, PATCH_JUMP);
InjectHook(0x5251C0, &CCullZones::FindAttributesForCoors, PATCH_JUMP);
InjectHook(0x525290, &CCullZones::FindZoneWithStairsAttributeForPlayer, PATCH_JUMP);
InjectHook(0x525610, &CCullZone::DoStuffLeavingZone, PATCH_JUMP);
InjectHook(0x525810, &CCullZone::DoStuffEnteringZone, PATCH_JUMP);
ENDPATCHES

94
src/core/ZoneCull.h Normal file
View File

@ -0,0 +1,94 @@
class CCullZone
{
public:
CVector position;
float minx;
float maxx;
float miny;
float maxy;
float minz;
float maxz;
// TODO: figure these out:
int32 m_indexStart;
int16 unk2;
int16 unk3;
int16 unk4;
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);
};
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; }
};

874
src/core/Zones.cpp Normal file
View File

@ -0,0 +1,874 @@
#include "common.h"
#include "patcher.h"
#include "Zones.h"
#include "Clock.h"
#include "Text.h"
#include "World.h"
eLevelName &CTheZones::m_CurrLevel = *(eLevelName*)0x8F2BC8;
CZone *&CTheZones::m_pPlayersZone = *(CZone**)0x8F254C;
int16 &CTheZones::FindIndex = *(int16*)0x95CC40;
uint16 &CTheZones::NumberOfAudioZones = *(uint16*)0x95CC84;
int16 *CTheZones::AudioZoneArray = (int16*)0x713BC0;
uint16 &CTheZones::TotalNumberOfMapZones = *(uint16*)0x95CC74;
uint16 &CTheZones::TotalNumberOfZones = *(uint16*)0x95CC36;
CZone *CTheZones::ZoneArray = (CZone*)0x86BEE0;
CZone *CTheZones::MapZoneArray = (CZone*)0x663EC0;
uint16 &CTheZones::TotalNumberOfZoneInfos = *(uint16*)0x95CC3C;
CZoneInfo *CTheZones::ZoneInfoArray = (CZoneInfo*)0x714400;
#define SWAPF(a, b) { float t; t = a; a = b; b = t; }
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;
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?
for(i = 0; i < NUMZONES; i++)
memset(&ZoneArray[i], 0, sizeof(CZone));
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_NONE;
TotalNumberOfZones = 1;
m_CurrLevel = LEVEL_NONE;
m_pPlayersZone = &ZoneArray[0];
for(i = 0; i < NUMMAPZONES; i++){
memset(&MapZoneArray[i], 0, sizeof(CZone));
MapZoneArray[i].type = ZONE_MAPZONE;
}
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_NONE;
TotalNumberOfMapZones = 1;
}
void
CTheZones::Update(void)
{
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)
{
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 = &ZoneArray[TotalNumberOfZones++];
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;
if(type == ZONE_AUDIO || type == ZONE_TYPE1 || type == ZONE_TYPE2){
zone->zoneinfoDay = TotalNumberOfZoneInfos++;
zone->zoneinfoNight = TotalNumberOfZoneInfos++;
}
}
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(ZoneArray[0].type == ZONE_AUDIO ||
ZoneArray[0].type == ZONE_TYPE1 ||
ZoneArray[0].type == ZONE_TYPE2)
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 == ZONE_AUDIO ||
zone->type == ZONE_TYPE1 ||
zone->type == ZONE_TYPE2)
best = zone;
zone = zone->child;
// otherwise try next zone
}else
zone = zone->next;
return best;
}
int16
CTheZones::FindZoneByLabelAndReturnIndex(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(zone->type == ZONE_AUDIO || zone->type == ZONE_TYPE1 || zone->type == ZONE_TYPE2)
ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].carDensity = cardensity;
}
void
CTheZones::SetPedDensity(uint16 zoneid, uint8 day, uint16 peddensity)
{
CZone *zone;
zone = GetZone(zoneid);
if(zone->type == ZONE_AUDIO || zone->type == ZONE_TYPE1 || zone->type == ZONE_TYPE2)
ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].pedDensity = peddensity;
}
void
CTheZones::SetPedGroup(uint16 zoneid, uint8 day, uint16 pedgroup)
{
CZone *zone;
zone = GetZone(zoneid);
if(zone->type == ZONE_AUDIO || zone->type == ZONE_TYPE1 || zone->type == ZONE_TYPE2)
ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].pedGroup = pedgroup;
}
int16
CTheZones::FindAudioZone(CVector *pos)
{
int i;
for(i = 0; i < NumberOfAudioZones; i++)
if(PointLiesWithinZone(*pos, GetZone(AudioZoneArray[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_NONE;
}
void
CTheZones::AddZoneToAudioZoneArray(CZone *zone)
{
int i, z;
if(zone->type != ZONE_AUDIO)
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;
}
}
}
void
CTheZones::SaveAllZones(uint8 *buffer, uint32 *length)
{
int i;
*length = 8 + 12 +
NUMZONES*56 + 2*NUMZONES*58 + 4 +
NUMMAPZONES*56 + NUMAUDIOZONES*2 + 4;
buffer[0] = 'Z';
buffer[1] = 'N';
buffer[2] = 'S';
buffer[3] = '\0';
*(uint32*)(buffer+4) = *length - 8;
buffer += 8;
*(int32*)(buffer) = GetIndexForZonePointer(m_pPlayersZone);
*(int32*)(buffer+4) = m_CurrLevel;
*(int16*)(buffer+8) = FindIndex;
*(int16*)(buffer+10) = 0;
buffer += 12;
for(i = 0; i < NUMZONES; i++){
memcpy(buffer, ZoneArray[i].name, 8);
*(float*)(buffer+8) = ZoneArray[i].minx;
*(float*)(buffer+12) = ZoneArray[i].miny;
*(float*)(buffer+16) = ZoneArray[i].minz;
*(float*)(buffer+20) = ZoneArray[i].maxx;
*(float*)(buffer+24) = ZoneArray[i].maxy;
*(float*)(buffer+28) = ZoneArray[i].maxz;
*(int32*)(buffer+32) = ZoneArray[i].type;
*(int32*)(buffer+36) = ZoneArray[i].level;
*(int16*)(buffer+40) = ZoneArray[i].zoneinfoDay;
*(int16*)(buffer+42) = ZoneArray[i].zoneinfoNight;
*(int32*)(buffer+44) = GetIndexForZonePointer(ZoneArray[i].child);
*(int32*)(buffer+48) = GetIndexForZonePointer(ZoneArray[i].parent);
*(int32*)(buffer+52) = GetIndexForZonePointer(ZoneArray[i].next);
buffer += 56;
}
for(i = 0; i < 2*NUMZONES; i++){
*(int16*)(buffer) = ZoneInfoArray[i].carDensity;
*(int16*)(buffer+2) = ZoneInfoArray[i].carThreshold[0];
*(int16*)(buffer+4) = ZoneInfoArray[i].carThreshold[1];
*(int16*)(buffer+6) = ZoneInfoArray[i].carThreshold[2];
*(int16*)(buffer+8) = ZoneInfoArray[i].carThreshold[3];
*(int16*)(buffer+10) = ZoneInfoArray[i].carThreshold[4];
*(int16*)(buffer+12) = ZoneInfoArray[i].carThreshold[5];
*(int16*)(buffer+14) = ZoneInfoArray[i].copThreshold;
*(int16*)(buffer+16) = ZoneInfoArray[i].gangThreshold[0];
*(int16*)(buffer+18) = ZoneInfoArray[i].gangThreshold[1];
*(int16*)(buffer+20) = ZoneInfoArray[i].gangThreshold[2];
*(int16*)(buffer+22) = ZoneInfoArray[i].gangThreshold[3];
*(int16*)(buffer+24) = ZoneInfoArray[i].gangThreshold[4];
*(int16*)(buffer+26) = ZoneInfoArray[i].gangThreshold[5];
*(int16*)(buffer+28) = ZoneInfoArray[i].gangThreshold[6];
*(int16*)(buffer+30) = ZoneInfoArray[i].gangThreshold[7];
*(int16*)(buffer+32) = ZoneInfoArray[i].gangThreshold[8];
*(uint16*)(buffer+34) = ZoneInfoArray[i].pedDensity;
*(uint16*)(buffer+36) = ZoneInfoArray[i].copDensity;
*(uint16*)(buffer+38) = ZoneInfoArray[i].gangDensity[0];
*(uint16*)(buffer+40) = ZoneInfoArray[i].gangDensity[1];
*(uint16*)(buffer+42) = ZoneInfoArray[i].gangDensity[2];
*(uint16*)(buffer+44) = ZoneInfoArray[i].gangDensity[3];
*(uint16*)(buffer+46) = ZoneInfoArray[i].gangDensity[4];
*(uint16*)(buffer+48) = ZoneInfoArray[i].gangDensity[5];
*(uint16*)(buffer+50) = ZoneInfoArray[i].gangDensity[6];
*(uint16*)(buffer+52) = ZoneInfoArray[i].gangDensity[7];
*(uint16*)(buffer+54) = ZoneInfoArray[i].gangDensity[8];
*(uint16*)(buffer+56) = ZoneInfoArray[i].pedGroup;
buffer += 58;
}
*(uint16*)(buffer) = TotalNumberOfZones;
*(uint16*)(buffer+2) = TotalNumberOfZoneInfos;
buffer += 4;
for(i = 0; i < NUMMAPZONES; i++){
memcpy(buffer, MapZoneArray[i].name, 8);
*(float*)(buffer+8) = MapZoneArray[i].minx;
*(float*)(buffer+12) = MapZoneArray[i].miny;
*(float*)(buffer+16) = MapZoneArray[i].minz;
*(float*)(buffer+20) = MapZoneArray[i].maxx;
*(float*)(buffer+24) = MapZoneArray[i].maxy;
*(float*)(buffer+28) = MapZoneArray[i].maxz;
*(int32*)(buffer+32) = MapZoneArray[i].type;
*(int32*)(buffer+36) = MapZoneArray[i].level;
*(int16*)(buffer+40) = MapZoneArray[i].zoneinfoDay;
*(int16*)(buffer+42) = MapZoneArray[i].zoneinfoNight;
#ifdef STANDALONE
// BUG: GetIndexForZonePointer uses ZoneArray
// so indices will be unpredictable with different memory layout
assert(0);
#endif
*(int32*)(buffer+44) = GetIndexForZonePointer(MapZoneArray[i].child);
*(int32*)(buffer+48) = GetIndexForZonePointer(MapZoneArray[i].parent);
*(int32*)(buffer+52) = GetIndexForZonePointer(MapZoneArray[i].next);
buffer += 56;
}
for(i = 0; i < NUMAUDIOZONES; i++){
*(int16*)buffer = AudioZoneArray[i];
buffer += 2;
}
*(uint16*)(buffer) = TotalNumberOfMapZones;
*(uint16*)(buffer+2) = NumberOfAudioZones;
}
void
CTheZones::LoadAllZones(uint8 *buffer, uint32 length)
{
int i;
assert(length == 8 + 12 +
NUMZONES*56 + 2*NUMZONES*58 + 4 +
NUMMAPZONES*56 + NUMAUDIOZONES*2 + 4);
assert(buffer[0] == 'Z');
assert(buffer[1] == 'N');
assert(buffer[2] == 'S');
assert(buffer[3] == '\0');
assert(*(uint32*)(buffer+4) == length - 8);
buffer += 8;
m_pPlayersZone = GetPointerForZoneIndex(*(int32*)(buffer));
m_CurrLevel = (eLevelName)*(int32*)(buffer+4);
FindIndex = *(int16*)(buffer+8);
assert(*(int16*)(buffer+10) == 0);
buffer += 12;
for(i = 0; i < NUMZONES; i++){
memcpy(ZoneArray[i].name, buffer, 8);
ZoneArray[i].minx = *(float*)(buffer+8);
ZoneArray[i].miny = *(float*)(buffer+12);
ZoneArray[i].minz = *(float*)(buffer+16);
ZoneArray[i].maxx = *(float*)(buffer+20);
ZoneArray[i].maxy = *(float*)(buffer+24);
ZoneArray[i].maxz = *(float*)(buffer+28);
ZoneArray[i].type = (eZoneType)*(int32*)(buffer+32);
ZoneArray[i].level = (eLevelName)*(int32*)(buffer+36);
ZoneArray[i].zoneinfoDay = *(int16*)(buffer+40);
ZoneArray[i].zoneinfoNight = *(int16*)(buffer+42);
ZoneArray[i].child = GetPointerForZoneIndex(*(int32*)(buffer+44));
ZoneArray[i].parent = GetPointerForZoneIndex(*(int32*)(buffer+48));
ZoneArray[i].next = GetPointerForZoneIndex(*(int32*)(buffer+52));
buffer += 56;
}
for(i = 0; i < 2*NUMZONES; i++){
ZoneInfoArray[i].carDensity = *(int16*)(buffer);
ZoneInfoArray[i].carThreshold[0] = *(int16*)(buffer+2);
ZoneInfoArray[i].carThreshold[1] = *(int16*)(buffer+4);
ZoneInfoArray[i].carThreshold[2] = *(int16*)(buffer+6);
ZoneInfoArray[i].carThreshold[3] = *(int16*)(buffer+8);
ZoneInfoArray[i].carThreshold[4] = *(int16*)(buffer+10);
ZoneInfoArray[i].carThreshold[5] = *(int16*)(buffer+12);
ZoneInfoArray[i].copThreshold = *(int16*)(buffer+14);
ZoneInfoArray[i].gangThreshold[0] = *(int16*)(buffer+16);
ZoneInfoArray[i].gangThreshold[1] = *(int16*)(buffer+18);
ZoneInfoArray[i].gangThreshold[2] = *(int16*)(buffer+20);
ZoneInfoArray[i].gangThreshold[3] = *(int16*)(buffer+22);
ZoneInfoArray[i].gangThreshold[4] = *(int16*)(buffer+24);
ZoneInfoArray[i].gangThreshold[5] = *(int16*)(buffer+26);
ZoneInfoArray[i].gangThreshold[6] = *(int16*)(buffer+28);
ZoneInfoArray[i].gangThreshold[7] = *(int16*)(buffer+30);
ZoneInfoArray[i].gangThreshold[8] = *(int16*)(buffer+32);
ZoneInfoArray[i].pedDensity = *(uint16*)(buffer+34);
ZoneInfoArray[i].copDensity = *(uint16*)(buffer+36);
ZoneInfoArray[i].gangDensity[0] = *(uint16*)(buffer+38);
ZoneInfoArray[i].gangDensity[1] = *(uint16*)(buffer+40);
ZoneInfoArray[i].gangDensity[2] = *(uint16*)(buffer+42);
ZoneInfoArray[i].gangDensity[3] = *(uint16*)(buffer+44);
ZoneInfoArray[i].gangDensity[4] = *(uint16*)(buffer+46);
ZoneInfoArray[i].gangDensity[5] = *(uint16*)(buffer+48);
ZoneInfoArray[i].gangDensity[6] = *(uint16*)(buffer+50);
ZoneInfoArray[i].gangDensity[7] = *(uint16*)(buffer+52);
ZoneInfoArray[i].gangDensity[8] = *(uint16*)(buffer+54);
ZoneInfoArray[i].pedGroup = *(uint16*)(buffer+56);
buffer += 58;
}
TotalNumberOfZones = *(uint16*)(buffer);
TotalNumberOfZoneInfos = *(uint16*)(buffer+2);
buffer += 4;
for(i = 0; i < NUMMAPZONES; i++){
memcpy(MapZoneArray[i].name, buffer, 8);
MapZoneArray[i].minx = *(float*)(buffer+8);
MapZoneArray[i].miny = *(float*)(buffer+12);
MapZoneArray[i].minz = *(float*)(buffer+16);
MapZoneArray[i].maxx = *(float*)(buffer+20);
MapZoneArray[i].maxy = *(float*)(buffer+24);
MapZoneArray[i].maxz = *(float*)(buffer+28);
MapZoneArray[i].type = (eZoneType)*(int32*)(buffer+32);
MapZoneArray[i].level = (eLevelName)*(int32*)(buffer+36);
MapZoneArray[i].zoneinfoDay = *(int16*)(buffer+40);
MapZoneArray[i].zoneinfoNight = *(int16*)(buffer+42);
#ifdef STANDALONE
// BUG: GetPointerForZoneIndex uses ZoneArray
// so pointers will be unpredictable with different memory layout
assert(0);
#endif
MapZoneArray[i].child = GetPointerForZoneIndex(*(int32*)(buffer+44));
MapZoneArray[i].parent = GetPointerForZoneIndex(*(int32*)(buffer+48));
MapZoneArray[i].next = GetPointerForZoneIndex(*(int32*)(buffer+52));
buffer += 56;
}
for(i = 0; i < NUMAUDIOZONES; i++){
AudioZoneArray[i] = *(int16*)buffer;
buffer += 2;
}
TotalNumberOfMapZones = *(uint16*)(buffer);
NumberOfAudioZones = *(uint16*)(buffer+2);
}
STARTPATCHES
InjectHook(0x4B5DD0, &CZone::GetTranslatedName, PATCH_JUMP);
InjectHook(0x4B5DE0, CTheZones::Init, PATCH_JUMP);
InjectHook(0x4B61D0, CTheZones::Update, PATCH_JUMP);
InjectHook(0x4B6210, CTheZones::CreateZone, PATCH_JUMP);
InjectHook(0x4B6380, CTheZones::CreateMapZone, PATCH_JUMP);
InjectHook(0x4B64C0, CTheZones::PostZoneCreation, PATCH_JUMP);
InjectHook(0x4B6500, CTheZones::InsertZoneIntoZoneHierarchy, PATCH_JUMP);
InjectHook(0x4B6530, CTheZones::InsertZoneIntoZoneHierRecursive, PATCH_JUMP);
InjectHook(0x4B65F0, CTheZones::ZoneIsEntirelyContainedWithinOtherZone, PATCH_JUMP);
InjectHook(0x4B6710, CTheZones::PointLiesWithinZone, PATCH_JUMP);
InjectHook(0x4B6910, CTheZones::GetLevelFromPosition, PATCH_JUMP);
InjectHook(0x4B69B0, CTheZones::FindSmallestZonePosition, PATCH_JUMP);
InjectHook(0x4B6790, CTheZones::FindSmallestZonePositionType, PATCH_JUMP);
InjectHook(0x4B6890, CTheZones::FindSmallestZonePositionILN, PATCH_JUMP);
InjectHook(0x4B6800, CTheZones::FindZoneByLabelAndReturnIndex, PATCH_JUMP);
InjectHook(0x4B6FA0, CTheZones::GetZone, PATCH_JUMP);
InjectHook(0x4B84F0, CTheZones::GetPointerForZoneIndex, PATCH_JUMP);
InjectHook(0x4B6A10, CTheZones::GetZoneInfo, PATCH_JUMP);
InjectHook(0x4B6FB0, CTheZones::GetZoneInfoForTimeOfDay, PATCH_JUMP);
InjectHook(0x4B6A50, CTheZones::SetZoneCarInfo, PATCH_JUMP);
InjectHook(0x4B6DC0, CTheZones::SetZonePedInfo, PATCH_JUMP);
InjectHook(0x4B6EB0, CTheZones::SetCarDensity, PATCH_JUMP);
InjectHook(0x4B6F00, CTheZones::SetPedDensity, PATCH_JUMP);
InjectHook(0x4B6F50, CTheZones::SetPedGroup, PATCH_JUMP);
InjectHook(0x4B83E0, CTheZones::FindAudioZone, PATCH_JUMP);
InjectHook(0x4B8430, CTheZones::FindZoneForPoint, PATCH_JUMP);
InjectHook(0x4B8340, CTheZones::AddZoneToAudioZoneArray, PATCH_JUMP);
InjectHook(0x4B8510, CTheZones::SaveAllZones, PATCH_JUMP);
InjectHook(0x4B8950, CTheZones::LoadAllZones, PATCH_JUMP);
ENDPATCHES

112
src/core/Zones.h Normal file
View File

@ -0,0 +1,112 @@
#pragma once
#include "Game.h"
enum eZoneType
{
ZONE_AUDIO,
ZONE_TYPE1, // this should be NAVIG
ZONE_TYPE2, // this should be INFO...but all except MAPINFO get zoneinfo??
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[9];
// Ped data
uint16 pedDensity;
uint16 copDensity;
uint16 gangDensity[9];
uint16 pedGroup;
};
class CTheZones
{
public:
static eLevelName &m_CurrLevel;
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];
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 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(CVector const &v);
static CZone *FindSmallestZonePosition(const CVector *v);
static CZone *FindSmallestZonePositionType(const CVector *v, eZoneType type);
static CZone *FindSmallestZonePositionILN(const CVector *v);
static int16 FindZoneByLabelAndReturnIndex(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(int32 i) { return i == -1 ? nil : &ZoneArray[i]; }
static int32 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);
};

178
src/core/common.h Normal file
View File

@ -0,0 +1,178 @@
#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: 4305) // double to float
#pragma warning(disable: 4838) // narrowing conversion
#pragma warning(disable: 4996) // POSIX names
#include <stdint.h>
#include <math.h>
//#include <assert.h>
#include <new>
#ifdef WITHD3D
#include <windows.h>
#include <d3d8types.h>
#endif
#include <rwcore.h>
#include <rpworld.h>
#define rwVENDORID_ROCKSTAR 0x0253F2
// Get rid of bullshit windows definitions, we're not running on an 8086
#ifdef far
#undef far
#endif
#ifdef near
#undef near
#endif
typedef uint8_t uint8;
typedef int8_t int8;
typedef uint16_t uint16;
typedef int16_t int16;
typedef uint32_t uint32;
typedef int32_t int32;
typedef uintptr_t uintptr;
typedef uint64_t uint64;
typedef int64_t int64;
// hardcode ucs-2
typedef uint16_t wchar;
#define nil nullptr
#include "config.h"
#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;
}
// little hack
extern void **rwengine;
#define RwEngineInstance (*rwengine)
#include "skeleton.h"
#include "Draw.h"
#define DEFAULT_SCREEN_WIDTH (640)
#define DEFAULT_SCREEN_HEIGHT (448)
#define DEFAULT_ASPECT_RATIO (4.0f/3.0f)
// game uses maximumWidth/Height, but this probably won't work
// with RW windowed mode
#define SCREEN_WIDTH ((float)RsGlobal.width)
#define SCREEN_HEIGHT ((float)RsGlobal.height)
#define SCREEN_ASPECT_RATIO (CDraw::GetAspectRatio())
// 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) * (4.0f / 3.0f) / SCREEN_ASPECT_RATIO)
#else
#define SCREEN_SCALE_AR(a) (a)
#endif
#include "math/Vector.h"
#include "math/Vector2D.h"
#include "math/Matrix.h"
#include "math/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) { }
#ifdef RWCORE_H
operator RwRGBA &(void) {
return rwRGBA;
}
operator RwRGBA *(void) {
return &rwRGBA;
}
operator RwRGBA (void) const {
return rwRGBA;
}
#endif
};
#define clamp(v, low, high) ((v)<(low) ? (low) : (v)>(high) ? (high) : (v))
inline float sq(float x) { return x*x; }
#define SQR(x) ((x) * (x))
#define PI M_PI
#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(char *format, ...);
void re3_trace(const char *filename, unsigned int lineno, const char *func, char *format, ...);
void re3_assert(const char *expr, const char *filename, unsigned int lineno, const char *func);
#define DEBUGBREAK() __debugbreak();
#define debug(f, ...) re3_debug("[DBG]: " f, __VA_ARGS__)
#define DEV(f, ...) re3_debug("[DEV]: " f, __VA_ARGS__)
#define TRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, f, __VA_ARGS__)
#define Error(f, ...) re3_debug("[ERROR]: " f, __VA_ARGS__)
#define assert(_Expression) (void)( (!!(_Expression)) || (re3_assert(#_Expression, __FILE__, __LINE__, __FUNCTION__), 0) )
#define ASSERT assert
#define _TODO(x)
#define _TODOCONST(x) (x)
#define VALIDATE_SIZE(struc, size) static_assert(sizeof(struc) == size, "Invalid structure size of " #struc)
#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 max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))

116
src/core/config.h Normal file
View File

@ -0,0 +1,116 @@
#pragma once
enum Config {
NUMCDIMAGES = 12, // gta3.img duplicates (not used on PC)
MAX_CDIMAGES = 8, // additional cdimages
MODELINFOSIZE = 5500,
TXDSTORESIZE = 850,
EXTRADIRSIZE = 128,
SIMPLEMODELSIZE = 5000,
TIMEMODELSIZE = 30,
CLUMPMODELSIZE = 5,
PEDMODELSIZE = 90,
VEHICLEMODELSIZE = 120,
TWODFXSIZE = 2000,
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,
// Link list lengths
// TODO: alpha list
NUMCOLCACHELINKS = 200,
NUMREFERENCES = 800,
// Zones
NUMAUDIOZONES = 36,
NUMZONES = 50,
NUMMAPZONES = 25,
// Cull zones
NUMCULLZONES = 512,
NUMATTRIBZONES = 288,
NUMZONEINDICES = 55000,
NUMHANDLINGS = 57,
PATHNODESIZE = 4500,
NUMWEATHERS = 4,
NUMHOURS = 24,
NUMEXTRADIRECTIONALS = 4,
NUMANTENNAS = 8,
NUMCORONAS = 56,
NUMPOINTLIGHTS = 32,
NUMONSCREENTIMERENTRIES = 1,
NUMRADARBLIPS = 32,
NUMPICKUPS = 336,
};
// We'll use this once we're ready to become independent of the game
// Use it to mark bugs in the code that will prevent the game from working then
//#define STANDALONE
// 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
// This enables things from the PS2 version on PC
#define GTA_PS2_STUFF
// 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
#if defined GTA_PS2
# define RANDOMSPLASH
#elif defined GTA_PC
# define GTA3_1_1_PATCH
# ifdef GTA_PS2_STUFF
//# define USE_PS2_RAND // this is unsafe until we have the game reversed
# define RANDOMSPLASH // use random splash as on PS2
# define PS2_MATFX
# endif
#elif defined GTA_XBOX
#endif
#ifdef MASTER
// only in master builds
#else
// not in master builds
#endif
#ifdef FINAL
// in all games
# define USE_MY_DOCUMENTS // use my documents directory for user files
#else
// not in any game
# define NASTY_GAME // nasty game for all languages
# define NO_MOVIES // disable intro videos
# define CHATTYSPLASH // print what the game is loading
#endif
#define FIX_BUGS // fix bugs in the game, TODO: use this more
#define KANGAROO_CHEAT
#define ASPECT_RATIO_SCALE

154
src/core/debugmenu_public.h Normal file
View File

@ -0,0 +1,154 @@
extern "C" {
typedef void (*TriggerFunc)(void);
struct DebugMenuEntry;
typedef DebugMenuEntry *(*DebugMenuAddInt8_TYPE)(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings);
typedef DebugMenuEntry *(*DebugMenuAddInt16_TYPE)(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings);
typedef DebugMenuEntry *(*DebugMenuAddInt32_TYPE)(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings);
typedef DebugMenuEntry *(*DebugMenuAddInt64_TYPE)(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings);
typedef DebugMenuEntry *(*DebugMenuAddUInt8_TYPE)(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings);
typedef DebugMenuEntry *(*DebugMenuAddUInt16_TYPE)(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings);
typedef DebugMenuEntry *(*DebugMenuAddUInt32_TYPE)(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings);
typedef DebugMenuEntry *(*DebugMenuAddUInt64_TYPE)(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings);
typedef DebugMenuEntry *(*DebugMenuAddFloat32_TYPE)(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound);
typedef DebugMenuEntry *(*DebugMenuAddFloat64_TYPE)(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound);
typedef DebugMenuEntry *(*DebugMenuAddCmd_TYPE)(const char *path, const char *name, TriggerFunc triggerFunc);
typedef void (*DebugMenuEntrySetWrap_TYPE)(DebugMenuEntry *e, bool wrap);
typedef void (*DebugMenuEntrySetStrings_TYPE)(DebugMenuEntry *e, const char **strings);
typedef void (*DebugMenuEntrySetAddress_TYPE)(DebugMenuEntry *e, void *addr);
struct DebugMenuAPI
{
bool isLoaded;
HMODULE module;
DebugMenuAddInt8_TYPE addint8;
DebugMenuAddInt16_TYPE addint16;
DebugMenuAddInt32_TYPE addint32;
DebugMenuAddInt64_TYPE addint64;
DebugMenuAddUInt8_TYPE adduint8;
DebugMenuAddUInt16_TYPE adduint16;
DebugMenuAddUInt32_TYPE adduint32;
DebugMenuAddUInt64_TYPE adduint64;
DebugMenuAddFloat32_TYPE addfloat32;
DebugMenuAddFloat64_TYPE addfloat64;
DebugMenuAddCmd_TYPE addcmd;
DebugMenuEntrySetWrap_TYPE setwrap;
DebugMenuEntrySetStrings_TYPE setstrings;
DebugMenuEntrySetAddress_TYPE setaddress;
};
extern DebugMenuAPI gDebugMenuAPI;
inline DebugMenuEntry *DebugMenuAddInt8(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings)
{ return gDebugMenuAPI.addint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddInt16(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings)
{ return gDebugMenuAPI.addint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddInt32(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings)
{ return gDebugMenuAPI.addint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddInt64(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings)
{ return gDebugMenuAPI.addint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddUInt8(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings)
{ return gDebugMenuAPI.adduint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddUInt16(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings)
{ return gDebugMenuAPI.adduint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddUInt32(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings)
{ return gDebugMenuAPI.adduint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddUInt64(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings)
{ return gDebugMenuAPI.adduint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddFloat32(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound)
{ return gDebugMenuAPI.addfloat32(path, name, ptr, triggerFunc, step, lowerBound, upperBound); }
inline DebugMenuEntry *DebugMenuAddFloat64(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound)
{ return gDebugMenuAPI.addfloat64(path, name, ptr, triggerFunc, step, lowerBound, upperBound); }
inline DebugMenuEntry *DebugMenuAddCmd(const char *path, const char *name, TriggerFunc triggerFunc)
{ return gDebugMenuAPI.addcmd(path, name, triggerFunc); }
inline void DebugMenuEntrySetWrap(DebugMenuEntry *e, bool wrap)
{ gDebugMenuAPI.setwrap(e, wrap); }
inline void DebugMenuEntrySetStrings(DebugMenuEntry *e, const char **strings)
{ gDebugMenuAPI.setstrings(e, strings); }
inline void DebugMenuEntrySetAddress(DebugMenuEntry *e, void *addr)
{ gDebugMenuAPI.setaddress(e, addr); }
inline bool DebugMenuLoad(void)
{
if(gDebugMenuAPI.isLoaded)
return true;
HMODULE mod = LoadLibraryA("debugmenu");
if(mod == nil){
char modulePath[MAX_PATH];
HMODULE dllModule;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)&gDebugMenuAPI, &dllModule);
GetModuleFileNameA(dllModule, modulePath, MAX_PATH);
char *p = strchr(modulePath, '\\');
if(p) p[1] = '\0';
strcat(modulePath, "debugmenu");
mod = LoadLibraryA(modulePath);
}
if(mod == nil)
return false;
gDebugMenuAPI.addint8 = (DebugMenuAddInt8_TYPE)GetProcAddress(mod, "DebugMenuAddInt8");
gDebugMenuAPI.addint16 = (DebugMenuAddInt16_TYPE)GetProcAddress(mod, "DebugMenuAddInt16");
gDebugMenuAPI.addint32 = (DebugMenuAddInt32_TYPE)GetProcAddress(mod, "DebugMenuAddInt32");
gDebugMenuAPI.addint64 = (DebugMenuAddInt64_TYPE)GetProcAddress(mod, "DebugMenuAddInt64");
gDebugMenuAPI.adduint8 = (DebugMenuAddUInt8_TYPE)GetProcAddress(mod, "DebugMenuAddUInt8");
gDebugMenuAPI.adduint16 = (DebugMenuAddUInt16_TYPE)GetProcAddress(mod, "DebugMenuAddUInt16");
gDebugMenuAPI.adduint32 = (DebugMenuAddUInt32_TYPE)GetProcAddress(mod, "DebugMenuAddUInt32");
gDebugMenuAPI.adduint64 = (DebugMenuAddUInt64_TYPE)GetProcAddress(mod, "DebugMenuAddUInt64");
gDebugMenuAPI.addfloat32 = (DebugMenuAddFloat32_TYPE)GetProcAddress(mod, "DebugMenuAddFloat32");
gDebugMenuAPI.addfloat64 = (DebugMenuAddFloat64_TYPE)GetProcAddress(mod, "DebugMenuAddFloat64");
gDebugMenuAPI.addcmd = (DebugMenuAddCmd_TYPE)GetProcAddress(mod, "DebugMenuAddCmd");
gDebugMenuAPI.setwrap = (DebugMenuEntrySetWrap_TYPE)GetProcAddress(mod, "DebugMenuEntrySetWrap");
gDebugMenuAPI.setstrings = (DebugMenuEntrySetStrings_TYPE)GetProcAddress(mod, "DebugMenuEntrySetStrings");
gDebugMenuAPI.setaddress = (DebugMenuEntrySetAddress_TYPE)GetProcAddress(mod, "DebugMenuEntrySetAddress");
gDebugMenuAPI.isLoaded = true;
gDebugMenuAPI.module = mod;
return true;
}
}
// Also overload them for simplicity
inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings)
{ return gDebugMenuAPI.addint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings)
{ return gDebugMenuAPI.addint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings)
{ return gDebugMenuAPI.addint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings)
{ return gDebugMenuAPI.addint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings)
{ return gDebugMenuAPI.adduint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings)
{ return gDebugMenuAPI.adduint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings)
{ return gDebugMenuAPI.adduint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings)
{ return gDebugMenuAPI.adduint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); }
inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound)
{ return gDebugMenuAPI.addfloat32(path, name, ptr, triggerFunc, step, lowerBound, upperBound); }
inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound)
{ return gDebugMenuAPI.addfloat64(path, name, ptr, triggerFunc, step, lowerBound, upperBound); }
inline DebugMenuEntry *DebugMenuAddVarBool32(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc)
{
static const char *boolstr[] = { "Off", "On" };
DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr);
DebugMenuEntrySetWrap(e, true);
return e;
}
inline DebugMenuEntry *DebugMenuAddVarBool16(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc)
{
static const char *boolstr[] = { "Off", "On" };
DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr);
DebugMenuEntrySetWrap(e, true);
return e;
}
inline DebugMenuEntry *DebugMenuAddVarBool8(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc)
{
static const char *boolstr[] = { "Off", "On" };
DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr);
DebugMenuEntrySetWrap(e, true);
return e;
}

891
src/core/main.cpp Normal file
View File

@ -0,0 +1,891 @@
#include "common.h"
#include "patcher.h"
#include "main.h"
#include "General.h"
#include "RwHelper.h"
#include "Clouds.h"
#include "Draw.h"
#include "Sprite2d.h"
#include "Renderer.h"
#include "Coronas.h"
#include "WaterLevel.h"
#include "Weather.h"
#include "Glass.h"
#include "WaterCannon.h"
#include "SpecialFX.h"
#include "Shadows.h"
#include "Skidmarks.h"
#include "Antennas.h"
#include "Rubbish.h"
#include "Particle.h"
#include "Pickups.h"
#include "WeaponEffects.h"
#include "PointLights.h"
#include "Fluff.h"
#include "Replay.h"
#include "Camera.h"
#include "World.h"
#include "Ped.h"
#include "Font.h"
#include "Pad.h"
#include "Hud.h"
#include "User.h"
#include "Messages.h"
#include "Darkel.h"
#include "Garages.h"
#include "MusicManager.h"
#include "VisibilityPlugins.h"
#include "NodeName.h"
#include "DMAudio.h"
#include "CutsceneMgr.h"
#include "Lights.h"
#include "Credits.h"
#include "ZoneCull.h"
#include "Timecycle.h"
#include "TxdStore.h"
#include "FileMgr.h"
#include "Text.h"
#include "RpAnimBlend.h"
#include "Frontend.h"
#define DEFAULT_VIEWWINDOW (tan(DEGTORAD(CDraw::GetFOV() * 0.5f)))
GlobalScene &Scene = *(GlobalScene*)0x726768;
uint8 work_buff[55000];
char gString[256];
wchar *gUString = (wchar*)0x74B018;
bool &b_FoundRecentSavedGameWantToLoad = *(bool*)0x95CDA8;
bool DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
void DoRWStuffEndOfFrame(void);
void RenderScene(void);
void RenderDebugShit(void);
void RenderEffects(void);
void Render2dStuff(void);
void RenderMenus(void);
void DoFade(void);
void Render2dStuffAfterFade(void);
CSprite2d *LoadSplash(const char *name);
void DestroySplashScreen(void);
extern void (*DebugMenuProcess)(void);
extern void (*DebugMenuRender)(void);
void DebugMenuInit(void);
void DebugMenuPopulate(void);
void PrintGameVersion();
RwRGBA gColourTop;
void
InitialiseGame(void)
{
LoadingScreen(nil, nil, "loadsc0");
CGame::Initialise("DATA\\GTA3.DAT");
}
void
Idle(void *arg)
{
#ifdef ASPECT_RATIO_SCALE
CDraw::SetAspectRatio(CDraw::FindAspectRatio());
#endif
CTimer::Update();
CSprite2d::InitPerFrame();
CFont::InitPerFrame();
CPointLights::InitPerFrame();
CGame::Process();
DMAudio.Service();
if(CGame::bDemoMode && CTimer::GetTimeInMilliseconds() > (3*60 + 30)*1000 && !CCutsceneMgr::IsCutsceneProcessing()){
FrontEndMenuManager.m_bStartGameLoading = true;
FrontEndMenuManager.m_bLoadingSavedGame = false;
return;
}
if(FrontEndMenuManager.m_bStartGameLoading || b_FoundRecentSavedGameWantToLoad)
return;
SetLightsWithTimeOfDayColour(Scene.world);
if(arg == nil)
return;
if((!FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.field_452 == 1) &&
TheCamera.GetScreenFadeStatus() != FADE_2){
#ifdef GTA_PC
// This is from SA, but it's nice for windowed mode
RwV2d pos;
pos.x = SCREEN_WIDTH/2.0f;
pos.y = SCREEN_HEIGHT/2.0f;
RsMouseSetPos(&pos);
#endif
CRenderer::ConstructRenderList();
CRenderer::PreRender();
if(CWeather::LightningFlash && !CCullZones::CamNoRain()){
if(!DoRWStuffStartOfFrame_Horizon(255, 255, 255, 255, 255, 255, 255))
return;
}else{
if(!DoRWStuffStartOfFrame_Horizon(CTimeCycle::GetSkyTopRed(), CTimeCycle::GetSkyTopGreen(), CTimeCycle::GetSkyTopBlue(),
CTimeCycle::GetSkyBottomRed(), CTimeCycle::GetSkyBottomGreen(), CTimeCycle::GetSkyBottomBlue(),
255))
return;
}
DefinedState();
// BUG. This has to be done BEFORE RwCameraBeginUpdate
RwCameraSetFarClipPlane(Scene.camera, CTimeCycle::GetFarClip());
RwCameraSetFogDistance(Scene.camera, CTimeCycle::GetFogStart());
RenderScene();
RenderDebugShit();
RenderEffects();
if((TheCamera.m_BlurType == MBLUR_NONE || TheCamera.m_BlurType == MBLUR_NORMAL) &&
TheCamera.m_ScreenReductionPercentage > 0.0)
TheCamera.SetMotionBlurAlpha(150);
TheCamera.RenderMotionBlur();
Render2dStuff();
}else{
float viewWindow = DEFAULT_VIEWWINDOW;
CameraSize(Scene.camera, nil, viewWindow, DEFAULT_ASPECT_RATIO);
CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
if(!RsCameraBeginUpdate(Scene.camera))
return;
}
RenderMenus();
#ifndef FINAL
PrintGameVersion();
#endif
DoFade();
Render2dStuffAfterFade();
CCredits::Render();
DoRWStuffEndOfFrame();
// if(g_SlowMode)
// ProcessSlowMode();
}
void
FrontendIdle(void)
{
#ifdef ASPECT_RATIO_SCALE
CDraw::SetAspectRatio(CDraw::FindAspectRatio());
#endif
CTimer::Update();
CSprite2d::SetRecipNearClip();
CSprite2d::InitPerFrame();
CFont::InitPerFrame();
CPad::UpdatePads();
FrontEndMenuManager.Process();
if(RsGlobal.quit)
return;
float viewWindow = DEFAULT_VIEWWINDOW;
CameraSize(Scene.camera, nil, viewWindow, DEFAULT_ASPECT_RATIO);
CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
if(!RsCameraBeginUpdate(Scene.camera))
return;
DefinedState();
RenderMenus();
#ifndef FINAL
PrintGameVersion();
#endif
DoFade();
Render2dStuffAfterFade();
CFont::DrawFonts();
DoRWStuffEndOfFrame();
}
bool
DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha)
{
CRGBA TopColor(TopRed, TopGreen, TopBlue, Alpha);
CRGBA BottomColor(BottomRed, BottomGreen, BottomBlue, Alpha);
CameraSize(Scene.camera, nil, DEFAULT_VIEWWINDOW, SCREEN_ASPECT_RATIO);
CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
if(!RsCameraBeginUpdate(Scene.camera))
return false;
CSprite2d::InitPerFrame();
if(Alpha != 0)
CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), BottomColor, BottomColor, TopColor, TopColor);
return true;
}
bool
DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha)
{
CameraSize(Scene.camera, nil, DEFAULT_VIEWWINDOW, SCREEN_ASPECT_RATIO);
CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
if(!RsCameraBeginUpdate(Scene.camera))
return false;
TheCamera.m_viewMatrix.Update();
CClouds::RenderBackground(TopRed, TopGreen, TopBlue, BottomRed, BottomGreen, BottomBlue, Alpha);
return true;
}
void
DoRWStuffEndOfFrame(void)
{
// CDebug::DebugDisplayTextBuffer();
// FlushObrsPrintfs();
RwCameraEndUpdate(Scene.camera);
RsCameraShowRaster(Scene.camera);
}
// This is certainly a very useful function
void
DoRWRenderHorizon(void)
{
CClouds::RenderHorizon();
}
void
RenderScene(void)
{
CClouds::Render();
DoRWRenderHorizon();
CRenderer::RenderRoads();
CCoronas::RenderReflections();
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
CRenderer::RenderEverythingBarRoads();
CRenderer::RenderBoats();
DefinedState();
CWaterLevel::RenderWater();
CRenderer::RenderFadingInEntities();
CRenderer::RenderVehiclesButNotBoats();
CWeather::RenderRainStreaks();
}
void
RenderDebugShit(void)
{
// CTheScripts::RenderTheScriptDebugLines()
}
void
RenderEffects(void)
{
CGlass::Render();
CWaterCannons::Render();
CSpecialFX::Render();
CShadows::RenderStaticShadows();
CShadows::RenderStoredShadows();
CSkidmarks::Render();
CAntennas::Render();
CRubbish::Render();
CCoronas::Render();
CParticle::Render();
CPacManPickups::Render();
CWeaponEffects::Render();
CPointLights::RenderFogEffect();
CMovingThings::Render();
CRenderer::RenderFirstPersonVehicle();
}
void
Render2dStuff(void)
{
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE);
CReplay::Display();
CPickups::RenderPickUpText();
if(TheCamera.m_WideScreenOn)
TheCamera.DrawBordersForWideScreen();
CPed *player = FindPlayerPed();
int weaponType = 0;
if(player)
weaponType = player->GetWeapon()->m_eWeaponType;
bool firstPersonWeapon = false;
int cammode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
if(cammode == CCam::MODE_SNIPER ||
cammode == CCam::MODE_SNIPER_RUN_AROUND ||
cammode == CCam::MODE_ROCKET ||
cammode == CCam::MODE_ROCKET_RUN_AROUND)
firstPersonWeapon = true;
// Draw black border for sniper and rocket launcher
if((weaponType == WEAPONTYPE_SNIPERRIFLE || weaponType == WEAPONTYPE_ROCKETLAUNCHER) && firstPersonWeapon){
CRGBA black(0, 0, 0, 255);
// top and bottom strips
if (weaponType == WEAPONTYPE_ROCKETLAUNCHER) {
CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(180)), black);
CSprite2d::DrawRect(CRect(0.0f, SCREEN_HEIGHT / 2 + SCREEN_SCALE_Y(170), SCREEN_WIDTH, SCREEN_HEIGHT), black);
}
else {
CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(210)), black);
CSprite2d::DrawRect(CRect(0.0f, SCREEN_HEIGHT / 2 + SCREEN_SCALE_Y(210), SCREEN_WIDTH, SCREEN_HEIGHT), black);
}
CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH / 2 - SCREEN_SCALE_X(210), SCREEN_HEIGHT), black);
CSprite2d::DrawRect(CRect(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(210), 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), black);
}
MusicManager.DisplayRadioStationName();
// TheConsole.Display();
/*
if(CSceneEdit::m_bEditOn)
CSceneEdit::Draw();
else
*/
CHud::Draw();
CUserDisplay::OnscnTimer.ProcessForDisplay();
CMessages::Display();
CDarkel::DrawMessages();
CGarages::PrintMessages();
CPad::PrintErrorMessage();
CFont::DrawFonts();
DebugMenuRender();
}
void
RenderMenus(void)
{
if(FrontEndMenuManager.m_bMenuActive)
FrontEndMenuManager.DrawFrontEnd();
}
bool &JustLoadedDontFadeInYet = *(bool*)0x95CDB4;
bool &StillToFadeOut = *(bool*)0x95CD99;
uint32 &TimeStartedCountingForFade = *(uint32*)0x9430EC;
uint32 &TimeToStayFadedBeforeFadeOut = *(uint32*)0x611564;
void
DoFade(void)
{
if(CTimer::GetIsPaused())
return;
if(JustLoadedDontFadeInYet){
JustLoadedDontFadeInYet = false;
TimeStartedCountingForFade = CTimer::GetTimeInMilliseconds();
}
if(StillToFadeOut){
if(CTimer::GetTimeInMilliseconds() - TimeStartedCountingForFade > TimeToStayFadedBeforeFadeOut){
StillToFadeOut = false;
TheCamera.Fade(3.0f, FADE_IN);
TheCamera.ProcessFade();
TheCamera.ProcessMusicFade();
}else{
TheCamera.SetFadeColour(0, 0, 0);
TheCamera.Fade(0.0f, FADE_OUT);
TheCamera.ProcessFade();
}
}
if(CDraw::FadeValue != 0 || CMenuManager::m_PrefsBrightness < 256){
CSprite2d *splash = LoadSplash(nil);
CRGBA fadeColor;
CRect rect;
int fadeValue = CDraw::FadeValue;
float brightness = min(CMenuManager::m_PrefsBrightness, 256);
if(brightness <= 50)
brightness = 50;
if(FrontEndMenuManager.m_bMenuActive)
brightness = 256;
if(TheCamera.m_FadeTargetIsSplashScreen)
fadeValue = 0;
float fade = fadeValue + 256 - brightness;
if(fade == 0){
fadeColor.r = 0;
fadeColor.g = 0;
fadeColor.b = 0;
fadeColor.a = 0;
}else{
fadeColor.r = fadeValue * CDraw::FadeRed / fade;
fadeColor.g = fadeValue * CDraw::FadeGreen / fade;
fadeColor.b = fadeValue * CDraw::FadeBlue / fade;
int alpha = 255 - brightness*(256 - fadeValue)/256;
if(alpha < 0)
alpha = 0;
fadeColor.a = alpha;
}
if(TheCamera.m_WideScreenOn){
// what's this?
float y = SCREEN_HEIGHT/2 * TheCamera.m_ScreenReductionPercentage/100.0f;
rect.left = 0.0f;
rect.right = SCREEN_WIDTH;
rect.top = y - 8.0f;
rect.bottom = SCREEN_HEIGHT - y - 8.0f;
}else{
rect.left = 0.0f;
rect.right = SCREEN_WIDTH;
rect.top = 0.0f;
rect.bottom = SCREEN_HEIGHT;
}
CSprite2d::DrawRect(rect, fadeColor);
if(CDraw::FadeValue != 0 && TheCamera.m_FadeTargetIsSplashScreen){
fadeColor.r = 255;
fadeColor.g = 255;
fadeColor.b = 255;
fadeColor.a = CDraw::FadeValue;
splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), fadeColor, fadeColor, fadeColor, fadeColor);
}
}
}
void
Render2dStuffAfterFade(void)
{
CHud::DrawAfterFade();
CFont::DrawFonts();
}
CSprite2d splash;
int splashTxdId = -1;
CSprite2d*
LoadSplash(const char *name)
{
RwTexDictionary *txd;
char filename[140];
RwTexture *tex = nil;
if(name == nil)
return &splash;
if(splashTxdId == -1)
splashTxdId = CTxdStore::AddTxdSlot("splash");
txd = CTxdStore::GetSlot(splashTxdId)->texDict;
if(txd)
tex = RwTexDictionaryFindNamedTexture(txd, name);
// if texture is found, splash was already set up below
if(tex == nil){
CFileMgr::SetDir("TXD\\");
sprintf(filename, "%s.txd", name);
if(splash.m_pTexture)
splash.Delete();
if(txd)
CTxdStore::RemoveTxd(splashTxdId);
CTxdStore::LoadTxd(splashTxdId, filename);
CTxdStore::AddRef(splashTxdId);
CTxdStore::PushCurrentTxd();
CTxdStore::SetCurrentTxd(splashTxdId);
splash.SetTexture(name);
CTxdStore::PopCurrentTxd();
CFileMgr::SetDir("");
}
return &splash;
}
void
DestroySplashScreen(void)
{
splash.Delete();
if(splashTxdId != -1)
CTxdStore::RemoveTxdSlot(splashTxdId);
splashTxdId = -1;
}
float NumberOfChunksLoaded;
#define TOTALNUMCHUNKS 73.0f
// TODO: compare with PS2
void
LoadingScreen(const char *str1, const char *str2, const char *splashscreen)
{
CSprite2d *splash;
#ifndef RANDOMSPLASH
if(CGame::frenchGame || CGame::germanGame || !CGame::nastyGame)
splashscreen = "mainsc2";
else
splashscreen = "mainsc1";
#endif
splash = LoadSplash(splashscreen);
if(RsGlobal.quit)
return;
if(DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255)){
CSprite2d::SetRecipNearClip();
CSprite2d::InitPerFrame();
CFont::InitPerFrame();
DefinedState();
RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
if(str1){
NumberOfChunksLoaded += 1;
float hpos = SCREEN_SCALE_X(40);
float length = SCREEN_WIDTH - SCREEN_SCALE_X(100);
float vpos = SCREEN_HEIGHT - SCREEN_SCALE_Y(13);
float height = SCREEN_SCALE_Y(7);
CSprite2d::DrawRect(CRect(hpos, vpos, hpos + length, vpos + height), CRGBA(40, 53, 68, 255));
length *= NumberOfChunksLoaded/TOTALNUMCHUNKS;
CSprite2d::DrawRect(CRect(hpos, vpos, hpos + length, vpos + height), CRGBA(81, 106, 137, 255));
// this is done by the game but is unused
CFont::SetScale(SCREEN_SCALE_X(2), SCREEN_SCALE_Y(2));
CFont::SetPropOn();
CFont::SetRightJustifyOn();
CFont::SetFontStyle(FONT_HEADING);
#ifdef CHATTYSPLASH
// my attempt
static wchar tmpstr[80];
float scale = SCREEN_SCALE_Y(0.8f);
vpos -= 50*scale;
CFont::SetScale(scale, scale);
CFont::SetPropOn();
CFont::SetRightJustifyOff();
CFont::SetFontStyle(FONT_BANK);
CFont::SetColor(CRGBA(255, 255, 255, 255));
AsciiToUnicode(str1, tmpstr);
CFont::PrintString(hpos, vpos, tmpstr);
vpos += 25*scale;
AsciiToUnicode(str2, tmpstr);
CFont::PrintString(hpos, vpos, tmpstr);
#endif
}
CFont::DrawFonts();
DoRWStuffEndOfFrame();
}
}
void
ResetLoadingScreenBar(void)
{
NumberOfChunksLoaded = 0.0f;
}
void
LoadingIslandScreen(const char *levelName)
{
CSprite2d *splash;
wchar *name;
char str[100];
wchar wstr[80];
CRGBA col;
splash = LoadSplash(nil);
name = TheText.Get(levelName);
if(!DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255))
return;
CSprite2d::SetRecipNearClip();
CSprite2d::InitPerFrame();
CFont::InitPerFrame();
DefinedState();
col = CRGBA(255, 255, 255, 255);
splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), col, col, col, col);
CFont::SetBackgroundOff();
CFont::SetScale(1.5f, 1.5f);
CFont::SetPropOn();
CFont::SetRightJustifyOn();
CFont::SetRightJustifyWrap(150.0f);
CFont::SetFontStyle(FONT_HEADING);
sprintf(str, "WELCOME TO");
AsciiToUnicode(str, wstr);
CFont::SetDropColor(CRGBA(0, 0, 0, 255));
CFont::SetDropShadowPosition(3);
CFont::SetColor(CRGBA(243, 237, 71, 255));
CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f));
CFont::PrintString(SCREEN_WIDTH - 20, SCREEN_STRETCH_FROM_BOTTOM(110.0f), TheText.Get("WELCOME"));
TextCopy(wstr, name);
TheText.UpperCase(wstr);
CFont::SetColor(CRGBA(243, 237, 71, 255));
CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f));
CFont::PrintString(SCREEN_WIDTH-20, SCREEN_STRETCH_FROM_BOTTOM(80.0f), wstr);
CFont::DrawFonts();
DoRWStuffEndOfFrame();
}
char*
GetLevelSplashScreen(int level)
{
static char *splashScreens[4] = {
nil,
"splash1",
"splash2",
"splash3",
};
return splashScreens[level];
}
char*
GetRandomSplashScreen(void)
{
int index;
static int index2 = 0;
static char splashName[128];
static int splashIndex[24] = {
25, 22, 4, 13,
1, 21, 14, 16,
10, 12, 5, 9,
11, 18, 3, 2,
19, 23, 7, 17,
15, 6, 8, 20
};
index = splashIndex[4*index2 + CGeneral::GetRandomNumberInRange(0, 3)];
index2++;
if(index2 == 6)
index2 = 0;
sprintf(splashName, "loadsc%d", index);
return splashName;
}
#include "rwcore.h"
#include "rpworld.h"
#include "rpmatfx.h"
#include "rpskin.h"
#include "rphanim.h"
#include "rtbmp.h"
_TODO("temp, move this includes out of here")
static RwBool
PluginAttach(void)
{
if( !RpWorldPluginAttach() )
{
printf("Couldn't attach world plugin\n");
return FALSE;
}
if( !RpSkinPluginAttach() )
{
printf("Couldn't attach RpSkin plugin\n");
return FALSE;
}
if( !RpHAnimPluginAttach() )
{
printf("Couldn't attach RpHAnim plugin\n");
return FALSE;
}
if( !NodeNamePluginAttach() )
{
printf("Couldn't attach node name plugin\n");
return FALSE;
}
if( !CVisibilityPlugins::PluginAttach() )
{
printf("Couldn't attach visibility plugins\n");
return FALSE;
}
if( !RpAnimBlendPluginAttach() )
{
printf("Couldn't attach RpAnimBlend plugin\n");
return FALSE;
}
if( !RpMatFXPluginAttach() )
{
printf("Couldn't attach RpMatFX plugin\n");
return FALSE;
}
return TRUE;
}
static RwBool
Initialise3D(void *param)
{
if (RsRwInitialise(param))
{
//
DebugMenuInit();
DebugMenuPopulate();
//
return CGame::InitialiseRenderWare();
}
return (FALSE);
}
static void
Terminate3D(void)
{
CGame::ShutdownRenderWare();
RsRwTerminate();
return;
}
RsEventStatus
AppEventHandler(RsEvent event, void *param)
{
switch( event )
{
case rsINITIALISE:
{
CGame::InitialiseOnceBeforeRW();
return RsInitialise() ? rsEVENTPROCESSED : rsEVENTERROR;
}
case rsCAMERASIZE:
{
CameraSize(Scene.camera, (RwRect *)param,
DEFAULT_VIEWWINDOW, DEFAULT_ASPECT_RATIO);
return rsEVENTPROCESSED;
}
case rsRWINITIALISE:
{
return Initialise3D(param) ? rsEVENTPROCESSED : rsEVENTERROR;
}
case rsRWTERMINATE:
{
Terminate3D();
return rsEVENTPROCESSED;
}
case rsTERMINATE:
{
CGame::FinalShutdown();
return rsEVENTPROCESSED;
}
case rsPLUGINATTACH:
{
return PluginAttach() ? rsEVENTPROCESSED : rsEVENTERROR;
}
case rsINPUTDEVICEATTACH:
{
AttachInputDevices();
return rsEVENTPROCESSED;
}
case rsIDLE:
{
Idle(param);
return rsEVENTPROCESSED;
}
case rsFRONTENDIDLE:
{
FrontendIdle();
return rsEVENTPROCESSED;
}
case rsACTIVATE:
{
param ? DMAudio.ReacquireDigitalHandle() : DMAudio.ReleaseDigitalHandle();
return rsEVENTPROCESSED;
}
default:
{
return rsEVENTNOTPROCESSED;
}
}
}
void PrintGameVersion()
{
CFont::SetPropOn();
CFont::SetBackgroundOff();
CFont::SetScale(SCREEN_SCALE_X(0.7f), SCREEN_SCALE_Y(0.5f));
CFont::SetCentreOff();
CFont::SetRightJustifyOff();
CFont::SetBackGroundOnlyTextOff();
CFont::SetFontStyle(FONT_BANK);
CFont::SetWrapx(SCREEN_WIDTH);
CFont::SetDropShadowPosition(0);
CFont::SetDropColor(CRGBA(0, 0, 0, 255));
CFont::SetColor(CRGBA(235, 170, 50, 255));
strcpy(gString, "RE3");
AsciiToUnicode(gString, gUString);
CFont::PrintString(SCREEN_SCALE_X(10.5f), SCREEN_SCALE_Y(8.0f), gUString);
}
STARTPATCHES
InjectHook(0x48E480, Idle, PATCH_JUMP);
InjectHook(0x48E700, FrontendIdle, PATCH_JUMP);
InjectHook(0x48CF10, DoRWStuffStartOfFrame, PATCH_JUMP);
InjectHook(0x48D040, DoRWStuffStartOfFrame_Horizon, PATCH_JUMP);
InjectHook(0x48E030, RenderScene, PATCH_JUMP);
InjectHook(0x48E080, RenderDebugShit, PATCH_JUMP);
InjectHook(0x48E090, RenderEffects, PATCH_JUMP);
InjectHook(0x48E0E0, Render2dStuff, PATCH_JUMP);
InjectHook(0x48E450, RenderMenus, PATCH_JUMP);
InjectHook(0x48D120, DoFade, PATCH_JUMP);
InjectHook(0x48E470, Render2dStuffAfterFade, PATCH_JUMP);
InjectHook(0x48D550, LoadSplash, PATCH_JUMP);
InjectHook(0x48D670, DestroySplashScreen, PATCH_JUMP);
InjectHook(0x48D770, LoadingScreen, PATCH_JUMP);
InjectHook(0x48D760, ResetLoadingScreenBar, PATCH_JUMP);
InjectHook(0x48D470, PluginAttach, PATCH_JUMP);
InjectHook(0x48D520, Initialise3D, PATCH_JUMP);
InjectHook(0x48D540, Terminate3D, PATCH_JUMP);
InjectHook(0x48E800, AppEventHandler, PATCH_JUMP);
ENDPATCHES

22
src/core/main.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
struct GlobalScene
{
RpWorld *world;
RwCamera *camera;
};
extern GlobalScene &Scene;
extern uint8 work_buff[55000];
extern char gString[256];
extern wchar *gUString;
extern bool &b_FoundRecentSavedGameWantToLoad;
class CSprite2d;
void InitialiseGame(void);
void LoadingScreen(const char *str1, const char *str2, const char *splashscreen);
void LoadingIslandScreen(const char *levelName);
CSprite2d *LoadSplash(const char *name);
char *GetLevelSplashScreen(int level);
char *GetRandomSplashScreen(void);

22
src/core/patcher.cpp Normal file
View File

@ -0,0 +1,22 @@
#include "common.h"
#include "patcher.h"
StaticPatcher *StaticPatcher::ms_head;
StaticPatcher::StaticPatcher(Patcher func)
: m_func(func)
{
m_next = ms_head;
ms_head = this;
}
void
StaticPatcher::Apply()
{
StaticPatcher *current = ms_head;
while(current){
current->Run();
current = current->m_next;
}
ms_head = nil;
}

192
src/core/patcher.h Normal file
View File

@ -0,0 +1,192 @@
#pragma once
#define WRAPPER __declspec(naked)
#define DEPRECATED __declspec(deprecated)
#define EAXJMP(a) { _asm mov eax, a _asm jmp eax }
#define VARJMP(a) { _asm jmp a }
#define WRAPARG(a) UNREFERENCED_PARAMETER(a)
#define NOVMT __declspec(novtable)
#define SETVMT(a) *((DWORD_PTR*)this) = (DWORD_PTR)a
#include <algorithm>
#include <vector>
#include "common.h"
enum
{
PATCH_CALL,
PATCH_JUMP,
PATCH_NOTHING,
};
enum
{
III_10 = 1,
III_11,
III_STEAM,
VC_10,
VC_11,
VC_STEAM
};
extern int gtaversion;
class StaticPatcher
{
private:
using Patcher = void(*)();
Patcher m_func;
StaticPatcher *m_next;
static StaticPatcher *ms_head;
void Run() { m_func(); }
public:
StaticPatcher(Patcher func);
static void Apply();
};
template<typename T>
inline T AddressByVersion(uint32_t addressIII10, uint32_t addressIII11, uint32_t addressIIISteam, uint32_t addressvc10, uint32_t addressvc11, uint32_t addressvcSteam)
{
if(gtaversion == -1){
if(*(uint32_t*)0x5C1E75 == 0xB85548EC) gtaversion = III_10;
else if(*(uint32_t*)0x5C2135 == 0xB85548EC) gtaversion = III_11;
else if(*(uint32_t*)0x5C6FD5 == 0xB85548EC) gtaversion = III_STEAM;
else if(*(uint32_t*)0x667BF5 == 0xB85548EC) gtaversion = VC_10;
else if(*(uint32_t*)0x667C45 == 0xB85548EC) gtaversion = VC_11;
else if(*(uint32_t*)0x666BA5 == 0xB85548EC) gtaversion = VC_STEAM;
else gtaversion = 0;
}
switch(gtaversion){
case III_10:
return (T)addressIII10;
case III_11:
return (T)addressIII11;
case III_STEAM:
return (T)addressIIISteam;
case VC_10:
return (T)addressvc10;
case VC_11:
return (T)addressvc11;
case VC_STEAM:
return (T)addressvcSteam;
default:
return (T)0;
}
}
inline bool
is10(void)
{
return gtaversion == III_10 || gtaversion == VC_10;
}
inline bool
isIII(void)
{
return gtaversion >= III_10 && gtaversion <= III_STEAM;
}
inline bool
isVC(void)
{
return gtaversion >= VC_10 && gtaversion <= VC_STEAM;
}
#define PTRFROMCALL(addr) (uint32_t)(*(uint32_t*)((uint32_t)addr+1) + (uint32_t)addr + 5)
#define INTERCEPT(saved, func, a) \
{ \
saved = PTRFROMCALL(a); \
InjectHook(a, func); \
}
template<typename T, typename AT> inline void
Patch(AT address, T value)
{
DWORD dwProtect[2];
VirtualProtect((void*)address, sizeof(T), PAGE_EXECUTE_READWRITE, &dwProtect[0]);
*(T*)address = value;
VirtualProtect((void*)address, sizeof(T), dwProtect[0], &dwProtect[1]);
}
template<typename AT> inline void
Nop(AT address, unsigned int nCount)
{
DWORD dwProtect[2];
VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
memset((void*)address, 0x90, nCount);
VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]);
}
template<typename AT> inline void
ClearCC(AT address, unsigned int nCount)
{
DWORD dwProtect[2];
VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
memset((void*)address, 0xCC, nCount);
VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]);
}
extern std::vector<int32> usedAddresses;
template<typename AT, typename HT> inline void
InjectHook(AT address, HT hook, unsigned int nType=PATCH_NOTHING)
{
if(std::any_of(usedAddresses.begin(), usedAddresses.end(),
[address](AT value) { return (int32)value == address; })) {
debug("Used address %#06x twice when injecting hook\n", address);
}
usedAddresses.push_back((int32)address);
DWORD dwProtect[2];
switch ( nType )
{
case PATCH_JUMP:
VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
*(BYTE*)address = 0xE9;
break;
case PATCH_CALL:
VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
*(BYTE*)address = 0xE8;
break;
default:
VirtualProtect((void*)((DWORD)address + 1), 4, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
break;
}
DWORD dwHook;
_asm
{
mov eax, hook
mov dwHook, eax
}
*(ptrdiff_t*)((DWORD)address + 1) = (DWORD)dwHook - (DWORD)address - 5;
if ( nType == PATCH_NOTHING )
VirtualProtect((void*)((DWORD)address + 1), 4, dwProtect[0], &dwProtect[1]);
else
VirtualProtect((void*)address, 5, dwProtect[0], &dwProtect[1]);
}
inline void ExtractCall(void *dst, uint32_t a)
{
*(uint32_t*)dst = (uint32_t)(*(uint32_t*)(a+1) + a + 5);
}
template<typename T>
inline void InterceptCall(void *dst, T func, uint32_t a)
{
ExtractCall(dst, a);
InjectHook(a, func);
}
template<typename T>
inline void InterceptVmethod(void *dst, T func, uint32_t a)
{
*(uint32_t*)dst = *(uint32_t*)a;
Patch(a, func);
}
#define STARTPATCHES static StaticPatcher Patcher([](){
#define ENDPATCHES });

381
src/core/re3.cpp Normal file
View File

@ -0,0 +1,381 @@
#include <direct.h>
#include <csignal>
#include <windows.h>
#include "common.h"
#include "patcher.h"
#include "Renderer.h"
#include "Credits.h"
#include "Camera.h"
#include "Weather.h"
#include "Clock.h"
#include "World.h"
#include "Vehicle.h"
#include "Streaming.h"
#include "PathFind.h"
#include "Boat.h"
#include "Automobile.h"
#include "debugmenu_public.h"
#include <vector>
std::vector<int32> usedAddresses;
void **rwengine = *(void***)0x5A10E1;
DebugMenuAPI gDebugMenuAPI;
WRAPPER void *gtanew(uint32 sz) { EAXJMP(0x5A0690); }
WRAPPER void gtadelete(void *p) { EAXJMP(0x5A07E0); }
// overload our own new/delete with GTA's functions
void *operator new(size_t sz) { return gtanew(sz); }
void operator delete(void *ptr) noexcept { gtadelete(ptr); }
#ifdef USE_PS2_RAND
unsigned __int64 myrand_seed = 1;
#else
unsigned long int myrand_seed = 1;
#endif
int
myrand(void)
{
#ifdef USE_PS2_RAND
// Use our own implementation of rand, stolen from PS2
myrand_seed = 0x5851F42D4C957F2D * myrand_seed + 1;
return ((myrand_seed >> 32) & 0x7FFFFFFF);
#else
// or original codewarrior rand
myrand_seed = myrand_seed * 1103515245 + 12345;
return((myrand_seed >> 16) & 0x7FFF);
#endif
}
void
mysrand(unsigned int seed)
{
myrand_seed = seed;
}
int (*open_script_orig)(const char *path, const char *mode);
int
open_script(const char *path, const char *mode)
{
static int scriptToLoad = 1;
if(GetAsyncKeyState('G') & 0x8000)
scriptToLoad = 0;
if(GetAsyncKeyState('R') & 0x8000)
scriptToLoad = 1;
if(GetAsyncKeyState('D') & 0x8000)
scriptToLoad = 2;
switch(scriptToLoad){
case 0: return open_script_orig(path, mode);
case 1: return open_script_orig("main_freeroam.scm", mode);
case 2: return open_script_orig("main_d.scm", mode);
}
return open_script_orig(path, mode);
}
int gDbgSurf;
void (*DebugMenuProcess)(void);
void (*DebugMenuRender)(void);
static void stub(void) { }
void
DebugMenuInit(void)
{
if(DebugMenuLoad()){
DebugMenuProcess = (void(*)(void))GetProcAddress(gDebugMenuAPI.module, "DebugMenuProcess");
DebugMenuRender = (void(*)(void))GetProcAddress(gDebugMenuAPI.module, "DebugMenuRender");
}
if(DebugMenuProcess == nil || DebugMenuRender == nil){
DebugMenuProcess = stub;
DebugMenuRender = stub;
}
}
void WeaponCheat();
void HealthCheat();
void TankCheat();
void BlowUpCarsCheat();
void ChangePlayerCheat();
void MayhemCheat();
void EverybodyAttacksPlayerCheat();
void WeaponsForAllCheat();
void FastTimeCheat();
void SlowTimeCheat();
void MoneyCheat();
void ArmourCheat();
void WantedLevelUpCheat();
void WantedLevelDownCheat();
void SunnyWeatherCheat();
void CloudyWeatherCheat();
void RainyWeatherCheat();
void FoggyWeatherCheat();
void FastWeatherCheat();
void OnlyRenderWheelsCheat();
void ChittyChittyBangBangCheat();
void StrongGripCheat();
void NastyLimbsCheat();
// needs too much stuff for now
#if 0
void
spawnCar(int id)
{
CVector playerpos;
CStreaming::RequestModel(id, 0);
CStreaming::LoadAllRequestedModels(false);
if(CStreaming::HasModelLoaded(id)){
FindPlayerCoors(playerpos);
int node = ThePaths.FindNodeClosestToCoors(playerpos, 0, 100.0f, false, false);
if(node < 0)
return;
CVehicle *v;
if(CModelInfo::IsBoatModel(id)){
// CBoat* boat = (CBoat*)CVehicle__new(0x484);
// boat = boat->ctor(id, 1);
// v = (CVehicle*)(boat);
}else{
// CAutomobile *au = (CAutomobile*)CVehicle__new(0x5A8);
// au = au->ctor(id, 1);
// v = (CVehicle*)au;
}
/*
// unlock doors
FIELD(int, v, 0x224) = 1;
// set player owned
FIELD(uint8, v, 0x1F7) |= 4;
DebugMenuEntrySetAddress(carCol1, &FIELD(uchar, v, 0x19C));
DebugMenuEntrySetAddress(carCol2, &FIELD(uchar, v, 0x19D));
//if(id == MODELID_ESPERANTO)
// FIELD(uchar, v, 0x19C) = 54;
v->matrix.matrix.pos.x = ThePaths.nodes[node].x;
v->matrix.matrix.pos.y = ThePaths.nodes[node].y;
v->matrix.matrix.pos.z = ThePaths.nodes[node].z + 4.0f;
float x = v->matrix.matrix.pos.x;
float y = v->matrix.matrix.pos.y;
float z = v->matrix.matrix.pos.z;
v->matrix.SetRotate(0.0f, 0.0f, 3.49f);
v->matrix.matrix.pos.x += x;
v->matrix.matrix.pos.y += y;
v->matrix.matrix.pos.z += z;
v->bfTypeStatus = v->bfTypeStatus & 7 | 0x20;
FIELD(int, v, 0x224) = 1;
*/
CWorld::Add(v);
}
}
#endif
void
DebugMenuPopulate(void)
{
if(DebugMenuLoad()){
static const char *weathers[] = {
"Sunny", "Cloudy", "Rainy", "Foggy"
};
DebugMenuEntry *e;
e = DebugMenuAddVar("Time & Weather", "Current Hour", &CClock::GetHoursRef(), nil, 1, 0, 23, nil);
DebugMenuEntrySetWrap(e, true);
e = DebugMenuAddVar("Time & Weather", "Current Minute", &CClock::GetMinutesRef(),
[](){ CWeather::InterpolationValue = CClock::GetMinutes()/60.0f; }, 1, 0, 59, nil);
DebugMenuEntrySetWrap(e, true);
e = DebugMenuAddVar("Time & Weather", "Old Weather", (int16*)&CWeather::OldWeatherType, nil, 1, 0, 3, weathers);
DebugMenuEntrySetWrap(e, true);
e = DebugMenuAddVar("Time & Weather", "New Weather", (int16*)&CWeather::NewWeatherType, nil, 1, 0, 3, weathers);
DebugMenuEntrySetWrap(e, true);
DebugMenuAddVar("Time & Weather", "Wind", (float*)&CWeather::Wind, nil, 0.1f, 0.0f, 1.0f);
DebugMenuAddVar("Time & Weather", "Time scale", (float*)0x8F2C20, nil, 0.1f, 0.0f, 10.0f);
DebugMenuAddCmd("Cheats", "Weapons", WeaponCheat);
DebugMenuAddCmd("Cheats", "Money", MoneyCheat);
DebugMenuAddCmd("Cheats", "Health", HealthCheat);
DebugMenuAddCmd("Cheats", "Wanted level up", WantedLevelUpCheat);
DebugMenuAddCmd("Cheats", "Wanted level down", WantedLevelDownCheat);
DebugMenuAddCmd("Cheats", "Tank", TankCheat);
DebugMenuAddCmd("Cheats", "Blow up cars", BlowUpCarsCheat);
DebugMenuAddCmd("Cheats", "Change player", ChangePlayerCheat);
DebugMenuAddCmd("Cheats", "Mayhem", MayhemCheat);
DebugMenuAddCmd("Cheats", "Everybody attacks player", EverybodyAttacksPlayerCheat);
DebugMenuAddCmd("Cheats", "Weapons for all", WeaponsForAllCheat);
DebugMenuAddCmd("Cheats", "Fast time", FastTimeCheat);
DebugMenuAddCmd("Cheats", "Slow time", SlowTimeCheat);
DebugMenuAddCmd("Cheats", "Armour", ArmourCheat);
DebugMenuAddCmd("Cheats", "Sunny weather", SunnyWeatherCheat);
DebugMenuAddCmd("Cheats", "Cloudy weather", CloudyWeatherCheat);
DebugMenuAddCmd("Cheats", "Rainy weather", RainyWeatherCheat);
DebugMenuAddCmd("Cheats", "Foggy weather", FoggyWeatherCheat);
DebugMenuAddCmd("Cheats", "Fast weather", FastWeatherCheat);
DebugMenuAddCmd("Cheats", "Only render wheels", OnlyRenderWheelsCheat);
DebugMenuAddCmd("Cheats", "Chitty chitty bang bang", ChittyChittyBangBangCheat);
DebugMenuAddCmd("Cheats", "Strong grip", StrongGripCheat);
DebugMenuAddCmd("Cheats", "Nasty limbs", NastyLimbsCheat);
DebugMenuAddVarBool8("Debug", "Show Ped Road Groups", (int8*)&gbShowPedRoadGroups, nil);
DebugMenuAddVarBool8("Debug", "Show Car Road Groups", (int8*)&gbShowCarRoadGroups, nil);
DebugMenuAddVarBool8("Debug", "Show Collision Polys", (int8*)&gbShowCollisionPolys, nil);
DebugMenuAddVarBool8("Debug", "Don't render Buildings", (int8*)&gbDontRenderBuildings, nil);
DebugMenuAddVarBool8("Debug", "Don't render Big Buildings", (int8*)&gbDontRenderBigBuildings, nil);
DebugMenuAddVarBool8("Debug", "Don't render Peds", (int8*)&gbDontRenderPeds, nil);
DebugMenuAddVarBool8("Debug", "Don't render Objects", (int8*)&gbDontRenderObjects, nil);
DebugMenuAddVar("Debug", "Dbg Surface", &gDbgSurf, nil, 1, 0, 34, nil);
DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start);
DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop);
}
}
/*
int (*RsEventHandler_orig)(int a, int b);
int
delayedPatches10(int a, int b)
{
DebugMenuInit();
DebugMenuPopulate();
return RsEventHandler_orig(a, b);
}
*/
void __declspec(naked) HeadlightsFix()
{
static const float fMinusOne = -1.0f;
_asm
{
fld [esp+708h-690h]
fcomp fMinusOne
fnstsw ax
and ah, 5
cmp ah, 1
jnz HeadlightsFix_DontLimit
fld fMinusOne
fstp [esp+708h-690h]
HeadlightsFix_DontLimit:
fld [esp+708h-690h]
fabs
fld st
push 0x5382F2
retn
}
}
const int re3_buffsize = 1024;
static char re3_buff[re3_buffsize];
void re3_assert(const char *expr, const char *filename, unsigned int lineno, const char *func)
{
int nCode;
strcpy_s(re3_buff, re3_buffsize, "Assertion failed!" );
strcat_s(re3_buff, re3_buffsize, "\n" );
strcat_s(re3_buff, re3_buffsize, "File: ");
strcat_s(re3_buff, re3_buffsize, filename );
strcat_s(re3_buff, re3_buffsize, "\n" );
strcat_s(re3_buff, re3_buffsize, "Line: " );
_itoa_s( lineno, re3_buff + strlen(re3_buff), re3_buffsize - strlen(re3_buff), 10 );
strcat_s(re3_buff, re3_buffsize, "\n");
strcat_s(re3_buff, re3_buffsize, "Function: ");
strcat_s(re3_buff, re3_buffsize, func );
strcat_s(re3_buff, re3_buffsize, "\n" );
strcat_s(re3_buff, re3_buffsize, "Expression: ");
strcat_s(re3_buff, re3_buffsize, expr);
strcat_s(re3_buff, re3_buffsize, "\n");
strcat_s(re3_buff, re3_buffsize, "\n" );
strcat_s(re3_buff, re3_buffsize, "(Press Retry to debug the application)");
nCode = ::MessageBoxA(nil, re3_buff, "RE3 Assertion Failed!",
MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL);
if (nCode == IDABORT)
{
raise(SIGABRT);
_exit(3);
}
if (nCode == IDRETRY)
{
__debugbreak();
return;
}
if (nCode == IDIGNORE)
return;
abort();
}
void re3_debug(char *format, ...)
{
va_list va;
va_start(va, format);
vsprintf_s(re3_buff, re3_buffsize, format, va);
va_end(va);
printf("%s", re3_buff);
}
void re3_trace(const char *filename, unsigned int lineno, const char *func, char *format, ...)
{
char buff[re3_buffsize *2];
va_list va;
va_start(va, format);
vsprintf_s(re3_buff, re3_buffsize, format, va);
va_end(va);
sprintf_s(buff, re3_buffsize * 2, "[%s.%s:%d]: %s", filename, func, lineno, re3_buff);
OutputDebugStringA(buff);
}
void
patch()
{
StaticPatcher::Apply();
// Patch<float>(0x46BC61+6, 1.0f); // car distance
InjectHook(0x59E460, printf, PATCH_JUMP);
InjectHook(0x475E00, printf, PATCH_JUMP); // _Error
// stolen from silentpatch (sorry)
Patch<WORD>(0x5382BF, 0x0EEB);
InjectHook(0x5382EC, HeadlightsFix, PATCH_JUMP);
InterceptCall(&open_script_orig, open_script, 0x438869);
// InterceptCall(&RsEventHandler_orig, delayedPatches10, 0x58275E);
}
BOOL WINAPI
DllMain(HINSTANCE hInst, DWORD reason, LPVOID)
{
if(reason == DLL_PROCESS_ATTACH){
AllocConsole();
freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
if (*(DWORD*)0x5C1E75 == 0xB85548EC) // 1.0
patch();
else
return FALSE;
}
return TRUE;
}

415
src/core/rw.cpp Normal file
View File

@ -0,0 +1,415 @@
#include "common.h"
#include "patcher.h"
#include "rwcore.h"
#include "rpworld.h"
#include "rpmatfx.h"
#include "rpskin.h"
#include "rphanim.h"
#include "rtbmp.h"
typedef RwV3d *(*rwVectorsMultFn) (RwV3d * pointsOut,
const RwV3d * pointsIn,
RwInt32 numPoints,
const RwMatrix * matrix);
WRAPPER void _rwObjectHasFrameSetFrame(void* object, RwFrame* frame) { EAXJMP(0x5BC950); }
WRAPPER RpAtomic* AtomicDefaultRenderCallBack(RpAtomic* atomic) { EAXJMP(0x59E690); }
WRAPPER void _rpAtomicResyncInterpolatedSphere(RpAtomic* atomic) { EAXJMP(0x59E6C0); }
WRAPPER RwSphere const* RpAtomicGetWorldBoundingSphere(RpAtomic* atomic) { EAXJMP(0x59E800); }
WRAPPER RwInt32 RpClumpGetNumAtomics(RpClump* clump) { EAXJMP(0x59ED50); }
WRAPPER RpClump* RpClumpRender(RpClump* clump) { EAXJMP(0x59ED80); }
WRAPPER RpClump* RpClumpForAllAtomics(RpClump* clump, RpAtomicCallBack callback, void* pData) { EAXJMP(0x59EDD0); }
WRAPPER RpClump* RpClumpForAllCameras(RpClump* clump, RwCameraCallBack callback, void* pData) { EAXJMP(0x59EE10); }
WRAPPER RpClump* RpClumpForAllLights(RpClump* clump, RpLightCallBack callback, void* pData) { EAXJMP(0x59EE60); }
WRAPPER RpAtomic* RpAtomicCreate() { EAXJMP(0x59EEB0); }
WRAPPER RpAtomic* RpAtomicSetGeometry(RpAtomic* atomic, RpGeometry* geometry, RwUInt32 flags) { EAXJMP(0x59EFA0); }
WRAPPER RwBool RpAtomicDestroy(RpAtomic* atomic) { EAXJMP(0x59F020); }
WRAPPER RpAtomic* RpAtomicClone(RpAtomic* atomic) { EAXJMP(0x59F0A0); }
WRAPPER RpClump* RpClumpClone(RpClump* clump) { EAXJMP(0x59F1B0); }
WRAPPER RpClump* RpClumpCreate() { EAXJMP(0x59F490); }
WRAPPER RwBool RpClumpDestroy(RpClump* clump) { EAXJMP(0x59F500); }
WRAPPER RpClump* RpClumpAddAtomic(RpClump* clump, RpAtomic* atomic) { EAXJMP(0x59F680); }
WRAPPER RpClump* RpClumpRemoveAtomic(RpClump* clump, RpAtomic* atomic) { EAXJMP(0x59F6B0); }
WRAPPER RpClump* RpClumpRemoveLight(RpClump* clump, RpLight* light) { EAXJMP(0x59F6E0); }
WRAPPER RpClump* RpClumpStreamRead(RwStream* stream) { EAXJMP(0x59FC50); }
WRAPPER RwInt32 RpAtomicRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5A0510); }
WRAPPER RwInt32 RpClumpRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5A0540); }
WRAPPER RwInt32 RpAtomicRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5A0570); }
WRAPPER RwInt32 RpAtomicSetStreamAlwaysCallBack(RwUInt32 pluginID, RwPluginDataChunkAlwaysCallBack alwaysCB) { EAXJMP(0x5A05A0); }
WRAPPER RwInt32 RpAtomicSetStreamRightsCallBack(RwUInt32 pluginID, RwPluginDataChunkRightsCallBack rightsCB) { EAXJMP(0x5A05C0); }
WRAPPER RwInt32 RpAtomicGetPluginOffset(RwUInt32 pluginID) { EAXJMP(0x5A05E0); }
WRAPPER RpAtomic* RpAtomicSetFrame(RpAtomic* atomic, RwFrame* frame) { EAXJMP(0x5A0600); }
WRAPPER RwInt32 RwEngineRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor initCB, RwPluginObjectDestructor termCB) { EAXJMP(0x5A0DC0); }
WRAPPER RwInt32 RwEngineGetPluginOffset(RwUInt32 pluginID) { EAXJMP(0x5A0DF0); }
WRAPPER RwInt32 RwEngineGetNumSubSystems() { EAXJMP(0x5A0E10); }
WRAPPER RwSubSystemInfo* RwEngineGetSubSystemInfo(RwSubSystemInfo* subSystemInfo, RwInt32 subSystemIndex) { EAXJMP(0x5A0E40); }
WRAPPER RwInt32 RwEngineGetCurrentSubSystem() { EAXJMP(0x5A0E70); }
WRAPPER RwBool RwEngineSetSubSystem(RwInt32 subSystemIndex) { EAXJMP(0x5A0EA0); }
WRAPPER RwInt32 RwEngineGetNumVideoModes() { EAXJMP(0x5A0ED0); }
WRAPPER RwVideoMode* RwEngineGetVideoModeInfo(RwVideoMode* modeinfo, RwInt32 modeIndex) { EAXJMP(0x5A0F00); }
WRAPPER RwInt32 RwEngineGetCurrentVideoMode() { EAXJMP(0x5A0F30); }
WRAPPER RwBool RwEngineSetVideoMode(RwInt32 modeIndex) { EAXJMP(0x5A0F60); }
WRAPPER RwBool RwEngineStop() { EAXJMP(0x5A0F90); }
WRAPPER RwBool RwEngineStart() { EAXJMP(0x5A0FE0); }
WRAPPER RwBool RwEngineClose() { EAXJMP(0x5A1070); }
WRAPPER RwBool RwEngineOpen(RwEngineOpenParams* initParams) { EAXJMP(0x5A10E0); }
WRAPPER RwBool RwEngineTerm() { EAXJMP(0x5A1290); }
WRAPPER RwBool RwEngineInit(RwMemoryFunctions* memFuncs, RwUInt32 initFlags, RwUInt32 resArenaSize) { EAXJMP(0x5A12D0); }
WRAPPER void* _rwFrameOpen(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A15E0); }
WRAPPER void* _rwFrameClose(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A1650); }
WRAPPER RwFrame* _rwFrameCloneAndLinkClones(RwFrame* root) { EAXJMP(0x5A1690); }
WRAPPER RwFrame* _rwFramePurgeClone(RwFrame* root) { EAXJMP(0x5A1880); }
WRAPPER RwBool RwFrameDirty(RwFrame const* frame) { EAXJMP(0x5A1930); }
WRAPPER void _rwFrameInit(RwFrame* frame) { EAXJMP(0x5A1950); }
WRAPPER RwFrame* RwFrameCreate() { EAXJMP(0x5A1A00); }
WRAPPER RwBool RwFrameDestroy(RwFrame* frame) { EAXJMP(0x5A1A30); }
WRAPPER RwBool RwFrameDestroyHierarchy(RwFrame* frame) { EAXJMP(0x5A1BF0); }
WRAPPER RwFrame* RwFrameUpdateObjects(RwFrame* frame) { EAXJMP(0x5A1C60); }
WRAPPER RwMatrix* RwFrameGetLTM(RwFrame* frame) { EAXJMP(0x5A1CE0); }
WRAPPER RwFrame* RwFrameAddChild(RwFrame* parent, RwFrame* child) { EAXJMP(0x5A1D00); }
WRAPPER RwFrame* RwFrameRemoveChild(RwFrame* child) { EAXJMP(0x5A1ED0); }
WRAPPER RwFrame* RwFrameForAllChildren(RwFrame* frame, RwFrameCallBack callBack, void* data) { EAXJMP(0x5A1FC0); }
WRAPPER RwFrame* RwFrameTranslate(RwFrame* frame, RwV3d const* v, RwOpCombineType combine) { EAXJMP(0x5A2000); }
WRAPPER RwFrame* RwFrameScale(RwFrame* frame, RwV3d const* v, RwOpCombineType combine) { EAXJMP(0x5A20A0); }
WRAPPER RwFrame* RwFrameTransform(RwFrame* frame, RwMatrix const* m, RwOpCombineType combine) { EAXJMP(0x5A2140); }
WRAPPER RwFrame* RwFrameRotate(RwFrame* frame, RwV3d const* axis, RwReal angle, RwOpCombineType combine) { EAXJMP(0x5A21E0); }
WRAPPER RwFrame* RwFrameSetIdentity(RwFrame* frame) { EAXJMP(0x5A2280); }
WRAPPER RwFrame* RwFrameForAllObjects(RwFrame* frame, RwObjectCallBack callBack, void* data) { EAXJMP(0x5A2340); }
WRAPPER RwInt32 RwFrameRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5A2380); }
WRAPPER RwBool _rwMatrixSetMultFn(rwMatrixMultFn multMat) { EAXJMP(0x5A23B0); }
WRAPPER RwReal _rwMatrixDeterminant(RwMatrix const* matrix) { EAXJMP(0x5A2520); }
WRAPPER RwReal _rwMatrixOrthogonalError(RwMatrix const* matrix) { EAXJMP(0x5A2570); }
WRAPPER RwReal _rwMatrixNormalError(RwMatrix const* matrix) { EAXJMP(0x5A25D0); }
WRAPPER RwReal _rwMatrixIdentityError(RwMatrix const* matrix) { EAXJMP(0x5A2660); }
WRAPPER void* _rwMatrixClose(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A2730); }
WRAPPER void* _rwMatrixOpen(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A2770); }
WRAPPER RwMatrix* RwMatrixOptimize(RwMatrix* matrix, RwMatrixTolerance const* tolerance) { EAXJMP(0x5A2820); }
WRAPPER RwMatrix* RwMatrixUpdate(RwMatrix* matrix) { EAXJMP(0x5A28E0); }
WRAPPER RwMatrix* RwMatrixMultiply(RwMatrix* matrixOut, RwMatrix const* MatrixIn1, RwMatrix const* matrixIn2) { EAXJMP(0x5A28F0); }
WRAPPER RwMatrix* RwMatrixRotateOneMinusCosineSine(RwMatrix* matrix, RwV3d const* unitAxis, RwReal oneMinusCosine, RwReal sine, RwOpCombineType combineOp) { EAXJMP(0x5A2960); }
WRAPPER RwMatrix* RwMatrixRotate(RwMatrix* matrix, RwV3d const* axis, RwReal angle, RwOpCombineType combineOp) { EAXJMP(0x5A2BF0); }
WRAPPER RwMatrix* RwMatrixInvert(RwMatrix* matrixOut, RwMatrix const* matrixIn) { EAXJMP(0x5A2C90); }
WRAPPER RwMatrix* RwMatrixScale(RwMatrix* matrix, RwV3d const* scale, RwOpCombineType combineOp) { EAXJMP(0x5A2EE0); }
WRAPPER RwMatrix* RwMatrixTranslate(RwMatrix* matrix, RwV3d const* translation, RwOpCombineType combineOp) { EAXJMP(0x5A3070); }
WRAPPER RwMatrix* RwMatrixTransform(RwMatrix* matrix, RwMatrix const* transform, RwOpCombineType combineOp) { EAXJMP(0x5A31C0); }
WRAPPER RwBool RwMatrixDestroy(RwMatrix* mpMat) { EAXJMP(0x5A3300); }
WRAPPER RwMatrix* RwMatrixCreate() { EAXJMP(0x5A3330); }
WRAPPER RwBool _rwVectorSetMultFn(rwVectorMultFn multPoint, rwVectorsMultFn multPoints, rwVectorMultFn multVector, rwVectorsMultFn multVectors) { EAXJMP(0x5A3450); }
WRAPPER RwReal _rwV3dNormalize(RwV3d* out, RwV3d const* in) { EAXJMP(0x5A3600); }
WRAPPER RwReal RwV3dLength(RwV3d const* in) { EAXJMP(0x5A36A0); }
WRAPPER RwReal _rwSqrt(RwReal const num) { EAXJMP(0x5A3710); }
WRAPPER RwReal _rwInvSqrt(RwReal const num) { EAXJMP(0x5A3770); }
WRAPPER RwV3d* RwV3dTransformPoints(RwV3d* pointsOut, RwV3d const* pointsIn, RwInt32 numPoints, RwMatrix const* matrix) { EAXJMP(0x5A37D0); }
WRAPPER RwV3d* RwV3dTransformVectors(RwV3d* vectorsOut, RwV3d const* vectorsIn, RwInt32 numPoints, RwMatrix const* matrix) { EAXJMP(0x5A37E0); }
WRAPPER void* _rwVectorClose(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A37F0); }
WRAPPER void* _rwVectorOpen(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A3860); }
WRAPPER RwUInt32 RwStreamRead(RwStream* stream, void* buffer, RwUInt32 length) { EAXJMP(0x5A3AD0); }
WRAPPER RwStream* RwStreamWrite(RwStream* stream, void const* buffer, RwUInt32 length) { EAXJMP(0x5A3C30); }
WRAPPER RwStream* RwStreamSkip(RwStream* stream, RwUInt32 offset) { EAXJMP(0x5A3DF0); }
WRAPPER RwBool RwStreamClose(RwStream* stream, void* pData) { EAXJMP(0x5A3F10); }
WRAPPER RwStream* RwStreamOpen(RwStreamType type, RwStreamAccessType accessType, void const* pData) { EAXJMP(0x5A3FE0); }
WRAPPER RwReal RwIm2DGetNearScreenZ() { EAXJMP(0x5A43A0); }
WRAPPER RwReal RwIm2DGetFarScreenZ() { EAXJMP(0x5A43B0); }
WRAPPER RwBool RwRenderStateSet(RwRenderState state, void* value) { EAXJMP(0x5A43C0); }
WRAPPER RwBool RwRenderStateGet(RwRenderState state, void* value) { EAXJMP(0x5A4410); }
WRAPPER RwBool RwIm2DRenderLine(RwIm2DVertex* vertices, RwInt32 numVertices, RwInt32 vert1, RwInt32 vert2) { EAXJMP(0x5A4420); }
WRAPPER RwBool RwIm2DRenderPrimitive(RwPrimitiveType primType, RwIm2DVertex* vertices, RwInt32 numVertices) { EAXJMP(0x5A4430); }
WRAPPER RwBool RwIm2DRenderIndexedPrimitive(RwPrimitiveType primType, RwIm2DVertex* vertices, RwInt32 numVertices, RwImVertexIndex* indices, RwInt32 numIndices) { EAXJMP(0x5A4440); }
WRAPPER RwCamera* RwCameraEndUpdate(RwCamera* camera) { EAXJMP(0x5A5020); }
WRAPPER RwCamera* RwCameraBeginUpdate(RwCamera* camera) { EAXJMP(0x5A5030); }
WRAPPER RwCamera* RwCameraSetViewOffset(RwCamera* camera, RwV2d const* offset) { EAXJMP(0x5A5040); }
WRAPPER RwCamera* RwCameraSetNearClipPlane(RwCamera* camera, RwReal nearClip) { EAXJMP(0x5A5070); }
WRAPPER RwCamera* RwCameraSetFarClipPlane(RwCamera* camera, RwReal farClip) { EAXJMP(0x5A5140); }
WRAPPER RwFrustumTestResult RwCameraFrustumTestSphere(RwCamera const* camera, RwSphere const* sphere) { EAXJMP(0x5A5170); }
WRAPPER RwCamera* RwCameraClear(RwCamera* camera, RwRGBA* colour, RwInt32 clearMode) { EAXJMP(0x5A51E0); }
WRAPPER RwCamera* RwCameraShowRaster(RwCamera* camera, void* pDev, RwUInt32 flags) { EAXJMP(0x5A5210); }
WRAPPER RwCamera* RwCameraSetProjection(RwCamera* camera, RwCameraProjection projection) { EAXJMP(0x5A5240); }
WRAPPER RwCamera* RwCameraSetViewWindow(RwCamera* camera, RwV2d const* viewWindow) { EAXJMP(0x5A52B0); }
WRAPPER RwInt32 RwCameraRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5A52F0); }
WRAPPER RwBool RwCameraDestroy(RwCamera* camera) { EAXJMP(0x5A5320); }
WRAPPER RwCamera* RwCameraCreate() { EAXJMP(0x5A5360); }
WRAPPER RwBool RwTextureSetMipmapping(RwBool enable) { EAXJMP(0x5A7100); }
WRAPPER RwBool RwTextureGetMipmapping() { EAXJMP(0x5A7120); }
WRAPPER RwBool RwTextureSetAutoMipmapping(RwBool enable) { EAXJMP(0x5A7130); }
WRAPPER RwBool RwTextureGetAutoMipmapping() { EAXJMP(0x5A7150); }
WRAPPER RwTexDictionary* RwTexDictionaryCreate() { EAXJMP(0x5A7160); }
WRAPPER RwBool RwTexDictionaryDestroy(RwTexDictionary* dict) { EAXJMP(0x5A7200); }
WRAPPER RwTexDictionary const* RwTexDictionaryForAllTextures(RwTexDictionary const* dict, RwTextureCallBack fpCallBack, void* pData) { EAXJMP(0x5A7290); }
WRAPPER RwTexture* RwTextureCreate(RwRaster* raster) { EAXJMP(0x5A72D0); }
WRAPPER RwBool RwTextureDestroy(RwTexture* texture) { EAXJMP(0x5A7330); }
WRAPPER RwTexture* RwTextureSetName(RwTexture* texture, RwChar const* name) { EAXJMP(0x5A73B0); }
WRAPPER RwTexture* RwTextureSetMaskName(RwTexture* texture, RwChar const* maskName) { EAXJMP(0x5A7420); }
WRAPPER RwTexture* RwTexDictionaryAddTexture(RwTexDictionary* dict, RwTexture* texture) { EAXJMP(0x5A7490); }
WRAPPER RwTexture* RwTexDictionaryFindNamedTexture(RwTexDictionary* dict, RwChar const* name) { EAXJMP(0x5A74D0); }
WRAPPER RwTexDictionary* RwTexDictionarySetCurrent(RwTexDictionary* dict) { EAXJMP(0x5A7550); }
WRAPPER RwTexDictionary* RwTexDictionaryGetCurrent() { EAXJMP(0x5A7570); }
WRAPPER RwTexture* RwTextureRead(RwChar const* name, RwChar const* maskName) { EAXJMP(0x5A7580); }
WRAPPER RwBool RwTextureRasterGenerateMipmaps(RwRaster* raster, RwImage* image) { EAXJMP(0x5A7780); }
WRAPPER RwImage* RwImageCreate(RwInt32 width, RwInt32 height, RwInt32 depth) { EAXJMP(0x5A9120); }
WRAPPER RwBool RwImageDestroy(RwImage* image) { EAXJMP(0x5A9180); }
WRAPPER RwImage* RwImageAllocatePixels(RwImage* image) { EAXJMP(0x5A91E0); }
WRAPPER RwImage* RwImageFreePixels(RwImage* image) { EAXJMP(0x5A92A0); }
WRAPPER RwImage* RwImageMakeMask(RwImage* image) { EAXJMP(0x5A92D0); }
WRAPPER RwImage* RwImageApplyMask(RwImage* image, RwImage const* mask) { EAXJMP(0x5A93A0); }
WRAPPER RwChar const* RwImageSetPath(RwChar const* path) { EAXJMP(0x5A9750); }
WRAPPER RwImage* RwImageRead(RwChar const* imageName) { EAXJMP(0x5A9810); }
WRAPPER RwChar const* RwImageFindFileType(RwChar const* imageName) { EAXJMP(0x5A9B40); }
WRAPPER RwImage* RwImageReadMaskedImage(RwChar const* imageName, RwChar const* maskname) { EAXJMP(0x5A9C10); }
WRAPPER RwImage* RwImageCopy(RwImage* destImage, RwImage const* sourceImage) { EAXJMP(0x5A9F50); }
WRAPPER RwImage* RwImageGammaCorrect(RwImage* image) { EAXJMP(0x5AA130); }
WRAPPER RwBool RwImageSetGamma(RwReal gammaValue) { EAXJMP(0x5AA2C0); }
WRAPPER RwStream* _rwStreamWriteVersionedChunkHeader(RwStream* stream, RwInt32 type, RwInt32 size, RwUInt32 version, RwUInt32 buildNum) { EAXJMP(0x5AA4E0); }
WRAPPER RwBool RwStreamFindChunk(RwStream* stream, RwUInt32 type, RwUInt32* lengthOut, RwUInt32* versionOut) { EAXJMP(0x5AA540); }
WRAPPER void* RwMemLittleEndian32(void* mem, RwUInt32 size) { EAXJMP(0x5AA640); }
WRAPPER void* RwMemNative32(void* mem, RwUInt32 size) { EAXJMP(0x5AA650); }
WRAPPER void* RwMemFloat32ToReal(void* mem, RwUInt32 size) { EAXJMP(0x5AA660); }
WRAPPER RwStream* RwStreamWriteReal(RwStream* stream, RwReal const* reals, RwUInt32 numBytes) { EAXJMP(0x5AA680); }
WRAPPER RwStream* RwStreamWriteInt32(RwStream* stream, RwInt32 const* ints, RwUInt32 numBytes) { EAXJMP(0x5AA720); }
WRAPPER RwStream* RwStreamReadReal(RwStream* stream, RwReal* reals, RwUInt32 numBytes) { EAXJMP(0x5AA740); }
WRAPPER RwStream* RwStreamReadInt32(RwStream* stream, RwInt32* ints, RwUInt32 numBytes) { EAXJMP(0x5AA7B0); }
WRAPPER RwUInt32 RwTextureStreamGetSize(RwTexture const* texture) { EAXJMP(0x5AA800); }
WRAPPER RwTexture const* RwTextureStreamWrite(RwTexture const* texture, RwStream* stream) { EAXJMP(0x5AA870); }
WRAPPER RwTexture* RwTextureStreamRead(RwStream* stream) { EAXJMP(0x5AAA40); }
WRAPPER RwTexDictionary const* RwTexDictionaryStreamWrite(RwTexDictionary const* texDict, RwStream* stream) { EAXJMP(0x5AB020); }
WRAPPER RpMorphTarget const* RpMorphTargetCalcBoundingSphere(RpMorphTarget const* morphTarget, RwSphere* boundingSphere) { EAXJMP(0x5AC890); }
WRAPPER RwInt32 RpGeometryAddMorphTargets(RpGeometry* geometry, RwInt32 mtcount) { EAXJMP(0x5AC9A0); }
WRAPPER RpGeometry const* RpGeometryTriangleSetVertexIndices(RpGeometry const* geometry, RpTriangle* triangle, RwUInt16 vert1, RwUInt16 vert2, RwUInt16 vert3) { EAXJMP(0x5ACB60); }
WRAPPER RpGeometry* RpGeometryTriangleSetMaterial(RpGeometry* geometry, RpTriangle* triangle, RpMaterial* material) { EAXJMP(0x5ACB90); }
WRAPPER RpGeometry* RpGeometryForAllMaterials(RpGeometry* geometry, RpMaterialCallBack fpCallBack, void* pData) { EAXJMP(0x5ACBF0); }
WRAPPER RpGeometry* RpGeometryLock(RpGeometry* geometry, RwInt32 lockMode) { EAXJMP(0x5ACC30); }
WRAPPER RpGeometry* RpGeometryUnlock(RpGeometry* geometry) { EAXJMP(0x5ACC60); }
WRAPPER RpGeometry* RpGeometryCreate(RwInt32 numVert, RwInt32 numTriangles, RwUInt32 format) { EAXJMP(0x5ACD10); }
WRAPPER RpGeometry* _rpGeometryAddRef(RpGeometry* geometry) { EAXJMP(0x5ACF40); }
WRAPPER RwBool RpGeometryDestroy(RpGeometry* geometry) { EAXJMP(0x5ACF50); }
WRAPPER RwInt32 RpGeometryRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5ACFF0); }
WRAPPER RwInt32 RpGeometryRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5AD020); }
WRAPPER RpGeometry* RpGeometryStreamRead(RwStream* stream) { EAXJMP(0x5AD050); }
WRAPPER RwRaster* RwRasterGetCurrentContext() { EAXJMP(0x5AD6D0); }
WRAPPER RwRaster* RwRasterUnlock(RwRaster* raster) { EAXJMP(0x5AD6F0); }
WRAPPER RwRaster* RwRasterRenderFast(RwRaster* raster, RwInt32 x, RwInt32 y) { EAXJMP(0x5AD710); }
WRAPPER RwRaster* RwRasterUnlockPalette(RwRaster* raster) { EAXJMP(0x5AD750); }
WRAPPER RwBool RwRasterDestroy(RwRaster* raster) { EAXJMP(0x5AD780); }
WRAPPER RwRaster* RwRasterPushContext(RwRaster* raster) { EAXJMP(0x5AD7C0); }
WRAPPER RwInt32 RwRasterRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5AD810); }
WRAPPER RwUInt8* RwRasterLockPalette(RwRaster* raster, RwInt32 lockMode) { EAXJMP(0x5AD840); }
WRAPPER RwRaster* RwRasterPopContext() { EAXJMP(0x5AD870); }
WRAPPER RwInt32 RwRasterGetNumLevels(RwRaster* raster) { EAXJMP(0x5AD8C0); }
WRAPPER RwRaster* RwRasterShowRaster(RwRaster* raster, void* dev, RwUInt32 flags) { EAXJMP(0x5AD900); }
WRAPPER RwRaster* RwRasterCreate(RwInt32 width, RwInt32 height, RwInt32 depth, RwInt32 flags) { EAXJMP(0x5AD930); }
WRAPPER RwUInt8* RwRasterLock(RwRaster* raster, RwUInt8 level, RwInt32 lockMode) { EAXJMP(0x5AD9D0); }
WRAPPER RpMaterial* RpMaterialCreate() { EAXJMP(0x5ADC30); }
WRAPPER RwBool RpMaterialDestroy(RpMaterial* material) { EAXJMP(0x5ADCB0); }
WRAPPER RpMaterial* RpMaterialSetTexture(RpMaterial* material, RwTexture* texture) { EAXJMP(0x5ADD10); }
WRAPPER RwInt32 RpMaterialRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5ADD40); }
WRAPPER RwInt32 RpMaterialRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5ADD70); }
WRAPPER RpMaterial* RpMaterialStreamRead(RwStream* stream) { EAXJMP(0x5ADDA0); }
WRAPPER RpWorldSector* _rpSectorDefaultRenderCallBack(RpWorldSector* sector) { EAXJMP(0x5AE0B0); }
WRAPPER RwBool _rpWorldForAllGlobalLights(RpLightCallBack callBack, void* pData) { EAXJMP(0x5AE100); }
WRAPPER RpWorldSector* _rpWorldSectorForAllLocalLights(RpWorldSector* sector, RpLightCallBack callBack, void* pData) { EAXJMP(0x5AE150); }
WRAPPER RpWorld* RpWorldUnlock(RpWorld* world) { EAXJMP(0x5AE190); }
WRAPPER RpWorld* RpWorldSectorGetWorld(RpWorldSector const* sector) { EAXJMP(0x5AE2B0); }
WRAPPER RwBool RpWorldDestroy(RpWorld* world) { EAXJMP(0x5AE340); }
WRAPPER RpWorld* RpWorldCreate(RwBBox* boundingBox) { EAXJMP(0x5AE6A0); }
WRAPPER RwInt32 RpWorldRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5AEA40); }
WRAPPER RwInt32 RpWorldRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5AEA70); }
WRAPPER RwBool RpWorldPluginAttach() { EAXJMP(0x5AEAA0); }
WRAPPER RpWorld* RpWorldAddCamera(RpWorld* world, RwCamera* camera) { EAXJMP(0x5AFB80); }
WRAPPER RpWorld* RpWorldRemoveCamera(RpWorld* world, RwCamera* camera) { EAXJMP(0x5AFBB0); }
WRAPPER RpWorld* RpAtomicGetWorld(RpAtomic const* atomic) { EAXJMP(0x5AFC10); }
WRAPPER RpWorld* RpWorldAddClump(RpWorld* world, RpClump* clump) { EAXJMP(0x5AFC20); }
WRAPPER RpWorld* RpWorldAddLight(RpWorld* world, RpLight* light) { EAXJMP(0x5AFDA0); }
WRAPPER RpWorld* RpWorldRemoveLight(RpWorld* world, RpLight* light) { EAXJMP(0x5AFDF0); }
WRAPPER RwImage* RtBMPImageRead(RwChar const* imageName) { EAXJMP(0x5AFE70); }
WRAPPER RwBool RpSkinPluginAttach() { EAXJMP(0x5B07D0); }
WRAPPER RpAtomic* RpSkinAtomicSetHAnimHierarchy(RpAtomic* atomic, RpHAnimHierarchy* hierarchy) { EAXJMP(0x5B1050); }
WRAPPER RpHAnimHierarchy* RpSkinAtomicGetHAnimHierarchy(RpAtomic const* atomic) { EAXJMP(0x5B1070); }
WRAPPER RpSkin* RpSkinGeometryGetSkin(RpGeometry* geometry) { EAXJMP(0x5B1080); }
WRAPPER RpGeometry* RpSkinGeometrySetSkin(RpGeometry* geometry, RpSkin* skin) { EAXJMP(0x5B1090); }
WRAPPER RwMatrix const* RpSkinGetSkinToBoneMatrices(RpSkin* skin) { EAXJMP(0x5B10D0); }
WRAPPER RpHAnimHierarchy* RpHAnimHierarchyCreate(RwInt32 numNodes, RwUInt32* nodeFlags, RwInt32* nodeIDs, RpHAnimHierarchyFlag flags, RwInt32 maxKeyFrameSize) { EAXJMP(0x5B10E0); }
WRAPPER RpHAnimHierarchy* RpHAnimFrameGetHierarchy(RwFrame* frame) { EAXJMP(0x5B11F0); }
WRAPPER RwBool RpHAnimHierarchySetCurrentAnim(RpHAnimHierarchy* hierarchy, RpHAnimAnimation* anim) { EAXJMP(0x5B1200); }
WRAPPER RwBool RpHAnimHierarchySubAnimTime(RpHAnimHierarchy* hierarchy, RwReal time) { EAXJMP(0x5B12B0); }
WRAPPER RwBool RpHAnimHierarchyAddAnimTime(RpHAnimHierarchy* hierarchy, RwReal time) { EAXJMP(0x5B1480); }
WRAPPER RwBool RpHAnimHierarchyUpdateMatrices(RpHAnimHierarchy* hierarchy) { EAXJMP(0x5B1780); }
WRAPPER RpHAnimAnimation* RpHAnimAnimationStreamRead(RwStream* stream) { EAXJMP(0x5B1C10); }
WRAPPER RwBool RpHAnimPluginAttach() { EAXJMP(0x5B1D50); }
WRAPPER RwBool RpMatFXPluginAttach() { EAXJMP(0x5B2640); }
WRAPPER RpAtomic* RpMatFXAtomicEnableEffects(RpAtomic* atomic) { EAXJMP(0x5B3750); }
WRAPPER RpMaterial* RpMatFXMaterialSetEffects(RpMaterial* material, RpMatFXMaterialFlags flags) { EAXJMP(0x5B3780); }
WRAPPER RpMaterial* RpMatFXMaterialSetupEnvMap(RpMaterial* material, RwTexture* texture, RwFrame* frame, RwBool useFrameBufferAlpha, RwReal coef) { EAXJMP(0x5B38D0); }
WRAPPER RpMaterial* RpMatFXMaterialSetBumpMapTexture(RpMaterial* material, RwTexture* texture) { EAXJMP(0x5B3A40); }
WRAPPER RwBool RwD3D8SetRenderState(RwUInt32 state, RwUInt32 value) { EAXJMP(0x5B3CF0); }
WRAPPER void RwD3D8GetRenderState(RwUInt32 state, void* value) { EAXJMP(0x5B3D40); }
WRAPPER RwBool RwD3D8SetTextureStageState(RwUInt32 stage, RwUInt32 type, RwUInt32 value) { EAXJMP(0x5B3D60); }
WRAPPER RwBool RwD3D8SetTexture(RwTexture* texture, RwUInt32 stage) { EAXJMP(0x5B53A0); }
WRAPPER void* RwIm3DTransform(RwIm3DVertex* pVerts, RwUInt32 numVerts, RwMatrix* ltm, RwUInt32 flags) { EAXJMP(0x5B6720); }
WRAPPER RwBool RwIm3DEnd() { EAXJMP(0x5B67F0); }
WRAPPER RwBool RwIm3DRenderIndexedPrimitive(RwPrimitiveType primType, RwImVertexIndex* indices, RwInt32 numIndices) { EAXJMP(0x5B6820); }
WRAPPER RwBool RwIm3DRenderLine(RwInt32 vert1, RwInt32 vert2) { EAXJMP(0x5B6980); }
WRAPPER RxPipeline* RwIm3DSetTransformPipeline(RxPipeline* pipeline) { EAXJMP(0x5B6A50); }
WRAPPER RxPipeline* RwIm3DSetRenderPipeline(RxPipeline* pipeline, RwPrimitiveType primType) { EAXJMP(0x5B6AC0); }
WRAPPER void RwD3D8EngineSetRefreshRate(RwUInt32 refreshRate) { EAXJMP(0x5B95D0); }
WRAPPER RwBool RwD3D8CameraAttachWindow(void* camera, void* hwnd) { EAXJMP(0x5B9640); }
WRAPPER RwBool RwD3D8DeviceSupportsDXTTexture() { EAXJMP(0x5BAEB0); }
WRAPPER RwBool RwD3D8SetVertexShader(RwUInt32 handle) { EAXJMP(0x5BAF90); }
WRAPPER RwBool RwD3D8SetPixelShader(RwUInt32 handle) { EAXJMP(0x5BAFD0); }
WRAPPER RwBool RwD3D8SetStreamSource(RwUInt32 streamNumber, void* streamData, RwUInt32 stride) { EAXJMP(0x5BB010); }
WRAPPER RwBool RwD3D8SetIndices(void* indexData, RwUInt32 baseVertexIndex) { EAXJMP(0x5BB060); }
WRAPPER RwBool RwD3D8DrawIndexedPrimitive(RwUInt32 primitiveType, RwUInt32 minIndex, RwUInt32 numVertices, RwUInt32 startIndex, RwUInt32 numIndices) { EAXJMP(0x5BB0B0); }
WRAPPER RwBool RwD3D8DrawPrimitive(RwUInt32 primitiveType, RwUInt32 startVertex, RwUInt32 numVertices) { EAXJMP(0x5BB140); }
WRAPPER RwBool RwD3D8SetTransform(RwUInt32 state, void const* matrix) { EAXJMP(0x5BB1D0); }
WRAPPER void RwD3D8GetTransform(RwUInt32 state, void* matrix) { EAXJMP(0x5BB310); }
WRAPPER RwBool RwD3D8SetTransformWorld(RwMatrix const* matrix) { EAXJMP(0x5BB340); }
WRAPPER RwBool RwD3D8SetSurfaceProperties(RwRGBA const* color, RwSurfaceProperties const* surfaceProps, RwBool modulate) { EAXJMP(0x5BB490); }
WRAPPER RwBool RwD3D8SetLight(RwInt32 index, void const* light) { EAXJMP(0x5BB7A0); }
WRAPPER RwBool RwD3D8EnableLight(RwInt32 index, RwBool enable) { EAXJMP(0x5BB890); }
WRAPPER RwBool RwD3D8DynamicVertexBufferCreate(RwUInt32 fvf, RwUInt32 size, void** vertexBuffer) { EAXJMP(0x5BB9F0); }
WRAPPER void RwD3D8DynamicVertexBufferDestroy(void* vertexBuffer) { EAXJMP(0x5BBAE0); }
WRAPPER RwBool RwD3D8IndexBufferCreate(RwUInt32 numIndices, void** indexBuffer) { EAXJMP(0x5BBB10); }
WRAPPER RwBool RwD3D8CreatePixelShader(RwUInt32 const* function, RwUInt32* handle) { EAXJMP(0x5BBB40); }
WRAPPER void RwD3D8DeletePixelShader(RwUInt32 handle) { EAXJMP(0x5BBB90); }
WRAPPER RwBool RwD3D8SetPixelShaderConstant(RwUInt32 registerAddress, void const* antData, RwUInt32 antCount) { EAXJMP(0x5BBC00); }
WRAPPER void const* RwD3D8GetCaps() { EAXJMP(0x5BBC30); }
WRAPPER RwBool RwD3D8CameraIsSphereFullyInsideFrustum(void const* camera, void const* sphere) { EAXJMP(0x5BBC40); }
WRAPPER RwBool RwD3D8CameraIsBBoxFullyInsideFrustum(void const* camera, void const* boundingBox) { EAXJMP(0x5BBCA0); }
WRAPPER RwBool RwD3D8DynamicVertexBufferLock(RwUInt32 vertexSize, RwUInt32 numVertex, void** vertexBufferOut, void** vertexDataOut, RwUInt32* baseIndexOut) { EAXJMP(0x5BBD30); }
WRAPPER RwBool RwD3D8DynamicVertexBufferUnlock(void* vertexBuffer) { EAXJMP(0x5BBEB0); }
WRAPPER RwBool _rwIntelSSEsupported() { EAXJMP(0x5BBED0); }
WRAPPER RwImage* RwImageSetFromRaster(RwImage* image, RwRaster* raster) { EAXJMP(0x5BBF10); }
WRAPPER RwRaster* RwRasterSetFromImage(RwRaster* raster, RwImage* image) { EAXJMP(0x5BBF50); }
WRAPPER RwImage* RwImageFindRasterFormat(RwImage* ipImage, RwInt32 nRasterType, RwInt32* npWidth, RwInt32* npHeight, RwInt32* npDepth, RwInt32* npFormat) { EAXJMP(0x5BBF80); }
WRAPPER RwInt32 RwFrameRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5BBFF0); }
WRAPPER rwFrameList* _rwFrameListDeinitialize(rwFrameList* frameList) { EAXJMP(0x5BC020); }
WRAPPER rwFrameList* _rwFrameListStreamRead(RwStream* stream, rwFrameList* fl) { EAXJMP(0x5BC050); }
WRAPPER RpLight* RpLightSetRadius(RpLight* light, RwReal radius) { EAXJMP(0x5BC300); }
WRAPPER RpLight* RpLightSetColor(RpLight* light, RwRGBAReal const* color) { EAXJMP(0x5BC320); }
WRAPPER RwReal RpLightGetConeAngle(RpLight const* light) { EAXJMP(0x5BC370); }
WRAPPER RwInt32 RpLightRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5BC5B0); }
WRAPPER RpLight* RpLightStreamRead(RwStream* stream) { EAXJMP(0x5BC5E0); }
WRAPPER RwBool RpLightDestroy(RpLight* light) { EAXJMP(0x5BC780); }
WRAPPER RpLight* RpLightCreate(RwInt32 type) { EAXJMP(0x5BC7C0); }
WRAPPER void _rwD3D8TexDictionaryEnableRasterFormatConversion(RwBool enable) { EAXJMP(0x5BE280); }
WRAPPER RwFileFunctions* RwOsGetFileInterface() { EAXJMP(0x5BF110); }
WRAPPER RwBool RwFreeListDestroy(RwFreeList* freelist) { EAXJMP(0x5C1720); }
WRAPPER RwFreeList* RwFreeListCreate(RwInt32 entrySize, RwInt32 entriesPerBlock, RwInt32 alignment) { EAXJMP(0x5C1790); }
WRAPPER RwInt32 RwFreeListPurge(RwFreeList* freelist) { EAXJMP(0x5C19F0); }
WRAPPER RwInt32 RwFreeListPurgeAllFreeLists() { EAXJMP(0x5C1B90); }
WRAPPER RwFreeList* RwFreeListForAllUsed(RwFreeList* freelist, RwFreeListCallBack fpCallBack, void* pData) { EAXJMP(0x5C1D40); }
WRAPPER RwBool _rxPipelineClose() { EAXJMP(0x5C2780); }
WRAPPER RwBool _rxPipelineOpen() { EAXJMP(0x5C27E0); }
WRAPPER RxHeap* RxHeapGetGlobalHeap() { EAXJMP(0x5C2AD0); }
WRAPPER RxPacket* RxPacketCreate(RxPipelineNode* node) { EAXJMP(0x5C2AE0); }
WRAPPER RxCluster* RxClusterSetExternalData(RxCluster* cluster, void* data, RwInt32 stride, RwInt32 numElements) { EAXJMP(0x5C2B10); }
WRAPPER RxCluster* RxClusterSetData(RxCluster* cluster, void* data, RwInt32 stride, RwInt32 numElements) { EAXJMP(0x5C2B70); }
WRAPPER RxCluster* RxClusterInitializeData(RxCluster* cluster, RwUInt32 numElements, RwUInt16 stride) { EAXJMP(0x5C2BD0); }
WRAPPER RxCluster* RxClusterResizeData(RxCluster* CurrentCluster, RwUInt32 NumElements) { EAXJMP(0x5C2C40); }
WRAPPER RxCluster* RxClusterLockWrite(RxPacket* packet, RwUInt32 clusterIndex, RxPipelineNode* node) { EAXJMP(0x5C2C90); }
WRAPPER RxPipeline* RxPipelineExecute(RxPipeline* pipeline, void* data, RwBool heapReset) { EAXJMP(0x5C2D60); }
WRAPPER RxPipeline* RxPipelineCreate() { EAXJMP(0x5C2E00); }
WRAPPER void _rxPipelineDestroy(RxPipeline* Pipeline) { EAXJMP(0x5C2E70); }
WRAPPER RwBool RwResourcesFreeResEntry(RwResEntry* entry) { EAXJMP(0x5C3080); }
WRAPPER void _rwResourcesPurge() { EAXJMP(0x5C30F0); }
WRAPPER RwResEntry* RwResourcesAllocateResEntry(void* owner, RwResEntry** ownerRef, RwInt32 size, RwResEntryDestroyNotify destroyNotify) { EAXJMP(0x5C3170); }
WRAPPER RwBool RwResourcesEmptyArena() { EAXJMP(0x5C3360); }
WRAPPER RwBool _rwPluginRegistryOpen() { EAXJMP(0x5C3450); }
WRAPPER RwBool _rwPluginRegistryClose() { EAXJMP(0x5C3480); }
WRAPPER RwInt32 _rwPluginRegistryGetPluginOffset(RwPluginRegistry const* reg, RwUInt32 pluginID) { EAXJMP(0x5C3590); }
WRAPPER RwInt32 _rwPluginRegistryAddPlugin(RwPluginRegistry* reg, RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5C35C0); }
WRAPPER RwPluginRegistry const* _rwPluginRegistryInitObject(RwPluginRegistry const* reg, void* object) { EAXJMP(0x5C37F0); }
WRAPPER RwPluginRegistry const* _rwPluginRegistryDeInitObject(RwPluginRegistry const* reg, void* object) { EAXJMP(0x5C3850); }
WRAPPER RwPluginRegistry const* _rwPluginRegistryCopyObject(RwPluginRegistry const* reg, void* dstObject, void const* srcObject) { EAXJMP(0x5C3880); }
WRAPPER RwError* RwErrorSet(RwError* code) { EAXJMP(0x5C3910); }
WRAPPER RwInt32 _rwerror(RwInt32 code, ...) { EAXJMP(0x5C3970); }
WRAPPER RwInt32 _rwPluginRegistryAddPluginStream(RwPluginRegistry* reg, RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5C3980); }
WRAPPER RwInt32 _rwPluginRegistryAddPlgnStrmlwysCB(RwPluginRegistry* reg, RwUInt32 pluginID, RwPluginDataChunkAlwaysCallBack alwaysCB) { EAXJMP(0x5C39C0); }
WRAPPER RwInt32 _rwPluginRegistryAddPlgnStrmRightsCB(RwPluginRegistry* reg, RwUInt32 pluginID, RwPluginDataChunkRightsCallBack rightsCB) { EAXJMP(0x5C39F0); }
WRAPPER RwPluginRegistry const* _rwPluginRegistryReadDataChunks(RwPluginRegistry const* reg, RwStream* stream, void* object) { EAXJMP(0x5C3A20); }
WRAPPER RwPluginRegistry const* _rwPluginRegistryInvokeRights(RwPluginRegistry const* reg, RwUInt32 id, void* obj, RwUInt32 extraData) { EAXJMP(0x5C3B50); }
WRAPPER RwInt32 _rwPluginRegistryGetSize(RwPluginRegistry const* reg, void const* object) { EAXJMP(0x5C3BA0); }
WRAPPER RwPluginRegistry const* _rwPluginRegistryWriteDataChunks(RwPluginRegistry const* reg, RwStream* stream, void const* object) { EAXJMP(0x5C3BE0); }
WRAPPER RwPluginRegistry const* _rwPluginRegistrySkipDataChunks(RwPluginRegistry const* reg, RwStream* stream) { EAXJMP(0x5C3CB0); }
WRAPPER RwCamera* RwCameraStreamRead(RwStream* stream) { EAXJMP(0x5C3D30); }
WRAPPER RwBBox* RwBBoxCalculate(RwBBox* boundBox, RwV3d const* verts, RwInt32 numVerts) { EAXJMP(0x5C5570); }
WRAPPER RwImage* RwImageResample(RwImage* dstImage, RwImage const* srcImage) { EAXJMP(0x5C72B0); }
WRAPPER RwImage* RwImageCreateResample(RwImage const* srcImage, RwInt32 width, RwInt32 height) { EAXJMP(0x5C7B30); }
WRAPPER RxRenderStateVector* RxRenderStateVectorSetDefaultRenderStateVector(RxRenderStateVector* rsvp) { EAXJMP(0x5D9240); }
WRAPPER RxRenderStateVector* RxRenderStateVectorCreate(RwBool current) { EAXJMP(0x5D9340); }
WRAPPER void RxRenderStateVectorDestroy(RxRenderStateVector* rsvp) { EAXJMP(0x5D9410); }
WRAPPER RxRenderStateVector* RxRenderStateVectorLoadDriverState(RxRenderStateVector* rsvp) { EAXJMP(0x5D9460); }
WRAPPER void _rxEmbeddedPacketBetweenPipelines(RxPipeline* fromPipeline, RxPipeline* toPipeline) { EAXJMP(0x5D95D0); }
WRAPPER RxPipelineNode* _rxEmbeddedPacketBetweenNodes(RxPipeline* pipeline, RxPipelineNode* nodeFrom, RwUInt32 whichOutput) { EAXJMP(0x5D9740); }
WRAPPER void _rxPacketDestroy(RxPacket* Packet) { EAXJMP(0x5D9810); }
WRAPPER RpMaterialList* _rpMaterialListDeinitialize(RpMaterialList* matList) { EAXJMP(0x5C8B10); }
WRAPPER RpMaterialList* _rpMaterialListInitialize(RpMaterialList* matList) { EAXJMP(0x5C8B70); }
WRAPPER RpMaterial* _rpMaterialListGetMaterial(RpMaterialList const* matList, RwInt32 matIndex) { EAXJMP(0x5C8B80); }
WRAPPER RwInt32 _rpMaterialListAppendMaterial(RpMaterialList* matList, RpMaterial* material) { EAXJMP(0x5C8B90); }
WRAPPER RwInt32 _rpMaterialListFindMaterialIndex(RpMaterialList const* matList, RpMaterial const* material) { EAXJMP(0x5C8C50); }
WRAPPER RpMaterialList* _rpMaterialListStreamRead(RwStream* stream, RpMaterialList* matList) { EAXJMP(0x5C8C80); }
WRAPPER RpMeshHeader* _rpMeshHeaderCreate(RwUInt32 size) { EAXJMP(0x5C8FE0); }
WRAPPER void* _rpMeshClose(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5C8FF0); }
WRAPPER void* _rpMeshOpen(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5C9020); }
WRAPPER RpBuildMesh* _rpBuildMeshCreate(RwUInt32 bufferSize) { EAXJMP(0x5C9140); }
WRAPPER RwBool _rpBuildMeshDestroy(RpBuildMesh* mesh) { EAXJMP(0x5C9220); }
WRAPPER RwBool _rpMeshDestroy(RpMeshHeader* mesh) { EAXJMP(0x5C9260); }
WRAPPER RpBuildMesh* _rpBuildMeshAddTriangle(RpBuildMesh* mesh, RpMaterial* material, RwInt32 vert1, RwInt32 vert2, RwInt32 vert3) { EAXJMP(0x5C92A0); }
WRAPPER RpMeshHeader* _rpMeshHeaderForAllMeshes(RpMeshHeader* meshHeader, RpMeshCallBack fpCallBack, void* pData) { EAXJMP(0x5C9380); }
WRAPPER RwStream* _rpMeshWrite(RpMeshHeader const* meshHeader, void const* object, RwStream* stream, RpMaterialList const* matList) { EAXJMP(0x5C93C0); }
WRAPPER RpMeshHeader* _rpMeshRead(RwStream* stream, void const* object, RpMaterialList const* matList) { EAXJMP(0x5C9510); }
WRAPPER RwInt32 _rpMeshSize(RpMeshHeader const* meshHeader, void const* object) { EAXJMP(0x5C96E0); }
WRAPPER RpMeshHeader* RpBuildMeshGenerateDefaultTriStrip(RpBuildMesh* buildmesh, void* data) { EAXJMP(0x5C9730); }
WRAPPER RpMeshHeader* _rpTriListMeshGenerate(RpBuildMesh* buildMesh, void* data) { EAXJMP(0x5CAE10); }
WRAPPER RpMeshHeader* _rpMeshOptimise(RpBuildMesh* buildmesh, RwUInt32 flags) { EAXJMP(0x5CB230); }
WRAPPER RwInt32 RpWorldSectorRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5CB2B0); }
WRAPPER RwInt32 RpWorldSectorRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5CB2E0); }
WRAPPER RxPipeline* RpWorldSetDefaultSectorPipeline(RxPipeline* pipeline) { EAXJMP(0x5CB630); }
WRAPPER RxPipeline* RpAtomicSetDefaultPipeline(RxPipeline* pipeline) { EAXJMP(0x5CB670); }
WRAPPER void RpHAnimStdKeyFrameToMatrix(RwMatrix* matrix, void* voidIFrame) { EAXJMP(0x5CDEE0); }
WRAPPER void RpHAnimStdKeyFrameInterpolate(void* voidOut, void* voidIn1, void* voidIn2, RwReal time) { EAXJMP(0x5CE000); }
WRAPPER void RpHAnimStdKeyFrameBlend(void* voidOut, void* voidIn1, void* voidIn2, RwReal alpha) { EAXJMP(0x5CE420); }
WRAPPER RpHAnimAnimation* RpHAnimStdKeyFrameStreamRead(RwStream* stream, RpHAnimAnimation* animation) { EAXJMP(0x5CE820); }
WRAPPER RwBool RpHAnimStdKeyFrameStreamWrite(RpHAnimAnimation* animation, RwStream* stream) { EAXJMP(0x5CE8C0); }
WRAPPER RwInt32 RpHAnimStdKeyFrameStreamGetSize(RpHAnimAnimation* animation) { EAXJMP(0x5CE930); }
WRAPPER void RpHAnimStdKeyFrameMulRecip(void* voidFrame, void* voidStart) { EAXJMP(0x5CE950); }
WRAPPER void RpHAnimStdKeyFrameAdd(void* voidOut, void* voidIn1, void* voidIn2) { EAXJMP(0x5CEAB0); }
WRAPPER void RxHeapFree(RxHeap* heap, void* block) { EAXJMP(0x5D1070); }
WRAPPER void* RxHeapAlloc(RxHeap* heap, RwUInt32 size) { EAXJMP(0x5D1260); }
WRAPPER void* RxHeapRealloc(RxHeap* heap, void* block, RwUInt32 newSize, RwBool allowCopy) { EAXJMP(0x5D14D0); }
WRAPPER RwBool _rxHeapReset(RxHeap* heap) { EAXJMP(0x5D1680); }
WRAPPER void RxHeapDestroy(RxHeap* heap) { EAXJMP(0x5D16F0); }
WRAPPER RxHeap* RxHeapCreate(RwUInt32 size) { EAXJMP(0x5D1750); }
WRAPPER RxNodeOutput RxPipelineNodeFindOutputByName(RxPipelineNode* node, RwChar const* outputname) { EAXJMP(0x5D1EC0); }
WRAPPER RxNodeInput RxPipelineNodeFindInput(RxPipelineNode* node) { EAXJMP(0x5D1F20); }
WRAPPER RxPipeline* RxPipelineNodeRequestCluster(RxPipeline* pipeline, RxPipelineNode* node, RxClusterDefinition* clusterDef) { EAXJMP(0x5D1F30); }
WRAPPER RxPipeline* RxLockedPipeUnlock(RxLockedPipe* pipeline) { EAXJMP(0x5D1FA0); }
WRAPPER RxLockedPipe* RxPipelineLock(RxPipeline* pipeline) { EAXJMP(0x5D29F0); }
WRAPPER RxPipelineNode* RxPipelineFindNodeByName(RxPipeline* pipeline, RwChar const* name, RxPipelineNode* start, RwInt32* nodeIndex) { EAXJMP(0x5D2B10); }
WRAPPER RxLockedPipe* RxLockedPipeAddFragment(RxLockedPipe *pipeline, RwUInt32 *firstIndex, RxNodeDefinition *nodeDef0, ...) { EAXJMP(0x5D2BA0); }
WRAPPER RxPipeline* RxLockedPipeAddPath(RxLockedPipe* pipeline, RxNodeOutput out, RxNodeInput in) { EAXJMP(0x5D2EE0); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmRenderSetup() { EAXJMP(0x5D31C0); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmMangleTriangleIndices() { EAXJMP(0x5D35C0); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetCullTriangle() { EAXJMP(0x5D3C60); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetClipTriangle() { EAXJMP(0x5D4F80); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetSubmitTriangle() { EAXJMP(0x5D51C0); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmInstance() { EAXJMP(0x5D5400); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetTransform() { EAXJMP(0x5D6000); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmStash() { EAXJMP(0x5D61C0); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmMangleLineIndices() { EAXJMP(0x5D6470); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetClipLine() { EAXJMP(0x5D7230); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetSubmitLine() { EAXJMP(0x5D74C0); }
WRAPPER RwBool _rwD3D8LightsOpen() { EAXJMP(0x5D9C90); }
WRAPPER void _rwD3D8LightsClose() { EAXJMP(0x5D9EF0); }
WRAPPER RwBool _rwD3D8LightsGlobalEnable(RpLightFlag flags) { EAXJMP(0x5D9F80); }
WRAPPER RwBool _rwD3D8LightLocalEnable(RpLight* light) { EAXJMP(0x5DA210); }
WRAPPER void _rwD3D8LightsEnable(RwBool enable, RwUInt32 type) { EAXJMP(0x5DA450); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetD3D8WorldSectorAllInOne() { EAXJMP(0x5DAAC0); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetD3D8AtomicAllInOne() { EAXJMP(0x5DC500); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetWorldSectorInstance() { EAXJMP(0x5DCC50); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetWorldSectorEnumerateLights() { EAXJMP(0x5DCD80); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetAtomicInstance() { EAXJMP(0x5DD800); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetAtomicEnumerateLights() { EAXJMP(0x5DD9B0); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetMaterialScatter() { EAXJMP(0x5DDAA0); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetLight() { EAXJMP(0x5DF040); }
WRAPPER RxNodeDefinition* RxNodeDefinitionGetPostLight() { EAXJMP(0x5DF560); }
WRAPPER void RxD3D8AllInOneSetRenderCallBack(RxPipelineNode* node, RxD3D8AllInOneRenderCallBack callback) { EAXJMP(0x5DFC60); }

205
src/core/templates.h Normal file
View File

@ -0,0 +1,205 @@
#pragma once
template<typename T, int n>
class CStore
{
public:
int allocPtr;
T store[n];
T *alloc(void){
if(this->allocPtr >= n){
printf("Size of this thing:%d needs increasing\n", n);
assert(0);
}
return &this->store[this->allocPtr++];
}
void clear(void){
this->allocPtr = 0;
}
};
template<typename T, typename U = T>
class CPool
{
U *m_entries;
union Flags {
struct {
uint8 id : 7;
uint8 free : 1;
};
uint8 u;
} *m_flags;
int m_size;
int m_allocPtr;
public:
CPool(int size){
m_entries = (U*)malloc(sizeof(U)*size);
m_flags = (Flags*)malloc(sizeof(Flags)*size);
m_size = size;
m_allocPtr = 0;
for(int i = 0; i < size; i++){
m_flags[i].id = 0;
m_flags[i].free = 1;
}
}
int GetSize(void) { return m_size; }
T *New(void){
bool wrapped = false;
do
if(++m_allocPtr == m_size){
if(wrapped)
return nil;
wrapped = true;
m_allocPtr = 0;
}
while(!m_flags[m_allocPtr].free);
m_flags[m_allocPtr].free = 0;
m_flags[m_allocPtr].id++;
return (T*)&m_entries[m_allocPtr];
}
T *New(int handle){
T *entry = (T*)&m_entries[handle>>8];
SetNotFreeAt(handle);
return entry;
}
void SetNotFreeAt(int handle){
int idx = handle>>8;
m_flags[idx].free = 0;
m_flags[idx].id = handle & 0x7F;
for(m_allocPtr = 0; m_allocPtr < m_size; m_allocPtr++)
if(m_flags[m_allocPtr].free)
return;
}
void Delete(T *entry){
int i = GetJustIndex(entry);
m_flags[i].free = 1;
if(i < m_allocPtr)
m_allocPtr = i;
}
T *GetSlot(int i){
return m_flags[i].free ? nil : (T*)&m_entries[i];
}
T *GetAt(int handle){
return m_flags[handle>>8].u == (handle & 0xFF) ?
(T*)&m_entries[handle >> 8] : nil;
}
int GetIndex(T *entry){
int i = GetJustIndex(entry);
return m_flags[i].u + (i<<8);
}
int GetJustIndex(T *entry){
// TODO: the cast is unsafe
return (int)((U*)entry - m_entries);
}
int GetNoOfUsedSpaces(void){
int i;
int n = 0;
for(i = 0; i < m_size; i++)
if(!m_flags[i].free)
n++;
return n;
}
void ClearStorage(uint8 *&flags, U *&entries){
free(flags);
free(entries);
flags = nil;
entries = nil;
}
void CopyBack(uint8 *&flags, U *&entries){
memcpy(m_flags, flags, sizeof(uint8)*m_size);
memcpy(m_entries, entries, sizeof(U)*m_size);
debug("Size copied:%d (%d)\n", sizeof(U)*m_size, sizeof(Flags)*m_size);
m_allocPtr = 0;
ClearStorage(flags, entries);
debug("CopyBack:%d (/%d)\n", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */
}
void Store(uint8 *&flags, U *&entries){
flags = (uint8*)malloc(sizeof(uint8)*m_size);
entries = (U*)malloc(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
}
int Count(void){
int n = 0;
CLink<T> *lnk;
for(lnk = head.next; lnk != &tail; lnk = lnk->next)
n++;
return n;
}
};