first commit
This commit is contained in:
commit
600bf03514
101
README.md
Normal file
101
README.md
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
# Intro
|
||||||
|
|
||||||
|
The aim of this project is to reverse GTA III for PC by replacing
|
||||||
|
parts of the game [one by one](https://en.wikipedia.org/wiki/Ship_of_Theseus)
|
||||||
|
such that we have a working game at all times.
|
||||||
|
|
||||||
|
# Strategy
|
||||||
|
|
||||||
|
A good approach is to start at the fringes of the code base,
|
||||||
|
i.e. classes that don't depend on code that we don't have reversed yet.
|
||||||
|
If a function uses only few unreversed functions that would be inconvenient
|
||||||
|
to reverse at the time, calling the original functions is acceptable.
|
||||||
|
|
||||||
|
# Progress
|
||||||
|
|
||||||
|
This is a list of some things that have been reversed to some non-trivial extent.
|
||||||
|
Not everything is listed, check the code.
|
||||||
|
|
||||||
|
```
|
||||||
|
CPool
|
||||||
|
CTxdStore
|
||||||
|
CVector
|
||||||
|
CVector2D
|
||||||
|
CMatrix
|
||||||
|
CModelInfo
|
||||||
|
CBaseModelInfo
|
||||||
|
CSimpleModelInfo
|
||||||
|
CTimeModelInfo
|
||||||
|
CClumpModelInfo
|
||||||
|
CPedModelInfo
|
||||||
|
CVehicleModelInfo
|
||||||
|
CVisibilityPlugins
|
||||||
|
CRenderer
|
||||||
|
CEntity
|
||||||
|
CPhysical
|
||||||
|
CCollision
|
||||||
|
CCullZones
|
||||||
|
CTheZones
|
||||||
|
CPathFind
|
||||||
|
```
|
||||||
|
|
||||||
|
# Low hanging fruit
|
||||||
|
|
||||||
|
There are a couple of things that have been reversed for other projects
|
||||||
|
already that could probably be put into this project without too much effort.
|
||||||
|
Again, the list is not complete:
|
||||||
|
|
||||||
|
* Animation (https://github.com/aap/iii_anim)
|
||||||
|
* File Loader (https://github.com/aap/librwgta/tree/master/tools/IIItest)
|
||||||
|
* ...
|
||||||
|
|
||||||
|
# Coding style
|
||||||
|
|
||||||
|
I started writing in [Plan 9 style](http://man.cat-v.org/plan_9/6/style),
|
||||||
|
but realize that this is not the most popular style, so I'm willing to compromise.
|
||||||
|
Try not to deviate too much so the code will look similar across the whole project.
|
||||||
|
|
||||||
|
To give examples, these two styles (or anything in between) are fine:
|
||||||
|
|
||||||
|
```
|
||||||
|
type
|
||||||
|
functionname(args)
|
||||||
|
{
|
||||||
|
if(a == b){
|
||||||
|
s1;
|
||||||
|
s2;
|
||||||
|
}
|
||||||
|
if(x != y)
|
||||||
|
s3;
|
||||||
|
}
|
||||||
|
|
||||||
|
type functionname(args)
|
||||||
|
{
|
||||||
|
if (a == b) {
|
||||||
|
s1;
|
||||||
|
s2;
|
||||||
|
}
|
||||||
|
if (x != y)
|
||||||
|
s3;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This one (or anything more extreme) is heavily discouraged:
|
||||||
|
|
||||||
|
```
|
||||||
|
type functionname ( args )
|
||||||
|
{
|
||||||
|
if ( a == b )
|
||||||
|
{
|
||||||
|
s1;
|
||||||
|
s2;
|
||||||
|
}
|
||||||
|
if ( x != y )
|
||||||
|
{
|
||||||
|
s3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Indentation is done with TABS.
|
||||||
|
|
1
premake5.cmd
Normal file
1
premake5.cmd
Normal file
@ -0,0 +1 @@
|
|||||||
|
premake5 vs2015
|
BIN
premake5.exe
Normal file
BIN
premake5.exe
Normal file
Binary file not shown.
38
premake5.lua
Normal file
38
premake5.lua
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
workspace "re3"
|
||||||
|
configurations { "Release","Debug" }
|
||||||
|
location "build"
|
||||||
|
|
||||||
|
files { "src/*.*" }
|
||||||
|
files { "src/math/*.*" }
|
||||||
|
files { "src/modelinfo/*.*" }
|
||||||
|
files { "src/entities/*.*" }
|
||||||
|
files { "src/render/*.*" }
|
||||||
|
|
||||||
|
includedirs { "src", "src/modelinfo" }
|
||||||
|
includedirs { "src", "src/entities" }
|
||||||
|
includedirs { "src", "src/render" }
|
||||||
|
includedirs { os.getenv("RWSDK33") }
|
||||||
|
|
||||||
|
project "re3"
|
||||||
|
kind "SharedLib"
|
||||||
|
language "C++"
|
||||||
|
targetname "re3"
|
||||||
|
targetdir "bin/%{cfg.buildcfg}"
|
||||||
|
targetextension ".dll"
|
||||||
|
characterset ("MBCS")
|
||||||
|
|
||||||
|
filter "configurations:Debug"
|
||||||
|
defines { "DEBUG" }
|
||||||
|
flags { "StaticRuntime" }
|
||||||
|
symbols "On"
|
||||||
|
debugdir "C:/Users/aap/games/gta3_re"
|
||||||
|
debugcommand "C:/Users/aap/games/gta3_re/gta3.exe"
|
||||||
|
postbuildcommands "copy /y \"$(TargetPath)\" \"C:\\Users\\aap\\games\\gta3_re\\plugins\\re3.dll\""
|
||||||
|
|
||||||
|
filter "configurations:Release"
|
||||||
|
defines { "NDEBUG" }
|
||||||
|
optimize "On"
|
||||||
|
flags { "StaticRuntime" }
|
||||||
|
debugdir "C:/Users/aap/games/gta3_re"
|
||||||
|
debugcommand "C:/Users/aap/games/gta3_re/gta3.exe"
|
||||||
|
postbuildcommands "copy /y \"$(TargetPath)\" \"C:\\Users\\aap\\games\\gta3_re\\plugins\\re3.dll\""
|
63
src/Camera.cpp
Normal file
63
src/Camera.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Draw.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
|
||||||
|
CCamera &TheCamera = *(CCamera*)0x6FACF8;
|
||||||
|
|
||||||
|
bool
|
||||||
|
CCamera::IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat)
|
||||||
|
{
|
||||||
|
RwV3d c;
|
||||||
|
c = *(RwV3d*)¢er;
|
||||||
|
RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix);
|
||||||
|
if(c.y + radius < CDraw::GetNearClipZ()) return false;
|
||||||
|
if(c.y - radius > CDraw::GetFarClipZ()) return false;
|
||||||
|
if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > radius) return false;
|
||||||
|
if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > radius) return false;
|
||||||
|
if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > radius) return false;
|
||||||
|
if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > radius) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CCamera::IsPointVisible(const CVector ¢er, const CMatrix *mat)
|
||||||
|
{
|
||||||
|
RwV3d c;
|
||||||
|
c = *(RwV3d*)¢er;
|
||||||
|
RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix);
|
||||||
|
if(c.y < CDraw::GetNearClipZ()) return false;
|
||||||
|
if(c.y > CDraw::GetFarClipZ()) return false;
|
||||||
|
if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > 0.0f) return false;
|
||||||
|
if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > 0.0f) return false;
|
||||||
|
if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > 0.0f) return false;
|
||||||
|
if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > 0.0f) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CCamera::IsBoxVisible(RwV3d *box, const CMatrix *mat)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int frustumTests[6] = { 0 };
|
||||||
|
RwV3dTransformPoints(box, box, 8, &mat->m_matrix);
|
||||||
|
|
||||||
|
for(i = 0; i < 8; i++){
|
||||||
|
if(box[i].y < CDraw::GetNearClipZ()) frustumTests[0]++;
|
||||||
|
if(box[i].y > CDraw::GetFarClipZ()) frustumTests[1]++;
|
||||||
|
if(box[i].x*m_vecFrustumNormals[0].x + box[i].y*m_vecFrustumNormals[0].y > 0.0f) frustumTests[2]++;
|
||||||
|
if(box[i].x*m_vecFrustumNormals[1].x + box[i].y*m_vecFrustumNormals[1].y > 0.0f) frustumTests[3]++;
|
||||||
|
// Why not test z?
|
||||||
|
// if(box[i].y*m_vecFrustumNormals[2].y + box[i].z*m_vecFrustumNormals[2].z > 0.0f) frustumTests[4]++;
|
||||||
|
// if(box[i].y*m_vecFrustumNormals[3].y + box[i].z*m_vecFrustumNormals[3].z > 0.0f) frustumTests[5]++;
|
||||||
|
}
|
||||||
|
for(i = 0; i < 6; i++)
|
||||||
|
if(frustumTests[i] == 8)
|
||||||
|
return false; // Box is completely outside of one plane
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x42C760, &CCamera::IsSphereVisible, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
420
src/Camera.h
Normal file
420
src/Camera.h
Normal file
@ -0,0 +1,420 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Placeable.h"
|
||||||
|
|
||||||
|
class CEntity;
|
||||||
|
class CPed;
|
||||||
|
class CAutomobile;
|
||||||
|
|
||||||
|
#define NUMBER_OF_VECTORS_FOR_AVERAGE 2
|
||||||
|
|
||||||
|
struct CCam
|
||||||
|
{
|
||||||
|
enum CamMode
|
||||||
|
{
|
||||||
|
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_FIRSTPERSONPEDONPC_38,
|
||||||
|
MODE_FIRSTPERSONPEDONPC_39,
|
||||||
|
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_unknownZOffset;
|
||||||
|
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 Process_Debug(float *vec, float a, float b, float c);
|
||||||
|
void Process_Kalvin(float*, float, float, float);
|
||||||
|
void GetVectorsReadyForRW(void);
|
||||||
|
};
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
CMatrix &GetCameraMatrix(void) { return m_cameraMatrix; }
|
||||||
|
CVector &GetGameCamPosition(void) { return m_vecGameCamPos; }
|
||||||
|
bool IsPointVisible(const CVector ¢er, const CMatrix *mat);
|
||||||
|
bool IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat);
|
||||||
|
bool IsBoxVisible(RwV3d *box, const CMatrix *mat);
|
||||||
|
};
|
||||||
|
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;
|
116
src/Clock.cpp
Normal file
116
src/Clock.cpp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "Pad.h"
|
||||||
|
#include "Clock.h"
|
||||||
|
|
||||||
|
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)->NewState.r1){
|
||||||
|
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){
|
||||||
|
ms_nGameClockMinutes++;
|
||||||
|
ms_nLastClockTick += ms_nMillisecondsPerGameMinute;
|
||||||
|
if(ms_nGameClockMinutes >= 60){
|
||||||
|
ms_nGameClockHours++;
|
||||||
|
ms_nGameClockMinutes = 0;
|
||||||
|
if(ms_nGameClockHours >= 24)
|
||||||
|
ms_nGameClockHours = 0;
|
||||||
|
// TODO: stats days passed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
27
src/Clock.h
Normal file
27
src/Clock.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#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 int8 GetHours(void) { return ms_nGameClockHours; }
|
||||||
|
static int8 GetMinutes(void) { return ms_nGameClockMinutes; }
|
||||||
|
static int16 GetSeconds(void) { return ms_nGameClockSeconds; }
|
||||||
|
};
|
1629
src/Collision.cpp
Normal file
1629
src/Collision.cpp
Normal file
File diff suppressed because it is too large
Load Diff
152
src/Collision.h
Normal file
152
src/Collision.h
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
#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 ¢er, uint8 surf, uint8 piece);
|
||||||
|
void Set(float radius, const CVector ¢er) { 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
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(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class CCollision
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static eLevelName &ms_collisionInMemory;
|
||||||
|
static CLinkList<CColModel*> &ms_colModelCache;
|
||||||
|
|
||||||
|
static void Init(void);
|
||||||
|
static void Update(void);
|
||||||
|
static void LoadCollisionWhenINeedIt(bool changeLevel);
|
||||||
|
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(CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSurf78);
|
||||||
|
|
||||||
|
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 ignoreSurf78);
|
||||||
|
static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSurf78, 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);
|
||||||
|
};
|
323
src/CullZones.cpp
Normal file
323
src/CullZones.cpp
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Building.h"
|
||||||
|
#include "Treadable.h"
|
||||||
|
#include "Pools.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
#include "World.h"
|
||||||
|
#include "CullZones.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::Update(void)
|
||||||
|
{
|
||||||
|
bool invisible;
|
||||||
|
CVector v;
|
||||||
|
|
||||||
|
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(v),
|
||||||
|
&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;
|
||||||
|
|
||||||
|
FindPlayerCoors(coors);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
WRAPPER void
|
||||||
|
CCullZones::MarkSubwayAsInvisible(bool visible)
|
||||||
|
{ EAXJMP(0x525AF0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)->m_bZoneCulled = false;
|
||||||
|
bb = CCullZones::aPointersToBigBuildingsForBuildings[i];
|
||||||
|
if(bb != -1)
|
||||||
|
CPools::GetBuildingPool()->GetSlot(bb)->m_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)->m_bZoneCulled = false;
|
||||||
|
CPools::GetTreadablePool()->GetSlot(i)->m_bZoneCulled2 = false;
|
||||||
|
bb = CCullZones::aPointersToBigBuildingsForTreadables[i];
|
||||||
|
if(bb != -1)
|
||||||
|
CPools::GetBuildingPool()->GetSlot(bb)->m_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)->m_bZoneCulled = true;
|
||||||
|
bb = CCullZones::aPointersToBigBuildingsForBuildings[i];
|
||||||
|
if(bb != -1)
|
||||||
|
CPools::GetBuildingPool()->GetSlot(bb)->m_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)->m_bZoneCulled = true;;
|
||||||
|
CPools::GetTreadablePool()->GetSlot(i)->m_bZoneCulled2 = true;;
|
||||||
|
bb = CCullZones::aPointersToBigBuildingsForTreadables[i];
|
||||||
|
if(bb != -1)
|
||||||
|
CPools::GetBuildingPool()->GetSlot(bb)->m_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)->m_bZoneCulled = true;;
|
||||||
|
bb = CCullZones::aPointersToBigBuildingsForTreadables[i];
|
||||||
|
if(bb != -1)
|
||||||
|
CPools::GetBuildingPool()->GetSlot(bb)->m_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(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
|
93
src/CullZones.h
Normal file
93
src/CullZones.h
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
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 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; }
|
||||||
|
};
|
5
src/Game.cpp
Normal file
5
src/Game.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Game.h"
|
||||||
|
|
||||||
|
int &CGame::currLevel = *(int*)0x941514;
|
15
src/Game.h
Normal file
15
src/Game.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum eLevelName
|
||||||
|
{
|
||||||
|
LEVEL_NONE = 0,
|
||||||
|
LEVEL_INDUSTRIAL,
|
||||||
|
LEVEL_COMMERCIAL,
|
||||||
|
LEVEL_SUBURBAN
|
||||||
|
};
|
||||||
|
|
||||||
|
class CGame
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static int &currLevel;
|
||||||
|
};
|
15
src/General.h
Normal file
15
src/General.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
class CGeneral
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static float GetATanOfXY(float x, float y){
|
||||||
|
if(y >= 0.0f) return atan2(x, y);
|
||||||
|
return atan2(x, y) + 2*M_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not too sure about all these...
|
||||||
|
static uint16 GetRandomNumber(void)
|
||||||
|
{ return myrand() & 0xFFFF; }
|
||||||
|
// Probably don't want to ever reach high
|
||||||
|
static float GetRandomNumberInRange(float low, float high)
|
||||||
|
{ return low + (high - low)*(GetRandomNumber()/65536.0f); }
|
||||||
|
};
|
15
src/Glass.cpp
Normal file
15
src/Glass.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Glass.h"
|
||||||
|
|
||||||
|
WRAPPER void
|
||||||
|
CGlass::WindowRespondsToCollision(CEntity *ent, float amount, CVector speed, CVector point, bool foo)
|
||||||
|
{
|
||||||
|
EAXJMP(0x503F10);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRAPPER void
|
||||||
|
CGlass::WindowRespondsToSoftCollision(CEntity *ent, float amount)
|
||||||
|
{
|
||||||
|
EAXJMP(0x504630);
|
||||||
|
}
|
10
src/Glass.h
Normal file
10
src/Glass.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CEntity;
|
||||||
|
|
||||||
|
class CGlass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void WindowRespondsToCollision(CEntity *ent, float amount, CVector speed, CVector point, bool foo);
|
||||||
|
static void WindowRespondsToSoftCollision(CEntity *ent, float amount);
|
||||||
|
};
|
26
src/Lists.cpp
Normal file
26
src/Lists.cpp
Normal 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/Lists.h
Normal file
130
src/Lists.h
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
4
src/MenuManager.cpp
Normal file
4
src/MenuManager.cpp
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "MenuManager.h"
|
||||||
|
|
||||||
|
int &CMenuManager::m_PrefsBrightness = *(int*)0x5F2E50;
|
5
src/MenuManager.h
Normal file
5
src/MenuManager.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
class CMenuManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static int &m_PrefsBrightness;
|
||||||
|
};
|
15
src/NodeName.cpp
Normal file
15
src/NodeName.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "NodeName.h"
|
||||||
|
|
||||||
|
int &gPluginOffset = *(int*)0x64C610;
|
||||||
|
|
||||||
|
#define NODENAMEEXT(o) (RWPLUGINOFFSET(char, o, gPluginOffset))
|
||||||
|
|
||||||
|
char*
|
||||||
|
GetFrameNodeName(RwFrame *frame)
|
||||||
|
{
|
||||||
|
if(gPluginOffset < 0)
|
||||||
|
return nil;
|
||||||
|
return NODENAMEEXT(frame);
|
||||||
|
}
|
3
src/NodeName.h
Normal file
3
src/NodeName.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
char *GetFrameNodeName(RwFrame *frame);
|
37
src/Pad.cpp
Normal file
37
src/Pad.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "Pad.h"
|
||||||
|
|
||||||
|
CPad *CPad::Pads = (CPad*)0x6F0360;
|
||||||
|
|
||||||
|
uint16 *CPad::OldKeyState = (uint16*)0x6F1E70;
|
||||||
|
uint16 *CPad::NewKeyState = (uint16*)0x6E60D0;
|
||||||
|
uint16 *CPad::TempKeyState = (uint16*)0x774DE8;
|
||||||
|
|
||||||
|
CMouseControllerState &CPad::OldMouseControllerState = *(CMouseControllerState*)0x8472A0;
|
||||||
|
CMouseControllerState &CPad::NewMouseControllerState = *(CMouseControllerState*)0x8809F0;
|
||||||
|
CMouseControllerState &CPad::PCTempMouseControllerState = *(CMouseControllerState*)0x6F1E60;
|
||||||
|
|
||||||
|
void
|
||||||
|
CControllerState::Clear(void)
|
||||||
|
{
|
||||||
|
leftX = 0;
|
||||||
|
leftY = 0;
|
||||||
|
rightX = 0;
|
||||||
|
rightY = 0;
|
||||||
|
l1 = 0;
|
||||||
|
l2 = 0;
|
||||||
|
r1 = 0;
|
||||||
|
r2 = 0;
|
||||||
|
up = 0;
|
||||||
|
down = 0;
|
||||||
|
left = 0;
|
||||||
|
right = 0;
|
||||||
|
start = 0;
|
||||||
|
select = 0;
|
||||||
|
square = 0;
|
||||||
|
triangle = 0;
|
||||||
|
cross = 0;
|
||||||
|
circle = 0;
|
||||||
|
leftshock = 0;
|
||||||
|
rightshock = 0;
|
||||||
|
}
|
116
src/Pad.h
Normal file
116
src/Pad.h
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#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 leftX, leftY;
|
||||||
|
int16 rightX, rightY;
|
||||||
|
int16 l1, l2;
|
||||||
|
int16 r1, r2;
|
||||||
|
int16 up, down, left, right;
|
||||||
|
int16 start, select;
|
||||||
|
int16 square, triangle, cross, circle;
|
||||||
|
int16 leftshock, rightshock;
|
||||||
|
int16 networktalk;
|
||||||
|
float getLeftX(void) { return leftX/32767.0f; };
|
||||||
|
float getLeftY(void) { return leftY/32767.0f; };
|
||||||
|
float getRightX(void) { return rightX/32767.0f; };
|
||||||
|
float getRightY(void) { return rightY/32767.0f; };
|
||||||
|
|
||||||
|
void Clear(void);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CControllerState) == 0x2A, "CControllerState: error");
|
||||||
|
|
||||||
|
struct CMouseControllerState
|
||||||
|
{
|
||||||
|
uint32 btns; // bit 0-2 button 1-3
|
||||||
|
int x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CPad
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CControllerState NewState;
|
||||||
|
CControllerState OldState;
|
||||||
|
CControllerState PCTempKeyState;
|
||||||
|
CControllerState PCTempJoyState;
|
||||||
|
CControllerState PCTempMouseState;
|
||||||
|
// straight out of my IDB
|
||||||
|
int16 Phase;
|
||||||
|
int16 Mode;
|
||||||
|
int16 ShakeDur;
|
||||||
|
int8 ShakeFreq;
|
||||||
|
int8 bHornHistory[5];
|
||||||
|
int8 iCurrHornHistory;
|
||||||
|
int8 DisablePlayerControls;
|
||||||
|
int8 JustOutOfFrontEnd;
|
||||||
|
int8 bApplyBrakes;
|
||||||
|
int32 unk[3];
|
||||||
|
int32 LastTimeTouched;
|
||||||
|
int32 AverageWeapon;
|
||||||
|
int32 AverageEntries;
|
||||||
|
|
||||||
|
static CPad *Pads; //[2];
|
||||||
|
static uint16 *OldKeyState; //[KEY_NUMKEYS];
|
||||||
|
static uint16 *NewKeyState; //[KEY_NUMKEYS];
|
||||||
|
static uint16 *TempKeyState; //[KEY_NUMKEYS];
|
||||||
|
static CMouseControllerState &OldMouseControllerState;
|
||||||
|
static CMouseControllerState &NewMouseControllerState;
|
||||||
|
static CMouseControllerState &PCTempMouseControllerState;
|
||||||
|
|
||||||
|
static CPad *GetPad(int n) { return &Pads[n]; }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CPad) == 0xFC, "CPad: error");
|
||||||
|
|
||||||
|
#define IsButtonJustDown(pad, btn) \
|
||||||
|
(!(pad)->OldState.btn && (pad)->NewState.btn)
|
5
src/ParticleObject.cpp
Normal file
5
src/ParticleObject.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "ParticleObject.h"
|
||||||
|
|
||||||
|
void CParticleObject::AddObject(uint16, const CVector &pos, bool remove) { EAXJMP(0x4BC4D0); }
|
31
src/ParticleObject.h
Normal file
31
src/ParticleObject.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum eParticleObjectType
|
||||||
|
{
|
||||||
|
POBJECT_PAVEMENT_STEAM,
|
||||||
|
POBJECT_PAVEMENT_STEAM_SLOWMOTION,
|
||||||
|
POBJECT_WALL_STEAM,
|
||||||
|
POBJECT_WALL_STEAM_SLOWMOTION,
|
||||||
|
POBJECT_DARK_SMOKE,
|
||||||
|
POBJECT_FIRE_HYDRANT,
|
||||||
|
POBJECT_CAR_WATER_SPLASH,
|
||||||
|
POBJECT_PED_WATER_SPLASH,
|
||||||
|
POBJECT_SPLASHES_AROUND,
|
||||||
|
POBJECT_SMALL_FIRE,
|
||||||
|
POBJECT_BIG_FIRE,
|
||||||
|
POBJECT_DRY_ICE,
|
||||||
|
POBJECT_DRY_ICE_SLOWMOTION,
|
||||||
|
POBJECT_FIRE_TRAIL,
|
||||||
|
POBJECT_SMOKE_TRAIL,
|
||||||
|
POBJECT_FIREBALL_AND_SMOKE,
|
||||||
|
POBJECT_ROCKET_TRAIL,
|
||||||
|
POBJECT_EXPLOSION_ONCE,
|
||||||
|
POBJECT_CATALINAS_GUNFLASH,
|
||||||
|
POBJECT_CATALINAS_SHOTGUNFLASH,
|
||||||
|
};
|
||||||
|
|
||||||
|
class CParticleObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void AddObject(uint16, const CVector &pos, bool remove);
|
||||||
|
};
|
591
src/PathFind.cpp
Normal file
591
src/PathFind.cpp
Normal file
@ -0,0 +1,591 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "PathFind.h"
|
||||||
|
|
||||||
|
CPathFind &ThePaths = *(CPathFind*)0x8F6754;
|
||||||
|
|
||||||
|
int TempListLength;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NodeTypeExtern = 1,
|
||||||
|
NodeTypeIntern = 2,
|
||||||
|
|
||||||
|
PathTypeCar = 0,
|
||||||
|
PathTypePed = 1,
|
||||||
|
|
||||||
|
PathNodeFlag1 = 1, // used?
|
||||||
|
PathNodeFlag2 = 2,
|
||||||
|
PathNodeDeadEnd = 4,
|
||||||
|
PathNodeDisabled = 8,
|
||||||
|
PathNodeBetweenLevels = 0x10,
|
||||||
|
};
|
||||||
|
|
||||||
|
// link flags:
|
||||||
|
// 1: crosses road
|
||||||
|
// 2: ped traffic light
|
||||||
|
// pathnode flags:
|
||||||
|
// 1:
|
||||||
|
// 2:
|
||||||
|
// 4: dead end
|
||||||
|
// 8: switched off
|
||||||
|
// 10: road between levels??
|
||||||
|
// navi node flags:
|
||||||
|
// 1: bridge light
|
||||||
|
// object flags:
|
||||||
|
// 1
|
||||||
|
// 2 east/west road(?)
|
||||||
|
|
||||||
|
CPathInfoForObject *&InfoForTileCars = *(CPathInfoForObject**)0x8F1A8C;
|
||||||
|
CPathInfoForObject *&InfoForTilePeds = *(CPathInfoForObject**)0x8F1AE4;
|
||||||
|
// unused
|
||||||
|
CTempDetachedNode *&DetachedNodesCars = *(CTempDetachedNode**)0x8E2824;
|
||||||
|
CTempDetachedNode *&DetachedNodesPeds = *(CTempDetachedNode**)0x8E28A0;
|
||||||
|
|
||||||
|
void
|
||||||
|
CPathFind::PreparePathData(void)
|
||||||
|
{
|
||||||
|
int i, j, k;
|
||||||
|
int numExtern, numIntern, numLanes;
|
||||||
|
float maxX, maxY;
|
||||||
|
CTempNode *tempNodes;
|
||||||
|
|
||||||
|
printf("PreparePathData\n");
|
||||||
|
// UNUSED: CPathFind::LoadPathFindData
|
||||||
|
if(InfoForTileCars && InfoForTilePeds &&
|
||||||
|
DetachedNodesCars && DetachedNodesPeds){
|
||||||
|
tempNodes = new CTempNode[4000];
|
||||||
|
|
||||||
|
m_numLinks = 0;
|
||||||
|
for(i = 0; i < PATHNODESIZE; i++)
|
||||||
|
m_pathNodes[i].flags &= ~(PathNodeFlag1 | PathNodeFlag2);
|
||||||
|
|
||||||
|
for(i = 0; i < PATHNODESIZE; i++){
|
||||||
|
numExtern = 0;
|
||||||
|
numIntern = 0;
|
||||||
|
for(j = 0; j < 12; j++){
|
||||||
|
if(InfoForTileCars[i*12 + j].type == NodeTypeExtern)
|
||||||
|
numExtern++;
|
||||||
|
if(InfoForTileCars[i*12 + j].type == NodeTypeIntern)
|
||||||
|
numIntern++;
|
||||||
|
}
|
||||||
|
if(numIntern > 1 && numExtern != 2)
|
||||||
|
printf("ILLEGAL BLOCK. MORE THAN 1 INTERNALS AND NOT 2 EXTERNALS (Modelindex:%d)\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < PATHNODESIZE; i++)
|
||||||
|
for(j = 0; j < 12; j++)
|
||||||
|
if(InfoForTileCars[i*12 + j].type == NodeTypeExtern){
|
||||||
|
if(InfoForTileCars[i*12 + j].numLeftLanes < 0)
|
||||||
|
printf("ILLEGAL BLOCK. NEGATIVE NUMBER OF LANES (Obj:%d)\n", i);
|
||||||
|
if(InfoForTileCars[i*12 + j].numRightLanes < 0)
|
||||||
|
printf("ILLEGAL BLOCK. NEGATIVE NUMBER OF LANES (Obj:%d)\n", i);
|
||||||
|
if(InfoForTileCars[i*12 + j].numLeftLanes + InfoForTileCars[i*12 + j].numRightLanes <= 0)
|
||||||
|
printf("ILLEGAL BLOCK. NO LANES IN NODE (Obj:%d)\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_numPathNodes = 0;
|
||||||
|
PreparePathDataForType(PathTypeCar, tempNodes, InfoForTileCars, 1.0f, DetachedNodesCars, 100);
|
||||||
|
m_numCarPathNodes = m_numPathNodes;
|
||||||
|
PreparePathDataForType(PathTypePed, tempNodes, InfoForTilePeds, 1.0f, DetachedNodesPeds, 50);
|
||||||
|
m_numPedPathNodes = m_numPathNodes - m_numCarPathNodes;
|
||||||
|
|
||||||
|
// TODO: figure out what exactly is going on here
|
||||||
|
// Some roads seem to get a west/east flag
|
||||||
|
for(i = 0; i < m_numMapObjects; i++){
|
||||||
|
numExtern = 0;
|
||||||
|
numIntern = 0;
|
||||||
|
numLanes = 0;
|
||||||
|
maxX = 0.0f;
|
||||||
|
maxY = 0.0f;
|
||||||
|
for(j = 0; j < 12; j++){
|
||||||
|
k = i*12 + j;
|
||||||
|
if(InfoForTileCars[k].type == NodeTypeExtern){
|
||||||
|
numExtern++;
|
||||||
|
if(InfoForTileCars[k].numLeftLanes + InfoForTileCars[k].numRightLanes > numLanes)
|
||||||
|
numLanes = InfoForTileCars[k].numLeftLanes + InfoForTileCars[k].numRightLanes;
|
||||||
|
maxX = max(maxX, fabs(InfoForTileCars[k].x));
|
||||||
|
maxY = max(maxY, fabs(InfoForTileCars[k].y));
|
||||||
|
}else if(InfoForTileCars[k].type == NodeTypeIntern)
|
||||||
|
numIntern++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(numIntern == 1 && numExtern == 2){
|
||||||
|
if(numLanes < 4){
|
||||||
|
if((i & 7) == 4){ // WHAT?
|
||||||
|
m_objectFlags[i] |= 1;
|
||||||
|
if(maxX > maxY)
|
||||||
|
m_objectFlags[i] |= 2;
|
||||||
|
else
|
||||||
|
m_objectFlags[i] &= ~2;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
m_objectFlags[i] |= 1;
|
||||||
|
if(maxX > maxY)
|
||||||
|
m_objectFlags[i] |= 2;
|
||||||
|
else
|
||||||
|
m_objectFlags[i] &= ~2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] tempNodes;
|
||||||
|
|
||||||
|
CountFloodFillGroups(PathTypeCar);
|
||||||
|
CountFloodFillGroups(PathTypePed);
|
||||||
|
|
||||||
|
delete[] InfoForTileCars;
|
||||||
|
InfoForTileCars = nil;
|
||||||
|
delete[] InfoForTilePeds;
|
||||||
|
InfoForTilePeds = nil;
|
||||||
|
delete[] DetachedNodesCars;
|
||||||
|
DetachedNodesCars = nil;
|
||||||
|
delete[] DetachedNodesPeds;
|
||||||
|
DetachedNodesPeds = nil;
|
||||||
|
}
|
||||||
|
printf("Done with PreparePathData\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* String together connected nodes in a list by a flood fill algorithm */
|
||||||
|
void
|
||||||
|
CPathFind::CountFloodFillGroups(uint8 type)
|
||||||
|
{
|
||||||
|
int start, end;
|
||||||
|
int i, l;
|
||||||
|
uint16 n;
|
||||||
|
CPathNode *node, *prev;
|
||||||
|
|
||||||
|
switch(type){
|
||||||
|
case PathTypeCar:
|
||||||
|
start = 0;
|
||||||
|
end = m_numCarPathNodes;
|
||||||
|
break;
|
||||||
|
case PathTypePed:
|
||||||
|
start = m_numCarPathNodes;
|
||||||
|
end = start + m_numPedPathNodes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = start; i < end; i++)
|
||||||
|
m_pathNodes[i].group = 0;
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
for(;;){
|
||||||
|
n++;
|
||||||
|
if(n > 1500){
|
||||||
|
for(i = start; m_pathNodes[i].group && i < end; i++);
|
||||||
|
printf("NumNodes:%d Accounted for:%d\n", end - start, i - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for unvisited node
|
||||||
|
for(i = start; m_pathNodes[i].group && i < end; i++);
|
||||||
|
if(i == end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
node = &m_pathNodes[i];
|
||||||
|
node->next = nil;
|
||||||
|
node->group = n;
|
||||||
|
|
||||||
|
if(node->numLinks == 0){
|
||||||
|
if(type == PathTypeCar)
|
||||||
|
printf("Single car node: %f %f %f (%d)\n",
|
||||||
|
node->pos.x, node->pos.y, node->pos.z,
|
||||||
|
m_mapObjects[node->objectIndex]->m_modelIndex);
|
||||||
|
else
|
||||||
|
printf("Single ped node: %f %f %f\n",
|
||||||
|
node->pos.x, node->pos.y, node->pos.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(node){
|
||||||
|
prev = node;
|
||||||
|
node = node->next;
|
||||||
|
for(i = 0; i < prev->numLinks; i++){
|
||||||
|
l = m_linkTo[prev->firstLink + i];
|
||||||
|
if(m_pathNodes[l].group == 0){
|
||||||
|
m_pathNodes[l].group = n;
|
||||||
|
if(m_pathNodes[l].group == 0)
|
||||||
|
m_pathNodes[l].group = 0x80; // ???
|
||||||
|
m_pathNodes[l].next = node;
|
||||||
|
node = &m_pathNodes[l];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_numGroups[type] = n-1;
|
||||||
|
printf("GraphType:%d. FloodFill groups:%d\n", type, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoForObject *objectpathinfo,
|
||||||
|
float maxdist, CTempDetachedNode *detachednodes, int unused)
|
||||||
|
{
|
||||||
|
static CVector CoorsXFormed;
|
||||||
|
int i, j, k, l;
|
||||||
|
int l1, l2;
|
||||||
|
int start, typeoff;
|
||||||
|
float posx, posy;
|
||||||
|
float dx, dy, mag;
|
||||||
|
float nearestDist;
|
||||||
|
int nearestId;
|
||||||
|
int next;
|
||||||
|
int oldNumPathNodes, oldNumLinks;
|
||||||
|
CVector dist;
|
||||||
|
int iseg, jseg;
|
||||||
|
int istart, jstart;
|
||||||
|
int done, cont;
|
||||||
|
|
||||||
|
typeoff = 12*type;
|
||||||
|
oldNumPathNodes = m_numPathNodes;
|
||||||
|
oldNumLinks = m_numLinks;
|
||||||
|
|
||||||
|
// Initialize map objects
|
||||||
|
for(i = 0; i < m_numMapObjects; i++)
|
||||||
|
for(j = 0; j < 12; j++)
|
||||||
|
m_mapObjects[i]->m_nodeIndicesCars[typeoff + j] = -1;
|
||||||
|
|
||||||
|
// Calculate internal nodes, store them and connect them to defining object
|
||||||
|
for(i = 0; i < m_numMapObjects; i++){
|
||||||
|
start = 12*m_mapObjects[i]->m_modelIndex;
|
||||||
|
for(j = 0; j < 12; j++){
|
||||||
|
if(objectpathinfo[start + j].type != NodeTypeIntern)
|
||||||
|
continue;
|
||||||
|
CalcNodeCoors(
|
||||||
|
objectpathinfo[start + j].x,
|
||||||
|
objectpathinfo[start + j].y,
|
||||||
|
objectpathinfo[start + j].z,
|
||||||
|
i,
|
||||||
|
&CoorsXFormed);
|
||||||
|
m_pathNodes[m_numPathNodes].pos = CoorsXFormed;
|
||||||
|
m_pathNodes[m_numPathNodes].objectIndex = i;
|
||||||
|
m_pathNodes[m_numPathNodes].flags |= 1;
|
||||||
|
m_mapObjects[i]->m_nodeIndicesCars[typeoff + j] = m_numPathNodes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert external nodes into TempList
|
||||||
|
TempListLength = 0;
|
||||||
|
for(i = 0; i < m_numMapObjects; i++){
|
||||||
|
start = 12*m_mapObjects[i]->m_modelIndex;
|
||||||
|
|
||||||
|
for(j = 0; j < 12; j++){
|
||||||
|
if(objectpathinfo[start + j].type != NodeTypeExtern)
|
||||||
|
continue;
|
||||||
|
CalcNodeCoors(
|
||||||
|
objectpathinfo[start + j].x,
|
||||||
|
objectpathinfo[start + j].y,
|
||||||
|
objectpathinfo[start + j].z,
|
||||||
|
i,
|
||||||
|
&CoorsXFormed);
|
||||||
|
|
||||||
|
// find closest unconnected node
|
||||||
|
nearestId = -1;
|
||||||
|
nearestDist = maxdist;
|
||||||
|
for(k = 0; k < TempListLength; k++){
|
||||||
|
if(tempnodes[k].linkState != 1)
|
||||||
|
continue;
|
||||||
|
dx = tempnodes[k].pos.x - CoorsXFormed.x;
|
||||||
|
if(fabs(dx) < nearestDist){
|
||||||
|
dy = tempnodes[k].pos.y - CoorsXFormed.y;
|
||||||
|
if(fabs(dy) < nearestDist){
|
||||||
|
nearestDist = max(fabs(dx), fabs(dy));
|
||||||
|
nearestId = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nearestId < 0){
|
||||||
|
// None found, add this one to temp list
|
||||||
|
tempnodes[TempListLength].pos = CoorsXFormed;
|
||||||
|
next = objectpathinfo[start + j].next;
|
||||||
|
if(next < 0){
|
||||||
|
// no link from this node, find link to this node
|
||||||
|
next = 0;
|
||||||
|
for(k = start; j != objectpathinfo[k].next; k++)
|
||||||
|
next++;
|
||||||
|
}
|
||||||
|
// link to connecting internal node
|
||||||
|
tempnodes[TempListLength].link1 = m_mapObjects[i]->m_nodeIndicesCars[typeoff + next];
|
||||||
|
if(type == PathTypeCar){
|
||||||
|
tempnodes[TempListLength].numLeftLanes = objectpathinfo[start + j].numLeftLanes;
|
||||||
|
tempnodes[TempListLength].numRightLanes = objectpathinfo[start + j].numRightLanes;
|
||||||
|
}
|
||||||
|
tempnodes[TempListLength++].linkState = 1;
|
||||||
|
}else{
|
||||||
|
// Found nearest, connect it to our neighbour
|
||||||
|
next = objectpathinfo[start + j].next;
|
||||||
|
if(next < 0){
|
||||||
|
// no link from this node, find link to this node
|
||||||
|
next = 0;
|
||||||
|
for(k = start; j != objectpathinfo[k].next; k++)
|
||||||
|
next++;
|
||||||
|
}
|
||||||
|
tempnodes[nearestId].link2 = m_mapObjects[i]->m_nodeIndicesCars[typeoff + next];
|
||||||
|
tempnodes[nearestId].linkState = 2;
|
||||||
|
|
||||||
|
// collapse this node with nearest we found
|
||||||
|
dx = m_pathNodes[tempnodes[nearestId].link1].pos.x - m_pathNodes[tempnodes[nearestId].link2].pos.x;
|
||||||
|
dy = m_pathNodes[tempnodes[nearestId].link1].pos.y - m_pathNodes[tempnodes[nearestId].link2].pos.y;
|
||||||
|
tempnodes[nearestId].pos.x = (tempnodes[nearestId].pos.x + CoorsXFormed.x)*0.5f;
|
||||||
|
tempnodes[nearestId].pos.y = (tempnodes[nearestId].pos.y + CoorsXFormed.y)*0.5f;
|
||||||
|
tempnodes[nearestId].pos.z = (tempnodes[nearestId].pos.z + CoorsXFormed.z)*0.5f;
|
||||||
|
mag = sqrt(dx*dx + dy*dy);
|
||||||
|
tempnodes[nearestId].dirX = dx/mag;
|
||||||
|
tempnodes[nearestId].dirY = dy/mag;
|
||||||
|
// do something when number of lanes doesn't agree
|
||||||
|
if(type == PathTypeCar)
|
||||||
|
if(tempnodes[nearestId].numLeftLanes != 0 && tempnodes[nearestId].numRightLanes != 0 &&
|
||||||
|
(objectpathinfo[start + j].numLeftLanes == 0 || objectpathinfo[start + j].numRightLanes == 0)){
|
||||||
|
tempnodes[nearestId].numLeftLanes = objectpathinfo[start + j].numLeftLanes;
|
||||||
|
tempnodes[nearestId].numRightLanes = objectpathinfo[start + j].numRightLanes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through previously added internal nodes and link them
|
||||||
|
for(i = oldNumPathNodes; i < m_numPathNodes; i++){
|
||||||
|
// Init link
|
||||||
|
m_pathNodes[i].numLinks = 0;
|
||||||
|
m_pathNodes[i].firstLink = m_numLinks;
|
||||||
|
|
||||||
|
// See if node connects to external nodes
|
||||||
|
for(j = 0; j < TempListLength; j++){
|
||||||
|
if(tempnodes[j].linkState != 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Add link to other side of the external
|
||||||
|
if(tempnodes[j].link1 == i)
|
||||||
|
m_linkTo[m_numLinks] = tempnodes[j].link2;
|
||||||
|
else if(tempnodes[j].link2 == i)
|
||||||
|
m_linkTo[m_numLinks] = tempnodes[j].link1;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
dist = m_pathNodes[i].pos - m_pathNodes[m_linkTo[m_numLinks]].pos;
|
||||||
|
m_distTo[m_numLinks] = dist.Magnitude();
|
||||||
|
m_linkFlags[m_numLinks] = 0;
|
||||||
|
|
||||||
|
if(type == PathTypeCar){
|
||||||
|
// IMPROVE: use a goto here
|
||||||
|
// Find existing navi node
|
||||||
|
for(k = 0; k < m_numNaviNodes; k++){
|
||||||
|
if(m_naviNodes[k].dirX == tempnodes[j].dirX &&
|
||||||
|
m_naviNodes[k].dirY == tempnodes[j].dirY &&
|
||||||
|
m_naviNodes[k].posX == tempnodes[j].pos.x &&
|
||||||
|
m_naviNodes[k].posY == tempnodes[j].pos.y){
|
||||||
|
m_naviNodeLinks[m_numLinks] = k;
|
||||||
|
k = m_numNaviNodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// k is m_numNaviNodes+1 if we found one
|
||||||
|
if(k == m_numNaviNodes){
|
||||||
|
m_naviNodes[m_numNaviNodes].dirX = tempnodes[j].dirX;
|
||||||
|
m_naviNodes[m_numNaviNodes].dirY = tempnodes[j].dirY;
|
||||||
|
m_naviNodes[m_numNaviNodes].posX = tempnodes[j].pos.x;
|
||||||
|
m_naviNodes[m_numNaviNodes].posY = tempnodes[j].pos.y;
|
||||||
|
m_naviNodes[m_numNaviNodes].pathNodeIndex = i;
|
||||||
|
m_naviNodes[m_numNaviNodes].numLeftLanes = tempnodes[j].numLeftLanes;
|
||||||
|
m_naviNodes[m_numNaviNodes].numRightLanes = tempnodes[j].numRightLanes;
|
||||||
|
m_naviNodes[m_numNaviNodes].trafficLightType = 0;
|
||||||
|
m_naviNodeLinks[m_numLinks] = m_numNaviNodes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pathNodes[i].numLinks++;
|
||||||
|
m_numLinks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find i inside path segment
|
||||||
|
iseg = 0;
|
||||||
|
for(j = max(oldNumPathNodes, i-12); j < i; j++)
|
||||||
|
if(m_pathNodes[j].objectIndex == m_pathNodes[i].objectIndex)
|
||||||
|
iseg++;
|
||||||
|
|
||||||
|
istart = 12*m_mapObjects[m_pathNodes[i].objectIndex]->m_modelIndex;
|
||||||
|
// Add links to other internal nodes
|
||||||
|
for(j = max(oldNumPathNodes, i-12); j < min(m_numPathNodes, i+12); j++){
|
||||||
|
if(m_pathNodes[i].objectIndex != m_pathNodes[j].objectIndex || i == j)
|
||||||
|
continue;
|
||||||
|
// N.B.: in every path segment, the externals have to be at the end
|
||||||
|
jseg = j-i + iseg;
|
||||||
|
|
||||||
|
jstart = 12*m_mapObjects[m_pathNodes[j].objectIndex]->m_modelIndex;
|
||||||
|
if(objectpathinfo[istart + iseg].next == jseg ||
|
||||||
|
objectpathinfo[jstart + jseg].next == iseg){
|
||||||
|
// Found a link between i and j
|
||||||
|
m_linkTo[m_numLinks] = j;
|
||||||
|
dist = m_pathNodes[i].pos - m_pathNodes[j].pos;
|
||||||
|
m_distTo[m_numLinks] = dist.Magnitude();
|
||||||
|
|
||||||
|
if(type == PathTypeCar){
|
||||||
|
posx = (m_pathNodes[i].pos.x + m_pathNodes[j].pos.x)*0.5f;
|
||||||
|
posy = (m_pathNodes[i].pos.y + m_pathNodes[j].pos.y)*0.5f;
|
||||||
|
dx = m_pathNodes[j].pos.x - m_pathNodes[i].pos.x;
|
||||||
|
dy = m_pathNodes[j].pos.y - m_pathNodes[i].pos.y;
|
||||||
|
mag = sqrt(dx*dx + dy*dy);
|
||||||
|
dx /= mag;
|
||||||
|
dy /= mag;
|
||||||
|
if(i < j){
|
||||||
|
dx = -dx;
|
||||||
|
dy = -dy;
|
||||||
|
}
|
||||||
|
// IMPROVE: use a goto here
|
||||||
|
// Find existing navi node
|
||||||
|
for(k = 0; k < m_numNaviNodes; k++){
|
||||||
|
if(m_naviNodes[k].dirX == dx &&
|
||||||
|
m_naviNodes[k].dirY == dy &&
|
||||||
|
m_naviNodes[k].posX == posx &&
|
||||||
|
m_naviNodes[k].posY == posy){
|
||||||
|
m_naviNodeLinks[m_numLinks] = k;
|
||||||
|
k = m_numNaviNodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// k is m_numNaviNodes+1 if we found one
|
||||||
|
if(k == m_numNaviNodes){
|
||||||
|
m_naviNodes[m_numNaviNodes].dirX = dx;
|
||||||
|
m_naviNodes[m_numNaviNodes].dirY = dy;
|
||||||
|
m_naviNodes[m_numNaviNodes].posX = posx;
|
||||||
|
m_naviNodes[m_numNaviNodes].posY = posy;
|
||||||
|
m_naviNodes[m_numNaviNodes].pathNodeIndex = i;
|
||||||
|
m_naviNodes[m_numNaviNodes].numLeftLanes = -1;
|
||||||
|
m_naviNodes[m_numNaviNodes].numRightLanes = -1;
|
||||||
|
m_naviNodes[m_numNaviNodes].trafficLightType = 0;
|
||||||
|
m_naviNodeLinks[m_numLinks] = m_numNaviNodes++;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
// Crosses road
|
||||||
|
if(objectpathinfo[istart + iseg].next == jseg && objectpathinfo[istart + iseg].flag & 1 ||
|
||||||
|
objectpathinfo[jstart + jseg].next == iseg && objectpathinfo[jstart + jseg].flag & 1)
|
||||||
|
m_linkFlags[m_numLinks] |= 1;
|
||||||
|
else
|
||||||
|
m_linkFlags[m_numLinks] &= ~1;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pathNodes[i].numLinks++;
|
||||||
|
m_numLinks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type == PathTypeCar){
|
||||||
|
done = 0;
|
||||||
|
// Set number of lanes for all nodes somehow
|
||||||
|
// very strange code
|
||||||
|
for(k = 0; !done && k < 10; k++){
|
||||||
|
done = 1;
|
||||||
|
for(i = 0; i < m_numPathNodes; i++){
|
||||||
|
if(m_pathNodes[i].numLinks != 2)
|
||||||
|
continue;
|
||||||
|
l1 = m_naviNodeLinks[m_pathNodes[i].firstLink];
|
||||||
|
l2 = m_naviNodeLinks[m_pathNodes[i].firstLink+1];
|
||||||
|
|
||||||
|
if(m_naviNodes[l1].numLeftLanes == -1 &&
|
||||||
|
m_naviNodes[l2].numLeftLanes != -1){
|
||||||
|
done = 0;
|
||||||
|
if(m_naviNodes[l2].pathNodeIndex == i){
|
||||||
|
// why switch left and right here?
|
||||||
|
m_naviNodes[l1].numLeftLanes = m_naviNodes[l2].numRightLanes;
|
||||||
|
m_naviNodes[l1].numRightLanes = m_naviNodes[l2].numLeftLanes;
|
||||||
|
}else{
|
||||||
|
m_naviNodes[l1].numLeftLanes = m_naviNodes[l2].numLeftLanes;
|
||||||
|
m_naviNodes[l1].numRightLanes = m_naviNodes[l2].numRightLanes;
|
||||||
|
}
|
||||||
|
m_naviNodes[l1].pathNodeIndex = i;
|
||||||
|
}else if(m_naviNodes[l1].numLeftLanes != -1 &&
|
||||||
|
m_naviNodes[l2].numLeftLanes == -1){
|
||||||
|
done = 0;
|
||||||
|
if(m_naviNodes[l1].pathNodeIndex == i){
|
||||||
|
// why switch left and right here?
|
||||||
|
m_naviNodes[l2].numLeftLanes = m_naviNodes[l1].numRightLanes;
|
||||||
|
m_naviNodes[l2].numRightLanes = m_naviNodes[l1].numLeftLanes;
|
||||||
|
}else{
|
||||||
|
m_naviNodes[l2].numLeftLanes = m_naviNodes[l1].numLeftLanes;
|
||||||
|
m_naviNodes[l2].numRightLanes = m_naviNodes[l1].numRightLanes;
|
||||||
|
}
|
||||||
|
m_naviNodes[l2].pathNodeIndex = i;
|
||||||
|
}else if(m_naviNodes[l1].numLeftLanes == -1 &&
|
||||||
|
m_naviNodes[l2].numLeftLanes == -1)
|
||||||
|
done = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to default values for number of lanes
|
||||||
|
for(i = 0; i < m_numPathNodes; i++)
|
||||||
|
for(j = 0; j < m_pathNodes[i].numLinks; j++){
|
||||||
|
k = m_naviNodeLinks[m_pathNodes[i].firstLink + j];
|
||||||
|
if(m_naviNodes[k].numLeftLanes < 0)
|
||||||
|
m_naviNodes[k].numLeftLanes = 1;
|
||||||
|
if(m_naviNodes[k].numRightLanes < 0)
|
||||||
|
m_naviNodes[k].numRightLanes = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set flags for car nodes
|
||||||
|
if(type == PathTypeCar){
|
||||||
|
do{
|
||||||
|
cont = 0;
|
||||||
|
for(i = 0; i < m_numPathNodes; i++){
|
||||||
|
m_pathNodes[i].flags &= ~PathNodeDisabled;
|
||||||
|
m_pathNodes[i].flags &= ~PathNodeBetweenLevels;
|
||||||
|
// See if node is a dead end, if so, we're not done yet
|
||||||
|
if((m_pathNodes[i].flags & PathNodeDeadEnd) == 0){
|
||||||
|
k = 0;
|
||||||
|
for(j = 0; j < m_pathNodes[i].numLinks; j++)
|
||||||
|
if((m_pathNodes[m_linkTo[m_pathNodes[i].firstLink + j]].flags & PathNodeDeadEnd) == 0)
|
||||||
|
k++;
|
||||||
|
if(k < 2){
|
||||||
|
m_pathNodes[i].flags |= PathNodeDeadEnd;
|
||||||
|
cont = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}while(cont);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove isolated ped nodes
|
||||||
|
if(type == PathTypePed)
|
||||||
|
for(i = oldNumPathNodes; i < m_numPathNodes; i++){
|
||||||
|
if(m_pathNodes[i].numLinks != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Remove node
|
||||||
|
for(j = i; j < m_numPathNodes-1; j++)
|
||||||
|
m_pathNodes[j] = m_pathNodes[j+1];
|
||||||
|
|
||||||
|
// Fix links
|
||||||
|
for(j = oldNumLinks; j < m_numLinks; j++)
|
||||||
|
if(m_linkTo[j] >= i)
|
||||||
|
m_linkTo[j]--;
|
||||||
|
|
||||||
|
// Also in treadables
|
||||||
|
for(j = 0; j < m_numMapObjects; j++)
|
||||||
|
for(k = 0; k < 12; k++){
|
||||||
|
if(m_mapObjects[j]->m_nodeIndicesPeds[k] == i){
|
||||||
|
// remove this one
|
||||||
|
for(l = k; l < 12-1; l++)
|
||||||
|
m_mapObjects[j]->m_nodeIndicesPeds[l] = m_mapObjects[j]->m_nodeIndicesPeds[l+1];
|
||||||
|
m_mapObjects[j]->m_nodeIndicesPeds[11] = -1;
|
||||||
|
}else if(m_mapObjects[j]->m_nodeIndicesPeds[k] > i)
|
||||||
|
m_mapObjects[j]->m_nodeIndicesPeds[k]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
i--;
|
||||||
|
m_numPathNodes--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPathFind::CalcNodeCoors(int16 x, int16 y, int16 z, int id, CVector *out)
|
||||||
|
{
|
||||||
|
CVector pos;
|
||||||
|
pos.x = x / 16.0f;
|
||||||
|
pos.y = y / 16.0f;
|
||||||
|
pos.z = z / 16.0f;
|
||||||
|
*out = m_mapObjects[id]->GetMatrix() * pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x429610, &CPathFind::PreparePathData, PATCH_JUMP);
|
||||||
|
InjectHook(0x429C20, &CPathFind::PreparePathDataForType, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
130
src/PathFind.h
Normal file
130
src/PathFind.h
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Treadable.h"
|
||||||
|
|
||||||
|
struct CPathNode
|
||||||
|
{
|
||||||
|
CVector pos;
|
||||||
|
CPathNode *prev; //?
|
||||||
|
CPathNode *next;
|
||||||
|
int16 unknown;
|
||||||
|
int16 objectIndex;
|
||||||
|
int16 firstLink;
|
||||||
|
uint8 numLinks;
|
||||||
|
uint8 flags;
|
||||||
|
uint8 group;
|
||||||
|
/* VC:
|
||||||
|
int16 unk1;
|
||||||
|
int16 nextIndex;
|
||||||
|
int16 x;
|
||||||
|
int16 y;
|
||||||
|
int16 z;
|
||||||
|
int16 unknown;
|
||||||
|
int16 firstLink;
|
||||||
|
int8 width;
|
||||||
|
int8 group;
|
||||||
|
int8 numLinks : 4;
|
||||||
|
int8 bDeadEnd : 1;
|
||||||
|
int8 bTurnedOff : 1; // flag 8 in node info
|
||||||
|
int8 flagA40 : 1; // flag 20 in node info
|
||||||
|
int8 flagA80 : 1; // flag 4 in node info
|
||||||
|
int8 flagB1 : 1; // flag 10 in node info
|
||||||
|
int8 flagB2 : 1; // flag 2 in node info
|
||||||
|
int8 flagB4 : 1;
|
||||||
|
int8 speedLimit : 2; // speed limit
|
||||||
|
int8 flagB20 : 1;
|
||||||
|
int8 flagB40 : 1;
|
||||||
|
int8 flagB80 : 1;
|
||||||
|
int8 spawnRate : 4;
|
||||||
|
int8 flagsC : 4;
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: name?
|
||||||
|
struct NaviNode
|
||||||
|
{
|
||||||
|
float posX;
|
||||||
|
float posY;
|
||||||
|
float dirX;
|
||||||
|
float dirY;
|
||||||
|
int16 pathNodeIndex;
|
||||||
|
int8 numLeftLanes;
|
||||||
|
int8 numRightLanes;
|
||||||
|
int8 trafficLightType;
|
||||||
|
// probably only padding
|
||||||
|
int8 field15;
|
||||||
|
int8 field16;
|
||||||
|
int8 field17;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CPathInfoForObject
|
||||||
|
{
|
||||||
|
int16 x;
|
||||||
|
int16 y;
|
||||||
|
int16 z;
|
||||||
|
int8 type;
|
||||||
|
int8 next;
|
||||||
|
int8 numLeftLanes;
|
||||||
|
int8 numRightLanes;
|
||||||
|
uint8 flag;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CTempNode
|
||||||
|
{
|
||||||
|
CVector pos;
|
||||||
|
float dirX;
|
||||||
|
float dirY;
|
||||||
|
int16 link1;
|
||||||
|
int16 link2;
|
||||||
|
int8 numLeftLanes;
|
||||||
|
int8 numRightLanes;
|
||||||
|
int8 linkState;
|
||||||
|
// probably padding
|
||||||
|
int8 field1B;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CTempDetachedNode // unused
|
||||||
|
{
|
||||||
|
uint8 foo[20];
|
||||||
|
};
|
||||||
|
|
||||||
|
class CPathFind
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/* For reference VC:
|
||||||
|
CPathNode pathNodes[9650];
|
||||||
|
NaviNode naviNodes[3500];
|
||||||
|
CBuilding *mapObjects[1250];
|
||||||
|
// 0x8000 is cross road flag
|
||||||
|
// 0x4000 is traffic light flag
|
||||||
|
uint16 linkTo[20400];
|
||||||
|
uint8 distTo[20400];
|
||||||
|
int16 naviNodeLinks[20400];
|
||||||
|
*/
|
||||||
|
CPathNode m_pathNodes[4930];
|
||||||
|
NaviNode m_naviNodes[2076];
|
||||||
|
CTreadable *m_mapObjects[1250];
|
||||||
|
uint8 m_objectFlags[1250];
|
||||||
|
int16 m_linkTo[10260];
|
||||||
|
int16 m_distTo[10260];
|
||||||
|
uint8 m_linkFlags[10260];
|
||||||
|
int16 m_naviNodeLinks[10260];
|
||||||
|
int32 m_numPathNodes;
|
||||||
|
int32 m_numCarPathNodes;
|
||||||
|
int32 m_numPedPathNodes;
|
||||||
|
int16 m_numMapObjects;
|
||||||
|
int16 m_numLinks;
|
||||||
|
int32 m_numNaviNodes;
|
||||||
|
int32 h;
|
||||||
|
uint8 m_numGroups[2];
|
||||||
|
CPathNode m_aExtraPaths[872];
|
||||||
|
|
||||||
|
void PreparePathData(void);
|
||||||
|
void CountFloodFillGroups(uint8 type);
|
||||||
|
void PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoForObject *objectpathinfo,
|
||||||
|
float unk, CTempDetachedNode *detachednodes, int unused);
|
||||||
|
void CalcNodeCoors(int16 x, int16 y, int16 z, int32 id, CVector *out);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CPathFind) == 0x4c8f4, "CPathFind: error");
|
||||||
|
|
||||||
|
extern CPathFind &ThePaths;
|
81
src/Placeable.cpp
Normal file
81
src/Placeable.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#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 x, xmin, xmax;
|
||||||
|
float y, ymin, ymax;
|
||||||
|
xmin = x1;
|
||||||
|
xmax = x2;
|
||||||
|
ymin = y1;
|
||||||
|
ymax = y2;
|
||||||
|
if(x2 > x1){
|
||||||
|
xmin = x2;
|
||||||
|
xmax = x1;
|
||||||
|
}
|
||||||
|
if(y2 > y1){
|
||||||
|
ymin = y2;
|
||||||
|
ymax = y1;
|
||||||
|
}
|
||||||
|
x = GetPosition().x;
|
||||||
|
y = GetPosition().y;
|
||||||
|
return xmin <= x && x <= xmax &&
|
||||||
|
ymin <= y && y <= ymax;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CPlaceable::IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2)
|
||||||
|
{
|
||||||
|
float x, xmin, xmax;
|
||||||
|
float y, ymin, ymax;
|
||||||
|
float z, zmin, zmax;
|
||||||
|
xmin = x1;
|
||||||
|
xmax = x2;
|
||||||
|
ymin = y1;
|
||||||
|
ymax = y2;
|
||||||
|
zmin = z1;
|
||||||
|
zmax = z2;
|
||||||
|
if(x2 > x1){
|
||||||
|
xmin = x2;
|
||||||
|
xmax = x1;
|
||||||
|
}
|
||||||
|
if(y2 > y1){
|
||||||
|
ymin = y2;
|
||||||
|
ymax = y1;
|
||||||
|
}
|
||||||
|
if(z2 > z1){
|
||||||
|
zmin = z2;
|
||||||
|
zmax = z1;
|
||||||
|
}
|
||||||
|
x = GetPosition().x;
|
||||||
|
y = GetPosition().y;
|
||||||
|
z = GetPosition().z;
|
||||||
|
return xmin <= x && x <= xmax &&
|
||||||
|
ymin <= y && y <= ymax &&
|
||||||
|
zmin <= z && z <= zmax;
|
||||||
|
}
|
||||||
|
|
||||||
|
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/Placeable.h
Normal file
26
src/Placeable.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CPlaceable
|
||||||
|
{
|
||||||
|
// disable allocation
|
||||||
|
static void *operator new(size_t) { assert(0); return nil; }
|
||||||
|
static void operator delete(void*, size_t) { assert(0); }
|
||||||
|
public:
|
||||||
|
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");
|
19
src/Pools.cpp
Normal file
19
src/Pools.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "Pools.h"
|
||||||
|
|
||||||
|
CCPtrNodePool *&CPools::ms_pPtrNodePool = *(CCPtrNodePool**)0x943044;
|
||||||
|
CEntryInfoNodePool *&CPools::ms_pEntryInfoNodePool = *(CEntryInfoNodePool**)0x941448;
|
||||||
|
CBuildingPool *&CPools::ms_pBuildingPool = *(CBuildingPool**)0x8F2C04;
|
||||||
|
CTreadablePool *&CPools::ms_pTreadablePool = *(CTreadablePool**)0x8F2568;
|
||||||
|
CObjectPool *&CPools::ms_pObjectPool = *(CObjectPool**)0x880E28;
|
||||||
|
|
||||||
|
void
|
||||||
|
CPools::Initialise(void)
|
||||||
|
{
|
||||||
|
// TODO: unused right now
|
||||||
|
ms_pPtrNodePool = new CCPtrNodePool(NUMPTRNODES);
|
||||||
|
ms_pEntryInfoNodePool = new CEntryInfoNodePool(NUMENTRYINFOS);
|
||||||
|
ms_pBuildingPool = new CBuildingPool(NUMBUILDINGS);
|
||||||
|
ms_pTreadablePool = new CTreadablePool(NUMTREADABLES);
|
||||||
|
ms_pObjectPool = new CObjectPool(NUMOBJECTS);
|
||||||
|
}
|
34
src/Pools.h
Normal file
34
src/Pools.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "templates.h"
|
||||||
|
#include "Lists.h"
|
||||||
|
#include "Treadable.h"
|
||||||
|
#include "Object.h"
|
||||||
|
#include "CutsceneHead.h"
|
||||||
|
|
||||||
|
typedef CPool<CPtrNode> CCPtrNodePool;
|
||||||
|
typedef CPool<CEntryInfoNode> CEntryInfoNodePool;
|
||||||
|
typedef CPool<CBuilding> CBuildingPool;
|
||||||
|
typedef CPool<CTreadable> CTreadablePool;
|
||||||
|
typedef CPool<CObject, CCutsceneHead> CObjectPool;
|
||||||
|
|
||||||
|
class CPools
|
||||||
|
{
|
||||||
|
static CCPtrNodePool *&ms_pPtrNodePool;
|
||||||
|
static CEntryInfoNodePool *&ms_pEntryInfoNodePool;
|
||||||
|
// ms_pPedPool
|
||||||
|
// ms_pVehiclePool
|
||||||
|
static CBuildingPool *&ms_pBuildingPool;
|
||||||
|
static CTreadablePool *&ms_pTreadablePool;
|
||||||
|
static CObjectPool *&ms_pObjectPool;
|
||||||
|
// ms_pDummyPool
|
||||||
|
// ms_pAudioScriptObjectPool
|
||||||
|
public:
|
||||||
|
static CCPtrNodePool *GetPtrNodePool(void) { return ms_pPtrNodePool; }
|
||||||
|
static CEntryInfoNodePool *GetEntryInfoNodePool(void) { return ms_pEntryInfoNodePool; }
|
||||||
|
static CBuildingPool *GetBuildingPool(void) { return ms_pBuildingPool; }
|
||||||
|
static CTreadablePool *GetTreadablePool(void) { return ms_pTreadablePool; }
|
||||||
|
static CObjectPool *GetObjectPool(void) { return ms_pObjectPool; }
|
||||||
|
|
||||||
|
static void Initialise(void);
|
||||||
|
};
|
22
src/References.cpp
Normal file
22
src/References.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x4A7350, CReferences::Init, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
17
src/References.h
Normal file
17
src/References.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CEntity;
|
||||||
|
|
||||||
|
struct CReference
|
||||||
|
{
|
||||||
|
CReference *next;
|
||||||
|
CEntity **pentity;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CReferences
|
||||||
|
{
|
||||||
|
static CReference *aRefs; //[NUMREFERENCES];
|
||||||
|
public:
|
||||||
|
static CReference *&pEmptyList;
|
||||||
|
static void Init(void);
|
||||||
|
};
|
19
src/RwHelper.cpp
Normal file
19
src/RwHelper.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
3
src/RwHelper.h
Normal file
3
src/RwHelper.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
RwObject *GetFirstObject(RwFrame *frame);
|
10
src/Streaming.cpp
Normal file
10
src/Streaming.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Streaming.h"
|
||||||
|
|
||||||
|
bool &CStreaming::ms_disableStreaming = *(bool*)0x95CD6E;
|
||||||
|
int32 &CStreaming::ms_numModelsRequested = *(int32*)0x8E2C10;
|
||||||
|
CStreamingInfo *CStreaming::ms_aInfoForModel = (CStreamingInfo*)0x6C7088;
|
||||||
|
|
||||||
|
WRAPPER void CStreaming::RemoveModel(int32 id) { EAXJMP(0x408830); }
|
||||||
|
WRAPPER void CStreaming::RequestModel(int32 model, int32 flags) { EAXJMP(0x407EA0); }
|
54
src/Streaming.h
Normal file
54
src/Streaming.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STREAM_OFFSET_MODEL = 0,
|
||||||
|
STREAM_OFFSET_TXD = STREAM_OFFSET_MODEL+MODELINFOSIZE,
|
||||||
|
NUMSTREAMINFO = STREAM_OFFSET_TXD+TXDSTORESIZE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum StreamFlags
|
||||||
|
{
|
||||||
|
STREAM_DONT_REMOVE = 0x01,
|
||||||
|
STREAM_SCRIPTOWNED = 0x02,
|
||||||
|
STREAM_DEPENDENCY = 0x04,
|
||||||
|
STREAM_PRIORITY = 0x08,
|
||||||
|
STREAM_NOFADE = 0x10,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum StreamLoadState
|
||||||
|
{
|
||||||
|
STREAM_NOTLOADED = 0,
|
||||||
|
STREAM_LOADED = 1,
|
||||||
|
STREAM_INQUEUE = 2,
|
||||||
|
STREAM_READING = 3, // what is this?
|
||||||
|
STREAM_BIGFILE = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
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 *pos, uint32 *size);
|
||||||
|
// void SetCdPosnAndSize(uint32 pos, uint32 size);
|
||||||
|
// void AddToList(CStreamingInfo *link);
|
||||||
|
// void RemoveFromList(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CStreaming
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool &ms_disableStreaming;
|
||||||
|
static int32 &ms_numModelsRequested;
|
||||||
|
static CStreamingInfo *ms_aInfoForModel; //[NUMSTREAMINFO]
|
||||||
|
|
||||||
|
static void RemoveModel(int32 id);
|
||||||
|
static void RequestModel(int32 model, int32 flags);
|
||||||
|
};
|
44
src/SurfaceTable.cpp
Normal file
44
src/SurfaceTable.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "SurfaceTable.h"
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
99
src/SurfaceTable.h
Normal file
99
src/SurfaceTable.h
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#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_ROAD0,
|
||||||
|
SURFACE_ROAD1,
|
||||||
|
SURFACE_GRASS,
|
||||||
|
SURFACE_DIRT,
|
||||||
|
SURFACE_MUD,
|
||||||
|
SURFACE_PAVEMENT,
|
||||||
|
SURFACE_METAL6,
|
||||||
|
SURFACE_GLASS,
|
||||||
|
SURFACE_HARD8,
|
||||||
|
SURFACE_METAL_DOOR,
|
||||||
|
SURFACE_METAL10,
|
||||||
|
SURFACE_METAL11,
|
||||||
|
SURFACE_METAL12,
|
||||||
|
SURFACE_METAL13,
|
||||||
|
SURFACE_METAL14,
|
||||||
|
SURFACE_METAL15,
|
||||||
|
SURFACE_METAL_FENCE,
|
||||||
|
SURFACE_FLESH,
|
||||||
|
SURFACE_SAND18,
|
||||||
|
SURFACE_WATER,
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
class CSurfaceTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static int GetAdhesionGroup(uint8 surfaceType);
|
||||||
|
};
|
92
src/Timecycle.cpp
Normal file
92
src/Timecycle.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "Timecycle.h"
|
||||||
|
|
||||||
|
int (*CTimeCycle::m_nAmbientRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x86AF78;
|
||||||
|
int (*CTimeCycle::m_nAmbientGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x665308;
|
||||||
|
int (*CTimeCycle::m_nAmbientBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x72CF88;
|
||||||
|
int (*CTimeCycle::m_nDirectionalRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6FAB78;
|
||||||
|
int (*CTimeCycle::m_nDirectionalGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6F4528;
|
||||||
|
int (*CTimeCycle::m_nDirectionalBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x83CE58;
|
||||||
|
int (*CTimeCycle::m_nSkyTopRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87FB90;
|
||||||
|
int (*CTimeCycle::m_nSkyTopGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x8460A8;
|
||||||
|
int (*CTimeCycle::m_nSkyTopBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87B158;
|
||||||
|
int (*CTimeCycle::m_nSkyBottomRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6FA960;
|
||||||
|
int (*CTimeCycle::m_nSkyBottomGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x70D6A8;
|
||||||
|
int (*CTimeCycle::m_nSkyBottomBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x83D288;
|
||||||
|
int (*CTimeCycle::m_nSunCoreRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x878360;
|
||||||
|
int (*CTimeCycle::m_nSunCoreGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6EE088;
|
||||||
|
int (*CTimeCycle::m_nSunCoreBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x773A68;
|
||||||
|
int (*CTimeCycle::m_nSunCoronaRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x664B60;
|
||||||
|
int (*CTimeCycle::m_nSunCoronaGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6F01E0;
|
||||||
|
int (*CTimeCycle::m_nSunCoronaBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6E6340;
|
||||||
|
float (*CTimeCycle::m_fSunSize)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x733510;
|
||||||
|
float (*CTimeCycle::m_fSpriteSize)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x87F820;
|
||||||
|
float (*CTimeCycle::m_fSpriteBrightness)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x6E96F0;
|
||||||
|
short (*CTimeCycle::m_nShadowStrength)[NUMWEATHERS] = (short(*)[NUMWEATHERS])0x83CFD8;
|
||||||
|
short (*CTimeCycle::m_nLightShadowStrength)[NUMWEATHERS] = (short(*)[NUMWEATHERS])0x72B0F8;
|
||||||
|
short (*CTimeCycle::m_nTreeShadowStrength)[NUMWEATHERS] = (short(*)[NUMWEATHERS])0x733450;
|
||||||
|
float (*CTimeCycle::m_fFogStart)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x8806C8;
|
||||||
|
float (*CTimeCycle::m_fFarClip)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x8804E0;
|
||||||
|
float (*CTimeCycle::m_fLightsOnGroundBrightness)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x83D108;
|
||||||
|
int (*CTimeCycle::m_nLowCloudsRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x726770;
|
||||||
|
int (*CTimeCycle::m_nLowCloudsGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87BF08;
|
||||||
|
int (*CTimeCycle::m_nLowCloudsBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87FA10;
|
||||||
|
int (*CTimeCycle::m_nFluffyCloudsTopRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x70F2B0;
|
||||||
|
int (*CTimeCycle::m_nFluffyCloudsTopGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x72D288;
|
||||||
|
int (*CTimeCycle::m_nFluffyCloudsTopBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x86B108;
|
||||||
|
int (*CTimeCycle::m_nFluffyCloudsBottomRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6E8DA8;
|
||||||
|
int (*CTimeCycle::m_nFluffyCloudsBottomGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x715AA8;
|
||||||
|
int (*CTimeCycle::m_nFluffyCloudsBottomBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6EE2D0;
|
||||||
|
float (*CTimeCycle::m_fBlurRed)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x87C7E0;
|
||||||
|
float (*CTimeCycle::m_fBlurGreen)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x774C10;
|
||||||
|
float (*CTimeCycle::m_fBlurBlue)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x8784E0;
|
||||||
|
float (*CTimeCycle::m_fBlurAlpha)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x733690;
|
||||||
|
|
||||||
|
float &CTimeCycle::m_fCurrentAmbientRed = *(float*)0x8F29B4;
|
||||||
|
float &CTimeCycle::m_fCurrentAmbientGreen = *(float*)0x94144C;
|
||||||
|
float &CTimeCycle::m_fCurrentAmbientBlue = *(float*)0x942FC0;
|
||||||
|
float &CTimeCycle::m_fCurrentDirectionalRed = *(float*)0x8F29D8;
|
||||||
|
float &CTimeCycle::m_fCurrentDirectionalGreen = *(float*)0x940594;
|
||||||
|
float &CTimeCycle::m_fCurrentDirectionalBlue = *(float*)0x942FAC;
|
||||||
|
int &CTimeCycle::m_nCurrentSkyTopRed = *(int*)0x9403C0;
|
||||||
|
int &CTimeCycle::m_nCurrentSkyTopGreen = *(int*)0x943074;
|
||||||
|
int &CTimeCycle::m_nCurrentSkyTopBlue = *(int*)0x8F29B8;
|
||||||
|
int &CTimeCycle::m_nCurrentSkyBottomRed = *(int*)0x9414D0;
|
||||||
|
int &CTimeCycle::m_nCurrentSkyBottomGreen = *(int*)0x8F2BD0;
|
||||||
|
int &CTimeCycle::m_nCurrentSkyBottomBlue = *(int*)0x8F625C;
|
||||||
|
int &CTimeCycle::m_nCurrentSunCoreRed = *(int*)0x8F2534;
|
||||||
|
int &CTimeCycle::m_nCurrentSunCoreGreen = *(int*)0x8F6264;
|
||||||
|
int &CTimeCycle::m_nCurrentSunCoreBlue = *(int*)0x94149C;
|
||||||
|
int &CTimeCycle::m_nCurrentSunCoronaRed = *(int*)0x8F2C1C;
|
||||||
|
int &CTimeCycle::m_nCurrentSunCoronaGreen = *(int*)0x885B54;
|
||||||
|
int &CTimeCycle::m_nCurrentSunCoronaBlue = *(int*)0x880F60;
|
||||||
|
float &CTimeCycle::m_fCurrentSunSize = *(float*)0x940588;
|
||||||
|
float &CTimeCycle::m_fCurrentSpriteSize = *(float*)0x8F1AA8;
|
||||||
|
float &CTimeCycle::m_fCurrentSpriteBrightness = *(float*)0x8F5FDC;
|
||||||
|
int &CTimeCycle::m_nCurrentShadowStrength = *(int*)0x95CC76;
|
||||||
|
int &CTimeCycle::m_nCurrentLightShadowStrength = *(int*)0x95CC66;
|
||||||
|
int &CTimeCycle::m_nCurrentTreeShadowStrength = *(int*)0x95CC86;
|
||||||
|
float &CTimeCycle::m_fCurrentFogStart = *(float*)0x8F1AE0;
|
||||||
|
float &CTimeCycle::m_fCurrentFarClip = *(float*)0x8F5FD8;
|
||||||
|
float &CTimeCycle::m_fCurrentLightsOnGroundBrightness = *(float*)0x8F1B60;
|
||||||
|
int &CTimeCycle::m_nCurrentLowCloudsRed = *(int*)0x95CB54;
|
||||||
|
int &CTimeCycle::m_nCurrentLowCloudsGreen = *(int*)0x95CB48;
|
||||||
|
int &CTimeCycle::m_nCurrentLowCloudsBlue = *(int*)0x95CC1C;
|
||||||
|
int &CTimeCycle::m_nCurrentFluffyCloudsTopRed = *(int*)0x8F2550;
|
||||||
|
int &CTimeCycle::m_nCurrentFluffyCloudsTopGreen = *(int*)0x8F59CC;
|
||||||
|
int &CTimeCycle::m_nCurrentFluffyCloudsTopBlue = *(int*)0x941434;
|
||||||
|
int &CTimeCycle::m_nCurrentFluffyCloudsBottomRed = *(int*)0x8F1A38;
|
||||||
|
int &CTimeCycle::m_nCurrentFluffyCloudsBottomGreen = *(int*)0x8E28B8;
|
||||||
|
int &CTimeCycle::m_nCurrentFluffyCloudsBottomBlue = *(int*)0x8F3960;
|
||||||
|
float &CTimeCycle::m_fCurrentBlurRed = *(float*)0x8F6000;
|
||||||
|
float &CTimeCycle::m_fCurrentBlurGreen = *(float*)0x9405A0;
|
||||||
|
float &CTimeCycle::m_fCurrentBlurBlue = *(float*)0x8F250C;
|
||||||
|
float &CTimeCycle::m_fCurrentBlurAlpha = *(float*)0x940728;
|
||||||
|
int &CTimeCycle::m_nCurrentFogColourRed = *(int*)0x940714;
|
||||||
|
int &CTimeCycle::m_nCurrentFogColourGreen = *(int*)0x8E2A60;
|
||||||
|
int &CTimeCycle::m_nCurrentFogColourBlue = *(int*)0x8F57EC;
|
||||||
|
|
||||||
|
int &CTimeCycle::m_FogReduction = *(int*)0x880FB8;
|
||||||
|
|
||||||
|
int &CTimeCycle::m_CurrentStoredValue = *(int*)0x94057C;
|
||||||
|
CVector *CTimeCycle::m_VectorToSun = (CVector*)0x665548; // [16]
|
111
src/Timecycle.h
Normal file
111
src/Timecycle.h
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
class CTimeCycle
|
||||||
|
{
|
||||||
|
static int (*m_nAmbientRed)[NUMWEATHERS];
|
||||||
|
static int (*m_nAmbientGreen)[NUMWEATHERS];
|
||||||
|
static int (*m_nAmbientBlue)[NUMWEATHERS];
|
||||||
|
|
||||||
|
static int (*m_nDirectionalRed)[NUMWEATHERS];
|
||||||
|
static int (*m_nDirectionalGreen)[NUMWEATHERS];
|
||||||
|
static int (*m_nDirectionalBlue)[NUMWEATHERS];
|
||||||
|
static int (*m_nSkyTopRed)[NUMWEATHERS];
|
||||||
|
static int (*m_nSkyTopGreen)[NUMWEATHERS];
|
||||||
|
static int (*m_nSkyTopBlue)[NUMWEATHERS];
|
||||||
|
static int (*m_nSkyBottomRed)[NUMWEATHERS];
|
||||||
|
static int (*m_nSkyBottomGreen)[NUMWEATHERS];
|
||||||
|
static int (*m_nSkyBottomBlue)[NUMWEATHERS];
|
||||||
|
static int (*m_nSunCoreRed)[NUMWEATHERS];
|
||||||
|
static int (*m_nSunCoreGreen)[NUMWEATHERS];
|
||||||
|
static int (*m_nSunCoreBlue)[NUMWEATHERS];
|
||||||
|
static int (*m_nSunCoronaRed)[NUMWEATHERS];
|
||||||
|
static int (*m_nSunCoronaGreen)[NUMWEATHERS];
|
||||||
|
static int (*m_nSunCoronaBlue)[NUMWEATHERS];
|
||||||
|
static float (*m_fSunSize)[NUMWEATHERS];
|
||||||
|
static float (*m_fSpriteSize)[NUMWEATHERS];
|
||||||
|
static float (*m_fSpriteBrightness)[NUMWEATHERS];
|
||||||
|
static short (*m_nShadowStrength)[NUMWEATHERS];
|
||||||
|
static short (*m_nLightShadowStrength)[NUMWEATHERS];
|
||||||
|
static short (*m_nTreeShadowStrength)[NUMWEATHERS];
|
||||||
|
static float (*m_fFogStart)[NUMWEATHERS];
|
||||||
|
static float (*m_fFarClip)[NUMWEATHERS];
|
||||||
|
static float (*m_fLightsOnGroundBrightness)[NUMWEATHERS];
|
||||||
|
static int (*m_nLowCloudsRed)[NUMWEATHERS];
|
||||||
|
static int (*m_nLowCloudsGreen)[NUMWEATHERS];
|
||||||
|
static int (*m_nLowCloudsBlue)[NUMWEATHERS];
|
||||||
|
static int (*m_nFluffyCloudsTopRed)[NUMWEATHERS];
|
||||||
|
static int (*m_nFluffyCloudsTopGreen)[NUMWEATHERS];
|
||||||
|
static int (*m_nFluffyCloudsTopBlue)[NUMWEATHERS];
|
||||||
|
static int (*m_nFluffyCloudsBottomRed)[NUMWEATHERS];
|
||||||
|
static int (*m_nFluffyCloudsBottomGreen)[NUMWEATHERS];
|
||||||
|
static int (*m_nFluffyCloudsBottomBlue)[NUMWEATHERS];
|
||||||
|
static float (*m_fBlurRed)[NUMWEATHERS];
|
||||||
|
static float (*m_fBlurGreen)[NUMWEATHERS];
|
||||||
|
static float (*m_fBlurBlue)[NUMWEATHERS];
|
||||||
|
static float (*m_fBlurAlpha)[NUMWEATHERS];
|
||||||
|
|
||||||
|
static float &m_fCurrentAmbientRed;
|
||||||
|
static float &m_fCurrentAmbientGreen;
|
||||||
|
static float &m_fCurrentAmbientBlue;
|
||||||
|
static float &m_fCurrentDirectionalRed;
|
||||||
|
static float &m_fCurrentDirectionalGreen;
|
||||||
|
static float &m_fCurrentDirectionalBlue;
|
||||||
|
static int &m_nCurrentSkyTopRed;
|
||||||
|
static int &m_nCurrentSkyTopGreen;
|
||||||
|
static int &m_nCurrentSkyTopBlue;
|
||||||
|
static int &m_nCurrentSkyBottomRed;
|
||||||
|
static int &m_nCurrentSkyBottomGreen;
|
||||||
|
static int &m_nCurrentSkyBottomBlue;
|
||||||
|
static int &m_nCurrentSunCoreRed;
|
||||||
|
static int &m_nCurrentSunCoreGreen;
|
||||||
|
static int &m_nCurrentSunCoreBlue;
|
||||||
|
static int &m_nCurrentSunCoronaRed;
|
||||||
|
static int &m_nCurrentSunCoronaGreen;
|
||||||
|
static int &m_nCurrentSunCoronaBlue;
|
||||||
|
static float &m_fCurrentSunSize;
|
||||||
|
static float &m_fCurrentSpriteSize;
|
||||||
|
static float &m_fCurrentSpriteBrightness;
|
||||||
|
static int &m_nCurrentShadowStrength;
|
||||||
|
static int &m_nCurrentLightShadowStrength;
|
||||||
|
static int &m_nCurrentTreeShadowStrength;
|
||||||
|
static float &m_fCurrentFogStart;
|
||||||
|
static float &m_fCurrentFarClip;
|
||||||
|
static float &m_fCurrentLightsOnGroundBrightness;
|
||||||
|
static int &m_nCurrentLowCloudsRed;
|
||||||
|
static int &m_nCurrentLowCloudsGreen;
|
||||||
|
static int &m_nCurrentLowCloudsBlue;
|
||||||
|
static int &m_nCurrentFluffyCloudsTopRed;
|
||||||
|
static int &m_nCurrentFluffyCloudsTopGreen;
|
||||||
|
static int &m_nCurrentFluffyCloudsTopBlue;
|
||||||
|
static int &m_nCurrentFluffyCloudsBottomRed;
|
||||||
|
static int &m_nCurrentFluffyCloudsBottomGreen;
|
||||||
|
static int &m_nCurrentFluffyCloudsBottomBlue;
|
||||||
|
static float &m_fCurrentBlurRed;
|
||||||
|
static float &m_fCurrentBlurGreen;
|
||||||
|
static float &m_fCurrentBlurBlue;
|
||||||
|
static float &m_fCurrentBlurAlpha;
|
||||||
|
static int &m_nCurrentFogColourRed;
|
||||||
|
static int &m_nCurrentFogColourGreen;
|
||||||
|
static int &m_nCurrentFogColourBlue;
|
||||||
|
|
||||||
|
static int &m_FogReduction;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static int &m_CurrentStoredValue;
|
||||||
|
static CVector *m_VectorToSun; // [16]
|
||||||
|
|
||||||
|
static float GetAmbientRed(void) { return m_fCurrentAmbientRed; }
|
||||||
|
static float GetAmbientGreen(void) { return m_fCurrentAmbientGreen; }
|
||||||
|
static float GetAmbientBlue(void) { return m_fCurrentAmbientBlue; }
|
||||||
|
static float GetDirectionalRed(void) { return m_fCurrentDirectionalRed; }
|
||||||
|
static float GetDirectionalGreen(void) { return m_fCurrentDirectionalGreen; }
|
||||||
|
static float GetDirectionalBlue(void) { return m_fCurrentDirectionalBlue; }
|
||||||
|
static int GetLowCloudsRed(void) { return m_nCurrentLowCloudsRed; }
|
||||||
|
static int GetLowCloudsGreen(void) { return m_nCurrentLowCloudsGreen; }
|
||||||
|
static int GetLowCloudsBlue(void) { return m_nCurrentLowCloudsBlue; }
|
||||||
|
static int GetFluffyCloudsTopRed(void) { return m_nCurrentFluffyCloudsTopRed; }
|
||||||
|
static int GetFluffyCloudsTopGreen(void) { return m_nCurrentFluffyCloudsTopGreen; }
|
||||||
|
static int GetFluffyCloudsTopBlue(void) { return m_nCurrentFluffyCloudsTopBlue; }
|
||||||
|
static int GetFluffyCloudsBottomRed(void) { return m_nCurrentFluffyCloudsBottomRed; }
|
||||||
|
static int GetFluffyCloudsBottomGreen(void) { return m_nCurrentFluffyCloudsBottomGreen; }
|
||||||
|
static int GetFluffyCloudsBottomBlue(void) { return m_nCurrentFluffyCloudsBottomBlue; }
|
||||||
|
|
||||||
|
};
|
14
src/Timer.cpp
Normal file
14
src/Timer.cpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.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;
|
19
src/Timer.h
Normal file
19
src/Timer.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#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 uint32 GetFrameCounter(void) { return m_FrameCounter; }
|
||||||
|
static uint32 GetTimeInMilliseconds(void) { return m_snTimeInMilliseconds; }
|
||||||
|
};
|
158
src/TxdStore.cpp
Normal file
158
src/TxdStore.cpp
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "templates.h"
|
||||||
|
#include "Streaming.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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(!rw::findChunk(stream, rw::ID_TEXDICTIONARY, nil, nil)){
|
||||||
|
return false;
|
||||||
|
}else{
|
||||||
|
def->texDict = rw::TexDictionary::streamRead(stream);
|
||||||
|
convertTxd(def->texDict);
|
||||||
|
return def->texDict != nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CTxdStore::LoadTxd(int slot, const char *filename)
|
||||||
|
{
|
||||||
|
rw::StreamFile stream;
|
||||||
|
if(stream.open(getPath(filename), "rb")){
|
||||||
|
LoadTxd(slot, &stream);
|
||||||
|
stream.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
printf("Failed to open TXD\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
CTxdStore::RemoveTxd(int slot)
|
||||||
|
{
|
||||||
|
TxdDef *def = GetSlot(slot);
|
||||||
|
if(def->texDict)
|
||||||
|
RwTexDictionaryDestroy(def->texDict);
|
||||||
|
def->texDict = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bool
|
||||||
|
//CTxdStore::isTxdLoaded(int slot)
|
||||||
|
//{
|
||||||
|
// return GetSlot(slot)->texDict != nil;
|
||||||
|
//}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x527440, CTxdStore::Initialize, PATCH_JUMP);
|
||||||
|
InjectHook(0x527470, CTxdStore::Shutdown, 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(0x527930, CTxdStore::AddRef, PATCH_JUMP);
|
||||||
|
InjectHook(0x527970, CTxdStore::RemoveRef, PATCH_JUMP);
|
||||||
|
InjectHook(0x5279C0, CTxdStore::RemoveRefWithoutDelete, PATCH_JUMP);
|
||||||
|
InjectHook(0x527870, CTxdStore::RemoveTxd, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
34
src/TxdStore.h
Normal file
34
src/TxdStore.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#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 int AddTxdSlot(const char *name);
|
||||||
|
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 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 void RemoveTxd(int slot);
|
||||||
|
|
||||||
|
static TxdDef *GetSlot(int slot) { return ms_pTxdPool->GetSlot(slot); }
|
||||||
|
static bool isTxdLoaded(int slot);
|
||||||
|
};
|
27
src/Weather.cpp
Normal file
27
src/Weather.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "Weather.h"
|
||||||
|
|
||||||
|
int32 &CWeather::SoundHandle = *(int32*)0x5FFBC4;
|
||||||
|
|
||||||
|
int32 &CWeather::WeatherTypeInList = *(int32*)0x8F626C;
|
||||||
|
int16 &CWeather::OldWeatherType = *(int16*)0x95CCEC;
|
||||||
|
int16 &CWeather::NewWeatherType = *(int16*)0x95CC70;
|
||||||
|
int16 &CWeather::ForcedWeatherType = *(int16*)0x95CC80;
|
||||||
|
|
||||||
|
bool &CWeather::LightningFlash = *(bool*)0x95CDA3;
|
||||||
|
bool &CWeather::LightningBurst = *(bool*)0x95CDAC;
|
||||||
|
uint32 &CWeather::LightningStart = *(uint32*)0x8F5F84;
|
||||||
|
uint32 &CWeather::LightningFlashLastChange = *(uint32*)0x8E2C0C;
|
||||||
|
uint32 &CWeather::WhenToPlayLightningSound = *(uint32*)0x8F57E4;
|
||||||
|
uint32 &CWeather::LightningDuration = *(uint32*)0x940578;
|
||||||
|
|
||||||
|
float &CWeather::Foggyness = *(float*)0x885AF4;
|
||||||
|
float &CWeather::CloudCoverage = *(float*)0x8E2818;
|
||||||
|
float &CWeather::Wind = *(float*)0x8E2BF8;
|
||||||
|
float &CWeather::Rain = *(float*)0x8E2BFC;
|
||||||
|
float &CWeather::InterpolationValue = *(float*)0x8F2520;
|
||||||
|
float &CWeather::WetRoads = *(float*)0x8F5FF8;
|
||||||
|
float &CWeather::Rainbow = *(float*)0x940598;
|
||||||
|
|
||||||
|
bool &CWeather::bScriptsForceRain = *(bool*)0x95CD7D;
|
||||||
|
bool &CWeather::Stored_StateStored = *(bool*)0x95CDC1;
|
35
src/Weather.h
Normal file
35
src/Weather.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
enum {
|
||||||
|
WEATHER_SUNNY,
|
||||||
|
WEATHER_CLOUDY,
|
||||||
|
WEATHER_RAINY,
|
||||||
|
WEATHER_FOGGY
|
||||||
|
};
|
||||||
|
|
||||||
|
class CWeather
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static int32 &SoundHandle;
|
||||||
|
|
||||||
|
static int32 &WeatherTypeInList;
|
||||||
|
static int16 &OldWeatherType;
|
||||||
|
static int16 &NewWeatherType;
|
||||||
|
static int16 &ForcedWeatherType;
|
||||||
|
|
||||||
|
static bool &LightningFlash;
|
||||||
|
static bool &LightningBurst;
|
||||||
|
static uint32 &LightningStart;
|
||||||
|
static uint32 &LightningFlashLastChange;
|
||||||
|
static uint32 &WhenToPlayLightningSound;
|
||||||
|
static uint32 &LightningDuration;
|
||||||
|
|
||||||
|
static float &Foggyness;
|
||||||
|
static float &CloudCoverage;
|
||||||
|
static float &Wind;
|
||||||
|
static float &Rain;
|
||||||
|
static float &InterpolationValue;
|
||||||
|
static float &WetRoads;
|
||||||
|
static float &Rainbow;
|
||||||
|
|
||||||
|
static bool &bScriptsForceRain;
|
||||||
|
static bool &Stored_StateStored;
|
||||||
|
};
|
39
src/World.cpp
Normal file
39
src/World.cpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Entity.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;
|
||||||
|
|
||||||
|
bool &CWorld::bNoMoreCollisionTorque = *(bool*)0x95CDCC;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x4B1F60, CWorld::ClearScanCodes, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
||||||
|
|
||||||
|
WRAPPER CVector &FindPlayerCoors(CVector &v) { EAXJMP(0x4A1030); }
|
||||||
|
WRAPPER CVehicle *FindPlayerVehicle(void) { EAXJMP(0x4A10C0); }
|
||||||
|
WRAPPER CVehicle *FindPlayerTrain(void) { EAXJMP(0x4A1120); }
|
66
src/World.h
Normal file
66
src/World.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game.h"
|
||||||
|
#include "Lists.h"
|
||||||
|
|
||||||
|
/* Sectors span from -2000 to 2000 in x and y.
|
||||||
|
* With 100x100 sectors, each is 40x40 units. */
|
||||||
|
|
||||||
|
#define NUMSECTORS_X 100
|
||||||
|
#define NUMSECTORS_Y 100
|
||||||
|
|
||||||
|
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 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 bool &bNoMoreCollisionTorque;
|
||||||
|
|
||||||
|
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 float GetSectorX(float f) { return ((f + 2000.0f)/40.0f); }
|
||||||
|
static float GetSectorY(float f) { return ((f + 2000.0f)/40.0f); }
|
||||||
|
static int GetSectorIndexX(float f) { return (int)GetSectorX(f); }
|
||||||
|
static int GetSectorIndexY(float f) { return (int)GetSectorY(f); }
|
||||||
|
};
|
||||||
|
|
||||||
|
CVector &FindPlayerCoors(CVector &v);
|
||||||
|
class CVehicle;
|
||||||
|
CVehicle *FindPlayerVehicle(void);
|
||||||
|
CVehicle *FindPlayerTrain(void);
|
614
src/Zones.cpp
Normal file
614
src/Zones.cpp
Normal file
@ -0,0 +1,614 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "World.h"
|
||||||
|
#include "Clock.h"
|
||||||
|
#include "Zones.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; }
|
||||||
|
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
FindPlayerCoors(pos);
|
||||||
|
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;
|
||||||
|
d = n - 1.0f;
|
||||||
|
}else{
|
||||||
|
d = (CClock::GetHours() - 5) / 3.0f;
|
||||||
|
n = d - 1.0f;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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->gangThreshold[0] = gang0Density;
|
||||||
|
if(gang1Density != -1) info->gangThreshold[1] = gang1Density;
|
||||||
|
if(gang2Density != -1) info->gangThreshold[2] = gang2Density;
|
||||||
|
if(gang3Density != -1) info->gangThreshold[3] = gang3Density;
|
||||||
|
if(gang4Density != -1) info->gangThreshold[4] = gang4Density;
|
||||||
|
if(gang5Density != -1) info->gangThreshold[5] = gang5Density;
|
||||||
|
if(gang6Density != -1) info->gangThreshold[6] = gang6Density;
|
||||||
|
if(gang7Density != -1) info->gangThreshold[7] = gang7Density;
|
||||||
|
if(gang8Density != -1) info->gangThreshold[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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
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(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(0x4B8380, CTheZones::InitialiseAudioZoneArray, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
107
src/Zones.h
Normal file
107
src/Zones.h
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CZoneInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Car data
|
||||||
|
uint16 carDensity;
|
||||||
|
uint16 carThreshold[6];
|
||||||
|
uint16 copThreshold;
|
||||||
|
uint16 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 void AddZoneToAudioZoneArray(CZone *zone);
|
||||||
|
static void InitialiseAudioZoneArray(void);
|
||||||
|
};
|
97
src/common.h
Normal file
97
src/common.h
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
#pragma warning(disable: 4244) // int to float
|
||||||
|
#pragma warning(disable: 4800) // int to bool
|
||||||
|
#pragma warning(disable: 4838) // narrowing conversion
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <rwcore.h>
|
||||||
|
#include <rpworld.h>
|
||||||
|
|
||||||
|
#define rwVENDORID_ROCKSTAR 0x0253F2
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
#define nil NULL
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define ALIGNPTR(p) (void*)((((uintptr)(void*)p) + sizeof(void*)-1) & ~(sizeof(void*)-1))
|
||||||
|
|
||||||
|
// little hack
|
||||||
|
extern void **rwengine;
|
||||||
|
#define RwEngineInstance (*rwengine)
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
struct RsInputDevice
|
||||||
|
{
|
||||||
|
int inputDeviceType;
|
||||||
|
int used;
|
||||||
|
void *inputEventHandler;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RsGlobalType
|
||||||
|
{
|
||||||
|
const char *appName;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int maximumWidth;
|
||||||
|
int maximumHeight;
|
||||||
|
int maxFPS;
|
||||||
|
int quit;
|
||||||
|
void *ps;
|
||||||
|
RsInputDevice keyboard;
|
||||||
|
RsInputDevice mouse;
|
||||||
|
RsInputDevice pad;
|
||||||
|
};
|
||||||
|
extern RsGlobalType &RsGlobal;
|
||||||
|
|
||||||
|
#define SCREENW (RsGlobal.maximumWidth)
|
||||||
|
#define SCREENH (RsGlobal.maximumHeight)
|
||||||
|
|
||||||
|
struct GlobalScene
|
||||||
|
{
|
||||||
|
RpWorld *world;
|
||||||
|
RwCamera *camera;
|
||||||
|
};
|
||||||
|
extern GlobalScene &Scene;
|
||||||
|
|
||||||
|
#include "math/Vector.h"
|
||||||
|
#include "math/Vector2D.h"
|
||||||
|
#include "math/Matrix.h"
|
||||||
|
#include "math/Rect.h"
|
||||||
|
|
||||||
|
class CRGBA
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint8 r, g, b, a;
|
||||||
|
CRGBA(void) { }
|
||||||
|
CRGBA(uint8 r, uint8 g, uint8 b, uint8 a) : r(r), g(g), b(b), a(a) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
inline float
|
||||||
|
clamp(float v, float min, float max){ return v<min ? min : v>max ? max : v; }
|
||||||
|
inline float
|
||||||
|
sq(float x) { return x*x; }
|
||||||
|
#define PI M_PI
|
||||||
|
#define DEGTORAD(d) (d/180.0f*PI)
|
||||||
|
|
||||||
|
int myrand(void);
|
||||||
|
void mysrand(unsigned int seed);
|
||||||
|
|
||||||
|
#define debug printf
|
||||||
|
|
||||||
|
//#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
//#define max(a, b) ((a) > (b) ? (a) : (b))
|
56
src/config.h
Normal file
56
src/config.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#ifndef _CONFIG_H_
|
||||||
|
#define _CONFIG_H_
|
||||||
|
|
||||||
|
enum Config {
|
||||||
|
NUMCDIMAGES = 50, // was 12
|
||||||
|
|
||||||
|
MODELINFOSIZE = 5500,
|
||||||
|
TXDSTORESIZE = 850,
|
||||||
|
EXTRADIRSIZE = 128,
|
||||||
|
|
||||||
|
SIMPLEMODELSIZE = 5000,
|
||||||
|
TIMEMODELSIZE = 30,
|
||||||
|
CLUMPMODELSIZE = 5,
|
||||||
|
PEDMODELSIZE = 90,
|
||||||
|
VEHICLEMODELSIZE = 120,
|
||||||
|
TWODFXSIZE = 2000,
|
||||||
|
|
||||||
|
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,
|
||||||
|
|
||||||
|
|
||||||
|
NUMPEDSTATS = 35,
|
||||||
|
NUMHANDLINGS = 57,
|
||||||
|
|
||||||
|
PATHNODESIZE = 4500,
|
||||||
|
|
||||||
|
NUMWEATHERS = 4,
|
||||||
|
NUMHOURS = 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
154
src/debugmenu_public.h
Normal file
154
src/debugmenu_public.h
Normal 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 == 0){
|
||||||
|
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 == 0)
|
||||||
|
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;
|
||||||
|
}
|
7
src/entities/Building.cpp
Normal file
7
src/entities/Building.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "rpworld.h"
|
||||||
|
#include "Building.h"
|
||||||
|
#include "Pools.h"
|
||||||
|
|
||||||
|
void *CBuilding::operator new(size_t sz) { return CPools::GetBuildingPool()->New(); }
|
||||||
|
void CBuilding::operator delete(void *p, size_t sz) { CPools::GetBuildingPool()->Delete((CBuilding*)p); }
|
15
src/entities/Building.h
Normal file
15
src/entities/Building.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Entity.h"
|
||||||
|
|
||||||
|
class CBuilding : public CEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// TODO: ReplaceWithNewModel
|
||||||
|
// TODO: ctor
|
||||||
|
static void *operator new(size_t);
|
||||||
|
static void operator delete(void*, size_t);
|
||||||
|
|
||||||
|
virtual bool GetIsATreadable(void) { return false; }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CBuilding) == 0x64, "CBuilding: error");
|
2
src/entities/CutsceneHead.cpp
Normal file
2
src/entities/CutsceneHead.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "CutsceneHead.h"
|
10
src/entities/CutsceneHead.h
Normal file
10
src/entities/CutsceneHead.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CutsceneObject.h"
|
||||||
|
|
||||||
|
class CCutsceneHead : public CCutsceneObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RwFrame *m_pHeadNode;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CCutsceneHead) == 0x19C, "CCutsceneHead: error");
|
2
src/entities/CutsceneObject.cpp
Normal file
2
src/entities/CutsceneObject.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "CutsceneObject.h"
|
9
src/entities/CutsceneObject.h
Normal file
9
src/entities/CutsceneObject.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Object.h"
|
||||||
|
|
||||||
|
class CCutsceneObject : public CObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CCutsceneObject) == 0x198, "CCutsceneObject: error");
|
391
src/entities/Entity.cpp
Normal file
391
src/entities/Entity.cpp
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "rpworld.h"
|
||||||
|
#include "Placeable.h"
|
||||||
|
#include "Entity.h"
|
||||||
|
#include "Lights.h"
|
||||||
|
#include "World.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
#include "References.h"
|
||||||
|
#include "TxdStore.h"
|
||||||
|
#include "Zones.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
|
||||||
|
int gBuildings;
|
||||||
|
|
||||||
|
void
|
||||||
|
CEntity::GetBoundCentre(CVector &out)
|
||||||
|
{
|
||||||
|
out = m_matrix * CModelInfo::GetModelInfo(m_modelIndex)->GetColModel()->boundingSphere.center;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
CEntity::GetIsTouching(CVector const ¢er, float radius)
|
||||||
|
{
|
||||||
|
return sq(GetBoundRadius()+radius) > (GetBoundCentre()-center).MagnitudeSqr();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CEntity::GetIsOnScreen(void)
|
||||||
|
{
|
||||||
|
return TheCamera.IsSphereVisible(GetBoundCentre(), GetBoundRadius(),
|
||||||
|
&TheCamera.GetCameraMatrix());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CEntity::GetIsOnScreenComplex(void)
|
||||||
|
{
|
||||||
|
RwV3d boundBox[8];
|
||||||
|
|
||||||
|
if(TheCamera.IsPointVisible(GetBoundCentre(), &TheCamera.GetCameraMatrix()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
CRect rect = GetBoundRect();
|
||||||
|
CColModel *colmodel = CModelInfo::GetModelInfo(m_modelIndex)->GetColModel();
|
||||||
|
float z = GetPosition().z;
|
||||||
|
float minz = z + colmodel->boundingBox.min.z;
|
||||||
|
float maxz = z + colmodel->boundingBox.max.z;
|
||||||
|
boundBox[0].x = rect.left;
|
||||||
|
boundBox[0].y = rect.top;
|
||||||
|
boundBox[0].z = minz;
|
||||||
|
boundBox[1].x = rect.left;
|
||||||
|
boundBox[1].y = rect.bottom;
|
||||||
|
boundBox[1].z = minz;
|
||||||
|
boundBox[2].x = rect.right;
|
||||||
|
boundBox[2].y = rect.top;
|
||||||
|
boundBox[2].z = minz;
|
||||||
|
boundBox[3].x = rect.right;
|
||||||
|
boundBox[3].y = rect.bottom;
|
||||||
|
boundBox[3].z = minz;
|
||||||
|
boundBox[4].x = rect.left;
|
||||||
|
boundBox[4].y = rect.top;
|
||||||
|
boundBox[4].z = maxz;
|
||||||
|
boundBox[5].x = rect.left;
|
||||||
|
boundBox[5].y = rect.bottom;
|
||||||
|
boundBox[5].z = maxz;
|
||||||
|
boundBox[6].x = rect.right;
|
||||||
|
boundBox[6].y = rect.top;
|
||||||
|
boundBox[6].z = maxz;
|
||||||
|
boundBox[7].x = rect.right;
|
||||||
|
boundBox[7].y = rect.bottom;
|
||||||
|
boundBox[7].z = maxz;
|
||||||
|
|
||||||
|
return TheCamera.IsBoxVisible(boundBox, &TheCamera.GetCameraMatrix());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CEntity::Add(void)
|
||||||
|
{
|
||||||
|
int x, xstart, xmid, xend;
|
||||||
|
int y, ystart, ymid, yend;
|
||||||
|
CSector *s;
|
||||||
|
CPtrList *list;
|
||||||
|
|
||||||
|
CRect bounds = GetBoundRect();
|
||||||
|
xstart = CWorld::GetSectorIndexX(bounds.left);
|
||||||
|
xend = CWorld::GetSectorIndexX(bounds.right);
|
||||||
|
xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f);
|
||||||
|
ystart = CWorld::GetSectorIndexY(bounds.bottom);
|
||||||
|
yend = CWorld::GetSectorIndexY(bounds.top);
|
||||||
|
ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f);
|
||||||
|
assert(xstart >= 0);
|
||||||
|
assert(xend < NUMSECTORS_X);
|
||||||
|
assert(ystart >= 0);
|
||||||
|
assert(yend < NUMSECTORS_Y);
|
||||||
|
|
||||||
|
for(y = ystart; y <= yend; y++)
|
||||||
|
for(x = xstart; x <= xend; x++){
|
||||||
|
s = CWorld::GetSector(x, y);
|
||||||
|
if(x == xmid && y == ymid) switch(m_type){
|
||||||
|
case ENTITY_TYPE_BUILDING:
|
||||||
|
list = &s->m_lists[ENTITYLIST_BUILDINGS];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_VEHICLE:
|
||||||
|
list = &s->m_lists[ENTITYLIST_VEHICLES];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_PED:
|
||||||
|
list = &s->m_lists[ENTITYLIST_PEDS];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_OBJECT:
|
||||||
|
list = &s->m_lists[ENTITYLIST_OBJECTS];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_DUMMY:
|
||||||
|
list = &s->m_lists[ENTITYLIST_DUMMIES];
|
||||||
|
break;
|
||||||
|
}else switch(m_type){
|
||||||
|
case ENTITY_TYPE_BUILDING:
|
||||||
|
list = &s->m_lists[ENTITYLIST_BUILDINGS_OVERLAP];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_VEHICLE:
|
||||||
|
list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_PED:
|
||||||
|
list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_OBJECT:
|
||||||
|
list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_DUMMY:
|
||||||
|
list = &s->m_lists[ENTITYLIST_DUMMIES_OVERLAP];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list->InsertItem(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CEntity::Remove(void)
|
||||||
|
{
|
||||||
|
int x, xstart, xmid, xend;
|
||||||
|
int y, ystart, ymid, yend;
|
||||||
|
CSector *s;
|
||||||
|
CPtrList *list;
|
||||||
|
|
||||||
|
CRect bounds = GetBoundRect();
|
||||||
|
xstart = CWorld::GetSectorIndexX(bounds.left);
|
||||||
|
xend = CWorld::GetSectorIndexX(bounds.right);
|
||||||
|
xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f);
|
||||||
|
ystart = CWorld::GetSectorIndexY(bounds.bottom);
|
||||||
|
yend = CWorld::GetSectorIndexY(bounds.top);
|
||||||
|
ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f);
|
||||||
|
assert(xstart >= 0);
|
||||||
|
assert(xend < NUMSECTORS_X);
|
||||||
|
assert(ystart >= 0);
|
||||||
|
assert(yend < NUMSECTORS_Y);
|
||||||
|
|
||||||
|
for(y = ystart; y <= yend; y++)
|
||||||
|
for(x = xstart; x <= xend; x++){
|
||||||
|
s = CWorld::GetSector(x, y);
|
||||||
|
if(x == xmid && y == ymid) switch(m_type){
|
||||||
|
case ENTITY_TYPE_BUILDING:
|
||||||
|
list = &s->m_lists[ENTITYLIST_BUILDINGS];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_VEHICLE:
|
||||||
|
list = &s->m_lists[ENTITYLIST_VEHICLES];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_PED:
|
||||||
|
list = &s->m_lists[ENTITYLIST_PEDS];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_OBJECT:
|
||||||
|
list = &s->m_lists[ENTITYLIST_OBJECTS];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_DUMMY:
|
||||||
|
list = &s->m_lists[ENTITYLIST_DUMMIES];
|
||||||
|
break;
|
||||||
|
}else switch(m_type){
|
||||||
|
case ENTITY_TYPE_BUILDING:
|
||||||
|
list = &s->m_lists[ENTITYLIST_BUILDINGS_OVERLAP];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_VEHICLE:
|
||||||
|
list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_PED:
|
||||||
|
list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_OBJECT:
|
||||||
|
list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_DUMMY:
|
||||||
|
list = &s->m_lists[ENTITYLIST_DUMMIES_OVERLAP];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list->RemoveItem(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CEntity::CreateRwObject(void)
|
||||||
|
{
|
||||||
|
CBaseModelInfo *mi;
|
||||||
|
|
||||||
|
mi = CModelInfo::GetModelInfo(m_modelIndex);
|
||||||
|
m_rwObject = mi->CreateInstance();
|
||||||
|
if(m_rwObject){
|
||||||
|
if(IsBuilding())
|
||||||
|
gBuildings++;
|
||||||
|
if(RwObjectGetType(m_rwObject) == rpATOMIC)
|
||||||
|
m_matrix.AttachRW(RwFrameGetMatrix(RpAtomicGetFrame(m_rwObject)), false);
|
||||||
|
else if(RwObjectGetType(m_rwObject) == rpCLUMP)
|
||||||
|
m_matrix.AttachRW(RwFrameGetMatrix(RpClumpGetFrame(m_rwObject)), false);
|
||||||
|
mi->AddRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CEntity::DeleteRwObject(void)
|
||||||
|
{
|
||||||
|
RwFrame *f;
|
||||||
|
|
||||||
|
m_matrix.Detach();
|
||||||
|
if(m_rwObject){
|
||||||
|
if(RwObjectGetType(m_rwObject) == rpATOMIC){
|
||||||
|
f = RpAtomicGetFrame(m_rwObject);
|
||||||
|
RpAtomicDestroy((RpAtomic*)m_rwObject);
|
||||||
|
RwFrameDestroy(f);
|
||||||
|
}else if(RwObjectGetType(m_rwObject) == rpCLUMP)
|
||||||
|
RpClumpDestroy((RpClump*)m_rwObject);
|
||||||
|
m_rwObject = nil;
|
||||||
|
CModelInfo::GetModelInfo(m_modelIndex)->RemoveRef();
|
||||||
|
if(IsBuilding())
|
||||||
|
gBuildings--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CEntity::UpdateRwFrame(void)
|
||||||
|
{
|
||||||
|
if(m_rwObject){
|
||||||
|
if(RwObjectGetType(m_rwObject) == rpATOMIC)
|
||||||
|
RwFrameUpdateObjects(RpAtomicGetFrame(m_rwObject));
|
||||||
|
else if(RwObjectGetType(m_rwObject) == rpCLUMP)
|
||||||
|
RwFrameUpdateObjects(RpClumpGetFrame(m_rwObject));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CEntity::SetupBigBuilding(void)
|
||||||
|
{
|
||||||
|
CSimpleModelInfo *mi;
|
||||||
|
|
||||||
|
mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(m_modelIndex);
|
||||||
|
bIsBIGBuilding = true;
|
||||||
|
m_flagC20 = true;
|
||||||
|
bUsesCollision = false;
|
||||||
|
m_level = CTheZones::GetLevelFromPosition(GetPosition());
|
||||||
|
if(m_level == LEVEL_NONE){
|
||||||
|
if(mi->GetTxdSlot() != CTxdStore::FindTxdSlot("generic")){
|
||||||
|
mi->SetTexDictionary("generic");
|
||||||
|
printf("%d:%s txd has been set to generic\n", m_modelIndex, mi->GetName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(mi->m_lodDistances[0] > 2000.0f)
|
||||||
|
m_level = LEVEL_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
CRect
|
||||||
|
CEntity::GetBoundRect(void)
|
||||||
|
{
|
||||||
|
CRect rect;
|
||||||
|
CVector v;
|
||||||
|
CColModel *col = CModelInfo::GetModelInfo(m_modelIndex)->GetColModel();
|
||||||
|
|
||||||
|
rect.ContainPoint(m_matrix * col->boundingBox.min);
|
||||||
|
rect.ContainPoint(m_matrix * col->boundingBox.max);
|
||||||
|
|
||||||
|
v = col->boundingBox.min;
|
||||||
|
v.x = col->boundingBox.max.x;
|
||||||
|
rect.ContainPoint(m_matrix * v);
|
||||||
|
|
||||||
|
v = col->boundingBox.max;
|
||||||
|
v.x = col->boundingBox.min.x;
|
||||||
|
rect.ContainPoint(m_matrix * v);
|
||||||
|
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CEntity::PreRender(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CEntity::Render(void)
|
||||||
|
{
|
||||||
|
if(m_rwObject){
|
||||||
|
bImBeingRendered = true;
|
||||||
|
if(RwObjectGetType(m_rwObject) == rpATOMIC)
|
||||||
|
RpAtomicRender((RpAtomic*)m_rwObject);
|
||||||
|
else
|
||||||
|
RpClumpRender((RpClump*)m_rwObject);
|
||||||
|
bImBeingRendered = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CEntity::SetupLighting(void)
|
||||||
|
{
|
||||||
|
DeActivateDirectional();
|
||||||
|
SetAmbientColours();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CEntity::RegisterReference(CEntity **pent)
|
||||||
|
{
|
||||||
|
if(IsBuilding())
|
||||||
|
return;
|
||||||
|
CReference *ref;
|
||||||
|
// check if already registered
|
||||||
|
for(ref = m_pFirstReference; ref; ref = ref->next)
|
||||||
|
if(ref->pentity == pent)
|
||||||
|
return;
|
||||||
|
// have to allocate new reference
|
||||||
|
ref = CReferences::pEmptyList;
|
||||||
|
if(ref){
|
||||||
|
CReferences::pEmptyList = ref->next;
|
||||||
|
|
||||||
|
ref->pentity = pent;
|
||||||
|
ref->next = m_pFirstReference;
|
||||||
|
m_pFirstReference = ref;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear all references to this entity
|
||||||
|
void
|
||||||
|
CEntity::ResolveReferences(void)
|
||||||
|
{
|
||||||
|
CReference *ref;
|
||||||
|
// clear pointers to this entity
|
||||||
|
for(ref = m_pFirstReference; ref; ref = ref->next)
|
||||||
|
if(*ref->pentity == this)
|
||||||
|
*ref->pentity = nil;
|
||||||
|
// free list
|
||||||
|
if(m_pFirstReference){
|
||||||
|
for(ref = m_pFirstReference; ref->next; ref = ref->next)
|
||||||
|
;
|
||||||
|
ref->next = CReferences::pEmptyList;
|
||||||
|
CReferences::pEmptyList = ref;
|
||||||
|
m_pFirstReference = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free all references that no longer point to this entity
|
||||||
|
void
|
||||||
|
CEntity::PruneReferences(void)
|
||||||
|
{
|
||||||
|
CReference *ref, *next, **lastnextp;
|
||||||
|
lastnextp = &m_pFirstReference;
|
||||||
|
for(ref = m_pFirstReference; ref; ref = next){
|
||||||
|
next = ref->next;
|
||||||
|
if(*ref->pentity == this)
|
||||||
|
lastnextp = &ref->next;
|
||||||
|
else{
|
||||||
|
*lastnextp = ref->next;
|
||||||
|
ref->next = CReferences::pEmptyList;
|
||||||
|
CReferences::pEmptyList = ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x4742C0, (void (CEntity::*)(CVector&))&CEntity::GetBoundCentre, PATCH_JUMP);
|
||||||
|
InjectHook(0x474310, &CEntity::GetBoundRadius, PATCH_JUMP);
|
||||||
|
InjectHook(0x474C10, &CEntity::GetIsTouching, PATCH_JUMP);
|
||||||
|
InjectHook(0x474CC0, &CEntity::GetIsOnScreen, PATCH_JUMP);
|
||||||
|
InjectHook(0x474D20, &CEntity::GetIsOnScreenComplex, PATCH_JUMP);
|
||||||
|
InjectHook(0x474CA0, &CEntity::IsVisible, PATCH_JUMP);
|
||||||
|
InjectHook(0x474330, &CEntity::UpdateRwFrame, PATCH_JUMP);
|
||||||
|
InjectHook(0x4755E0, &CEntity::SetupBigBuilding, PATCH_JUMP);
|
||||||
|
InjectHook(0x4A7480, &CEntity::RegisterReference, PATCH_JUMP);
|
||||||
|
InjectHook(0x4A74E0, &CEntity::ResolveReferences, PATCH_JUMP);
|
||||||
|
InjectHook(0x4A7530, &CEntity::PruneReferences, PATCH_JUMP);
|
||||||
|
|
||||||
|
InjectHook(0x475080, &CEntity::Add_, PATCH_JUMP);
|
||||||
|
InjectHook(0x475310, &CEntity::Remove_, PATCH_JUMP);
|
||||||
|
InjectHook(0x473EA0, &CEntity::CreateRwObject_, PATCH_JUMP);
|
||||||
|
InjectHook(0x473F90, &CEntity::DeleteRwObject_, PATCH_JUMP);
|
||||||
|
InjectHook(0x474000, &CEntity::GetBoundRect_, PATCH_JUMP);
|
||||||
|
InjectHook(0x474BD0, &CEntity::Render_, PATCH_JUMP);
|
||||||
|
InjectHook(0x4A7C60, &CEntity::SetupLighting_, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
146
src/entities/Entity.h
Normal file
146
src/entities/Entity.h
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ModelInfo.h"
|
||||||
|
#include "Placeable.h"
|
||||||
|
|
||||||
|
struct CReference;
|
||||||
|
|
||||||
|
enum eEntityType
|
||||||
|
{
|
||||||
|
ENTITY_TYPE_NOTHING = 0,
|
||||||
|
ENTITY_TYPE_BUILDING,
|
||||||
|
ENTITY_TYPE_VEHICLE,
|
||||||
|
ENTITY_TYPE_PED,
|
||||||
|
ENTITY_TYPE_OBJECT,
|
||||||
|
ENTITY_TYPE_DUMMY,
|
||||||
|
ENTITY_TYPE_6,
|
||||||
|
ENTITY_TYPE_7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eEntityStatus
|
||||||
|
{
|
||||||
|
// from SA MTA! let's hope they didn't change from III
|
||||||
|
STATUS_PLAYER = 0,
|
||||||
|
STATUS_PLAYER_PLAYBACKFROMBUFFER,
|
||||||
|
STATUS_SIMPLE,
|
||||||
|
STATUS_PHYSICS,
|
||||||
|
STATUS_ABANDONED,
|
||||||
|
STATUS_WRECKED,
|
||||||
|
STATUS_TRAIN_MOVING,
|
||||||
|
STATUS_TRAIN_NOT_MOVING,
|
||||||
|
STATUS_HELI,
|
||||||
|
STATUS_PLANE,
|
||||||
|
STATUS_PLAYER_REMOTE,
|
||||||
|
STATUS_PLAYER_DISABLED,
|
||||||
|
//STATUS_TRAILER,
|
||||||
|
//STATUS_SIMPLE_TRAILER
|
||||||
|
};
|
||||||
|
|
||||||
|
class CEntity : public CPlaceable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RwObject *m_rwObject;
|
||||||
|
uint32 m_type : 3;
|
||||||
|
uint32 m_status : 5;
|
||||||
|
|
||||||
|
// flagsA
|
||||||
|
uint32 bUsesCollision : 1;
|
||||||
|
uint32 bCollisionProcessed : 1;
|
||||||
|
uint32 bIsStatic : 1;
|
||||||
|
uint32 bHasContacted : 1;
|
||||||
|
uint32 bPedPhysics : 1;
|
||||||
|
uint32 bIsStuck : 1;
|
||||||
|
uint32 bIsInSafePosition : 1;
|
||||||
|
uint32 bUseCollisionRecords : 1;
|
||||||
|
|
||||||
|
// flagsB
|
||||||
|
uint32 bWasPostponed : 1;
|
||||||
|
uint32 m_flagB2 : 1; // explosion proof?
|
||||||
|
uint32 bIsVisible : 1;
|
||||||
|
uint32 bHasCollided : 1; //
|
||||||
|
uint32 bRenderScorched : 1;
|
||||||
|
uint32 m_flagB20 : 1; // bFlashing?
|
||||||
|
uint32 bIsBIGBuilding : 1;
|
||||||
|
// VC inserts one more flag here: if drawdist <= 2000
|
||||||
|
uint32 bRenderDamaged : 1;
|
||||||
|
|
||||||
|
// flagsC
|
||||||
|
uint32 m_flagC1 : 1; // bullet proof?
|
||||||
|
uint32 m_flagC2 : 1; // fire proof?
|
||||||
|
uint32 m_flagC4 : 1; // collision proof?
|
||||||
|
uint32 m_flagC8 : 1; // melee proof?
|
||||||
|
uint32 m_flagC10 : 1; // bOnlyDamagedByPlayer?
|
||||||
|
uint32 m_flagC20 : 1;
|
||||||
|
uint32 m_bZoneCulled : 1;
|
||||||
|
uint32 m_bZoneCulled2 : 1; // only treadables+10m
|
||||||
|
|
||||||
|
// flagsD
|
||||||
|
uint32 bRemoveFromWorld : 1;
|
||||||
|
uint32 bHasHitWall : 1;
|
||||||
|
uint32 bImBeingRendered : 1;
|
||||||
|
uint32 m_flagD8 : 1;
|
||||||
|
uint32 m_flagD10 : 1;
|
||||||
|
uint32 bDrawLast : 1;
|
||||||
|
uint32 m_flagD40 : 1;
|
||||||
|
uint32 m_flagD80 : 1;
|
||||||
|
|
||||||
|
// flagsE
|
||||||
|
uint32 bDistanceFade : 1;
|
||||||
|
uint32 m_flagE2 : 1;
|
||||||
|
|
||||||
|
uint16 m_scanCode;
|
||||||
|
int16 m_randomSeed;
|
||||||
|
int16 m_modelIndex;
|
||||||
|
uint16 m_level; // int16
|
||||||
|
CReference *m_pFirstReference;
|
||||||
|
|
||||||
|
virtual void Add(void);
|
||||||
|
virtual void Remove(void);
|
||||||
|
virtual void SetModelIndex(uint32 i) { m_modelIndex = i; CreateRwObject(); }
|
||||||
|
virtual void SetModelIndexNoCreate(uint32 i) { m_modelIndex = i; }
|
||||||
|
virtual void CreateRwObject(void);
|
||||||
|
virtual void DeleteRwObject(void);
|
||||||
|
virtual CRect GetBoundRect(void);
|
||||||
|
virtual void ProcessControl(void) {}
|
||||||
|
virtual void ProcessCollision(void) {}
|
||||||
|
virtual void ProcessShift(void) {}
|
||||||
|
virtual void Teleport(CVector v) {}
|
||||||
|
virtual void PreRender(void);
|
||||||
|
virtual void Render(void);
|
||||||
|
virtual bool SetupLighting(void);
|
||||||
|
virtual void RemoveLighting(bool) {}
|
||||||
|
virtual void FlagToDestroyWhenNextProcessed(void) {}
|
||||||
|
|
||||||
|
bool IsBuilding(void) { return m_type == ENTITY_TYPE_BUILDING; }
|
||||||
|
bool IsVehicle(void) { return m_type == ENTITY_TYPE_VEHICLE; }
|
||||||
|
bool IsPed(void) { return m_type == ENTITY_TYPE_PED; }
|
||||||
|
bool IsObject(void) { return m_type == ENTITY_TYPE_OBJECT; }
|
||||||
|
bool IsDummy(void) { return m_type == ENTITY_TYPE_DUMMY; }
|
||||||
|
|
||||||
|
void GetBoundCentre(CVector &out);
|
||||||
|
CVector GetBoundCentre(void) { CVector v; GetBoundCentre(v); return v; }
|
||||||
|
float GetBoundRadius(void) { return CModelInfo::GetModelInfo(m_modelIndex)->GetColModel()->boundingSphere.radius; }
|
||||||
|
bool GetIsTouching(CVector const ¢er, float r);
|
||||||
|
bool GetIsOnScreen(void);
|
||||||
|
bool GetIsOnScreenComplex(void);
|
||||||
|
bool IsVisible(void) { return m_rwObject && bIsVisible && GetIsOnScreen(); }
|
||||||
|
bool IsVisibleComplex(void) { return m_rwObject && bIsVisible && GetIsOnScreenComplex(); }
|
||||||
|
int GetModelIndex(void) { return m_modelIndex; }
|
||||||
|
void UpdateRwFrame(void);
|
||||||
|
void SetupBigBuilding(void);
|
||||||
|
|
||||||
|
void RegisterReference(CEntity **pent);
|
||||||
|
void ResolveReferences(void);
|
||||||
|
void PruneReferences(void);
|
||||||
|
|
||||||
|
|
||||||
|
// to make patching virtual functions possible
|
||||||
|
void Add_(void) { CEntity::Add(); }
|
||||||
|
void Remove_(void) { CEntity::Remove(); }
|
||||||
|
void CreateRwObject_(void) { CEntity::CreateRwObject(); }
|
||||||
|
void DeleteRwObject_(void) { CEntity::DeleteRwObject(); }
|
||||||
|
CRect GetBoundRect_(void) { return CEntity::GetBoundRect(); }
|
||||||
|
void Render_(void) { CEntity::Render(); }
|
||||||
|
bool SetupLighting_(void) { return CEntity::SetupLighting(); }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CEntity) == 0x64, "CEntity: error");
|
9
src/entities/Object.cpp
Normal file
9
src/entities/Object.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Object.h"
|
||||||
|
#include "Pools.h"
|
||||||
|
|
||||||
|
void *CObject::operator new(size_t sz) { return CPools::GetObjectPool()->New(); }
|
||||||
|
void CObject::operator delete(void *p, size_t sz) { CPools::GetObjectPool()->Delete((CObject*)p); }
|
||||||
|
|
||||||
|
WRAPPER void CObject::ObjectDamage(float amount) { EAXJMP(0x4BB240); }
|
50
src/entities/Object.h
Normal file
50
src/entities/Object.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Physical.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GAME_OBJECT = 1,
|
||||||
|
MISSION_OBJECT = 2,
|
||||||
|
TEMP_OBJECT = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
class CObject : public CPhysical
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CMatrix m_objectMatrix;
|
||||||
|
float m_fUprootLimit;
|
||||||
|
int8 ObjectCreatedBy;
|
||||||
|
// int8 m_nObjectFlags;
|
||||||
|
int8 m_obj_flag1 : 1;
|
||||||
|
int8 m_obj_flag2 : 1;
|
||||||
|
int8 m_obj_flag4 : 1;
|
||||||
|
int8 m_obj_flag8 : 1;
|
||||||
|
int8 m_obj_flag10 : 1;
|
||||||
|
int8 bHasBeenDamaged : 1;
|
||||||
|
int8 m_obj_flag40 : 1;
|
||||||
|
int8 m_obj_flag80 : 1;
|
||||||
|
int8 field_172;
|
||||||
|
int8 field_173;
|
||||||
|
float m_fCollisionDamageMultiplier;
|
||||||
|
int8 m_nCollisionDamageEffect;
|
||||||
|
int8 m_bSpecialCollisionResponseCases;
|
||||||
|
int8 m_bCameraToAvoidThisObject;
|
||||||
|
int8 field_17B;
|
||||||
|
int8 field_17C;
|
||||||
|
int8 field_17D;
|
||||||
|
int8 field_17E;
|
||||||
|
int8 field_17F;
|
||||||
|
int32 m_nEndOfLifeTime;
|
||||||
|
int16 m_nRefModelIndex;
|
||||||
|
int8 field_186;
|
||||||
|
int8 field_187;
|
||||||
|
CEntity *m_pCurSurface;
|
||||||
|
CEntity *field_18C;
|
||||||
|
int8 m_colour1, m_colour2;
|
||||||
|
|
||||||
|
static void *operator new(size_t);
|
||||||
|
static void operator delete(void*, size_t);
|
||||||
|
|
||||||
|
void ObjectDamage(float amount);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CObject) == 0x198, "CObject: error");
|
35
src/entities/Ped.h
Normal file
35
src/entities/Ped.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Physical.h"
|
||||||
|
|
||||||
|
enum PedAction
|
||||||
|
{
|
||||||
|
PED_PASSENGER = 44,
|
||||||
|
};
|
||||||
|
|
||||||
|
class CVehicle;
|
||||||
|
|
||||||
|
class CPed : public CPhysical
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// 0x128
|
||||||
|
uint8 stuff1[252];
|
||||||
|
int32 m_nPedState;
|
||||||
|
uint8 stuff2[196];
|
||||||
|
CEntity *m_pCurrentPhysSurface;
|
||||||
|
CVector m_vecOffsetFromPhysSurface;
|
||||||
|
CEntity *m_pCurSurface;
|
||||||
|
uint8 stuff3[16];
|
||||||
|
CVehicle *m_pMyVehicle;
|
||||||
|
bool bInVehicle;
|
||||||
|
uint8 stuff4[23];
|
||||||
|
int32 m_nPedType;
|
||||||
|
uint8 stuff5[528];
|
||||||
|
|
||||||
|
bool IsPlayer(void) { return m_nPedType == 0 || m_nPedType== 1 || m_nPedType == 2 || m_nPedType == 3; }
|
||||||
|
};
|
||||||
|
static_assert(offsetof(CPed, m_nPedState) == 0x224, "CPed: error");
|
||||||
|
static_assert(offsetof(CPed, m_pCurSurface) == 0x2FC, "CPed: error");
|
||||||
|
static_assert(offsetof(CPed, m_pMyVehicle) == 0x310, "CPed: error");
|
||||||
|
static_assert(offsetof(CPed, m_nPedType) == 0x32C, "CPed: error");
|
||||||
|
static_assert(sizeof(CPed) == 0x540, "CPed: error");
|
916
src/entities/Physical.cpp
Normal file
916
src/entities/Physical.cpp
Normal file
@ -0,0 +1,916 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "World.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "ModelIndices.h"
|
||||||
|
#include "Vehicle.h"
|
||||||
|
#include "Ped.h"
|
||||||
|
#include "Object.h"
|
||||||
|
#include "Glass.h"
|
||||||
|
#include "ParticleObject.h"
|
||||||
|
#include "Particle.h"
|
||||||
|
#include "SurfaceTable.h"
|
||||||
|
#include "Physical.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::Add(void)
|
||||||
|
{
|
||||||
|
int x, xstart, xmid, xend;
|
||||||
|
int y, ystart, ymid, yend;
|
||||||
|
CSector *s;
|
||||||
|
CPtrList *list;
|
||||||
|
|
||||||
|
CRect bounds = GetBoundRect();
|
||||||
|
xstart = CWorld::GetSectorIndexX(bounds.left);
|
||||||
|
xend = CWorld::GetSectorIndexX(bounds.right);
|
||||||
|
xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f);
|
||||||
|
ystart = CWorld::GetSectorIndexY(bounds.bottom);
|
||||||
|
yend = CWorld::GetSectorIndexY(bounds.top);
|
||||||
|
ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f);
|
||||||
|
assert(xstart >= 0);
|
||||||
|
assert(xend < NUMSECTORS_X);
|
||||||
|
assert(ystart >= 0);
|
||||||
|
assert(yend < NUMSECTORS_Y);
|
||||||
|
|
||||||
|
for(y = ystart; y <= yend; y++)
|
||||||
|
for(x = xstart; x <= xend; x++){
|
||||||
|
s = CWorld::GetSector(x, y);
|
||||||
|
if(x == xmid && y == ymid) switch(m_type){
|
||||||
|
case ENTITY_TYPE_VEHICLE:
|
||||||
|
list = &s->m_lists[ENTITYLIST_VEHICLES];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_PED:
|
||||||
|
list = &s->m_lists[ENTITYLIST_PEDS];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_OBJECT:
|
||||||
|
list = &s->m_lists[ENTITYLIST_OBJECTS];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}else switch(m_type){
|
||||||
|
case ENTITY_TYPE_VEHICLE:
|
||||||
|
list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_PED:
|
||||||
|
list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_OBJECT:
|
||||||
|
list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
CPtrNode *node = list->InsertItem(this);
|
||||||
|
assert(node);
|
||||||
|
m_entryInfoList.InsertItem(list, node, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::Remove(void)
|
||||||
|
{
|
||||||
|
CEntryInfoNode *node, *next;
|
||||||
|
for(node = m_entryInfoList.first; node; node = next){
|
||||||
|
next = node->next;
|
||||||
|
node->list->DeleteNode(node->listnode);
|
||||||
|
m_entryInfoList.DeleteNode(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::RemoveAndAdd(void)
|
||||||
|
{
|
||||||
|
int x, xstart, xmid, xend;
|
||||||
|
int y, ystart, ymid, yend;
|
||||||
|
CSector *s;
|
||||||
|
CPtrList *list;
|
||||||
|
|
||||||
|
CRect bounds = GetBoundRect();
|
||||||
|
xstart = CWorld::GetSectorIndexX(bounds.left);
|
||||||
|
xend = CWorld::GetSectorIndexX(bounds.right);
|
||||||
|
xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f);
|
||||||
|
ystart = CWorld::GetSectorIndexY(bounds.bottom);
|
||||||
|
yend = CWorld::GetSectorIndexY(bounds.top);
|
||||||
|
ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f);
|
||||||
|
assert(xstart >= 0);
|
||||||
|
assert(xend < NUMSECTORS_X);
|
||||||
|
assert(ystart >= 0);
|
||||||
|
assert(yend < NUMSECTORS_Y);
|
||||||
|
|
||||||
|
// we'll try to recycle nodes from here
|
||||||
|
CEntryInfoNode *next = m_entryInfoList.first;
|
||||||
|
|
||||||
|
for(y = ystart; y <= yend; y++)
|
||||||
|
for(x = xstart; x <= xend; x++){
|
||||||
|
s = CWorld::GetSector(x, y);
|
||||||
|
if(x == xmid && y == ymid) switch(m_type){
|
||||||
|
case ENTITY_TYPE_VEHICLE:
|
||||||
|
list = &s->m_lists[ENTITYLIST_VEHICLES];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_PED:
|
||||||
|
list = &s->m_lists[ENTITYLIST_PEDS];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_OBJECT:
|
||||||
|
list = &s->m_lists[ENTITYLIST_OBJECTS];
|
||||||
|
break;
|
||||||
|
}else switch(m_type){
|
||||||
|
case ENTITY_TYPE_VEHICLE:
|
||||||
|
list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_PED:
|
||||||
|
list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP];
|
||||||
|
break;
|
||||||
|
case ENTITY_TYPE_OBJECT:
|
||||||
|
list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(next){
|
||||||
|
// If we still have old nodes, use them
|
||||||
|
next->list->RemoveNode(next->listnode);
|
||||||
|
list->InsertNode(next->listnode);
|
||||||
|
next->list = list;
|
||||||
|
next->sector = s;
|
||||||
|
next = next->next;
|
||||||
|
}else{
|
||||||
|
CPtrNode *node = list->InsertItem(this);
|
||||||
|
m_entryInfoList.InsertItem(list, node, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove old nodes we no longer need
|
||||||
|
CEntryInfoNode *node;
|
||||||
|
for(node = next; node; node = next){
|
||||||
|
next = node->next;
|
||||||
|
node->list->DeleteNode(node->listnode);
|
||||||
|
m_entryInfoList.DeleteNode(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CRect
|
||||||
|
CPhysical::GetBoundRect(void)
|
||||||
|
{
|
||||||
|
CVector center;
|
||||||
|
float radius;
|
||||||
|
GetBoundCentre(center);
|
||||||
|
radius = GetBoundRadius();
|
||||||
|
return CRect(center.x-radius, center.y-radius, center.x+radius, center.y+radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::AddToMovingList(void)
|
||||||
|
{
|
||||||
|
m_movingListNode = CWorld::GetMovingEntityList().InsertItem(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::RemoveFromMovingList(void)
|
||||||
|
{
|
||||||
|
if(m_movingListNode){
|
||||||
|
CWorld::GetMovingEntityList().DeleteNode(m_movingListNode);
|
||||||
|
m_movingListNode = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some quantities (german in parens):
|
||||||
|
*
|
||||||
|
* acceleration: distance/time^2: a
|
||||||
|
* velocity: distance/time: v (GTA: speed)
|
||||||
|
* momentum (impuls): velocity*mass: p
|
||||||
|
* impulse (kraftstoss): delta momentum, force*time: J
|
||||||
|
*
|
||||||
|
* angular equivalents:
|
||||||
|
* velocity -> angular velocity (GTA: turn speed)
|
||||||
|
* momentum -> angular momentum (drehimpuls): L = r cross p
|
||||||
|
* force -> torque (drehmoment): tau = r cross F
|
||||||
|
* mass -> moment of inertia, angular mass (drehmoment, drehmasse): I = L/omega (GTA: turn mass)
|
||||||
|
*/
|
||||||
|
|
||||||
|
CVector
|
||||||
|
CPhysical::GetSpeed(const CVector &r)
|
||||||
|
{
|
||||||
|
return m_vecMoveSpeed + m_vecMoveFriction + CrossProduct(m_vecTurnFriction + m_vecTurnSpeed, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::ApplyMoveSpeed(void)
|
||||||
|
{
|
||||||
|
GetPosition() += m_vecMoveSpeed * CTimer::GetTimeStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::ApplyTurnSpeed(void)
|
||||||
|
{
|
||||||
|
// Move the coordinate axes by their speed
|
||||||
|
// Note that this denormalizes the matrix
|
||||||
|
CVector turnvec = m_vecTurnSpeed*CTimer::GetTimeStep();
|
||||||
|
GetRight() += CrossProduct(turnvec, GetRight());
|
||||||
|
GetForward() += CrossProduct(turnvec, GetForward());
|
||||||
|
GetUp() += CrossProduct(turnvec, GetUp());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::ApplyMoveForce(float jx, float jy, float jz)
|
||||||
|
{
|
||||||
|
m_vecMoveSpeed += CVector(jx, jy, jz)*(1.0f/m_fMass);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::ApplyTurnForce(float jx, float jy, float jz, float px, float py, float pz)
|
||||||
|
{
|
||||||
|
CVector com = Multiply3x3(m_matrix, m_vecCentreOfMass);
|
||||||
|
CVector turnimpulse = CrossProduct(CVector(px, py, pz)-com, CVector(jx, jy, jz));
|
||||||
|
m_vecTurnSpeed += turnimpulse*(1.0f/m_fTurnMass);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::ApplyFrictionMoveForce(float jx, float jy, float jz)
|
||||||
|
{
|
||||||
|
m_vecMoveFriction += CVector(jx, jy, jz)*(1.0f/m_fMass);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::ApplyFrictionTurnForce(float jx, float jy, float jz, float px, float py, float pz)
|
||||||
|
{
|
||||||
|
CVector com = Multiply3x3(m_matrix, m_vecCentreOfMass);
|
||||||
|
CVector turnimpulse = CrossProduct(CVector(px, py, pz)-com, CVector(jx, jy, jz));
|
||||||
|
m_vecTurnFriction += turnimpulse*(1.0f/m_fTurnMass);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::ApplySpringCollision(float f1, CVector &v, CVector &p, float f2, float f3)
|
||||||
|
{
|
||||||
|
if(1.0f - f2 <= 0.0f)
|
||||||
|
return;
|
||||||
|
float step = min(CTimer::GetTimeStep(), 3.0f);
|
||||||
|
float strength = -0.008f*m_fMass*2.0f*step * f1 * (1.0f-f2) * f3;
|
||||||
|
ApplyMoveForce(v.x*strength, v.y*strength, v.z*strength);
|
||||||
|
ApplyTurnForce(v.x*strength, v.y*strength, v.z*strength, p.x, p.y, p.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::ApplyGravity(void)
|
||||||
|
{
|
||||||
|
if(bAffectedByGravity)
|
||||||
|
m_vecMoveSpeed.z -= 0.008f * CTimer::GetTimeStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::ApplyFriction(void)
|
||||||
|
{
|
||||||
|
m_vecMoveSpeed += m_vecMoveFriction;
|
||||||
|
m_vecTurnSpeed += m_vecTurnFriction;
|
||||||
|
m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f);
|
||||||
|
m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::ApplyAirResistance(void)
|
||||||
|
{
|
||||||
|
if(m_fAirResistance > 0.1f){
|
||||||
|
float f = powf(m_fAirResistance, CTimer::GetTimeStep());
|
||||||
|
m_vecMoveSpeed *= f;
|
||||||
|
m_vecTurnSpeed *= f;
|
||||||
|
}else{
|
||||||
|
float f = powf(1.0f/(m_fAirResistance*0.5f*m_vecMoveSpeed.MagnitudeSqr() + 1.0f), CTimer::GetTimeStep());
|
||||||
|
m_vecMoveSpeed *= f;
|
||||||
|
m_vecTurnSpeed *= 0.99f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, float &impulseB)
|
||||||
|
{
|
||||||
|
float eA, eB;
|
||||||
|
CPhysical *A = this;
|
||||||
|
CObject *Bobj = (CObject*)B;
|
||||||
|
|
||||||
|
bool ispedcontactA = false;
|
||||||
|
bool ispedcontactB = false;
|
||||||
|
|
||||||
|
float timestepA;
|
||||||
|
if(B->bPedPhysics){
|
||||||
|
timestepA = 10.0f;
|
||||||
|
if(B->IsPed() && ((CPed*)B)->m_pCurrentPhysSurface == A)
|
||||||
|
ispedcontactA = true;
|
||||||
|
}else
|
||||||
|
timestepA = A->m_phy_flagA1 ? 2.0f : 1.0f;
|
||||||
|
|
||||||
|
float timestepB;
|
||||||
|
if(A->bPedPhysics){
|
||||||
|
if(A->IsPed() && ((CPed*)A)->IsPlayer() && B->IsVehicle() &&
|
||||||
|
(B->m_status == STATUS_ABANDONED || B->m_status == STATUS_WRECKED || A->bHasHitWall))
|
||||||
|
timestepB = 2200.0f / B->m_fMass;
|
||||||
|
else
|
||||||
|
timestepB = 10.0f;
|
||||||
|
|
||||||
|
if(A->IsPed() && ((CPed*)A)->m_pCurrentPhysSurface == B)
|
||||||
|
ispedcontactB = true;
|
||||||
|
}else
|
||||||
|
timestepB = B->m_phy_flagA1 ? 2.0f : 1.0f;
|
||||||
|
|
||||||
|
float speedA, speedB;
|
||||||
|
if(B->bIsStatic){
|
||||||
|
if(A->bPedPhysics){
|
||||||
|
speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal);
|
||||||
|
if(speedA < 0.0f){
|
||||||
|
if(B->IsObject()){
|
||||||
|
impulseA = -speedA * A->m_fMass;
|
||||||
|
impulseB = impulseA;
|
||||||
|
if(impulseA > Bobj->m_fUprootLimit){
|
||||||
|
if(IsGlass(B->GetModelIndex()))
|
||||||
|
CGlass::WindowRespondsToCollision(B, impulseA, A->m_vecMoveSpeed, colpoint.point, false);
|
||||||
|
else if(!B->bInfiniteMass)
|
||||||
|
B->bIsStatic = false;
|
||||||
|
}else{
|
||||||
|
if(IsGlass(B->GetModelIndex()))
|
||||||
|
CGlass::WindowRespondsToSoftCollision(B, impulseA);
|
||||||
|
if(!A->bInfiniteMass)
|
||||||
|
A->ApplyMoveForce(colpoint.normal*(1.0f + A->m_fElasticity)*impulseA);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}else if(!B->bInfiniteMass)
|
||||||
|
B->bIsStatic = false;
|
||||||
|
|
||||||
|
if(B->bInfiniteMass){
|
||||||
|
impulseA = -speedA * A->m_fMass;
|
||||||
|
impulseB = 0.0f;
|
||||||
|
if(!A->bInfiniteMass)
|
||||||
|
A->ApplyMoveForce(colpoint.normal*(1.0f + A->m_fElasticity)*impulseA);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
CVector pointposA = colpoint.point - A->GetPosition();
|
||||||
|
speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal);
|
||||||
|
if(speedA < 0.0f){
|
||||||
|
if(B->IsObject()){
|
||||||
|
if(A->bHasHitWall)
|
||||||
|
eA = -1.0f;
|
||||||
|
else
|
||||||
|
eA = -(1.0f + A->m_fElasticity);
|
||||||
|
impulseA = eA * speedA * A->GetMass(pointposA, colpoint.normal);
|
||||||
|
impulseB = impulseA;
|
||||||
|
|
||||||
|
if(Bobj->m_nCollisionDamageEffect && impulseA > 20.0f){
|
||||||
|
Bobj->ObjectDamage(impulseA);
|
||||||
|
if(!B->bUsesCollision){
|
||||||
|
if(!A->bInfiniteMass){
|
||||||
|
A->ApplyMoveForce(colpoint.normal*0.2f*impulseA);
|
||||||
|
A->ApplyTurnForce(colpoint.normal*0.2f*impulseA, pointposA);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((impulseA > Bobj->m_fUprootLimit || A->bIsStuck) &&
|
||||||
|
!B->bInfiniteMass){
|
||||||
|
if(IsGlass(B->GetModelIndex()))
|
||||||
|
CGlass::WindowRespondsToCollision(B, impulseA, A->m_vecMoveSpeed, colpoint.point, false);
|
||||||
|
else
|
||||||
|
B->bIsStatic = false;
|
||||||
|
int16 model = B->GetModelIndex();
|
||||||
|
if(model == MI_FIRE_HYDRANT && !Bobj->bHasBeenDamaged){
|
||||||
|
CParticleObject::AddObject(POBJECT_FIRE_HYDRANT, B->GetPosition() - CVector(0.0f, 0.0f, 0.5f), true);
|
||||||
|
Bobj->bHasBeenDamaged = true;
|
||||||
|
}else if(B->IsObject() && model != MI_EXPLODINGBARREL && model != MI_PETROLPUMP)
|
||||||
|
Bobj->bHasBeenDamaged = true;
|
||||||
|
}else{
|
||||||
|
if(IsGlass(B->GetModelIndex()))
|
||||||
|
CGlass::WindowRespondsToSoftCollision(B, impulseA);
|
||||||
|
CVector f = colpoint.normal * impulseA;
|
||||||
|
if(A->IsVehicle() && colpoint.normal.z < 0.7f)
|
||||||
|
f.z *= 0.3f;
|
||||||
|
if(!A->bInfiniteMass){
|
||||||
|
A->ApplyMoveForce(f);
|
||||||
|
if(!A->IsVehicle() || !CWorld::bNoMoreCollisionTorque)
|
||||||
|
A->ApplyTurnForce(f, pointposA);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}else if(!B->bInfiniteMass)
|
||||||
|
B->bIsStatic = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(B->bIsStatic)
|
||||||
|
return false;
|
||||||
|
if(!B->bInfiniteMass)
|
||||||
|
B->AddToMovingList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// B is not static
|
||||||
|
|
||||||
|
if(A->bPedPhysics && B->bPedPhysics){
|
||||||
|
// negative if A is moving towards B
|
||||||
|
speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal);
|
||||||
|
// positive if B is moving towards A
|
||||||
|
// not interested in how much B moves into A apparently?
|
||||||
|
// only interested in cases where A collided into B
|
||||||
|
speedB = max(0.0f, DotProduct(B->m_vecMoveSpeed, colpoint.normal));
|
||||||
|
// A has moved into B
|
||||||
|
if(speedA < speedB){
|
||||||
|
if(!A->bHasHitWall)
|
||||||
|
speedB -= (speedA - speedB) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||||
|
impulseA = (speedB-speedA) * A->m_fMass * timestepA;
|
||||||
|
if(!A->bInfiniteMass)
|
||||||
|
A->ApplyMoveForce(colpoint.normal*(impulseA/timestepA));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}else if(A->bPedPhysics){
|
||||||
|
CVector pointposB = colpoint.point - B->GetPosition();
|
||||||
|
speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal);
|
||||||
|
speedB = DotProduct(B->GetSpeed(pointposB), colpoint.normal);
|
||||||
|
|
||||||
|
float a = A->m_fMass*timestepA;
|
||||||
|
float b = B->GetMassTime(pointposB, colpoint.normal, timestepB);
|
||||||
|
float speedSum = (b*speedB + a*speedA)/(a + b);
|
||||||
|
if(speedA < speedSum){
|
||||||
|
if(A->bHasHitWall)
|
||||||
|
eA = speedSum;
|
||||||
|
else
|
||||||
|
eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||||
|
if(B->bHasHitWall)
|
||||||
|
eB = speedSum;
|
||||||
|
else
|
||||||
|
eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||||
|
impulseA = (eA - speedA) * a;
|
||||||
|
impulseB = -(eB - speedB) * b;
|
||||||
|
CVector fA = colpoint.normal*(impulseA/timestepA);
|
||||||
|
CVector fB = colpoint.normal*(-impulseB/timestepB);
|
||||||
|
if(!A->bInfiniteMass){
|
||||||
|
if(fA.z < 0.0f) fA.z = 0.0f;
|
||||||
|
if(ispedcontactB){
|
||||||
|
fA.x *= 2.0f;
|
||||||
|
fA.y *= 2.0f;
|
||||||
|
}
|
||||||
|
A->ApplyMoveForce(fA);
|
||||||
|
}
|
||||||
|
if(!B->bInfiniteMass && !ispedcontactB){
|
||||||
|
B->ApplyMoveForce(fB);
|
||||||
|
B->ApplyTurnForce(fB, pointposB);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}else if(B->bPedPhysics){
|
||||||
|
CVector pointposA = colpoint.point - A->GetPosition();
|
||||||
|
speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal);
|
||||||
|
speedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal);
|
||||||
|
|
||||||
|
float a = A->GetMassTime(pointposA, colpoint.normal, timestepA);
|
||||||
|
float b = B->m_fMass*timestepB;
|
||||||
|
float speedSum = (b*speedB + a*speedA)/(a + b);
|
||||||
|
if(speedA < speedSum){
|
||||||
|
if(A->bHasHitWall)
|
||||||
|
eA = speedSum;
|
||||||
|
else
|
||||||
|
eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||||
|
if(B->bHasHitWall)
|
||||||
|
eB = speedSum;
|
||||||
|
else
|
||||||
|
eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||||
|
impulseA = (eA - speedA) * a;
|
||||||
|
impulseB = -(eB - speedB) * b;
|
||||||
|
CVector fA = colpoint.normal*(impulseA/timestepA);
|
||||||
|
CVector fB = colpoint.normal*(-impulseB/timestepB);
|
||||||
|
if(!A->bInfiniteMass && !ispedcontactA){
|
||||||
|
if(fA.z < 0.0f) fA.z = 0.0f;
|
||||||
|
A->ApplyMoveForce(fA);
|
||||||
|
A->ApplyTurnForce(fA, pointposA);
|
||||||
|
}
|
||||||
|
if(!B->bInfiniteMass){
|
||||||
|
if(fB.z < 0.0f){
|
||||||
|
fB.z = 0.0f;
|
||||||
|
if(fabs(speedA) < 0.01f)
|
||||||
|
fB *= 0.5f;
|
||||||
|
}
|
||||||
|
if(ispedcontactA){
|
||||||
|
fB.x *= 2.0f;
|
||||||
|
fB.y *= 2.0f;
|
||||||
|
}
|
||||||
|
B->ApplyMoveForce(fB);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
CVector pointposA = colpoint.point - A->GetPosition();
|
||||||
|
CVector pointposB = colpoint.point - B->GetPosition();
|
||||||
|
speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal);
|
||||||
|
speedB = DotProduct(B->GetSpeed(pointposB), colpoint.normal);
|
||||||
|
float a = A->GetMassTime(pointposA, colpoint.normal, timestepA);
|
||||||
|
float b = B->GetMassTime(pointposB, colpoint.normal, timestepB);
|
||||||
|
float speedSum = (b*speedB + a*speedA)/(a + b);
|
||||||
|
if(speedA < speedSum){
|
||||||
|
if(A->bHasHitWall)
|
||||||
|
eA = speedSum;
|
||||||
|
else
|
||||||
|
eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||||
|
if(B->bHasHitWall)
|
||||||
|
eB = speedSum;
|
||||||
|
else
|
||||||
|
eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||||
|
impulseA = (eA - speedA) * a;
|
||||||
|
impulseB = -(eB - speedB) * b;
|
||||||
|
CVector fA = colpoint.normal*(impulseA/timestepA);
|
||||||
|
CVector fB = colpoint.normal*(-impulseB/timestepB);
|
||||||
|
if(A->IsVehicle() && !A->bHasHitWall){
|
||||||
|
fA.x *= 1.4f;
|
||||||
|
fA.y *= 1.4f;
|
||||||
|
if(colpoint.normal.z < 0.7f)
|
||||||
|
fA.z *= 0.3f;
|
||||||
|
if(A->m_status == STATUS_PLAYER)
|
||||||
|
pointposA *= 0.8f;
|
||||||
|
if(CWorld::bNoMoreCollisionTorque){
|
||||||
|
A->ApplyFrictionMoveForce(fA*-0.3f);
|
||||||
|
A->ApplyFrictionTurnForce(fA*-0.3f, pointposA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(B->IsVehicle() && !B->bHasHitWall){
|
||||||
|
fB.x *= 1.4f;
|
||||||
|
fB.y *= 1.4f;
|
||||||
|
if(colpoint.normal.z < 0.7f)
|
||||||
|
fB.z *= 0.3f;
|
||||||
|
if(B->m_status == STATUS_PLAYER)
|
||||||
|
pointposB *= 0.8f;
|
||||||
|
if(CWorld::bNoMoreCollisionTorque){
|
||||||
|
// BUG: the game actually uses A here, but this can't be right
|
||||||
|
B->ApplyFrictionMoveForce(fB*-0.3f);
|
||||||
|
B->ApplyFrictionTurnForce(fB*-0.3f, pointposB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!A->bInfiniteMass){
|
||||||
|
A->ApplyMoveForce(fA);
|
||||||
|
A->ApplyTurnForce(fA, pointposA);
|
||||||
|
}
|
||||||
|
if(!B->bInfiniteMass){
|
||||||
|
if(B->bIsInSafePosition)
|
||||||
|
B->UnsetIsInSafePosition();
|
||||||
|
B->ApplyMoveForce(fB);
|
||||||
|
B->ApplyTurnForce(fB, pointposB);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CPhysical::ApplyCollisionAlt(CEntity *B, CColPoint &colpoint, float &impulse, CVector &moveSpeed, CVector &turnSpeed)
|
||||||
|
{
|
||||||
|
float normalSpeed;
|
||||||
|
float e;
|
||||||
|
CVector speed;
|
||||||
|
CVector vImpulse;
|
||||||
|
|
||||||
|
if(bPedPhysics){
|
||||||
|
normalSpeed = DotProduct(m_vecMoveSpeed, colpoint.normal);
|
||||||
|
if(normalSpeed < 0.0f){
|
||||||
|
impulse = -normalSpeed * m_fMass;
|
||||||
|
ApplyMoveForce(colpoint.normal * impulse);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
CVector pointpos = colpoint.point - GetPosition();
|
||||||
|
speed = GetSpeed(pointpos);
|
||||||
|
normalSpeed = DotProduct(speed, colpoint.normal);
|
||||||
|
if(normalSpeed < 0.0f){
|
||||||
|
float minspeed = 0.0104f * CTimer::GetTimeStep();
|
||||||
|
if((IsObject() || IsVehicle() && GetUp().z < -0.3f) &&
|
||||||
|
!bHasContacted &&
|
||||||
|
fabs(m_vecMoveSpeed.x) < minspeed &&
|
||||||
|
fabs(m_vecMoveSpeed.y) < minspeed &&
|
||||||
|
fabs(m_vecMoveSpeed.z) < minspeed*2.0f)
|
||||||
|
e = -1.0f;
|
||||||
|
else
|
||||||
|
e = -(m_fElasticity + 1.0f);
|
||||||
|
impulse = normalSpeed * e * GetMass(pointpos, colpoint.normal);
|
||||||
|
|
||||||
|
// ApplyMoveForce
|
||||||
|
vImpulse = colpoint.normal*impulse;
|
||||||
|
if(IsVehicle() &&
|
||||||
|
(!bHasHitWall ||
|
||||||
|
!(m_vecMoveSpeed.MagnitudeSqr() > 0.1 || !(B->IsBuilding() || ((CPhysical*)B)->bInfiniteMass))))
|
||||||
|
moveSpeed += vImpulse * 1.2f * (1.0f/m_fMass);
|
||||||
|
else
|
||||||
|
moveSpeed += vImpulse * (1.0f/m_fMass);
|
||||||
|
|
||||||
|
// ApplyTurnForce
|
||||||
|
CVector com = Multiply3x3(m_matrix, m_vecCentreOfMass);
|
||||||
|
CVector turnimpulse = CrossProduct(pointpos-com, vImpulse);
|
||||||
|
turnSpeed += turnimpulse*(1.0f/m_fTurnMass);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint)
|
||||||
|
{
|
||||||
|
CVector speedA, speedB;
|
||||||
|
float normalSpeedA, normalSpeedB;
|
||||||
|
CVector vOtherSpeedA, vOtherSpeedB;
|
||||||
|
float fOtherSpeedA, fOtherSpeedB;
|
||||||
|
float speedSum;
|
||||||
|
CVector frictionDir;
|
||||||
|
float impulseA, impulseB;
|
||||||
|
float impulseLimit;
|
||||||
|
CPhysical *A = this;
|
||||||
|
|
||||||
|
if(A->bPedPhysics && B->bPedPhysics){
|
||||||
|
normalSpeedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal);
|
||||||
|
normalSpeedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal);
|
||||||
|
vOtherSpeedA = A->m_vecMoveSpeed - colpoint.normal*normalSpeedA;
|
||||||
|
vOtherSpeedB = B->m_vecMoveSpeed - colpoint.normal*normalSpeedB;
|
||||||
|
|
||||||
|
fOtherSpeedA = vOtherSpeedA.Magnitude();
|
||||||
|
fOtherSpeedB = vOtherSpeedB.Magnitude();
|
||||||
|
|
||||||
|
frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA);
|
||||||
|
speedSum = (B->m_fMass*fOtherSpeedB + A->m_fMass*fOtherSpeedA)/(B->m_fMass + A->m_fMass);
|
||||||
|
if(fOtherSpeedA > speedSum){
|
||||||
|
impulseA = (speedSum - fOtherSpeedA) * A->m_fMass;
|
||||||
|
impulseB = (speedSum - fOtherSpeedB) * B->m_fMass;
|
||||||
|
impulseLimit = adhesiveLimit*CTimer::GetTimeStep();
|
||||||
|
if(impulseA < -impulseLimit) impulseA = -impulseLimit;
|
||||||
|
if(impulseB > impulseLimit) impulseB = impulseLimit; // BUG: game has A's clamp again here, but this can't be right
|
||||||
|
A->ApplyFrictionMoveForce(frictionDir*impulseA);
|
||||||
|
B->ApplyFrictionMoveForce(frictionDir*impulseB);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}else if(A->bPedPhysics){
|
||||||
|
if(B->IsVehicle())
|
||||||
|
return false;
|
||||||
|
CVector pointposB = colpoint.point - B->GetPosition();
|
||||||
|
speedB = B->GetSpeed(pointposB);
|
||||||
|
|
||||||
|
normalSpeedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal);
|
||||||
|
normalSpeedB = DotProduct(speedB, colpoint.normal);
|
||||||
|
vOtherSpeedA = A->m_vecMoveSpeed - colpoint.normal*normalSpeedA;
|
||||||
|
vOtherSpeedB = speedB - colpoint.normal*normalSpeedB;
|
||||||
|
|
||||||
|
fOtherSpeedA = vOtherSpeedA.Magnitude();
|
||||||
|
fOtherSpeedB = vOtherSpeedB.Magnitude();
|
||||||
|
|
||||||
|
frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA);
|
||||||
|
float massB = B->GetMass(pointposB, frictionDir);
|
||||||
|
speedSum = (massB*fOtherSpeedB + A->m_fMass*fOtherSpeedA)/(massB + A->m_fMass);
|
||||||
|
if(fOtherSpeedA > speedSum){
|
||||||
|
impulseA = (speedSum - fOtherSpeedA) * A->m_fMass;
|
||||||
|
impulseB = (speedSum - fOtherSpeedB) * massB;
|
||||||
|
impulseLimit = adhesiveLimit*CTimer::GetTimeStep();
|
||||||
|
if(impulseA < -impulseLimit) impulseA = -impulseLimit;
|
||||||
|
if(impulseB > impulseLimit) impulseB = impulseLimit;
|
||||||
|
A->ApplyFrictionMoveForce(frictionDir*impulseA);
|
||||||
|
B->ApplyFrictionMoveForce(frictionDir*impulseB);
|
||||||
|
B->ApplyFrictionTurnForce(frictionDir*impulseB, pointposB);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}else if(B->bPedPhysics){
|
||||||
|
if(A->IsVehicle())
|
||||||
|
return false;
|
||||||
|
CVector pointposA = colpoint.point - A->GetPosition();
|
||||||
|
speedA = A->GetSpeed(pointposA);
|
||||||
|
|
||||||
|
normalSpeedA = DotProduct(speedA, colpoint.normal);
|
||||||
|
normalSpeedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal);
|
||||||
|
vOtherSpeedA = speedA - colpoint.normal*normalSpeedA;
|
||||||
|
vOtherSpeedB = B->m_vecMoveSpeed - colpoint.normal*normalSpeedB;
|
||||||
|
|
||||||
|
fOtherSpeedA = vOtherSpeedA.Magnitude();
|
||||||
|
fOtherSpeedB = vOtherSpeedB.Magnitude();
|
||||||
|
|
||||||
|
frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA);
|
||||||
|
float massA = A->GetMass(pointposA, frictionDir);
|
||||||
|
speedSum = (B->m_fMass*fOtherSpeedB + massA*fOtherSpeedA)/(B->m_fMass + massA);
|
||||||
|
if(fOtherSpeedA > speedSum){
|
||||||
|
impulseA = (speedSum - fOtherSpeedA) * massA;
|
||||||
|
impulseB = (speedSum - fOtherSpeedB) * B->m_fMass;
|
||||||
|
impulseLimit = adhesiveLimit*CTimer::GetTimeStep();
|
||||||
|
if(impulseA < -impulseLimit) impulseA = -impulseLimit;
|
||||||
|
if(impulseB > impulseLimit) impulseB = impulseLimit;
|
||||||
|
A->ApplyFrictionMoveForce(frictionDir*impulseA);
|
||||||
|
A->ApplyFrictionTurnForce(frictionDir*impulseA, pointposA);
|
||||||
|
B->ApplyFrictionMoveForce(frictionDir*impulseB);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
CVector pointposA = colpoint.point - A->GetPosition();
|
||||||
|
CVector pointposB = colpoint.point - B->GetPosition();
|
||||||
|
speedA = A->GetSpeed(pointposA);
|
||||||
|
speedB = B->GetSpeed(pointposB);
|
||||||
|
|
||||||
|
normalSpeedA = DotProduct(speedA, colpoint.normal);
|
||||||
|
normalSpeedB = DotProduct(speedB, colpoint.normal);
|
||||||
|
vOtherSpeedA = speedA - colpoint.normal*normalSpeedA;
|
||||||
|
vOtherSpeedB = speedB - colpoint.normal*normalSpeedB;
|
||||||
|
|
||||||
|
fOtherSpeedA = vOtherSpeedA.Magnitude();
|
||||||
|
fOtherSpeedB = vOtherSpeedB.Magnitude();
|
||||||
|
|
||||||
|
frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA);
|
||||||
|
float massA = A->GetMass(pointposA, frictionDir);
|
||||||
|
float massB = B->GetMass(pointposB, frictionDir);
|
||||||
|
speedSum = (massB*fOtherSpeedB + massA*fOtherSpeedA)/(massB + massA);
|
||||||
|
if(fOtherSpeedA > speedSum){
|
||||||
|
impulseA = (speedSum - fOtherSpeedA) * massA;
|
||||||
|
impulseB = (speedSum - fOtherSpeedB) * massB;
|
||||||
|
impulseLimit = adhesiveLimit*CTimer::GetTimeStep();
|
||||||
|
if(impulseA < -impulseLimit) impulseA = -impulseLimit;
|
||||||
|
if(impulseB > impulseLimit) impulseB = impulseLimit;
|
||||||
|
A->ApplyFrictionMoveForce(frictionDir*impulseA);
|
||||||
|
A->ApplyFrictionTurnForce(frictionDir*impulseA, pointposA);
|
||||||
|
B->ApplyFrictionMoveForce(frictionDir*impulseB);
|
||||||
|
B->ApplyFrictionTurnForce(frictionDir*impulseB, pointposB);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CPhysical::ApplyFriction(float adhesiveLimit, CColPoint &colpoint)
|
||||||
|
{
|
||||||
|
CVector speed;
|
||||||
|
float normalSpeed;
|
||||||
|
CVector vOtherSpeed;
|
||||||
|
float fOtherSpeed;
|
||||||
|
CVector frictionDir;
|
||||||
|
float fImpulse;
|
||||||
|
float impulseLimit;
|
||||||
|
|
||||||
|
if(bPedPhysics){
|
||||||
|
normalSpeed = DotProduct(m_vecMoveSpeed, colpoint.normal);
|
||||||
|
vOtherSpeed = m_vecMoveSpeed - colpoint.normal*normalSpeed;
|
||||||
|
|
||||||
|
fOtherSpeed = vOtherSpeed.Magnitude();
|
||||||
|
if(fOtherSpeed > 0.0f){
|
||||||
|
frictionDir = vOtherSpeed * (1.0f/fOtherSpeed);
|
||||||
|
// not really impulse but speed
|
||||||
|
// maybe use ApplyFrictionMoveForce instead?
|
||||||
|
fImpulse = -fOtherSpeed;
|
||||||
|
impulseLimit = adhesiveLimit*CTimer::GetTimeStep() / m_fMass;
|
||||||
|
if(fImpulse < -impulseLimit) fImpulse = -impulseLimit;
|
||||||
|
CVector vImpulse = frictionDir*fImpulse;
|
||||||
|
m_vecMoveFriction += CVector(vImpulse.x, vImpulse.y, 0.0f);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
CVector pointpos = colpoint.point - GetPosition();
|
||||||
|
speed = GetSpeed(pointpos);
|
||||||
|
normalSpeed = DotProduct(speed, colpoint.normal);
|
||||||
|
vOtherSpeed = speed - colpoint.normal*normalSpeed;
|
||||||
|
|
||||||
|
fOtherSpeed = vOtherSpeed.Magnitude();
|
||||||
|
if(fOtherSpeed > 0.0f){
|
||||||
|
frictionDir = vOtherSpeed * (1.0f/fOtherSpeed);
|
||||||
|
fImpulse = -fOtherSpeed * m_fMass;
|
||||||
|
impulseLimit = adhesiveLimit*CTimer::GetTimeStep() * 1.5f;
|
||||||
|
if(fImpulse < -impulseLimit) fImpulse = -impulseLimit;
|
||||||
|
ApplyFrictionMoveForce(frictionDir*fImpulse);
|
||||||
|
ApplyFrictionTurnForce(frictionDir*fImpulse, pointpos);
|
||||||
|
|
||||||
|
if(fOtherSpeed > 0.1f &&
|
||||||
|
colpoint.surfaceB != SURFACE_2 && colpoint.surfaceB != SURFACE_4 &&
|
||||||
|
CSurfaceTable::GetAdhesionGroup(colpoint.surfaceA) == ADHESIVE_HARD){
|
||||||
|
CVector v = frictionDir * fOtherSpeed * 0.25f;
|
||||||
|
for(int i = 0; i < 4; i++)
|
||||||
|
CParticle::AddParticle(PARTICLE_SPARK_SMALL, colpoint.point, v);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::AddCollisionRecord(CEntity *ent)
|
||||||
|
{
|
||||||
|
AddCollisionRecord_Treadable(ent);
|
||||||
|
this->bHasCollided = true;
|
||||||
|
ent->bHasCollided = true;
|
||||||
|
if(IsVehicle() && ent->IsVehicle()){
|
||||||
|
if(((CVehicle*)this)->m_nAlarmState == -1)
|
||||||
|
((CVehicle*)this)->m_nAlarmState = 15000;
|
||||||
|
if(((CVehicle*)ent)->m_nAlarmState == -1)
|
||||||
|
((CVehicle*)ent)->m_nAlarmState = 15000;
|
||||||
|
}
|
||||||
|
if(bUseCollisionRecords){
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < m_nCollisionRecords; i++)
|
||||||
|
if(m_aCollisionRecords[i] == ent)
|
||||||
|
return;
|
||||||
|
if(m_nCollisionRecords < PHYSICAL_MAX_COLLISIONRECORDS)
|
||||||
|
m_aCollisionRecords[m_nCollisionRecords++] = ent;
|
||||||
|
m_nLastTimeCollided = CTimer::GetTimeInMilliseconds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::AddCollisionRecord_Treadable(CEntity *ent)
|
||||||
|
{
|
||||||
|
if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable()){
|
||||||
|
CTreadable *t = (CTreadable*)ent;
|
||||||
|
if(t->m_nodeIndicesPeds[0] >= 0 ||
|
||||||
|
t->m_nodeIndicesPeds[1] >= 0 ||
|
||||||
|
t->m_nodeIndicesPeds[2] >= 0 ||
|
||||||
|
t->m_nodeIndicesPeds[3] >= 0)
|
||||||
|
m_pedTreadable = t;
|
||||||
|
if(t->m_nodeIndicesCars[0] >= 0 ||
|
||||||
|
t->m_nodeIndicesCars[1] >= 0 ||
|
||||||
|
t->m_nodeIndicesCars[2] >= 0 ||
|
||||||
|
t->m_nodeIndicesCars[3] >= 0)
|
||||||
|
m_carTreadable = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CPhysical::GetHasCollidedWith(CEntity *ent)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if(bUseCollisionRecords)
|
||||||
|
for(i = 0; i < m_nCollisionRecords; i++)
|
||||||
|
if(m_aCollisionRecords[i] == ent)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPhysical::ProcessControl(void)
|
||||||
|
{
|
||||||
|
if(!IsPed())
|
||||||
|
m_phy_flagA8 = false;
|
||||||
|
bHasContacted = false;
|
||||||
|
bIsInSafePosition = false;
|
||||||
|
bWasPostponed = false;
|
||||||
|
bHasHitWall = false;
|
||||||
|
|
||||||
|
if(m_status == STATUS_SIMPLE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_nCollisionRecords = 0;
|
||||||
|
bHasCollided = false;
|
||||||
|
m_nCollisionPieceType = 0;
|
||||||
|
m_fCollisionImpulse = 0.0f;
|
||||||
|
m_pCollidingEntity = nil;
|
||||||
|
|
||||||
|
if(!bIsStuck){
|
||||||
|
if(IsObject() ||
|
||||||
|
IsPed() && !bPedPhysics){
|
||||||
|
m_vecMoveSpeedAvg = (m_vecMoveSpeedAvg + m_vecMoveSpeed)/2.0f;
|
||||||
|
m_vecTurnSpeedAvg = (m_vecTurnSpeedAvg + m_vecTurnSpeed)/2.0f;
|
||||||
|
float step = CTimer::GetTimeStep() * 0.003;
|
||||||
|
if(m_vecMoveSpeedAvg.MagnitudeSqr() < step*step &&
|
||||||
|
m_vecTurnSpeedAvg.MagnitudeSqr() < step*step){
|
||||||
|
m_nStaticFrames++;
|
||||||
|
if(m_nStaticFrames > 10){
|
||||||
|
m_nStaticFrames = 10;
|
||||||
|
bIsStatic = true;
|
||||||
|
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
|
||||||
|
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
|
||||||
|
m_vecMoveFriction = m_vecMoveSpeed;
|
||||||
|
m_vecTurnFriction = m_vecTurnSpeed;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}else
|
||||||
|
m_nStaticFrames = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ApplyGravity();
|
||||||
|
ApplyFriction();
|
||||||
|
ApplyAirResistance();
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x4951F0, &CPhysical::Add_, PATCH_JUMP);
|
||||||
|
InjectHook(0x4954B0, &CPhysical::Remove_, PATCH_JUMP);
|
||||||
|
InjectHook(0x495540, &CPhysical::RemoveAndAdd, PATCH_JUMP);
|
||||||
|
InjectHook(0x495F10, &CPhysical::ProcessControl_, PATCH_JUMP);
|
||||||
|
InjectHook(0x4958F0, &CPhysical::AddToMovingList, PATCH_JUMP);
|
||||||
|
InjectHook(0x495940, &CPhysical::RemoveFromMovingList, PATCH_JUMP);
|
||||||
|
|
||||||
|
InjectHook(0x497180, &CPhysical::AddCollisionRecord, PATCH_JUMP);
|
||||||
|
InjectHook(0x4970C0, &CPhysical::AddCollisionRecord_Treadable, PATCH_JUMP);
|
||||||
|
InjectHook(0x497240, &CPhysical::GetHasCollidedWith, PATCH_JUMP);
|
||||||
|
|
||||||
|
#define F3 float, float, float
|
||||||
|
InjectHook(0x495B10, &CPhysical::ApplyMoveSpeed, PATCH_JUMP);
|
||||||
|
InjectHook(0x497280, &CPhysical::ApplyTurnSpeed, PATCH_JUMP);
|
||||||
|
InjectHook(0x4959A0, (void (CPhysical::*)(F3))&CPhysical::ApplyMoveForce, PATCH_JUMP);
|
||||||
|
InjectHook(0x495A10, (void (CPhysical::*)(F3, F3))&CPhysical::ApplyTurnForce, PATCH_JUMP);
|
||||||
|
InjectHook(0x495D90, (void (CPhysical::*)(F3))&CPhysical::ApplyFrictionMoveForce, PATCH_JUMP);
|
||||||
|
InjectHook(0x495E10, (void (CPhysical::*)(F3, F3))&CPhysical::ApplyFrictionTurnForce, PATCH_JUMP);
|
||||||
|
InjectHook(0x499890, &CPhysical::ApplySpringCollision, PATCH_JUMP);
|
||||||
|
InjectHook(0x495B50, &CPhysical::ApplyGravity, PATCH_JUMP);
|
||||||
|
InjectHook(0x495B80, (void (CPhysical::*)(void))&CPhysical::ApplyFriction, PATCH_JUMP);
|
||||||
|
InjectHook(0x495C20, &CPhysical::ApplyAirResistance, PATCH_JUMP);
|
||||||
|
|
||||||
|
InjectHook(0x4973A0, &CPhysical::ApplyCollision, PATCH_JUMP);
|
||||||
|
InjectHook(0x4992A0, &CPhysical::ApplyCollisionAlt, PATCH_JUMP);
|
||||||
|
InjectHook(0x499BE0, (bool (CPhysical::*)(float, CColPoint&))&CPhysical::ApplyFriction, PATCH_JUMP);
|
||||||
|
InjectHook(0x49A180, (bool (CPhysical::*)(CPhysical*, float, CColPoint&))&CPhysical::ApplyFriction, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
137
src/entities/Physical.h
Normal file
137
src/entities/Physical.h
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Lists.h"
|
||||||
|
#include "Entity.h"
|
||||||
|
#include "Treadable.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PHYSICAL_MAX_COLLISIONRECORDS = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
class CPhysical : public CEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// The not properly indented fields haven't been checked properly yet
|
||||||
|
|
||||||
|
int uAudioEntityId;
|
||||||
|
float unk1;
|
||||||
|
CTreadable *m_carTreadable;
|
||||||
|
CTreadable *m_pedTreadable;
|
||||||
|
uint32 m_nLastTimeCollided;
|
||||||
|
CVector m_vecMoveSpeed; // velocity
|
||||||
|
CVector m_vecTurnSpeed; // angular velocity
|
||||||
|
CVector m_vecMoveFriction;
|
||||||
|
CVector m_vecTurnFriction;
|
||||||
|
CVector m_vecMoveSpeedAvg;
|
||||||
|
CVector m_vecTurnSpeedAvg;
|
||||||
|
float m_fMass;
|
||||||
|
float m_fTurnMass; // moment of inertia
|
||||||
|
float fForceMultiplier;
|
||||||
|
float m_fAirResistance;
|
||||||
|
float m_fElasticity;
|
||||||
|
float fPercentSubmerged;
|
||||||
|
CVector m_vecCentreOfMass;
|
||||||
|
CEntryInfoList m_entryInfoList;
|
||||||
|
CPtrNode *m_movingListNode;
|
||||||
|
|
||||||
|
char field_EC;
|
||||||
|
uint8 m_nStaticFrames;
|
||||||
|
uint8 m_nCollisionRecords;
|
||||||
|
char field_EF;
|
||||||
|
CEntity *m_aCollisionRecords[PHYSICAL_MAX_COLLISIONRECORDS];
|
||||||
|
|
||||||
|
float m_fDistanceTravelled;
|
||||||
|
|
||||||
|
// damaged piece
|
||||||
|
float m_fCollisionImpulse;
|
||||||
|
CEntity *m_pCollidingEntity;
|
||||||
|
CVector m_vecCollisionDirection;
|
||||||
|
int16 m_nCollisionPieceType;
|
||||||
|
|
||||||
|
uint8 m_phy_flagA1 : 1;
|
||||||
|
uint8 bAffectedByGravity : 1;
|
||||||
|
uint8 bInfiniteMass : 1;
|
||||||
|
uint8 m_phy_flagA8 : 1;
|
||||||
|
uint8 m_phy_flagA10 : 1;
|
||||||
|
uint8 m_phy_flagA20 : 1;
|
||||||
|
uint8 m_phy_flagA40 : 1;
|
||||||
|
uint8 m_phy_flagA80 : 1;
|
||||||
|
|
||||||
|
uint8 m_phy_flagB1 : 1;
|
||||||
|
uint8 m_phy_flagB2 : 1;
|
||||||
|
uint8 m_phy_flagB4 : 1;
|
||||||
|
uint8 m_phy_flagB8 : 1;
|
||||||
|
uint8 m_phy_flagB10 : 1;
|
||||||
|
uint8 m_phy_flagB20 : 1;
|
||||||
|
uint8 m_phy_flagB40 : 1;
|
||||||
|
uint8 m_phy_flagB80 : 1;
|
||||||
|
|
||||||
|
char byteLastCollType;
|
||||||
|
char byteZoneLevel;
|
||||||
|
int16 pad;
|
||||||
|
|
||||||
|
|
||||||
|
// from CEntity
|
||||||
|
void Add(void);
|
||||||
|
void Remove(void);
|
||||||
|
CRect GetBoundRect(void);
|
||||||
|
void ProcessControl(void);
|
||||||
|
|
||||||
|
void RemoveAndAdd(void);
|
||||||
|
void AddToMovingList(void);
|
||||||
|
void RemoveFromMovingList(void);
|
||||||
|
|
||||||
|
// get speed of point p relative to entity center
|
||||||
|
CVector GetSpeed(const CVector &r);
|
||||||
|
CVector GetSpeed(void) { return GetSpeed(CVector(0.0f, 0.0f, 0.0f)); }
|
||||||
|
float GetMass(const CVector &pos, const CVector &dir) {
|
||||||
|
return 1.0f / (CrossProduct(pos, dir).MagnitudeSqr()/m_fTurnMass +
|
||||||
|
1.0f/m_fMass);
|
||||||
|
}
|
||||||
|
float GetMassTime(const CVector &pos, const CVector &dir, float t) {
|
||||||
|
return 1.0f / (CrossProduct(pos, dir).MagnitudeSqr()/(m_fTurnMass*t) +
|
||||||
|
1.0f/(m_fMass*t));
|
||||||
|
}
|
||||||
|
void UnsetIsInSafePosition(void) {
|
||||||
|
m_vecMoveSpeed *= -1.0f;
|
||||||
|
m_vecTurnSpeed *= -1.0f;
|
||||||
|
ApplyTurnSpeed();
|
||||||
|
ApplyMoveSpeed();
|
||||||
|
m_vecMoveSpeed *= -1.0f;
|
||||||
|
m_vecTurnSpeed *= -1.0f;
|
||||||
|
bIsInSafePosition = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplyMoveSpeed(void);
|
||||||
|
void ApplyTurnSpeed(void);
|
||||||
|
// Force actually means Impulse here
|
||||||
|
void ApplyMoveForce(float jx, float jy, float jz);
|
||||||
|
void ApplyMoveForce(const CVector &j) { ApplyMoveForce(j.x, j.y, j.z); }
|
||||||
|
// v(x,y,z) is direction of force, p(x,y,z) is point relative to model center where force is applied
|
||||||
|
void ApplyTurnForce(float jx, float jy, float jz, float rx, float ry, float rz);
|
||||||
|
// v is direction of force, p is point relative to model center where force is applied
|
||||||
|
void ApplyTurnForce(const CVector &j, const CVector &p) { ApplyTurnForce(j.x, j.y, j.z, p.x, p.y, p.z); }
|
||||||
|
void ApplyFrictionMoveForce(float jx, float jy, float jz);
|
||||||
|
void ApplyFrictionMoveForce(const CVector &j) { ApplyFrictionMoveForce(j.x, j.y, j.z); }
|
||||||
|
void ApplyFrictionTurnForce(float jx, float jy, float jz, float rx, float ry, float rz);
|
||||||
|
void ApplyFrictionTurnForce(const CVector &j, const CVector &p) { ApplyFrictionTurnForce(j.x, j.y, j.z, p.x, p.y, p.z); }
|
||||||
|
void ApplySpringCollision(float f1, CVector &v, CVector &p, float f2, float f3);
|
||||||
|
void ApplyGravity(void);
|
||||||
|
void ApplyFriction(void);
|
||||||
|
void ApplyAirResistance(void);
|
||||||
|
bool ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, float &impulseB);
|
||||||
|
bool ApplyCollisionAlt(CEntity *B, CColPoint &colpoint, float &impulse, CVector &moveSpeed, CVector &turnSpeed);
|
||||||
|
bool ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint);
|
||||||
|
bool ApplyFriction(float adhesiveLimit, CColPoint &colpoint);
|
||||||
|
|
||||||
|
void AddCollisionRecord(CEntity *ent);
|
||||||
|
void AddCollisionRecord_Treadable(CEntity *ent);
|
||||||
|
bool GetHasCollidedWith(CEntity *ent);
|
||||||
|
|
||||||
|
// to make patching virtual functions possible
|
||||||
|
void Add_(void) { CPhysical::Add(); }
|
||||||
|
void Remove_(void) { CPhysical::Remove(); }
|
||||||
|
CRect GetBoundRect_(void) { return CPhysical::GetBoundRect(); }
|
||||||
|
void ProcessControl_(void) { CPhysical::ProcessControl(); }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CPhysical) == 0x128, "CPhysical: error");
|
7
src/entities/Treadable.cpp
Normal file
7
src/entities/Treadable.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "rpworld.h"
|
||||||
|
#include "Treadable.h"
|
||||||
|
#include "Pools.h"
|
||||||
|
|
||||||
|
void *CTreadable::operator new(size_t sz) { return CPools::GetTreadablePool()->New(); }
|
||||||
|
void CTreadable::operator delete(void *p, size_t sz) { CPools::GetTreadablePool()->Delete((CTreadable*)p); }
|
16
src/entities/Treadable.h
Normal file
16
src/entities/Treadable.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Building.h"
|
||||||
|
|
||||||
|
class CTreadable : public CBuilding
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void *operator new(size_t);
|
||||||
|
static void operator delete(void*, size_t);
|
||||||
|
|
||||||
|
int16 m_nodeIndicesCars[12];
|
||||||
|
int16 m_nodeIndicesPeds[12];
|
||||||
|
|
||||||
|
virtual bool GetIsATreadable(void) { return true; }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CTreadable) == 0x94, "CTreadable: error");
|
21
src/entities/Vehicle.h
Normal file
21
src/entities/Vehicle.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Physical.h"
|
||||||
|
|
||||||
|
class CPed;
|
||||||
|
|
||||||
|
class CVehicle : public CPhysical
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// 0x128
|
||||||
|
uint8 stuff1[120];
|
||||||
|
int16 m_nAlarmState;
|
||||||
|
CPed *pDriver;
|
||||||
|
CPed *pPassengers[8];
|
||||||
|
uint8 stuff2[24];
|
||||||
|
CEntity *m_pCurSurface;
|
||||||
|
uint8 stuff3[160];
|
||||||
|
int32 m_vehType;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CVehicle) == 0x288, "CVehicle: error");
|
||||||
|
static_assert(offsetof(CVehicle, m_pCurSurface) == 0x1E0, "CVehicle: error");
|
98
src/main.cpp
Normal file
98
src/main.cpp
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include <Windows.h>
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include "debugmenu_public.h"
|
||||||
|
|
||||||
|
void **rwengine = *(void***)0x5A10E1;
|
||||||
|
|
||||||
|
RsGlobalType &RsGlobal = *(RsGlobalType*)0x8F4360;
|
||||||
|
|
||||||
|
GlobalScene &Scene = *(GlobalScene*)0x726768;
|
||||||
|
|
||||||
|
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); }
|
||||||
|
|
||||||
|
// Use our own implementation of rand, stolen from PS2
|
||||||
|
|
||||||
|
unsigned __int64 myrand_seed = 1;
|
||||||
|
|
||||||
|
int
|
||||||
|
myrand(void)
|
||||||
|
{
|
||||||
|
myrand_seed = 0x5851F42D4C957F2D * myrand_seed + 1;
|
||||||
|
return ((myrand_seed >> 32) & 0x7FFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if(GetAsyncKeyState('D') & 0x8000)
|
||||||
|
return open_script_orig("main_d.scm", mode);
|
||||||
|
// if(GetAsyncKeyState('R') & 0x8000)
|
||||||
|
return open_script_orig("main_freeroam.scm", mode);
|
||||||
|
return open_script_orig(path, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int (*RsEventHandler_orig)(int a, int b);
|
||||||
|
int
|
||||||
|
delayedPatches10(int a, int b)
|
||||||
|
{
|
||||||
|
if(DebugMenuLoad()){
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RsEventHandler_orig(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
patch()
|
||||||
|
{
|
||||||
|
StaticPatcher::Apply();
|
||||||
|
|
||||||
|
Patch<float>(0x46BC61+6, 1.0f); // car distance
|
||||||
|
InjectHook(0x59E460, printf, 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;
|
||||||
|
}
|
245
src/math/Matrix.h
Normal file
245
src/math/Matrix.h
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CMatrix
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RwMatrix m_matrix;
|
||||||
|
RwMatrix *m_attachment;
|
||||||
|
bool m_hasRwMatrix; // are we the owner?
|
||||||
|
|
||||||
|
CMatrix(void){
|
||||||
|
m_attachment = nil;
|
||||||
|
m_hasRwMatrix = false;
|
||||||
|
}
|
||||||
|
CMatrix(CMatrix const &m){
|
||||||
|
m_attachment = nil;
|
||||||
|
m_hasRwMatrix = false;
|
||||||
|
*this = m;
|
||||||
|
}
|
||||||
|
CMatrix(RwMatrix *matrix, bool attach){
|
||||||
|
m_attachment = nil;
|
||||||
|
Attach(matrix, attach);
|
||||||
|
}
|
||||||
|
~CMatrix(void){
|
||||||
|
if(m_hasRwMatrix && m_attachment)
|
||||||
|
RwMatrixDestroy(m_attachment);
|
||||||
|
}
|
||||||
|
void Attach(RwMatrix *matrix, bool attach){
|
||||||
|
if(m_hasRwMatrix && m_attachment)
|
||||||
|
RwMatrixDestroy(m_attachment);
|
||||||
|
m_attachment = matrix;
|
||||||
|
m_hasRwMatrix = attach;
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
void AttachRW(RwMatrix *matrix, bool attach){
|
||||||
|
if(m_hasRwMatrix && m_attachment)
|
||||||
|
RwMatrixDestroy(m_attachment);
|
||||||
|
m_attachment = matrix;
|
||||||
|
m_hasRwMatrix = attach;
|
||||||
|
UpdateRW();
|
||||||
|
}
|
||||||
|
void Detach(void){
|
||||||
|
if(m_hasRwMatrix && m_attachment)
|
||||||
|
RwMatrixDestroy(m_attachment);
|
||||||
|
m_attachment = nil;
|
||||||
|
}
|
||||||
|
void Update(void){
|
||||||
|
m_matrix = *m_attachment;
|
||||||
|
}
|
||||||
|
void UpdateRW(void){
|
||||||
|
if(m_attachment){
|
||||||
|
*m_attachment = m_matrix;
|
||||||
|
RwMatrixUpdate(m_attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void operator=(CMatrix const &rhs){
|
||||||
|
m_matrix = rhs.m_matrix;
|
||||||
|
if(m_attachment)
|
||||||
|
UpdateRW();
|
||||||
|
}
|
||||||
|
|
||||||
|
CVector *GetPosition(void){ return (CVector*)&m_matrix.pos; }
|
||||||
|
CVector *GetRight(void) { return (CVector*)&m_matrix.right; }
|
||||||
|
CVector *GetForward(void) { return (CVector*)&m_matrix.up; }
|
||||||
|
CVector *GetUp(void) { return (CVector*)&m_matrix.at; }
|
||||||
|
void SetScale(float s){
|
||||||
|
m_matrix.right.x = s;
|
||||||
|
m_matrix.right.y = 0.0f;
|
||||||
|
m_matrix.right.z = 0.0f;
|
||||||
|
|
||||||
|
m_matrix.up.x = 0.0f;
|
||||||
|
m_matrix.up.y = s;
|
||||||
|
m_matrix.up.z = 0.0f;
|
||||||
|
|
||||||
|
m_matrix.at.x = 0.0f;
|
||||||
|
m_matrix.at.y = 0.0f;
|
||||||
|
m_matrix.at.z = s;
|
||||||
|
|
||||||
|
m_matrix.pos.x = 0.0f;
|
||||||
|
m_matrix.pos.y = 0.0f;
|
||||||
|
m_matrix.pos.z = 0.0f;
|
||||||
|
}
|
||||||
|
void SetRotateXOnly(float angle){
|
||||||
|
float c = cos(angle);
|
||||||
|
float s = sin(angle);
|
||||||
|
|
||||||
|
m_matrix.right.x = 1.0f;
|
||||||
|
m_matrix.right.y = 0.0f;
|
||||||
|
m_matrix.right.z = 0.0f;
|
||||||
|
|
||||||
|
m_matrix.up.x = 0.0f;
|
||||||
|
m_matrix.up.y = c;
|
||||||
|
m_matrix.up.z = s;
|
||||||
|
|
||||||
|
m_matrix.at.x = 0.0f;
|
||||||
|
m_matrix.at.y = -s;
|
||||||
|
m_matrix.at.z = c;
|
||||||
|
}
|
||||||
|
void SetRotateX(float angle){
|
||||||
|
SetRotateXOnly(angle);
|
||||||
|
m_matrix.pos.x = 0.0f;
|
||||||
|
m_matrix.pos.y = 0.0f;
|
||||||
|
m_matrix.pos.z = 0.0f;
|
||||||
|
}
|
||||||
|
void SetRotateYOnly(float angle){
|
||||||
|
float c = cos(angle);
|
||||||
|
float s = sin(angle);
|
||||||
|
|
||||||
|
m_matrix.right.x = c;
|
||||||
|
m_matrix.right.y = 0.0f;
|
||||||
|
m_matrix.right.z = -s;
|
||||||
|
|
||||||
|
m_matrix.up.x = 0.0f;
|
||||||
|
m_matrix.up.y = 1.0f;
|
||||||
|
m_matrix.up.z = 0.0f;
|
||||||
|
|
||||||
|
m_matrix.at.x = s;
|
||||||
|
m_matrix.at.y = 0.0f;
|
||||||
|
m_matrix.at.z = c;
|
||||||
|
}
|
||||||
|
void SetRotateY(float angle){
|
||||||
|
SetRotateYOnly(angle);
|
||||||
|
m_matrix.pos.x = 0.0f;
|
||||||
|
m_matrix.pos.y = 0.0f;
|
||||||
|
m_matrix.pos.z = 0.0f;
|
||||||
|
}
|
||||||
|
void SetRotateZOnly(float angle){
|
||||||
|
float c = cos(angle);
|
||||||
|
float s = sin(angle);
|
||||||
|
|
||||||
|
m_matrix.right.x = c;
|
||||||
|
m_matrix.right.y = s;
|
||||||
|
m_matrix.right.z = 0.0f;
|
||||||
|
|
||||||
|
m_matrix.up.x = -s;
|
||||||
|
m_matrix.up.y = c;
|
||||||
|
m_matrix.up.z = 0.0f;
|
||||||
|
|
||||||
|
m_matrix.at.x = 0.0f;
|
||||||
|
m_matrix.at.y = 0.0f;
|
||||||
|
m_matrix.at.z = 1.0f;
|
||||||
|
}
|
||||||
|
void SetRotateZ(float angle){
|
||||||
|
SetRotateZOnly(angle);
|
||||||
|
m_matrix.pos.x = 0.0f;
|
||||||
|
m_matrix.pos.y = 0.0f;
|
||||||
|
m_matrix.pos.z = 0.0f;
|
||||||
|
}
|
||||||
|
void Reorthogonalise(void){
|
||||||
|
CVector &r = *GetRight();
|
||||||
|
CVector &f = *GetForward();
|
||||||
|
CVector &u = *GetUp();
|
||||||
|
u = CrossProduct(r, f);
|
||||||
|
u.Normalise();
|
||||||
|
r = CrossProduct(f, u);
|
||||||
|
r.Normalise();
|
||||||
|
f = CrossProduct(u, r);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline CMatrix&
|
||||||
|
Invert(const CMatrix &src, CMatrix &dst)
|
||||||
|
{
|
||||||
|
// GTA handles this as a raw 4x4 orthonormal matrix
|
||||||
|
// and trashes the RW flags, let's not do that
|
||||||
|
// actual copy of librw code:
|
||||||
|
RwMatrix *d = &dst.m_matrix;
|
||||||
|
const RwMatrix *s = &src.m_matrix;
|
||||||
|
d->right.x = s->right.x;
|
||||||
|
d->right.y = s->up.x;
|
||||||
|
d->right.z = s->at.x;
|
||||||
|
d->up.x = s->right.y;
|
||||||
|
d->up.y = s->up.y;
|
||||||
|
d->up.z = s->at.y;
|
||||||
|
d->at.x = s->right.z;
|
||||||
|
d->at.y = s->up.z;
|
||||||
|
d->at.z = s->at.z;
|
||||||
|
d->pos.x = -(s->pos.x*s->right.x +
|
||||||
|
s->pos.y*s->right.y +
|
||||||
|
s->pos.z*s->right.z);
|
||||||
|
d->pos.y = -(s->pos.x*s->up.x +
|
||||||
|
s->pos.y*s->up.y +
|
||||||
|
s->pos.z*s->up.z);
|
||||||
|
d->pos.z = -(s->pos.x*s->at.x +
|
||||||
|
s->pos.y*s->at.y +
|
||||||
|
s->pos.z*s->at.z);
|
||||||
|
d->flags = rwMATRIXTYPEORTHONORMAL;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CMatrix
|
||||||
|
Invert(const CMatrix &matrix)
|
||||||
|
{
|
||||||
|
CMatrix inv;
|
||||||
|
return Invert(matrix, inv);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CVector
|
||||||
|
operator*(const CMatrix &mat, const CVector &vec)
|
||||||
|
{
|
||||||
|
return CVector(
|
||||||
|
mat.m_matrix.right.x * vec.x + mat.m_matrix.up.x * vec.y + mat.m_matrix.at.x * vec.z + mat.m_matrix.pos.x,
|
||||||
|
mat.m_matrix.right.y * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.at.y * vec.z + mat.m_matrix.pos.y,
|
||||||
|
mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z + mat.m_matrix.pos.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CMatrix
|
||||||
|
operator*(const CMatrix &m1, const CMatrix &m2)
|
||||||
|
{
|
||||||
|
CMatrix out;
|
||||||
|
RwMatrix *dst = &out.m_matrix;
|
||||||
|
const RwMatrix *src1 = &m1.m_matrix;
|
||||||
|
const RwMatrix *src2 = &m2.m_matrix;
|
||||||
|
dst->right.x = src1->right.x*src2->right.x + src1->up.x*src2->right.y + src1->at.x*src2->right.z;
|
||||||
|
dst->right.y = src1->right.y*src2->right.x + src1->up.y*src2->right.y + src1->at.y*src2->right.z;
|
||||||
|
dst->right.z = src1->right.z*src2->right.x + src1->up.z*src2->right.y + src1->at.z*src2->right.z;
|
||||||
|
dst->up.x = src1->right.x*src2->up.x + src1->up.x*src2->up.y + src1->at.x*src2->up.z;
|
||||||
|
dst->up.y = src1->right.y*src2->up.x + src1->up.y*src2->up.y + src1->at.y*src2->up.z;
|
||||||
|
dst->up.z = src1->right.z*src2->up.x + src1->up.z*src2->up.y + src1->at.z*src2->up.z;
|
||||||
|
dst->at.x = src1->right.x*src2->at.x + src1->up.x*src2->at.y + src1->at.x*src2->at.z;
|
||||||
|
dst->at.y = src1->right.y*src2->at.x + src1->up.y*src2->at.y + src1->at.y*src2->at.z;
|
||||||
|
dst->at.z = src1->right.z*src2->at.x + src1->up.z*src2->at.y + src1->at.z*src2->at.z;
|
||||||
|
dst->pos.x = src1->right.x*src2->pos.x + src1->up.x*src2->pos.y + src1->at.x*src2->pos.z + src1->pos.x;
|
||||||
|
dst->pos.y = src1->right.y*src2->pos.x + src1->up.y*src2->pos.y + src1->at.y*src2->pos.z + src1->pos.y;
|
||||||
|
dst->pos.z = src1->right.z*src2->pos.x + src1->up.z*src2->pos.y + src1->at.z*src2->pos.z + src1->pos.z;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CVector
|
||||||
|
MultiplyInverse(const CMatrix &mat, const CVector &vec)
|
||||||
|
{
|
||||||
|
CVector v(vec.x - mat.m_matrix.pos.x, vec.y - mat.m_matrix.pos.y, vec.z - mat.m_matrix.pos.z);
|
||||||
|
return CVector(
|
||||||
|
mat.m_matrix.right.x * v.x + mat.m_matrix.right.y * v.y + mat.m_matrix.right.z * v.z,
|
||||||
|
mat.m_matrix.up.x * v.x + mat.m_matrix.up.y * v.y + mat.m_matrix.up.z * v.z,
|
||||||
|
mat.m_matrix.at.x * v.x + mat.m_matrix.at.y * v.y + mat.m_matrix.at.z * v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CVector
|
||||||
|
Multiply3x3(const CMatrix &mat, const CVector &vec)
|
||||||
|
{
|
||||||
|
return CVector(
|
||||||
|
mat.m_matrix.right.x * vec.x + mat.m_matrix.up.x * vec.y + mat.m_matrix.at.x * vec.z,
|
||||||
|
mat.m_matrix.right.y * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.at.y * vec.z,
|
||||||
|
mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z);
|
||||||
|
}
|
31
src/math/Rect.h
Normal file
31
src/math/Rect.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CRect
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float left; // x min
|
||||||
|
float top; // y max
|
||||||
|
float right; // x max
|
||||||
|
float bottom; // y min
|
||||||
|
|
||||||
|
CRect(void){
|
||||||
|
left = 1000000.0f;
|
||||||
|
bottom = 1000000.0f;
|
||||||
|
right = -1000000.0f;
|
||||||
|
top = -1000000.0f;
|
||||||
|
}
|
||||||
|
CRect(float l, float b, float r, float t){
|
||||||
|
left = l;
|
||||||
|
bottom = b;
|
||||||
|
right = r;
|
||||||
|
top = t;
|
||||||
|
}
|
||||||
|
void ContainPoint(CVector const &v){
|
||||||
|
if(v.x < left) left = v.x;
|
||||||
|
if(v.x > right) right = v.x;
|
||||||
|
if(v.y < bottom) bottom = v.y;
|
||||||
|
if(v.y > top) top = v.y;
|
||||||
|
}
|
||||||
|
};
|
82
src/math/Vector.h
Normal file
82
src/math/Vector.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CVector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float x, y, z;
|
||||||
|
CVector(void) {}
|
||||||
|
CVector(float x, float y, float z) : x(x), y(y), z(z) {}
|
||||||
|
// CVector(rw::V3d const &v) : x(v.x), y(v.y), z(v.z) {}
|
||||||
|
float Magnitude(void) const { return sqrt(x*x + y*y + z*z); }
|
||||||
|
float MagnitudeSqr(void) const { return x*x + y*y + z*z; }
|
||||||
|
float Magnitude2D(void) const { return sqrt(x*x + y*y); }
|
||||||
|
void Normalise(void){
|
||||||
|
float sq = MagnitudeSqr();
|
||||||
|
if(sq > 0.0f){
|
||||||
|
float invsqrt = 1.0f/sqrt(sq);
|
||||||
|
x *= invsqrt;
|
||||||
|
y *= invsqrt;
|
||||||
|
z *= invsqrt;
|
||||||
|
}else
|
||||||
|
x = 1.0f;
|
||||||
|
}
|
||||||
|
// rw::V3d ToRW(void){
|
||||||
|
// return rw::makeV3d(x, y, z);
|
||||||
|
// }
|
||||||
|
// void operator=(rw::V3d const &rhs){
|
||||||
|
// x = rhs.x;
|
||||||
|
// y = rhs.y;
|
||||||
|
// z = rhs.z;
|
||||||
|
// }
|
||||||
|
CVector operator-(const CVector &rhs) const {
|
||||||
|
return CVector(x-rhs.x, y-rhs.y, z-rhs.z);
|
||||||
|
}
|
||||||
|
CVector operator+(const CVector &rhs) const {
|
||||||
|
return CVector(x+rhs.x, y+rhs.y, z+rhs.z);
|
||||||
|
}
|
||||||
|
CVector operator*(float t) const {
|
||||||
|
return CVector(x*t, y*t, z*t);
|
||||||
|
}
|
||||||
|
CVector operator/(float t) const {
|
||||||
|
return CVector(x/t, y/t, z/t);
|
||||||
|
}
|
||||||
|
CVector &operator-=(const CVector &rhs) {
|
||||||
|
this->x -= rhs.x;
|
||||||
|
this->y -= rhs.y;
|
||||||
|
this->z -= rhs.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
CVector &operator+=(const CVector &rhs) {
|
||||||
|
this->x += rhs.x;
|
||||||
|
this->y += rhs.y;
|
||||||
|
this->z += rhs.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
CVector &operator*=(float t) {
|
||||||
|
this->x *= t;
|
||||||
|
this->y *= t;
|
||||||
|
this->z *= t;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
CVector &operator/=(float t) {
|
||||||
|
this->x /= t;
|
||||||
|
this->y /= t;
|
||||||
|
this->z /= t;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline float
|
||||||
|
DotProduct(const CVector &v1, const CVector &v2)
|
||||||
|
{
|
||||||
|
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CVector
|
||||||
|
CrossProduct(const CVector &v1, const CVector &v2)
|
||||||
|
{
|
||||||
|
return CVector(
|
||||||
|
v1.y*v2.z - v1.z*v2.y,
|
||||||
|
v1.z*v2.x - v1.x*v2.z,
|
||||||
|
v1.x*v2.y - v1.y*v2.x);
|
||||||
|
}
|
37
src/math/Vector2D.h
Normal file
37
src/math/Vector2D.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CVector2D
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float x, y;
|
||||||
|
CVector2D(void) {}
|
||||||
|
CVector2D(float x, float y) : x(x), y(y) {}
|
||||||
|
CVector2D(const CVector &v) : x(v.x), y(v.y) {}
|
||||||
|
float Magnitude(void) const { return sqrt(x*x + y*y); }
|
||||||
|
float MagnitudeSqr(void) const { return x*x + y*y; }
|
||||||
|
|
||||||
|
void Normalise(void){
|
||||||
|
float sq = MagnitudeSqr();
|
||||||
|
if(sq > 0.0f){
|
||||||
|
float invsqrt = 1.0f/sqrt(sq);
|
||||||
|
x *= invsqrt;
|
||||||
|
y *= invsqrt;
|
||||||
|
}else
|
||||||
|
x = 0.0f;
|
||||||
|
}
|
||||||
|
CVector2D operator-(const CVector2D &rhs) const {
|
||||||
|
return CVector2D(x-rhs.x, y-rhs.y);
|
||||||
|
}
|
||||||
|
CVector2D operator+(const CVector2D &rhs) const {
|
||||||
|
return CVector2D(x+rhs.x, y+rhs.y);
|
||||||
|
}
|
||||||
|
CVector2D operator*(float t) const {
|
||||||
|
return CVector2D(x*t, y*t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline float
|
||||||
|
CrossProduct2D(const CVector2D &v1, const CVector2D &v2)
|
||||||
|
{
|
||||||
|
return v1.x*v2.y - v1.y*v2.x;
|
||||||
|
}
|
117
src/modelinfo/BaseModelInfo.cpp
Normal file
117
src/modelinfo/BaseModelInfo.cpp
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "templates.h"
|
||||||
|
#include "TxdStore.h"
|
||||||
|
#include "2dEffect.h"
|
||||||
|
#include "BaseModelInfo.h"
|
||||||
|
|
||||||
|
|
||||||
|
CBaseModelInfo::CBaseModelInfo(ModeInfoType type)
|
||||||
|
{
|
||||||
|
m_colModel = nil;
|
||||||
|
m_twodEffects = 0;
|
||||||
|
m_objectId = -1;
|
||||||
|
m_refCount = 0;
|
||||||
|
m_txdSlot = -1;
|
||||||
|
m_type = type;
|
||||||
|
m_num2dEffects = 0;
|
||||||
|
m_freeCol = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBaseModelInfo::Shutdown(void)
|
||||||
|
{
|
||||||
|
DeleteCollisionModel();
|
||||||
|
DeleteRwObject();
|
||||||
|
m_twodEffects = 0;
|
||||||
|
m_num2dEffects = 0;
|
||||||
|
m_txdSlot = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBaseModelInfo::DeleteCollisionModel(void)
|
||||||
|
{
|
||||||
|
if(m_colModel && m_freeCol){
|
||||||
|
if(m_colModel)
|
||||||
|
delete m_colModel;
|
||||||
|
m_colModel = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBaseModelInfo::AddRef(void)
|
||||||
|
{
|
||||||
|
m_refCount++;
|
||||||
|
AddTexDictionaryRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBaseModelInfo::RemoveRef(void)
|
||||||
|
{
|
||||||
|
m_refCount--;
|
||||||
|
RemoveTexDictionaryRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBaseModelInfo::SetTexDictionary(const char *name)
|
||||||
|
{
|
||||||
|
int slot = CTxdStore::FindTxdSlot(name);
|
||||||
|
if(slot < 0)
|
||||||
|
slot = CTxdStore::AddTxdSlot(name);
|
||||||
|
m_txdSlot = slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBaseModelInfo::AddTexDictionaryRef(void)
|
||||||
|
{
|
||||||
|
CTxdStore::AddRef(m_txdSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBaseModelInfo::RemoveTexDictionaryRef(void)
|
||||||
|
{
|
||||||
|
CTxdStore::RemoveRef(m_txdSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBaseModelInfo::Init2dEffects(void)
|
||||||
|
{
|
||||||
|
m_twodEffects = nil;
|
||||||
|
m_num2dEffects = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBaseModelInfo::Add2dEffect(C2dEffect *fx)
|
||||||
|
{
|
||||||
|
if(m_twodEffects)
|
||||||
|
m_num2dEffects++;
|
||||||
|
else{
|
||||||
|
m_twodEffects = fx;
|
||||||
|
m_num2dEffects = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
C2dEffect*
|
||||||
|
CBaseModelInfo::Get2dEffect(int n)
|
||||||
|
{
|
||||||
|
if(m_twodEffects)
|
||||||
|
return &m_twodEffects[n];
|
||||||
|
else
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
// can't easily replace ctor at 4F6A50
|
||||||
|
InjectHook(0x4F6A90, &CBaseModelInfo::Shutdown_, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F6AC0, &CBaseModelInfo::DeleteCollisionModel, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F6B70, &CBaseModelInfo::ClearTexDictionary, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F6BA0, &CBaseModelInfo::AddRef, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F6BB0, &CBaseModelInfo::RemoveRef, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F6B40, &CBaseModelInfo::SetTexDictionary, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F6B80, &CBaseModelInfo::AddTexDictionaryRef, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F6B90, &CBaseModelInfo::RemoveTexDictionaryRef, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F6B20, &CBaseModelInfo::Add2dEffect, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F6AF0, &CBaseModelInfo::Init2dEffects, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F6B00, &CBaseModelInfo::Get2dEffect, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
66
src/modelinfo/BaseModelInfo.h
Normal file
66
src/modelinfo/BaseModelInfo.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Collision.h"
|
||||||
|
|
||||||
|
enum ModeInfoType : uint8
|
||||||
|
{
|
||||||
|
MITYPE_NA = 0,
|
||||||
|
MITYPE_SIMPLE = 1,
|
||||||
|
MITYPE_MLO = 2,
|
||||||
|
MITYPE_TIME = 3,
|
||||||
|
MITYPE_CLUMP = 4,
|
||||||
|
MITYPE_VEHICLE = 5,
|
||||||
|
MITYPE_PED = 6,
|
||||||
|
MITYPE_XTRACOMPS = 7,
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ModeInfoType) == 1, "ModeInfoType: error");
|
||||||
|
|
||||||
|
class C2dEffect;
|
||||||
|
|
||||||
|
class CBaseModelInfo
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
// TODO?: make more things protected
|
||||||
|
char m_name[24];
|
||||||
|
CColModel *m_colModel;
|
||||||
|
C2dEffect *m_twodEffects;
|
||||||
|
int16 m_objectId;
|
||||||
|
public:
|
||||||
|
uint16 m_refCount;
|
||||||
|
int16 m_txdSlot;
|
||||||
|
ModeInfoType m_type;
|
||||||
|
uint8 m_num2dEffects;
|
||||||
|
bool m_freeCol;
|
||||||
|
|
||||||
|
CBaseModelInfo(ModeInfoType type);
|
||||||
|
virtual ~CBaseModelInfo() {}
|
||||||
|
virtual void Shutdown(void);
|
||||||
|
virtual void DeleteRwObject(void) = 0;
|
||||||
|
virtual RwObject *CreateInstance(RwMatrix *) = 0;
|
||||||
|
virtual RwObject *CreateInstance(void) = 0;
|
||||||
|
virtual RwObject *GetRwObject(void) = 0;
|
||||||
|
|
||||||
|
bool IsSimple(void) { return m_type == MITYPE_SIMPLE || m_type == MITYPE_TIME; }
|
||||||
|
char *GetName(void) { return m_name; }
|
||||||
|
void SetName(const char *name) { strncpy(m_name, name, 24); }
|
||||||
|
void SetColModel(CColModel *col, bool free = false){
|
||||||
|
m_colModel = col; m_freeCol = free; }
|
||||||
|
CColModel *GetColModel(void) { return m_colModel; }
|
||||||
|
void DeleteCollisionModel(void);
|
||||||
|
void ClearTexDictionary(void) { m_txdSlot = -1; }
|
||||||
|
short GetObjectID(void) { return m_objectId; }
|
||||||
|
void SetObjectID(short id) { m_objectId = id; }
|
||||||
|
short GetTxdSlot(void) { return m_txdSlot; }
|
||||||
|
void AddRef(void);
|
||||||
|
void RemoveRef(void);
|
||||||
|
void SetTexDictionary(const char *name);
|
||||||
|
void AddTexDictionaryRef(void);
|
||||||
|
void RemoveTexDictionaryRef(void);
|
||||||
|
void Init2dEffects(void);
|
||||||
|
void Add2dEffect(C2dEffect *fx);
|
||||||
|
C2dEffect *Get2dEffect(int n);
|
||||||
|
|
||||||
|
void Shutdown_(void) { this->CBaseModelInfo::Shutdown(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(CBaseModelInfo) == 0x30, "CBaseModelInfo: error");
|
156
src/modelinfo/ClumpModelInfo.cpp
Normal file
156
src/modelinfo/ClumpModelInfo.cpp
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "NodeName.h"
|
||||||
|
#include "VisibilityPlugins.h"
|
||||||
|
#include "ModelInfo.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
CClumpModelInfo::DeleteRwObject(void)
|
||||||
|
{
|
||||||
|
if(m_clump){
|
||||||
|
RpClumpDestroy(m_clump);
|
||||||
|
m_clump = nil;
|
||||||
|
RemoveTexDictionaryRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RwObject*
|
||||||
|
CClumpModelInfo::CreateInstance(void)
|
||||||
|
{
|
||||||
|
if(m_clump)
|
||||||
|
return (RwObject*)RpClumpClone(m_clump);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
RwObject*
|
||||||
|
CClumpModelInfo::CreateInstance(RwMatrix *m)
|
||||||
|
{
|
||||||
|
if(m_clump){
|
||||||
|
RpClump *clump = (RpClump*)CreateInstance();
|
||||||
|
*RwFrameGetMatrix(RpClumpGetFrame(clump)) = *m;
|
||||||
|
return (RwObject*)clump;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
CClumpModelInfo::SetAtomicRendererCB(RpAtomic *atomic, void *data)
|
||||||
|
{
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, (RpAtomicCallBackRender)data);
|
||||||
|
return atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClumpModelInfo::SetClump(RpClump *clump)
|
||||||
|
{
|
||||||
|
m_clump = clump;
|
||||||
|
CVisibilityPlugins::SetClumpModelInfo(m_clump, this);
|
||||||
|
AddTexDictionaryRef();
|
||||||
|
RpClumpForAllAtomics(clump, SetAtomicRendererCB, nil);
|
||||||
|
if(strncmp(GetName(), "playerh", 8) == 0)
|
||||||
|
RpClumpForAllAtomics(clump, SetAtomicRendererCB, CVisibilityPlugins::RenderPlayerCB);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClumpModelInfo::SetFrameIds(RwObjectNameIdAssocation *assocs)
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
RwObjectNameAssociation objname;
|
||||||
|
|
||||||
|
for(i = 0; assocs[i].name; i++)
|
||||||
|
if((assocs[i].flags & CLUMP_FLAG_NO_HIERID) == 0){
|
||||||
|
objname.frame = nil;
|
||||||
|
objname.name = assocs[i].name;
|
||||||
|
RwFrameForAllChildren(RpClumpGetFrame(m_clump), FindFrameFromNameWithoutIdCB, &objname);
|
||||||
|
if(objname.frame)
|
||||||
|
CVisibilityPlugins::SetFrameHierarchyId(objname.frame, assocs[i].hierId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RwFrame*
|
||||||
|
CClumpModelInfo::FindFrameFromIdCB(RwFrame *frame, void *data)
|
||||||
|
{
|
||||||
|
RwObjectIdAssociation *assoc = (RwObjectIdAssociation*)data;
|
||||||
|
|
||||||
|
if(CVisibilityPlugins::GetFrameHierarchyId(frame) != assoc->id){
|
||||||
|
RwFrameForAllChildren(frame, FindFrameFromIdCB, assoc);
|
||||||
|
return assoc->frame ? nil : frame;
|
||||||
|
}else{
|
||||||
|
assoc->frame = frame;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RwFrame*
|
||||||
|
CClumpModelInfo::FindFrameFromNameCB(RwFrame *frame, void *data)
|
||||||
|
{
|
||||||
|
RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data;
|
||||||
|
|
||||||
|
if(_strcmpi(GetFrameNodeName(frame), assoc->name) != 0){
|
||||||
|
RwFrameForAllChildren(frame, FindFrameFromNameCB, assoc);
|
||||||
|
return assoc->frame ? nil : frame;
|
||||||
|
}else{
|
||||||
|
assoc->frame = frame;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RwFrame*
|
||||||
|
CClumpModelInfo::FindFrameFromNameWithoutIdCB(RwFrame *frame, void *data)
|
||||||
|
{
|
||||||
|
RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data;
|
||||||
|
|
||||||
|
if(CVisibilityPlugins::GetFrameHierarchyId(frame) ||
|
||||||
|
_strcmpi(GetFrameNodeName(frame), assoc->name) != 0){
|
||||||
|
RwFrameForAllChildren(frame, FindFrameFromNameWithoutIdCB, assoc);
|
||||||
|
return assoc->frame ? nil : frame;
|
||||||
|
}else{
|
||||||
|
assoc->frame = frame;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RwFrame*
|
||||||
|
CClumpModelInfo::FillFrameArrayCB(RwFrame *frame, void *data)
|
||||||
|
{
|
||||||
|
int32 id;
|
||||||
|
RwFrame **frames = (RwFrame**)data;
|
||||||
|
id = CVisibilityPlugins::GetFrameHierarchyId(frame);
|
||||||
|
if(id > 0)
|
||||||
|
frames[id] = frame;
|
||||||
|
RwFrameForAllChildren(frame, FillFrameArrayCB, data);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClumpModelInfo::FillFrameArray(RpClump *clump, RwFrame **frames)
|
||||||
|
{
|
||||||
|
RwFrameForAllChildren(RpClumpGetFrame(clump), FillFrameArrayCB, frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
RwFrame*
|
||||||
|
CClumpModelInfo::GetFrameFromId(RpClump *clump, int32 id)
|
||||||
|
{
|
||||||
|
RwObjectIdAssociation assoc;
|
||||||
|
assoc.id = id;
|
||||||
|
assoc.frame = nil;
|
||||||
|
RwFrameForAllChildren(RpClumpGetFrame(clump), FindFrameFromIdCB, &assoc);
|
||||||
|
return assoc.frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x4F8800, &CClumpModelInfo::DeleteRwObject_, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F8920, &CClumpModelInfo::CreateInstance_1, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F88A0, &CClumpModelInfo::CreateInstance_2, PATCH_JUMP);
|
||||||
|
InjectHook(0x50C1C0, &CClumpModelInfo::GetRwObject_, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F8830, &CClumpModelInfo::SetClump_, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F8940, &CClumpModelInfo::SetAtomicRendererCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F8960, &CClumpModelInfo::FindFrameFromNameCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F8A10, &CClumpModelInfo::FindFrameFromNameWithoutIdCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F8AD0, &CClumpModelInfo::FindFrameFromIdCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F8BB0, &CClumpModelInfo::SetFrameIds, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F8B20, &CClumpModelInfo::FillFrameArrayCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F8B90, &CClumpModelInfo::FillFrameArray, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F8B50, &CClumpModelInfo::GetFrameFromId, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
60
src/modelinfo/ClumpModelInfo.h
Normal file
60
src/modelinfo/ClumpModelInfo.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BaseModelInfo.h"
|
||||||
|
|
||||||
|
struct RwObjectNameIdAssocation
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
int32 hierId;
|
||||||
|
uint32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RwObjectNameAssociation
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
RwFrame *frame;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RwObjectIdAssociation
|
||||||
|
{
|
||||||
|
int32 id;
|
||||||
|
RwFrame *frame;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CLUMP_FLAG_NO_HIERID = 0x1,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CClumpModelInfo : public CBaseModelInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RpClump *m_clump;
|
||||||
|
|
||||||
|
CClumpModelInfo(void) : CBaseModelInfo(MITYPE_CLUMP) {}
|
||||||
|
CClumpModelInfo(ModeInfoType id) : CBaseModelInfo(id) {}
|
||||||
|
~CClumpModelInfo() {}
|
||||||
|
void DeleteRwObject(void);
|
||||||
|
RwObject *CreateInstance(void);
|
||||||
|
RwObject *CreateInstance(RwMatrix *);
|
||||||
|
RwObject *GetRwObject(void) { return (RwObject*)m_clump; }
|
||||||
|
|
||||||
|
virtual void SetClump(RpClump *);
|
||||||
|
|
||||||
|
static RpAtomic *SetAtomicRendererCB(RpAtomic *atomic, void *data);
|
||||||
|
void SetFrameIds(RwObjectNameIdAssocation *assocs);
|
||||||
|
static RwFrame *FindFrameFromNameCB(RwFrame *frame, void *data);
|
||||||
|
static RwFrame *FindFrameFromNameWithoutIdCB(RwFrame *frame, void *data);
|
||||||
|
static RwFrame *FindFrameFromIdCB(RwFrame *frame, void *data);
|
||||||
|
static void FillFrameArray(RpClump *clump, RwFrame **frames);
|
||||||
|
static RwFrame *FillFrameArrayCB(RwFrame *frame, void *data);
|
||||||
|
static RwFrame *GetFrameFromId(RpClump *clump, int32 id);
|
||||||
|
|
||||||
|
|
||||||
|
void DeleteRwObject_(void) { this->CClumpModelInfo::DeleteRwObject(); }
|
||||||
|
RwObject *CreateInstance_1(void) { return this->CClumpModelInfo::CreateInstance(); }
|
||||||
|
RwObject *CreateInstance_2(RwMatrix *m) { return this->CClumpModelInfo::CreateInstance(m); }
|
||||||
|
RwObject *GetRwObject_(void) { return this->CClumpModelInfo::GetRwObject(); }
|
||||||
|
void SetClump_(RpClump *clump) { this->CClumpModelInfo::SetClump(clump); }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CClumpModelInfo) == 0x34, "CClumpModelInfo: error");
|
32
src/modelinfo/ModelIndices.cpp
Normal file
32
src/modelinfo/ModelIndices.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "ModelIndices.h"
|
||||||
|
|
||||||
|
#define X(name, var, addr) int16 &var = *(int16*)addr;
|
||||||
|
MODELINDICES
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
void
|
||||||
|
InitModelIndices(void)
|
||||||
|
{
|
||||||
|
#define X(name, var, addr) var = -1;
|
||||||
|
MODELINDICES
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MatchModelString(const char *modelname, int16 id)
|
||||||
|
{
|
||||||
|
#define X(name, var, addr) \
|
||||||
|
if(strcmp(name, modelname) == 0){ \
|
||||||
|
var = id; \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
MODELINDICES
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x48EB60, InitModelIndices, PATCH_JUMP);
|
||||||
|
InjectHook(0x48F030, MatchModelString, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
224
src/modelinfo/ModelIndices.h
Normal file
224
src/modelinfo/ModelIndices.h
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
#define MODELINDICES \
|
||||||
|
X("fire_hydrant", MI_FIRE_HYDRANT, 0x5F5A00) \
|
||||||
|
X("bagelstnd02", MI_BAGELSTAND2, 0x5F59FC) \
|
||||||
|
X("fish01", MI_FISHSTALL01, 0x5F59EC) \
|
||||||
|
X("fishstall02", MI_FISHSTALL02, 0x5F59F0) \
|
||||||
|
X("fishstall03", MI_FISHSTALL03, 0x5F59F4) \
|
||||||
|
X("fishstall04", MI_FISHSTALL04, 0x5F59F8) \
|
||||||
|
X("taxisign", MI_TAXISIGN, 0x5F59E8) \
|
||||||
|
X("phonesign", MI_PHONESIGN, 0x5F59E4) \
|
||||||
|
X("noparkingsign1", MI_NOPARKINGSIGN1, 0x5F59E0) \
|
||||||
|
X("bussign1", MI_BUSSIGN1, 0x5F59DC) \
|
||||||
|
X("roadworkbarrier1", MI_ROADWORKBARRIER1, 0x5F59D8) \
|
||||||
|
X("dump1", MI_DUMP1, 0x5F59D4) \
|
||||||
|
X("trafficcone", MI_TRAFFICCONE, 0x5F59D0) \
|
||||||
|
X("newsstand1", MI_NEWSSTAND, 0x5F59CC) \
|
||||||
|
X("postbox1", MI_POSTBOX1, 0x5F59C8) \
|
||||||
|
X("bin1", MI_BIN, 0x5F59C4) \
|
||||||
|
X("wastebin", MI_WASTEBIN, 0x5F59C0) \
|
||||||
|
X("phonebooth1", MI_PHONEBOOTH1, 0x5F59BC) \
|
||||||
|
X("parkingmeter", MI_PARKINGMETER, 0x5F59B8) \
|
||||||
|
X("trafficlight1", MI_TRAFFICLIGHTS, 0x5F5958) \
|
||||||
|
X("lamppost1", MI_SINGLESTREETLIGHTS1, 0x5F595C) \
|
||||||
|
X("lamppost2", MI_SINGLESTREETLIGHTS2, 0x5F5960) \
|
||||||
|
X("lamppost3", MI_SINGLESTREETLIGHTS3, 0x5F5964) \
|
||||||
|
X("doublestreetlght1", MI_DOUBLESTREETLIGHTS, 0x5F5968) \
|
||||||
|
X("rd_Road2A10", MI_ROADSFORROADBLOCKSSTART, 0x5F596C) \
|
||||||
|
X("rd_Road1A30", MI_ROADSFORROADBLOCKSEND, 0x5F5970) \
|
||||||
|
X("veg_tree1", MI_TREE1, 0x5F5974) \
|
||||||
|
X("veg_tree3", MI_TREE2, 0x5F5978) \
|
||||||
|
X("veg_treea1", MI_TREE3, 0x5F597C) \
|
||||||
|
X("veg_treenew01", MI_TREE4, 0x5F5980) \
|
||||||
|
X("veg_treenew05", MI_TREE5, 0x5F5984) \
|
||||||
|
X("veg_treeb1", MI_TREE6, 0x5F5988) \
|
||||||
|
X("veg_treenew10", MI_TREE7, 0x5F598C) \
|
||||||
|
X("veg_treea3", MI_TREE8, 0x5F5990) \
|
||||||
|
X("veg_treenew09", MI_TREE9, 0x5F5994) \
|
||||||
|
X("veg_treenew08", MI_TREE10, 0x5F5998) \
|
||||||
|
X("veg_treenew03", MI_TREE11, 0x5F599C) \
|
||||||
|
X("veg_treenew16", MI_TREE12, 0x5F59A0) \
|
||||||
|
X("veg_treenew17", MI_TREE13, 0x5F59A4) \
|
||||||
|
X("veg_treenew06", MI_TREE14, 0x5F59A8) \
|
||||||
|
X("doc_crane_cab", MODELID_CRANE_1, 0x5F59AC) \
|
||||||
|
X("cranetopb", MODELID_CRANE_2, 0x5F59B0) \
|
||||||
|
X("cranetopa", MODELID_CRANE_3, 0x5F59B4) \
|
||||||
|
X("package1", MI_COLLECTABLE1, 0x5F5A04) \
|
||||||
|
X("Money", MI_MONEY, 0x5F5A08) \
|
||||||
|
X("barrel1", MI_CARMINE, 0x5F5A0C) \
|
||||||
|
X("oddjgaragdoor", MI_GARAGEDOOR1, 0x5F5A10) \
|
||||||
|
X("bombdoor", MI_GARAGEDOOR2, 0x5F5A14) \
|
||||||
|
X("door_bombshop", MI_GARAGEDOOR3, 0x5F5A18) \
|
||||||
|
X("vheistlocdoor", MI_GARAGEDOOR4, 0x5F5A1C) \
|
||||||
|
X("door2_garage", MI_GARAGEDOOR5, 0x5F5A20) \
|
||||||
|
X("ind_slidedoor", MI_GARAGEDOOR6, 0x5F5A24) \
|
||||||
|
X("bankjobdoor", MI_GARAGEDOOR7, 0x5F5A28) \
|
||||||
|
X("door_jmsgrage", MI_GARAGEDOOR9, 0x5F5A2C) \
|
||||||
|
X("jamesgrge_kb", MI_GARAGEDOOR10, 0x5F5A30) \
|
||||||
|
X("door_sfehousegrge", MI_GARAGEDOOR11, 0x5F5A34) \
|
||||||
|
X("shedgaragedoor", MI_GARAGEDOOR12, 0x5F5A38) \
|
||||||
|
X("door4_garage", MI_GARAGEDOOR13, 0x5F5A3C) \
|
||||||
|
X("door_col_compnd_01", MI_GARAGEDOOR14, 0x5F5A40) \
|
||||||
|
X("door_col_compnd_02", MI_GARAGEDOOR15, 0x5F5A44) \
|
||||||
|
X("door_col_compnd_03", MI_GARAGEDOOR16, 0x5F5A48) \
|
||||||
|
X("door_col_compnd_04", MI_GARAGEDOOR17, 0x5F5A4C) \
|
||||||
|
X("door_col_compnd_05", MI_GARAGEDOOR18, 0x5F5A50) \
|
||||||
|
X("impex_door", MI_GARAGEDOOR19, 0x5F5A54) \
|
||||||
|
X("SalvGarage", MI_GARAGEDOOR20, 0x5F5A58) \
|
||||||
|
X("door3_garage", MI_GARAGEDOOR21, 0x5F5A5C) \
|
||||||
|
X("leveldoor2", MI_GARAGEDOOR22, 0x5F5A60) \
|
||||||
|
X("double_garage_dr", MI_GARAGEDOOR23, 0x5F5A64) \
|
||||||
|
X("amcogaragedoor", MI_GARAGEDOOR24, 0x5F5A68) \
|
||||||
|
X("towergaragedoor1", MI_GARAGEDOOR25, 0x5F5A6C) \
|
||||||
|
X("towergaragedoor2", MI_GARAGEDOOR26, 0x5F5A70) \
|
||||||
|
X("towergaragedoor3", MI_GARAGEDOOR27, 0x5F5A74) \
|
||||||
|
X("plysve_gragedoor", MI_GARAGEDOOR28, 0x5F5A78) \
|
||||||
|
X("impexpsubgrgdoor", MI_GARAGEDOOR29, 0x5F5A7C) \
|
||||||
|
X("Sub_sprayshopdoor", MI_GARAGEDOOR30, 0x5F5A80) \
|
||||||
|
X("ind_plyrwoor", MI_GARAGEDOOR31, 0x5F5A84) \
|
||||||
|
X("8ballsuburbandoor", MI_GARAGEDOOR32, 0x5F5A88) \
|
||||||
|
X("barrel2", MI_NAUTICALMINE, 0x5F5A8C) \
|
||||||
|
X("crushercrush", MI_CRUSHERBODY, 0x5F5A90) \
|
||||||
|
X("crushertop", MI_CRUSHERLID, 0x5F5A94) \
|
||||||
|
X("donkeymag", MI_DONKEYMAG, 0x5F5A98) \
|
||||||
|
X("bullion", MI_BULLION, 0x5F5A9C) \
|
||||||
|
X("floatpackge1", MI_FLOATPACKAGE1, 0x5F5AA0) \
|
||||||
|
X("briefcase", MI_BRIEFCASE, 0x5F5AA4) \
|
||||||
|
X("chinabanner1", MI_CHINABANNER1, 0x5F5AA8) \
|
||||||
|
X("chinabanner2", MI_CHINABANNER2, 0x5F5AAC) \
|
||||||
|
X("chinabanner3", MI_CHINABANNER3, 0x5F5AB0) \
|
||||||
|
X("chinabanner4", MI_CHINABANNER4, 0x5F5AB4) \
|
||||||
|
X("iten_chinatown5", MI_CHINABANNER5, 0x5F5AB8) \
|
||||||
|
X("iten_chinatown7", MI_CHINABANNER6, 0x5F5ABC) \
|
||||||
|
X("iten_chinatown3", MI_CHINABANNER7, 0x5F5AC0) \
|
||||||
|
X("iten_chinatown2", MI_CHINABANNER8, 0x5F5AC4) \
|
||||||
|
X("iten_chinatown4", MI_CHINABANNER9, 0x5F5AC8) \
|
||||||
|
X("iten_washline01", MI_CHINABANNER10, 0x5F5ACC) \
|
||||||
|
X("iten_washline02", MI_CHINABANNER11, 0x5F5AD0) \
|
||||||
|
X("iten_washline03", MI_CHINABANNER12, 0x5F5AD4) \
|
||||||
|
X("chinalanterns", MI_CHINALANTERN, 0x5F5AD8) \
|
||||||
|
X("glassfx1", MI_GLASS1, 0x5F5ADC) \
|
||||||
|
X("glassfx2", MI_GLASS2, 0x5F5AE0) \
|
||||||
|
X("glassfx3", MI_GLASS3, 0x5F5AE4) \
|
||||||
|
X("glassfx4", MI_GLASS4, 0x5F5AE8) \
|
||||||
|
X("glassfx55", MI_GLASS5, 0x5F5AEC) \
|
||||||
|
X("glassfxsub1", MI_GLASS6, 0x5F5AF0) \
|
||||||
|
X("glassfxsub2", MI_GLASS7, 0x5F5AF4) \
|
||||||
|
X("glassfx_composh", MI_GLASS8, 0x5F5AF8) \
|
||||||
|
X("bridge_liftsec", MI_BRIDGELIFT, 0x5F5AFC) \
|
||||||
|
X("bridge_liftweight", MI_BRIDGEWEIGHT, 0x5F5B00) \
|
||||||
|
X("subbridge_lift", MI_BRIDGEROADSEGMENT, 0x5F5B04) \
|
||||||
|
X("barrel4", MI_EXPLODINGBARREL, 0x5F5B08) \
|
||||||
|
X("flagsitaly", MI_ITALYBANNER1, 0x5F5B0C) \
|
||||||
|
X("adrenaline", MI_PICKUP_ADRENALINE, 0x5F5B10) \
|
||||||
|
X("bodyarmour", MI_PICKUP_BODYARMOUR, 0x5F5B14) \
|
||||||
|
X("info", MI_PICKUP_INFO, 0x5F5B18) \
|
||||||
|
X("health", MI_PICKUP_HEALTH, 0x5F5B1C) \
|
||||||
|
X("bonus", MI_PICKUP_BONUS, 0x5F5B20) \
|
||||||
|
X("bribe", MI_PICKUP_BRIBE, 0x5F5B24) \
|
||||||
|
X("killfrenzy", MI_PICKUP_KILLFRENZY, 0x5F5B28) \
|
||||||
|
X("camerapickup", MI_PICKUP_CAMERA, 0x5F5B2C) \
|
||||||
|
X("bollardlight", MI_BOLLARDLIGHT, 0x5F5B30) \
|
||||||
|
X("magnet", MI_MAGNET, 0x5F5B34) \
|
||||||
|
X("streetlamp1", MI_STREETLAMP1, 0x5F5B38) \
|
||||||
|
X("streetlamp2", MI_STREETLAMP2, 0x5F5B3C) \
|
||||||
|
X("railtrax_lo4b", MI_RAILTRACKS, 0x5F5B40) \
|
||||||
|
X("bar_barrier10", MI_FENCE, 0x5F5B44) \
|
||||||
|
X("bar_barrier12", MI_FENCE2, 0x5F5B48) \
|
||||||
|
X("petrolpump", MI_PETROLPUMP, 0x5F5B4C) \
|
||||||
|
X("bodycast", MI_BODYCAST, 0x5F5B50) \
|
||||||
|
X("backdoor", MI_BACKDOOR, 0x5F5B54) \
|
||||||
|
X("coffee", MI_COFFEE, 0x5F5B58) \
|
||||||
|
X("bouy", MI_BUOY, 0x5F5B5C) \
|
||||||
|
X("parktable1", MI_PARKTABLE, 0x5F5B60) \
|
||||||
|
X("sbwy_tunl_start", MI_SUBWAY1, 0x5F5B64) \
|
||||||
|
X("sbwy_tunl_bit", MI_SUBWAY2, 0x5F5B68) \
|
||||||
|
X("sbwy_tunl_bend", MI_SUBWAY3, 0x5F5B6C) \
|
||||||
|
X("sbwy_tunl_cstm6", MI_SUBWAY4, 0x5F5B70) \
|
||||||
|
X("sbwy_tunl_cstm7", MI_SUBWAY5, 0x5F5B74) \
|
||||||
|
X("sbwy_tunl_cstm8", MI_SUBWAY6, 0x5F5B78) \
|
||||||
|
X("sbwy_tunl_cstm10", MI_SUBWAY7, 0x5F5B7C) \
|
||||||
|
X("sbwy_tunl_cstm9", MI_SUBWAY8, 0x5F5B80) \
|
||||||
|
X("sbwy_tunl_cstm11", MI_SUBWAY9, 0x5F5B84) \
|
||||||
|
X("sbwy_tunl_cstm1", MI_SUBWAY10, 0x5F5B88) \
|
||||||
|
X("sbwy_tunl_cstm2", MI_SUBWAY11, 0x5F5B8C) \
|
||||||
|
X("sbwy_tunl_cstm4", MI_SUBWAY12, 0x5F5B90) \
|
||||||
|
X("sbwy_tunl_cstm3", MI_SUBWAY13, 0x5F5B94) \
|
||||||
|
X("sbwy_tunl_cstm5", MI_SUBWAY14, 0x5F5B98) \
|
||||||
|
X("subplatform_n2", MI_SUBWAY15, 0x5F5B9C) \
|
||||||
|
X("suby_tunl_start", MI_SUBWAY16, 0x5F5BA0) \
|
||||||
|
X("sbwy_tunl_start2", MI_SUBWAY17, 0x5F5BA4) \
|
||||||
|
X("indy_tunl_start", MI_SUBWAY18, 0x5F5BA8) \
|
||||||
|
X("indsubway03", MI_SUBPLATFORM_IND, 0x5F5BAC) \
|
||||||
|
X("comerside_subway", MI_SUBPLATFORM_COMS, 0x5F5BB0) \
|
||||||
|
X("subplatform", MI_SUBPLATFORM_COMS2, 0x5F5BB4) \
|
||||||
|
X("subplatform_n", MI_SUBPLATFORM_COMN, 0x5F5BB8) \
|
||||||
|
X("Otherside_subway", MI_SUBPLATFORM_SUB, 0x5F5BBC) \
|
||||||
|
X("subplatform_sub", MI_SUBPLATFORM_SUB2, 0x5F5BC0) \
|
||||||
|
X("files", MI_FILES, 0x5F5BC4)
|
||||||
|
|
||||||
|
#define X(name, var, addr) extern int16 &var;
|
||||||
|
MODELINDICES
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
// and some hardcoded ones
|
||||||
|
// expand as needed
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MI_COP = 1,
|
||||||
|
MI_SWAT,
|
||||||
|
MI_FBI,
|
||||||
|
MI_ARMY,
|
||||||
|
MI_MEDIC,
|
||||||
|
MI_FIREMAN,
|
||||||
|
MI_MALE01,
|
||||||
|
MI_TAXI_D,
|
||||||
|
MI_PIMP,
|
||||||
|
MI_GANG01,
|
||||||
|
MI_GANG02,
|
||||||
|
MI_GANG03,
|
||||||
|
MI_GANG04,
|
||||||
|
MI_GANG05,
|
||||||
|
MI_GANG06,
|
||||||
|
MI_GANG07,
|
||||||
|
MI_GANG08,
|
||||||
|
MI_GANG09,
|
||||||
|
MI_GANG10,
|
||||||
|
MI_GANG11,
|
||||||
|
MI_GANG12,
|
||||||
|
MI_GANG13,
|
||||||
|
MI_GANG14,
|
||||||
|
MI_CRIMINAL01,
|
||||||
|
MI_CRIMINAL02,
|
||||||
|
MI_SPECIAL01,
|
||||||
|
MI_SPECIAL02,
|
||||||
|
MI_SPECIAL03,
|
||||||
|
MI_SPECIAL04,
|
||||||
|
MI_MALE02,
|
||||||
|
MI_MALE03,
|
||||||
|
MI_FATMALE01,
|
||||||
|
MI_FATMALE02,
|
||||||
|
MI_FEMALE01,
|
||||||
|
MI_FEMALE02,
|
||||||
|
MI_FEMALE03,
|
||||||
|
MI_FATFEMALE01,
|
||||||
|
MI_FATFEMALE02,
|
||||||
|
|
||||||
|
MI_RHINO = 122,
|
||||||
|
MI_COACH = 127,
|
||||||
|
};
|
||||||
|
|
||||||
|
void InitModelIndices(void);
|
||||||
|
void MatchModelString(const char *name, int16 id);
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
IsGlass(int16 id)
|
||||||
|
{
|
||||||
|
return id == MI_GLASS1 ||
|
||||||
|
id == MI_GLASS2 ||
|
||||||
|
id == MI_GLASS3 ||
|
||||||
|
id == MI_GLASS4 ||
|
||||||
|
id == MI_GLASS5 ||
|
||||||
|
id == MI_GLASS6 ||
|
||||||
|
id == MI_GLASS7 ||
|
||||||
|
id == MI_GLASS8;
|
||||||
|
}
|
124
src/modelinfo/ModelInfo.cpp
Normal file
124
src/modelinfo/ModelInfo.cpp
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "ModelInfo.h"
|
||||||
|
|
||||||
|
CBaseModelInfo **CModelInfo::ms_modelInfoPtrs = (CBaseModelInfo**)0x83D408;
|
||||||
|
|
||||||
|
//CStore<CSimpleModelInfo, SIMPLEMODELSIZE> &CModelInfo::ms_simpleModelStore = *(CStore<CSimpleModelInfo, SIMPLEMODELSIZE>*)0x885BB4;
|
||||||
|
//CStore<CTimeModelInfo, TIMEMODELSIZE> &CModelInfo::ms_timeModelStore = *(CStore<CTimeModelInfo, TIMEMODELSIZE>*)0x94076C;
|
||||||
|
//CStore<C2dEffect, TWODFXSIZE> &CModelInfo::ms_2dEffectStore = *(CStore<C2dEffect, TWODFXSIZE>*)0x9434F8;
|
||||||
|
CStore<CSimpleModelInfo, SIMPLEMODELSIZE> CModelInfo::ms_simpleModelStore;
|
||||||
|
CStore<CTimeModelInfo, TIMEMODELSIZE> CModelInfo::ms_timeModelStore;
|
||||||
|
CStore<CClumpModelInfo, CLUMPMODELSIZE> CModelInfo::ms_clumpModelStore;
|
||||||
|
CStore<CPedModelInfo, PEDMODELSIZE> CModelInfo::ms_pedModelStore;
|
||||||
|
CStore<CVehicleModelInfo, VEHICLEMODELSIZE> CModelInfo::ms_vehicleModelStore;
|
||||||
|
CStore<C2dEffect, TWODFXSIZE> CModelInfo::ms_2dEffectStore;
|
||||||
|
|
||||||
|
void
|
||||||
|
CModelInfo::Initialise(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < MODELINFOSIZE; i++)
|
||||||
|
ms_modelInfoPtrs[i] = nil;
|
||||||
|
ms_2dEffectStore.clear();
|
||||||
|
ms_simpleModelStore.clear();
|
||||||
|
ms_timeModelStore.clear();
|
||||||
|
ms_clumpModelStore.clear();
|
||||||
|
ms_pedModelStore.clear();
|
||||||
|
ms_vehicleModelStore.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CModelInfo::Shutdown(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < ms_simpleModelStore.allocPtr; i++)
|
||||||
|
ms_simpleModelStore.store[i].Shutdown();
|
||||||
|
for(i = 0; i < ms_timeModelStore.allocPtr; i++)
|
||||||
|
ms_timeModelStore.store[i].Shutdown();
|
||||||
|
for(i = 0; i < ms_clumpModelStore.allocPtr; i++)
|
||||||
|
ms_clumpModelStore.store[i].Shutdown();
|
||||||
|
for(i = 0; i < ms_pedModelStore.allocPtr; i++)
|
||||||
|
ms_pedModelStore.store[i].Shutdown();
|
||||||
|
for(i = 0; i < ms_vehicleModelStore.allocPtr; i++)
|
||||||
|
ms_vehicleModelStore.store[i].Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
CSimpleModelInfo*
|
||||||
|
CModelInfo::AddSimpleModel(int id)
|
||||||
|
{
|
||||||
|
CSimpleModelInfo *modelinfo;
|
||||||
|
modelinfo = CModelInfo::ms_simpleModelStore.alloc();
|
||||||
|
CModelInfo::ms_modelInfoPtrs[id] = modelinfo;
|
||||||
|
modelinfo->Init();
|
||||||
|
return modelinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
CTimeModelInfo*
|
||||||
|
CModelInfo::AddTimeModel(int id)
|
||||||
|
{
|
||||||
|
CTimeModelInfo *modelinfo;
|
||||||
|
modelinfo = CModelInfo::ms_timeModelStore.alloc();
|
||||||
|
CModelInfo::ms_modelInfoPtrs[id] = modelinfo;
|
||||||
|
modelinfo->Init();
|
||||||
|
return modelinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
CClumpModelInfo*
|
||||||
|
CModelInfo::AddClumpModel(int id)
|
||||||
|
{
|
||||||
|
CClumpModelInfo *modelinfo;
|
||||||
|
modelinfo = CModelInfo::ms_clumpModelStore.alloc();
|
||||||
|
CModelInfo::ms_modelInfoPtrs[id] = modelinfo;
|
||||||
|
modelinfo->m_clump = nil;
|
||||||
|
return modelinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
CPedModelInfo*
|
||||||
|
CModelInfo::AddPedModel(int id)
|
||||||
|
{
|
||||||
|
CPedModelInfo *modelinfo;
|
||||||
|
modelinfo = CModelInfo::ms_pedModelStore.alloc();
|
||||||
|
CModelInfo::ms_modelInfoPtrs[id] = modelinfo;
|
||||||
|
modelinfo->m_clump = nil;
|
||||||
|
return modelinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
CVehicleModelInfo*
|
||||||
|
CModelInfo::AddVehicleModel(int id)
|
||||||
|
{
|
||||||
|
CVehicleModelInfo *modelinfo;
|
||||||
|
modelinfo = CModelInfo::ms_vehicleModelStore.alloc();
|
||||||
|
CModelInfo::ms_modelInfoPtrs[id] = modelinfo;
|
||||||
|
modelinfo->m_clump = nil;
|
||||||
|
modelinfo->m_vehicleType = -1;
|
||||||
|
modelinfo->m_wheelId = -1;
|
||||||
|
modelinfo->m_materials1[0] = nil;
|
||||||
|
modelinfo->m_materials2[0] = nil;
|
||||||
|
modelinfo->m_bikeSteerAngle = 999.99f;
|
||||||
|
return modelinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBaseModelInfo*
|
||||||
|
CModelInfo::GetModelInfo(const char *name, int *id)
|
||||||
|
{
|
||||||
|
CBaseModelInfo *modelinfo;
|
||||||
|
for(int i = 0; i < MODELINFOSIZE; i++){
|
||||||
|
modelinfo = CModelInfo::ms_modelInfoPtrs[i];
|
||||||
|
if(modelinfo && _strcmpi(modelinfo->GetName(), name) == 0){
|
||||||
|
if(id)
|
||||||
|
*id = i;
|
||||||
|
return modelinfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
// InjectHook(0x50B920, CModelInfo::AddSimpleModel, PATCH_JUMP);
|
||||||
|
// InjectHook(0x50B9C0, CModelInfo::AddTimeModel, PATCH_JUMP);
|
||||||
|
// InjectHook(0x50BA10, CModelInfo::AddClumpModel, PATCH_JUMP);
|
||||||
|
// InjectHook(0x50BAD0, CModelInfo::AddPedModel, PATCH_JUMP);
|
||||||
|
// InjectHook(0x50BA60, CModelInfo::AddPedModel, PATCH_JUMP);
|
||||||
|
InjectHook(0x50B860, (CBaseModelInfo *(*)(const char*, int*))CModelInfo::GetModelInfo, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
35
src/modelinfo/ModelInfo.h
Normal file
35
src/modelinfo/ModelInfo.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "2dEffect.h"
|
||||||
|
#include "BaseModelInfo.h"
|
||||||
|
#include "SimpleModelInfo.h"
|
||||||
|
#include "TimeModelInfo.h"
|
||||||
|
#include "ClumpModelInfo.h"
|
||||||
|
#include "PedModelInfo.h"
|
||||||
|
#include "VehicleModelInfo.h"
|
||||||
|
|
||||||
|
class CModelInfo
|
||||||
|
{
|
||||||
|
static CBaseModelInfo **ms_modelInfoPtrs; //[MODELINFOSIZE];
|
||||||
|
static CStore<CSimpleModelInfo, SIMPLEMODELSIZE> ms_simpleModelStore;
|
||||||
|
static CStore<CTimeModelInfo, TIMEMODELSIZE> ms_timeModelStore;
|
||||||
|
static CStore<CClumpModelInfo, CLUMPMODELSIZE> ms_clumpModelStore;
|
||||||
|
static CStore<CPedModelInfo, PEDMODELSIZE> ms_pedModelStore;
|
||||||
|
static CStore<CVehicleModelInfo, VEHICLEMODELSIZE> ms_vehicleModelStore;
|
||||||
|
static CStore<C2dEffect, TWODFXSIZE> ms_2dEffectStore;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void Initialise(void);
|
||||||
|
static void Shutdown(void);
|
||||||
|
|
||||||
|
static CSimpleModelInfo *AddSimpleModel(int id);
|
||||||
|
static CTimeModelInfo *AddTimeModel(int id);
|
||||||
|
static CClumpModelInfo *AddClumpModel(int id);
|
||||||
|
static CPedModelInfo *AddPedModel(int id);
|
||||||
|
static CVehicleModelInfo *AddVehicleModel(int id);
|
||||||
|
|
||||||
|
static CBaseModelInfo *GetModelInfo(const char *name, int *id);
|
||||||
|
static CBaseModelInfo *GetModelInfo(int id){
|
||||||
|
return ms_modelInfoPtrs[id];
|
||||||
|
}
|
||||||
|
};
|
197
src/modelinfo/PedModelInfo.cpp
Normal file
197
src/modelinfo/PedModelInfo.cpp
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "NodeName.h"
|
||||||
|
#include "VisibilityPlugins.h"
|
||||||
|
#include "ModelInfo.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
CPedModelInfo::DeleteRwObject(void)
|
||||||
|
{
|
||||||
|
CClumpModelInfo::DeleteRwObject();
|
||||||
|
if(m_hitColModel)
|
||||||
|
delete m_hitColModel;
|
||||||
|
m_hitColModel = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
RwObjectNameIdAssocation CPedModelInfo::m_pPedIds[12] = {
|
||||||
|
{ "Smid", PED_TORSO, 0, }, // that is strange...
|
||||||
|
{ "Shead", PED_HEAD, 0, },
|
||||||
|
{ "Supperarml", PED_UPPERARML, 0, },
|
||||||
|
{ "Supperarmr", PED_UPPERARMR, 0, },
|
||||||
|
{ "SLhand", PED_HANDL, 0, },
|
||||||
|
{ "SRhand", PED_HANDR, 0, },
|
||||||
|
{ "Supperlegl", PED_UPPERLEGL, 0, },
|
||||||
|
{ "Supperlegr", PED_UPPERLEGR, 0, },
|
||||||
|
{ "Sfootl", PED_FOOTL, 0, },
|
||||||
|
{ "Sfootr", PED_FOOTR, 0, },
|
||||||
|
{ "Slowerlegr", PED_LOWERLEGR, 0, },
|
||||||
|
{ NULL, 0, 0, },
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
CPedModelInfo::SetClump(RpClump *clump)
|
||||||
|
{
|
||||||
|
CClumpModelInfo::SetClump(clump);
|
||||||
|
SetFrameIds(m_pPedIds);
|
||||||
|
if(m_hitColModel == nil)
|
||||||
|
CreateHitColModel();
|
||||||
|
if(strncmp(GetName(), "player", 7) == 0)
|
||||||
|
RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, CVisibilityPlugins::RenderPlayerCB);
|
||||||
|
}
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
CountAtomicsCB(RpAtomic *atomic, void *data)
|
||||||
|
{
|
||||||
|
(*(int32*)data)++;
|
||||||
|
return atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
GetAtomicListCB(RpAtomic *atomic, void *data)
|
||||||
|
{
|
||||||
|
**(RpAtomic***)data = atomic;
|
||||||
|
(*(RpAtomic***)data)++;
|
||||||
|
return atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
RwFrame*
|
||||||
|
FindPedFrameFromNameCB(RwFrame *frame, void *data)
|
||||||
|
{
|
||||||
|
RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data;
|
||||||
|
|
||||||
|
if(_strcmpi(GetFrameNodeName(frame)+1, assoc->name+1) != 0){
|
||||||
|
RwFrameForAllChildren(frame, FindPedFrameFromNameCB, assoc);
|
||||||
|
return assoc->frame ? nil : frame;
|
||||||
|
}else{
|
||||||
|
assoc->frame = frame;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPedModelInfo::SetLowDetailClump(RpClump *lodclump)
|
||||||
|
{
|
||||||
|
RpAtomic *atomics[16];
|
||||||
|
RpAtomic **pAtm;
|
||||||
|
int32 numAtm, numLodAtm;
|
||||||
|
int i;
|
||||||
|
RwObjectNameAssociation assoc;
|
||||||
|
|
||||||
|
numAtm = 0;
|
||||||
|
numLodAtm = 0;
|
||||||
|
RpClumpForAllAtomics(m_clump, CountAtomicsCB, &numAtm); // actually unused
|
||||||
|
RpClumpForAllAtomics(lodclump, CountAtomicsCB, &numLodAtm);
|
||||||
|
|
||||||
|
RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, CVisibilityPlugins::RenderPedHiDetailCB);
|
||||||
|
RpClumpForAllAtomics(lodclump, SetAtomicRendererCB, CVisibilityPlugins::RenderPedLowDetailCB);
|
||||||
|
|
||||||
|
pAtm = atomics;
|
||||||
|
RpClumpForAllAtomics(lodclump, GetAtomicListCB, &pAtm);
|
||||||
|
|
||||||
|
for(i = 0; i < numLodAtm; i++){
|
||||||
|
assoc.name = GetFrameNodeName(RpAtomicGetFrame(atomics[i]));
|
||||||
|
assoc.frame = nil;
|
||||||
|
RwFrameForAllChildren(RpClumpGetFrame(m_clump), FindPedFrameFromNameCB, &assoc);
|
||||||
|
if(assoc.frame){
|
||||||
|
RpAtomicSetFrame(atomics[i], assoc.frame);
|
||||||
|
RpClumpRemoveAtomic(lodclump, atomics[i]);
|
||||||
|
RpClumpAddAtomic(m_clump, atomics[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ColNodeInfo
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
int pedNode;
|
||||||
|
int pieceType;
|
||||||
|
float x, z;
|
||||||
|
float radius;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: find out piece types
|
||||||
|
#define NUMPEDINFONODES 8
|
||||||
|
ColNodeInfo m_pColNodeInfos[NUMPEDINFONODES] = {
|
||||||
|
{ NULL, PED_HEAD, 6, 0.0f, 0.05f, 0.2f },
|
||||||
|
{ "Storso", 0, 0, 0.0f, 0.15f, 0.2f },
|
||||||
|
{ "Storso", 0, 0, 0.0f, -0.05f, 0.3f },
|
||||||
|
{ NULL, PED_TORSO, 1, 0.0f, -0.07f, 0.3f },
|
||||||
|
{ NULL, PED_UPPERARML, 2, 0.07f, -0.1f, 0.2f },
|
||||||
|
{ NULL, PED_UPPERARMR, 3, -0.07f, -0.1f, 0.2f },
|
||||||
|
{ "Slowerlegl", 0, 4, 0.0f, 0.07f, 0.25f },
|
||||||
|
{ NULL, PED_LOWERLEGR, 5, 0.0f, 0.07f, 0.25f },
|
||||||
|
};
|
||||||
|
|
||||||
|
RwObject*
|
||||||
|
FindHeadRadiusCB(RwObject *object, void *data)
|
||||||
|
{
|
||||||
|
RpAtomic *atomic = (RpAtomic*)object;
|
||||||
|
*(float*)data = RpAtomicGetBoundingSphere(atomic)->radius;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPedModelInfo::CreateHitColModel(void)
|
||||||
|
{
|
||||||
|
RwObjectNameAssociation nameAssoc;
|
||||||
|
RwObjectIdAssociation idAssoc;
|
||||||
|
CVector center;
|
||||||
|
RwFrame *nodeFrame;
|
||||||
|
CColModel *colmodel = new CColModel;
|
||||||
|
CColSphere *spheres = (CColSphere*)RwMalloc(NUMPEDINFONODES*sizeof(CColSphere));
|
||||||
|
RwFrame *root = RpClumpGetFrame(m_clump);
|
||||||
|
RwMatrix *mat = RwMatrixCreate();
|
||||||
|
for(int i = 0; i < NUMPEDINFONODES; i++){
|
||||||
|
nodeFrame = nil;
|
||||||
|
if(m_pColNodeInfos[i].name){
|
||||||
|
nameAssoc.name = m_pColNodeInfos[i].name;
|
||||||
|
nameAssoc.frame = nil;
|
||||||
|
RwFrameForAllChildren(root, FindFrameFromNameCB, &nameAssoc);
|
||||||
|
nodeFrame = nameAssoc.frame;
|
||||||
|
}else{
|
||||||
|
idAssoc.id = m_pColNodeInfos[i].pedNode;
|
||||||
|
idAssoc.frame = nil;
|
||||||
|
RwFrameForAllChildren(root, FindFrameFromIdCB, &idAssoc);
|
||||||
|
nodeFrame = idAssoc.frame;
|
||||||
|
}
|
||||||
|
if(nodeFrame){
|
||||||
|
float radius = m_pColNodeInfos[i].radius;
|
||||||
|
if(m_pColNodeInfos[i].pieceType == 6)
|
||||||
|
RwFrameForAllObjects(nodeFrame, FindHeadRadiusCB, &radius);
|
||||||
|
RwMatrixTransform(mat, RwFrameGetMatrix(nodeFrame), rwCOMBINEREPLACE);
|
||||||
|
const char *name = GetFrameNodeName(nodeFrame);
|
||||||
|
for(nodeFrame = RwFrameGetParent(nodeFrame);
|
||||||
|
nodeFrame;
|
||||||
|
nodeFrame = RwFrameGetParent(nodeFrame)){
|
||||||
|
name = GetFrameNodeName(nodeFrame);
|
||||||
|
RwMatrixTransform(mat, RwFrameGetMatrix(nodeFrame), rwCOMBINEPOSTCONCAT);
|
||||||
|
if(RwFrameGetParent(nodeFrame) == root)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
center.x = mat->pos.x + m_pColNodeInfos[i].x;
|
||||||
|
center.y = mat->pos.y + 0.0f;
|
||||||
|
center.z = mat->pos.z + m_pColNodeInfos[i].z;
|
||||||
|
spheres[i].Set(radius, center, 17, m_pColNodeInfos[i].pieceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RwMatrixDestroy(mat);
|
||||||
|
colmodel->spheres = spheres;
|
||||||
|
colmodel->numSpheres = NUMPEDINFONODES;
|
||||||
|
center.x = center.y = center.z = 0.0f;
|
||||||
|
colmodel->boundingSphere.Set(2.0f, center, 0, 0);
|
||||||
|
CVector min, max;
|
||||||
|
min.x = min.y = -0.5f;
|
||||||
|
min.z = -1.2f;
|
||||||
|
max.x = max.y = 0.5f;
|
||||||
|
max.z = 1.2f;
|
||||||
|
colmodel->boundingBox.Set(min, max, 0, 0);
|
||||||
|
colmodel->level = 0;
|
||||||
|
m_hitColModel = colmodel;
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x510210, &CPedModelInfo::SetClump_, PATCH_JUMP);
|
||||||
|
InjectHook(0x510280, &CPedModelInfo::DeleteRwObject_, PATCH_JUMP);
|
||||||
|
InjectHook(0x510390, &CPedModelInfo::SetLowDetailClump, PATCH_JUMP);
|
||||||
|
InjectHook(0x5104D0, &CPedModelInfo::CreateHitColModel, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
47
src/modelinfo/PedModelInfo.h
Normal file
47
src/modelinfo/PedModelInfo.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ClumpModelInfo.h"
|
||||||
|
|
||||||
|
enum PedNode {
|
||||||
|
PED_WAIST,
|
||||||
|
PED_TORSO, // Smid on PS2/PC, Storso on mobile/xbox
|
||||||
|
PED_HEAD,
|
||||||
|
PED_UPPERARML,
|
||||||
|
PED_UPPERARMR,
|
||||||
|
PED_HANDL,
|
||||||
|
PED_HANDR,
|
||||||
|
PED_UPPERLEGL,
|
||||||
|
PED_UPPERLEGR,
|
||||||
|
PED_FOOTL,
|
||||||
|
PED_FOOTR,
|
||||||
|
PED_LOWERLEGR,
|
||||||
|
// This is not valid apparently
|
||||||
|
PED_LOWERLEGL,
|
||||||
|
};
|
||||||
|
|
||||||
|
class CPedModelInfo : public CClumpModelInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void *m_animGroup; // TODO
|
||||||
|
int32 m_pedType;
|
||||||
|
int32 m_pedStatType;
|
||||||
|
uint32 m_carsCanDrive;
|
||||||
|
CColModel *m_hitColModel;
|
||||||
|
RpAtomic *m_head;
|
||||||
|
RpAtomic *m_lhand;
|
||||||
|
RpAtomic *m_rhand;
|
||||||
|
|
||||||
|
static RwObjectNameIdAssocation m_pPedIds[12];
|
||||||
|
|
||||||
|
CPedModelInfo(void) : CClumpModelInfo(MITYPE_PED) { }
|
||||||
|
void DeleteRwObject(void);
|
||||||
|
void SetClump(RpClump *);
|
||||||
|
|
||||||
|
void SetLowDetailClump(RpClump*);
|
||||||
|
void CreateHitColModel(void);
|
||||||
|
|
||||||
|
|
||||||
|
void DeleteRwObject_(void) { this->CPedModelInfo::DeleteRwObject(); }
|
||||||
|
void SetClump_(RpClump *clump) { this->CPedModelInfo::SetClump(clump); }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CPedModelInfo) == 0x54, "CPedModelInfo: error");
|
174
src/modelinfo/SimpleModelInfo.cpp
Normal file
174
src/modelinfo/SimpleModelInfo.cpp
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
#include "ModelInfo.h"
|
||||||
|
|
||||||
|
#define LOD_DISTANCE (300.0f)
|
||||||
|
|
||||||
|
void
|
||||||
|
CSimpleModelInfo::DeleteRwObject(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
RwFrame *f;
|
||||||
|
for(i = 0; i < m_numAtomics; i++)
|
||||||
|
if(m_atomics[i]){
|
||||||
|
f = RpAtomicGetFrame(m_atomics[i]);
|
||||||
|
RpAtomicDestroy(m_atomics[i]);
|
||||||
|
RwFrameDestroy(f);
|
||||||
|
m_atomics[i] = nil;
|
||||||
|
RemoveTexDictionaryRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RwObject*
|
||||||
|
CSimpleModelInfo::CreateInstance(void)
|
||||||
|
{
|
||||||
|
RpAtomic *atomic;
|
||||||
|
if(m_atomics[0] == nil)
|
||||||
|
return nil;
|
||||||
|
atomic = RpAtomicClone(m_atomics[0]);
|
||||||
|
RpAtomicSetFrame(atomic, RwFrameCreate());
|
||||||
|
return (RwObject*)atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
RwObject*
|
||||||
|
CSimpleModelInfo::CreateInstance(RwMatrix *matrix)
|
||||||
|
{
|
||||||
|
RpAtomic *atomic;
|
||||||
|
RwFrame *frame;
|
||||||
|
|
||||||
|
if(m_atomics[0] == nil)
|
||||||
|
return nil;
|
||||||
|
atomic = RpAtomicClone(m_atomics[0]);
|
||||||
|
frame = RwFrameCreate();
|
||||||
|
*RwFrameGetMatrix(frame) = *matrix;
|
||||||
|
RpAtomicSetFrame(atomic, frame);
|
||||||
|
return (RwObject*)atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CSimpleModelInfo::Init(void)
|
||||||
|
{
|
||||||
|
m_atomics[0] = nil;
|
||||||
|
m_atomics[1] = nil;
|
||||||
|
m_atomics[2] = nil;
|
||||||
|
m_numAtomics = 0;
|
||||||
|
m_furthest = 0;
|
||||||
|
m_normalCull = 0;
|
||||||
|
m_isDamaged = 0;
|
||||||
|
m_isBigBuilding = 0;
|
||||||
|
m_noFade = 0;
|
||||||
|
m_drawLast = 0;
|
||||||
|
m_additive = 0;
|
||||||
|
m_isSubway = 0;
|
||||||
|
m_ignoreLight = 0;
|
||||||
|
m_noZwrite = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CSimpleModelInfo::SetAtomic(int n, RpAtomic *atomic)
|
||||||
|
{
|
||||||
|
AddTexDictionaryRef();
|
||||||
|
m_atomics[n] = atomic;
|
||||||
|
if(m_ignoreLight){
|
||||||
|
RpGeometry *geo = RpAtomicGetGeometry(atomic);
|
||||||
|
RpGeometrySetFlags(geo, RpGeometryGetFlags(geo) & ~rpGEOMETRYLIGHT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CSimpleModelInfo::SetLodDistances(float *dist)
|
||||||
|
{
|
||||||
|
m_lodDistances[0] = dist[0];
|
||||||
|
m_lodDistances[1] = dist[1];
|
||||||
|
m_lodDistances[2] = dist[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CSimpleModelInfo::IncreaseAlpha(void)
|
||||||
|
{
|
||||||
|
if(m_alpha >= 0xEF)
|
||||||
|
m_alpha = 0xFF;
|
||||||
|
else
|
||||||
|
m_alpha += 0x10;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
CSimpleModelInfo::GetNearDistance(void)
|
||||||
|
{
|
||||||
|
return m_lodDistances[2] * TheCamera.LODDistMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
CSimpleModelInfo::GetLargestLodDistance(void)
|
||||||
|
{
|
||||||
|
float d;
|
||||||
|
// TODO: what exactly is going on here?
|
||||||
|
if(m_furthest != 0 && !m_isDamaged)
|
||||||
|
d = m_lodDistances[m_furthest-1];
|
||||||
|
else
|
||||||
|
d = m_lodDistances[m_numAtomics-1];
|
||||||
|
return d * TheCamera.LODDistMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
CSimpleModelInfo::GetAtomicFromDistance(float dist)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
i = 0;
|
||||||
|
// TODO: what exactly is going on here?
|
||||||
|
if(m_isDamaged)
|
||||||
|
i = m_furthest;
|
||||||
|
for(; i < m_numAtomics; i++)
|
||||||
|
if(dist < m_lodDistances[i] *TheCamera.LODDistMultiplier)
|
||||||
|
return m_atomics[i];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CSimpleModelInfo::FindRelatedModel(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
CBaseModelInfo *mi;
|
||||||
|
for(i = 0; i < MODELINFOSIZE; i++){
|
||||||
|
mi = CModelInfo::GetModelInfo(i);
|
||||||
|
if(mi && mi != this &&
|
||||||
|
strcmp(GetName()+3, mi->GetName()+3) == 0){
|
||||||
|
assert(mi->IsSimple());
|
||||||
|
this->SetRelatedModel((CSimpleModelInfo*)mi);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CSimpleModelInfo::SetupBigBuilding(void)
|
||||||
|
{
|
||||||
|
CSimpleModelInfo *related;
|
||||||
|
if(m_lodDistances[0] > LOD_DISTANCE && m_atomics[2] == nil){
|
||||||
|
m_isBigBuilding = 1;
|
||||||
|
FindRelatedModel();
|
||||||
|
related = GetRelatedModel();
|
||||||
|
if(related)
|
||||||
|
m_lodDistances[2] = related->GetLargestLodDistance()/TheCamera.LODDistMultiplier;
|
||||||
|
else
|
||||||
|
m_lodDistances[2] = 100.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x5179B0, &CSimpleModelInfo::DeleteRwObject_, PATCH_JUMP);
|
||||||
|
InjectHook(0x517B60, &CSimpleModelInfo::CreateInstance_1, PATCH_JUMP);
|
||||||
|
InjectHook(0x517AC0, &CSimpleModelInfo::CreateInstance_2, PATCH_JUMP);
|
||||||
|
InjectHook(0x4A9BA0, &CSimpleModelInfo::GetRwObject_, PATCH_JUMP);
|
||||||
|
InjectHook(0x517990, &CSimpleModelInfo::Init, PATCH_JUMP);
|
||||||
|
InjectHook(0x517C60, &CSimpleModelInfo::IncreaseAlpha, PATCH_JUMP);
|
||||||
|
InjectHook(0x517950, &CSimpleModelInfo::SetAtomic, PATCH_JUMP);
|
||||||
|
InjectHook(0x517AA0, &CSimpleModelInfo::SetLodDistances, PATCH_JUMP);
|
||||||
|
InjectHook(0x517A90, &CSimpleModelInfo::GetNearDistance, PATCH_JUMP);
|
||||||
|
InjectHook(0x517A60, &CSimpleModelInfo::GetLargestLodDistance, PATCH_JUMP);
|
||||||
|
InjectHook(0x517A00, &CSimpleModelInfo::GetAtomicFromDistance, PATCH_JUMP);
|
||||||
|
InjectHook(0x517C00, &CSimpleModelInfo::FindRelatedModel, PATCH_JUMP);
|
||||||
|
InjectHook(0x517B90, &CSimpleModelInfo::SetupBigBuilding, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
57
src/modelinfo/SimpleModelInfo.h
Normal file
57
src/modelinfo/SimpleModelInfo.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BaseModelInfo.h"
|
||||||
|
|
||||||
|
class CSimpleModelInfo : public CBaseModelInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// atomics[2] is often a pointer to the non-LOD modelinfo
|
||||||
|
RpAtomic *m_atomics[3];
|
||||||
|
// m_lodDistances[2] holds the near distance for LODs
|
||||||
|
float m_lodDistances[3];
|
||||||
|
uint8 m_numAtomics;
|
||||||
|
uint8 m_alpha;
|
||||||
|
uint16 m_furthest : 2; // 0: numAtomics-1 is furthest visible
|
||||||
|
// 1: atomic 0 is furthest
|
||||||
|
// 2: atomic 1 is furthest
|
||||||
|
uint16 m_normalCull : 1;
|
||||||
|
uint16 m_isDamaged : 1;
|
||||||
|
uint16 m_isBigBuilding : 1;
|
||||||
|
uint16 m_noFade : 1;
|
||||||
|
uint16 m_drawLast : 1;
|
||||||
|
uint16 m_additive : 1;
|
||||||
|
uint16 m_isSubway : 1;
|
||||||
|
uint16 m_ignoreLight : 1;
|
||||||
|
uint16 m_noZwrite : 1;
|
||||||
|
|
||||||
|
CSimpleModelInfo(void) : CBaseModelInfo(MITYPE_SIMPLE) {}
|
||||||
|
CSimpleModelInfo(ModeInfoType id) : CBaseModelInfo(id) {}
|
||||||
|
~CSimpleModelInfo() {}
|
||||||
|
void DeleteRwObject(void);
|
||||||
|
RwObject *CreateInstance(void);
|
||||||
|
RwObject *CreateInstance(RwMatrix *);
|
||||||
|
RwObject *GetRwObject(void) { return (RwObject*)m_atomics[0]; }
|
||||||
|
|
||||||
|
void Init(void);
|
||||||
|
void IncreaseAlpha(void);
|
||||||
|
void SetAtomic(int n, RpAtomic *atomic);
|
||||||
|
void SetLodDistances(float *dist);
|
||||||
|
float GetLodDistance(int i) { return m_lodDistances[i]; }
|
||||||
|
float GetNearDistance(void);
|
||||||
|
float GetLargestLodDistance(void);
|
||||||
|
RpAtomic *GetAtomicFromDistance(float dist);
|
||||||
|
void FindRelatedModel(void);
|
||||||
|
void SetupBigBuilding(void);
|
||||||
|
|
||||||
|
void SetNumAtomics(int n) { m_numAtomics = n; }
|
||||||
|
CSimpleModelInfo *GetRelatedModel(void){
|
||||||
|
return (CSimpleModelInfo*)m_atomics[2]; }
|
||||||
|
void SetRelatedModel(CSimpleModelInfo *m){
|
||||||
|
m_atomics[2] = (RpAtomic*)m; }
|
||||||
|
|
||||||
|
void DeleteRwObject_(void) { this->CSimpleModelInfo::DeleteRwObject(); }
|
||||||
|
RwObject *CreateInstance_1(void) { return this->CSimpleModelInfo::CreateInstance(); }
|
||||||
|
RwObject *CreateInstance_2(RwMatrix *m) { return this->CSimpleModelInfo::CreateInstance(m); }
|
||||||
|
RwObject *GetRwObject_(void) { return this->CSimpleModelInfo::GetRwObject(); }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CSimpleModelInfo) == 0x4C, "CSimpleModelInfo: error");
|
36
src/modelinfo/TimeModelInfo.cpp
Normal file
36
src/modelinfo/TimeModelInfo.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
#include "ModelInfo.h"
|
||||||
|
|
||||||
|
CTimeModelInfo*
|
||||||
|
CTimeModelInfo::FindOtherTimeModel(void)
|
||||||
|
{
|
||||||
|
char name[40];
|
||||||
|
char *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
strcpy(name, GetName());
|
||||||
|
// change _nt to _dy
|
||||||
|
if(p = strstr(name, "_nt"))
|
||||||
|
strncpy(p, "_dy", 4);
|
||||||
|
// change _dy to _nt
|
||||||
|
else if(p = strstr(name, "_dy"))
|
||||||
|
strncpy(p, "_nt", 4);
|
||||||
|
else
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
for(i = 0; i < MODELINFOSIZE; i++){
|
||||||
|
CBaseModelInfo *mi = CModelInfo::GetModelInfo(i);
|
||||||
|
if(mi && mi->m_type == MITYPE_TIME &&
|
||||||
|
strncmp(name, mi->GetName(), 24) == 0){
|
||||||
|
m_otherTimeModelID = i;
|
||||||
|
return (CTimeModelInfo*)mi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x517C80, &CTimeModelInfo::FindOtherTimeModel, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
18
src/modelinfo/TimeModelInfo.h
Normal file
18
src/modelinfo/TimeModelInfo.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SimpleModelInfo.h"
|
||||||
|
|
||||||
|
class CTimeModelInfo : public CSimpleModelInfo
|
||||||
|
{
|
||||||
|
int32 m_timeOn;
|
||||||
|
int32 m_timeOff;
|
||||||
|
int32 m_otherTimeModelID;
|
||||||
|
public:
|
||||||
|
CTimeModelInfo(void) : CSimpleModelInfo(MITYPE_TIME) { m_otherTimeModelID = -1; }
|
||||||
|
|
||||||
|
int32 GetTimeOn(void) { return m_timeOn; }
|
||||||
|
int32 GetTimeOff(void) { return m_timeOff; }
|
||||||
|
int32 GetOtherTimeModel(void) { return m_otherTimeModelID; }
|
||||||
|
CTimeModelInfo *FindOtherTimeModel(void);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CTimeModelInfo) == 0x58, "CTimeModelInfo: error");
|
917
src/modelinfo/VehicleModelInfo.cpp
Normal file
917
src/modelinfo/VehicleModelInfo.cpp
Normal file
@ -0,0 +1,917 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include <rpmatfx.h>
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "RwHelper.h"
|
||||||
|
#include "General.h"
|
||||||
|
#include "NodeName.h"
|
||||||
|
#include "TxdStore.h"
|
||||||
|
#include "Weather.h"
|
||||||
|
#include "VisibilityPlugins.h"
|
||||||
|
#include "ModelInfo.h"
|
||||||
|
|
||||||
|
int8 *CVehicleModelInfo::ms_compsToUse = (int8*)0x5FF2EC; // -2, -2
|
||||||
|
int8 *CVehicleModelInfo::ms_compsUsed = (int8*)0x95CCB2;
|
||||||
|
RwTexture **CVehicleModelInfo::ms_pEnvironmentMaps = (RwTexture **)0x8F1A30;
|
||||||
|
RwRGBA *CVehicleModelInfo::ms_vehicleColourTable = (RwRGBA*)0x86BA88;
|
||||||
|
RwTexture **CVehicleModelInfo::ms_colourTextureTable = (RwTexture**)0x711C40;
|
||||||
|
|
||||||
|
RwTexture *&gpWhiteTexture = *(RwTexture**)0x64C4F8;
|
||||||
|
RwFrame *&pMatFxIdentityFrame = *(RwFrame**)0x64C510;
|
||||||
|
|
||||||
|
// TODO This depends on handling
|
||||||
|
WRAPPER void CVehicleModelInfo::SetVehicleComponentFlags(RwFrame *frame, uint32 flags) { EAXJMP(0x5203C0); }
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CAR_WHEEL_RF = 1,
|
||||||
|
CAR_WHEEL_RM = 2,
|
||||||
|
CAR_WHEEL_RB = 3,
|
||||||
|
CAR_WHEEL_LF = 4,
|
||||||
|
CAR_WHEEL_LM = 5,
|
||||||
|
CAR_WHEEL_LB = 6,
|
||||||
|
CAR_BUMP_FRONT = 7,
|
||||||
|
CAR_BUMP_REAR = 8,
|
||||||
|
CAR_WING_RF = 9,
|
||||||
|
CAR_WING_RR = 10,
|
||||||
|
CAR_DOOR_RF = 11,
|
||||||
|
CAR_DOOR_RR = 12,
|
||||||
|
CAR_WING_LF = 13,
|
||||||
|
CAR_WING_LR = 14,
|
||||||
|
CAR_DOOR_LF = 15,
|
||||||
|
CAR_DOOR_LR = 16,
|
||||||
|
CAR_BONNET = 17,
|
||||||
|
CAR_BOOT = 18,
|
||||||
|
CAR_WINDSCREEN = 19,
|
||||||
|
|
||||||
|
CAR_POS_HEADLIGHTS = 0,
|
||||||
|
CAR_POS_TAILLIGHTS = 1,
|
||||||
|
CAR_POS_FRONTSEAT = 2,
|
||||||
|
CAR_POS_BACKSEAT = 3,
|
||||||
|
CAR_POS_EXHAUST = 9,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VEHICLE_FLAG_COLLAPSE = 0x2,
|
||||||
|
VEHICLE_FLAG_ADD_WHEEL = 0x4,
|
||||||
|
VEHICLE_FLAG_POS = 0x8,
|
||||||
|
VEHICLE_FLAG_DOOR = 0x10,
|
||||||
|
VEHICLE_FLAG_LEFT = 0x20,
|
||||||
|
VEHICLE_FLAG_RIGHT = 0x40,
|
||||||
|
VEHICLE_FLAG_FRONT = 0x80,
|
||||||
|
VEHICLE_FLAG_REAR = 0x100,
|
||||||
|
VEHICLE_FLAG_COMP = 0x200,
|
||||||
|
VEHICLE_FLAG_DRAWLAST = 0x400,
|
||||||
|
VEHICLE_FLAG_WINDSCREEN = 0x800,
|
||||||
|
VEHICLE_FLAG_ANGLECULL = 0x1000,
|
||||||
|
VEHICLE_FLAG_REARDOOR = 0x2000,
|
||||||
|
VEHICLE_FLAG_FRONTDOOR = 0x4000,
|
||||||
|
};
|
||||||
|
|
||||||
|
RwObjectNameIdAssocation carIds[] = {
|
||||||
|
{ "wheel_rf_dummy", CAR_WHEEL_RF, VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_ADD_WHEEL },
|
||||||
|
{ "wheel_rm_dummy", CAR_WHEEL_RM, VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_ADD_WHEEL },
|
||||||
|
{ "wheel_rb_dummy", CAR_WHEEL_RB, VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_ADD_WHEEL },
|
||||||
|
{ "wheel_lf_dummy", CAR_WHEEL_LF, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_ADD_WHEEL },
|
||||||
|
{ "wheel_lm_dummy", CAR_WHEEL_LM, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_ADD_WHEEL },
|
||||||
|
{ "wheel_lb_dummy", CAR_WHEEL_LB, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_ADD_WHEEL },
|
||||||
|
{ "bump_front_dummy", CAR_BUMP_FRONT, VEHICLE_FLAG_FRONT | VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "bonnet_dummy", CAR_BONNET, VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "wing_rf_dummy", CAR_WING_RF, VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "wing_rr_dummy", CAR_WING_RR, VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "door_rf_dummy", CAR_DOOR_RF, VEHICLE_FLAG_FRONTDOOR | VEHICLE_FLAG_ANGLECULL | VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_DOOR | VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "door_rr_dummy", CAR_DOOR_RR, VEHICLE_FLAG_REARDOOR | VEHICLE_FLAG_ANGLECULL | VEHICLE_FLAG_REAR | VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_DOOR | VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "wing_lf_dummy", CAR_WING_LF, VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "wing_lr_dummy", CAR_WING_LR, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "door_lf_dummy", CAR_DOOR_LF, VEHICLE_FLAG_FRONTDOOR | VEHICLE_FLAG_ANGLECULL | VEHICLE_FLAG_LEFT | VEHICLE_FLAG_DOOR | VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "door_lr_dummy", CAR_DOOR_LR, VEHICLE_FLAG_REARDOOR | VEHICLE_FLAG_ANGLECULL | VEHICLE_FLAG_REAR | VEHICLE_FLAG_LEFT | VEHICLE_FLAG_DOOR | VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "boot_dummy", CAR_BOOT, VEHICLE_FLAG_REAR | VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "bump_rear_dummy", CAR_BUMP_REAR, VEHICLE_FLAG_REAR | VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "windscreen_dummy", CAR_WINDSCREEN, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_FRONT | VEHICLE_FLAG_COLLAPSE },
|
||||||
|
|
||||||
|
{ "ped_frontseat", CAR_POS_FRONTSEAT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "ped_backseat", CAR_POS_BACKSEAT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "headlights", CAR_POS_HEADLIGHTS, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "taillights", CAR_POS_TAILLIGHTS, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "exhaust", CAR_POS_EXHAUST, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "extra1", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "extra2", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "extra3", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "extra4", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "extra5", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "extra6", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ nil, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
RwObjectNameIdAssocation boatIds[] = {
|
||||||
|
{ "boat_moving_hi", 1, VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "boat_rudder_hi", 3, VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "windscreen", 2, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "ped_frontseat", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ nil, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
RwObjectNameIdAssocation trainIds[] = {
|
||||||
|
{ "door_lhs_dummy", 1, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "door_rhs_dummy", 2, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "light_front", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "light_rear", 1, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "ped_left_entry", 2, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "ped_mid_entry", 3, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "ped_right_entry", 4, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ nil, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
RwObjectNameIdAssocation heliIds[] = {
|
||||||
|
{ "chassis_dummy", 1, VEHICLE_FLAG_COLLAPSE },
|
||||||
|
{ "toprotor", 2, 0 },
|
||||||
|
{ "backrotor", 3, 0 },
|
||||||
|
{ "tail", 4, 0 },
|
||||||
|
{ "topknot", 5, 0 },
|
||||||
|
{ "skid_left", 6, 0 },
|
||||||
|
{ "skid_right", 7, 0 },
|
||||||
|
{ nil, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
RwObjectNameIdAssocation planeIds[] = {
|
||||||
|
{ "wheel_front_dummy", 2, 0 },
|
||||||
|
{ "wheel_rear_dummy", 3, 0 },
|
||||||
|
{ "light_tailplane", 2, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "light_left", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "light_right", 1, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ nil, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
RwObjectNameIdAssocation bikeIds[] = {
|
||||||
|
{ "chassis_dummy", 1, 0 },
|
||||||
|
{ "forks_front", 2, 0 },
|
||||||
|
{ "forks_rear", 3, 0 },
|
||||||
|
{ "wheel_front", 4, 0 },
|
||||||
|
{ "wheel_rear", 5, 0 },
|
||||||
|
{ "mudguard", 6, 0 },
|
||||||
|
{ "ped_frontseat", 2, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "headlights", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "taillights", 1, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "exhaust", 9, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "extra1", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "extra2", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "extra3", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "extra4", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "extra5", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ "extra6", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID },
|
||||||
|
{ nil, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
RwObjectNameIdAssocation *CVehicleModelInfo::ms_vehicleDescs[] = {
|
||||||
|
carIds,
|
||||||
|
boatIds,
|
||||||
|
trainIds,
|
||||||
|
heliIds,
|
||||||
|
planeIds,
|
||||||
|
bikeIds
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CVehicleModelInfo::CVehicleModelInfo(void)
|
||||||
|
: CClumpModelInfo(MITYPE_VEHICLE)
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
for(i = 0; i < NUM_VEHICLE_POSITIONS; i++){
|
||||||
|
m_positions[i].x = 0.0f;
|
||||||
|
m_positions[i].y = 0.0f;
|
||||||
|
m_positions[i].z = 0.0f;
|
||||||
|
}
|
||||||
|
m_numColours = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CVehicleModelInfo::DeleteRwObject(void)
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
RwFrame *f;
|
||||||
|
|
||||||
|
for(i = 0; i < m_numComps; i++){
|
||||||
|
f = RpAtomicGetFrame(m_comps[i]);
|
||||||
|
RpAtomicDestroy(m_comps[i]);
|
||||||
|
RwFrameDestroy(f);
|
||||||
|
}
|
||||||
|
m_numComps = 0;
|
||||||
|
CClumpModelInfo::DeleteRwObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
RwObject*
|
||||||
|
CVehicleModelInfo::CreateInstance(void)
|
||||||
|
{
|
||||||
|
RpClump *clump;
|
||||||
|
RpAtomic *atomic;
|
||||||
|
RwFrame *clumpframe, *f;
|
||||||
|
int32 comp1, comp2;
|
||||||
|
|
||||||
|
clump = (RpClump*)CClumpModelInfo::CreateInstance();
|
||||||
|
if(m_numComps != 0){
|
||||||
|
clumpframe = RpClumpGetFrame(clump);
|
||||||
|
|
||||||
|
comp1 = ChooseComponent();
|
||||||
|
if(comp1 != -1){
|
||||||
|
atomic = RpAtomicClone(m_comps[comp1]);
|
||||||
|
f = RwFrameCreate();
|
||||||
|
RwFrameTransform(f,
|
||||||
|
RwFrameGetMatrix(RpAtomicGetFrame(m_comps[comp1])),
|
||||||
|
rwCOMBINEREPLACE);
|
||||||
|
RpAtomicSetFrame(atomic, f);
|
||||||
|
RpClumpAddAtomic(clump, atomic);
|
||||||
|
RwFrameAddChild(clumpframe, f);
|
||||||
|
}
|
||||||
|
ms_compsUsed[0] = comp1;
|
||||||
|
|
||||||
|
comp2 = ChooseSecondComponent();
|
||||||
|
if(comp2 != -1){
|
||||||
|
atomic = RpAtomicClone(m_comps[comp2]);
|
||||||
|
f = RwFrameCreate();
|
||||||
|
RwFrameTransform(f,
|
||||||
|
RwFrameGetMatrix(RpAtomicGetFrame(m_comps[comp2])),
|
||||||
|
rwCOMBINEREPLACE);
|
||||||
|
RpAtomicSetFrame(atomic, f);
|
||||||
|
RpClumpAddAtomic(clump, atomic);
|
||||||
|
RwFrameAddChild(clumpframe, f);
|
||||||
|
}
|
||||||
|
ms_compsUsed[1] = comp2;
|
||||||
|
}else{
|
||||||
|
ms_compsUsed[0] = -1;
|
||||||
|
ms_compsUsed[1] = -1;
|
||||||
|
}
|
||||||
|
return (RwObject*)clump;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CVehicleModelInfo::SetClump(RpClump *clump)
|
||||||
|
{
|
||||||
|
CClumpModelInfo::SetClump(clump);
|
||||||
|
SetAtomicRenderCallbacks();
|
||||||
|
SetFrameIds(ms_vehicleDescs[m_vehicleType]);
|
||||||
|
PreprocessHierarchy();
|
||||||
|
FindEditableMaterialList();
|
||||||
|
m_envMap = nil;
|
||||||
|
SetEnvironmentMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
RwFrame*
|
||||||
|
CVehicleModelInfo::CollapseFramesCB(RwFrame *frame, void *data)
|
||||||
|
{
|
||||||
|
RwFrameForAllChildren(frame, CollapseFramesCB, data);
|
||||||
|
RwFrameForAllObjects(frame, MoveObjectsCB, data);
|
||||||
|
RwFrameDestroy(frame);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
RwObject*
|
||||||
|
CVehicleModelInfo::MoveObjectsCB(RwObject *object, void *data)
|
||||||
|
{
|
||||||
|
RpAtomicSetFrame((RpAtomic*)object, (RwFrame*)data);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
CVehicleModelInfo::HideDamagedAtomicCB(RpAtomic *atomic, void *data)
|
||||||
|
{
|
||||||
|
if(strstr(GetFrameNodeName(RpAtomicGetFrame(atomic)), "_dam")){
|
||||||
|
RpAtomicSetFlags(atomic, 0);
|
||||||
|
CVisibilityPlugins::SetAtomicFlag(atomic, ATOMIC_FLAG_DAM);
|
||||||
|
}else if(strstr(GetFrameNodeName(RpAtomicGetFrame(atomic)), "_ok"))
|
||||||
|
CVisibilityPlugins::SetAtomicFlag(atomic, ATOMIC_FLAG_OK);
|
||||||
|
return atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpMaterial*
|
||||||
|
CVehicleModelInfo::HasAlphaMaterialCB(RpMaterial *material, void *data)
|
||||||
|
{
|
||||||
|
if(RpMaterialGetColor(material)->alpha != 0xFF){
|
||||||
|
*(bool*)data = true;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
CVehicleModelInfo::SetAtomicRendererCB(RpAtomic *atomic, void *data)
|
||||||
|
{
|
||||||
|
RpClump *clump;
|
||||||
|
char *name;
|
||||||
|
bool alpha;
|
||||||
|
|
||||||
|
clump = (RpClump*)data;
|
||||||
|
name = GetFrameNodeName(RpAtomicGetFrame(atomic));
|
||||||
|
alpha = false;
|
||||||
|
RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), HasAlphaMaterialCB, &alpha);
|
||||||
|
if(strstr(name, "_hi") || strncmp(name, "extra", 5) == 0){
|
||||||
|
if(alpha || strncmp(name, "windscreen", 10) == 0)
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailAlphaCB);
|
||||||
|
else
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailCB);
|
||||||
|
}else if(strstr(name, "_lo")){
|
||||||
|
RpClumpRemoveAtomic(clump, atomic);
|
||||||
|
RpAtomicDestroy(atomic);
|
||||||
|
return atomic; // BUG: not done by gta
|
||||||
|
}else if(strstr(name, "_vlo"))
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleReallyLowDetailCB);
|
||||||
|
else
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
|
||||||
|
HideDamagedAtomicCB(atomic, nil);
|
||||||
|
return atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
CVehicleModelInfo::SetAtomicRendererCB_BigVehicle(RpAtomic *atomic, void *data)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
bool alpha;
|
||||||
|
|
||||||
|
name = GetFrameNodeName(RpAtomicGetFrame(atomic));
|
||||||
|
alpha = false;
|
||||||
|
RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), HasAlphaMaterialCB, &alpha);
|
||||||
|
if(strstr(name, "_hi") || strncmp(name, "extra", 5) == 0){
|
||||||
|
if(alpha)
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailAlphaCB_BigVehicle);
|
||||||
|
else
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailCB_BigVehicle);
|
||||||
|
}else if(strstr(name, "_lo")){
|
||||||
|
if(alpha)
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleLowDetailAlphaCB_BigVehicle);
|
||||||
|
else
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleLowDetailCB_BigVehicle);
|
||||||
|
}else if(strstr(name, "_vlo"))
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleReallyLowDetailCB_BigVehicle);
|
||||||
|
else
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
|
||||||
|
HideDamagedAtomicCB(atomic, nil);
|
||||||
|
return atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
CVehicleModelInfo::SetAtomicRendererCB_Train(RpAtomic *atomic, void *data)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
bool alpha;
|
||||||
|
|
||||||
|
name = GetFrameNodeName(RpAtomicGetFrame(atomic));
|
||||||
|
alpha = false;
|
||||||
|
RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), HasAlphaMaterialCB, &alpha);
|
||||||
|
if(strstr(name, "_hi")){
|
||||||
|
if(alpha)
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderTrainHiDetailAlphaCB);
|
||||||
|
else
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderTrainHiDetailCB);
|
||||||
|
}else if(strstr(name, "_vlo"))
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleReallyLowDetailCB_BigVehicle);
|
||||||
|
else
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
|
||||||
|
HideDamagedAtomicCB(atomic, nil);
|
||||||
|
return atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
CVehicleModelInfo::SetAtomicRendererCB_Boat(RpAtomic *atomic, void *data)
|
||||||
|
{
|
||||||
|
RpClump *clump;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
clump = (RpClump*)data;
|
||||||
|
name = GetFrameNodeName(RpAtomicGetFrame(atomic));
|
||||||
|
if(strcmp(name, "boat_hi") == 0 || strncmp(name, "extra", 5) == 0)
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailCB_Boat);
|
||||||
|
else if(strstr(name, "_hi"))
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailCB);
|
||||||
|
else if(strstr(name, "_lo")){
|
||||||
|
RpClumpRemoveAtomic(clump, atomic);
|
||||||
|
RpAtomicDestroy(atomic);
|
||||||
|
return atomic; // BUG: not done by gta
|
||||||
|
}else if(strstr(name, "_vlo"))
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleReallyLowDetailCB_BigVehicle);
|
||||||
|
else
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
|
||||||
|
HideDamagedAtomicCB(atomic, nil);
|
||||||
|
return atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
CVehicleModelInfo::SetAtomicRendererCB_Heli(RpAtomic *atomic, void *data)
|
||||||
|
{
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
|
||||||
|
return atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CVehicleModelInfo::SetAtomicRenderCallbacks(void)
|
||||||
|
{
|
||||||
|
switch(m_vehicleType){
|
||||||
|
case VEHICLE_TYPE_TRAIN:
|
||||||
|
RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_Train, nil);
|
||||||
|
break;
|
||||||
|
case VEHICLE_TYPE_HELI:
|
||||||
|
RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_Heli, nil);
|
||||||
|
break;
|
||||||
|
case VEHICLE_TYPE_PLANE:
|
||||||
|
RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_BigVehicle, nil);
|
||||||
|
break;
|
||||||
|
case VEHICLE_TYPE_BOAT:
|
||||||
|
RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_Boat, m_clump);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, m_clump);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
CVehicleModelInfo::SetAtomicFlagCB(RpAtomic *atomic, void *data)
|
||||||
|
{
|
||||||
|
CVisibilityPlugins::SetAtomicFlag(atomic, (int)data);
|
||||||
|
return atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
CVehicleModelInfo::ClearAtomicFlagCB(RpAtomic *atomic, void *data)
|
||||||
|
{
|
||||||
|
CVisibilityPlugins::ClearAtomicFlag(atomic, (int)data);
|
||||||
|
return atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
RwObject*
|
||||||
|
GetOkAndDamagedAtomicCB(RwObject *object, void *data)
|
||||||
|
{
|
||||||
|
RpAtomic *atomic = (RpAtomic*)object;
|
||||||
|
if(CVisibilityPlugins::GetAtomicId(atomic) & ATOMIC_FLAG_OK)
|
||||||
|
((RpAtomic**)data)[0] = atomic;
|
||||||
|
else if(CVisibilityPlugins::GetAtomicId(atomic) & ATOMIC_FLAG_DAM)
|
||||||
|
((RpAtomic**)data)[1] = atomic;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CVehicleModelInfo::PreprocessHierarchy(void)
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
RwObjectNameIdAssocation *desc;
|
||||||
|
RwFrame *f;
|
||||||
|
RpAtomic *atomic;
|
||||||
|
RwV3d *rwvec;
|
||||||
|
|
||||||
|
desc = ms_vehicleDescs[m_vehicleType];
|
||||||
|
m_numDoors = 0;
|
||||||
|
m_numComps = 0;
|
||||||
|
|
||||||
|
for(i = 0; desc[i].name; i++){
|
||||||
|
RwObjectNameAssociation assoc;
|
||||||
|
|
||||||
|
if((desc[i].flags & (VEHICLE_FLAG_COMP|VEHICLE_FLAG_POS)) == 0)
|
||||||
|
continue;
|
||||||
|
assoc.frame = nil;
|
||||||
|
assoc.name = desc[i].name;
|
||||||
|
RwFrameForAllChildren(RpClumpGetFrame(m_clump),
|
||||||
|
FindFrameFromNameWithoutIdCB, &assoc);
|
||||||
|
if(assoc.frame == nil)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(desc[i].flags & VEHICLE_FLAG_DOOR)
|
||||||
|
m_numDoors++;
|
||||||
|
|
||||||
|
if(desc[i].flags & VEHICLE_FLAG_POS){
|
||||||
|
f = assoc.frame;
|
||||||
|
rwvec = (RwV3d*)&m_positions[desc[i].hierId];
|
||||||
|
*rwvec = *RwMatrixGetPos(RwFrameGetMatrix(f));
|
||||||
|
for(f = RwFrameGetParent(f); f; f = RwFrameGetParent(f))
|
||||||
|
RwV3dTransformPoints(rwvec, rwvec, 1, RwFrameGetMatrix(f));
|
||||||
|
RwFrameDestroy(assoc.frame);
|
||||||
|
}else{
|
||||||
|
atomic = (RpAtomic*)GetFirstObject(assoc.frame);
|
||||||
|
RpClumpRemoveAtomic(m_clump, atomic);
|
||||||
|
RwFrameRemoveChild(assoc.frame);
|
||||||
|
SetVehicleComponentFlags(assoc.frame, desc[i].flags);
|
||||||
|
m_comps[m_numComps++] = atomic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; desc[i].name; i++){
|
||||||
|
RwObjectIdAssociation assoc;
|
||||||
|
|
||||||
|
if(desc[i].flags & (VEHICLE_FLAG_COMP|VEHICLE_FLAG_POS))
|
||||||
|
continue;
|
||||||
|
assoc.frame = nil;
|
||||||
|
assoc.id = desc[i].hierId;
|
||||||
|
RwFrameForAllChildren(RpClumpGetFrame(m_clump),
|
||||||
|
FindFrameFromIdCB, &assoc);
|
||||||
|
if(assoc.frame == nil)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(desc[i].flags & VEHICLE_FLAG_DOOR)
|
||||||
|
m_numDoors++;
|
||||||
|
|
||||||
|
if(desc[i].flags & VEHICLE_FLAG_COLLAPSE){
|
||||||
|
RpAtomic *okdam[2] = { nil, nil };
|
||||||
|
RwFrameForAllChildren(assoc.frame, CollapseFramesCB, assoc.frame);
|
||||||
|
RwFrameUpdateObjects(assoc.frame);
|
||||||
|
RwFrameForAllObjects(assoc.frame, GetOkAndDamagedAtomicCB, okdam);
|
||||||
|
if(okdam[0] && okdam[1])
|
||||||
|
RpAtomicSetRenderCallBack(okdam[1], RpAtomicGetRenderCallBack(okdam[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
SetVehicleComponentFlags(assoc.frame, desc[i].flags);
|
||||||
|
|
||||||
|
if(desc[i].flags & VEHICLE_FLAG_ADD_WHEEL){
|
||||||
|
if(m_wheelId == -1)
|
||||||
|
RwFrameDestroy(assoc.frame);
|
||||||
|
else{
|
||||||
|
RwV3d scale;
|
||||||
|
atomic = (RpAtomic*)CModelInfo::GetModelInfo(m_wheelId)->CreateInstance();
|
||||||
|
RwFrameDestroy(RpAtomicGetFrame(atomic));
|
||||||
|
RpAtomicSetFrame(atomic, assoc.frame);
|
||||||
|
RpClumpAddAtomic(m_clump, atomic);
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic,
|
||||||
|
CVisibilityPlugins::RenderWheelAtomicCB);
|
||||||
|
scale.x = m_wheelScale;
|
||||||
|
scale.y = m_wheelScale;
|
||||||
|
scale.z = m_wheelScale;
|
||||||
|
RwFrameScale(assoc.frame, &scale, rwCOMBINEPRECONCAT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define COMPRULE_RULE(comprule) (((comprule) >> 12) & 0xF)
|
||||||
|
#define COMPRULE_COMPS(comprule) ((comprule) & 0xFFF)
|
||||||
|
#define COMPRULE_COMPN(comps, n) (((comps) >> 4*(n)) & 0xF)
|
||||||
|
#define COMPRULE2_RULE(comprule) (((comprule) >> (12+16)) & 0xF)
|
||||||
|
#define COMPRULE2_COMPS(comprule) ((comprule >> 16) & 0xFFF)
|
||||||
|
#define COMPRULE2_COMPN(comps, n) (((comps >> 16) >> 4*(n)) & 0xF)
|
||||||
|
|
||||||
|
bool
|
||||||
|
IsValidCompRule(int rule)
|
||||||
|
{
|
||||||
|
if(rule == 2)
|
||||||
|
return CWeather::OldWeatherType == WEATHER_RAINY ||
|
||||||
|
CWeather::NewWeatherType == WEATHER_RAINY;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
CountCompsInRule(int comps)
|
||||||
|
{
|
||||||
|
int32 n;
|
||||||
|
for(n = 0; comps != 0; comps >>= 4)
|
||||||
|
if((comps & 0xF) != 0xF)
|
||||||
|
n++;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
ChooseComponent(int32 rule, int32 comps)
|
||||||
|
{
|
||||||
|
int32 n;
|
||||||
|
switch(rule){
|
||||||
|
// identical cases....
|
||||||
|
case 1:
|
||||||
|
n = CGeneral::GetRandomNumberInRange(0, CountCompsInRule(comps));
|
||||||
|
return COMPRULE_COMPN(comps, n);
|
||||||
|
case 2:
|
||||||
|
// only valid in rain
|
||||||
|
n = CGeneral::GetRandomNumberInRange(0, CountCompsInRule(comps));
|
||||||
|
return COMPRULE_COMPN(comps, n);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
GetListOfComponentsNotUsedByRules(uint32 comprules, int32 numComps, int32 *comps)
|
||||||
|
{
|
||||||
|
int32 i, n;
|
||||||
|
int32 unused[6] = { 0, 1, 2, 3, 4, 5 };
|
||||||
|
|
||||||
|
// first comprule
|
||||||
|
if(COMPRULE_RULE(comprules) && IsValidCompRule(COMPRULE_RULE(comprules)))
|
||||||
|
for(i = 0; i < 3; i++){
|
||||||
|
n = COMPRULE_COMPN(comprules, i);
|
||||||
|
if(n != 0xF)
|
||||||
|
unused[n] = 0xF;
|
||||||
|
}
|
||||||
|
// second comprule
|
||||||
|
comprules >>= 16;
|
||||||
|
if(COMPRULE_RULE(comprules) && IsValidCompRule(COMPRULE_RULE(comprules)))
|
||||||
|
for(i = 0; i < 3; i++){
|
||||||
|
n = COMPRULE_COMPN(comprules, i);
|
||||||
|
if(n != 0xF)
|
||||||
|
unused[n] = 0xF;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
for(i = 0; i < numComps; i++)
|
||||||
|
if(unused[i] != 0xF)
|
||||||
|
comps[n++] = unused[i];
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 wheelIds[] = { CAR_WHEEL_LF, CAR_WHEEL_LB, CAR_WHEEL_RF, CAR_WHEEL_RB };
|
||||||
|
|
||||||
|
void
|
||||||
|
CVehicleModelInfo::GetWheelPosn(int32 n, CVector &pos)
|
||||||
|
{
|
||||||
|
RwMatrix *m = RwFrameGetMatrix(GetFrameFromId(m_clump, wheelIds[n]));
|
||||||
|
pos.x = RwMatrixGetPos(m)->x;
|
||||||
|
pos.y = RwMatrixGetPos(m)->y;
|
||||||
|
pos.z = RwMatrixGetPos(m)->z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
CVehicleModelInfo::ChooseComponent(void)
|
||||||
|
{
|
||||||
|
int32 comp;
|
||||||
|
int32 comps[8];
|
||||||
|
int32 n;
|
||||||
|
|
||||||
|
comp = -1;
|
||||||
|
if(ms_compsToUse[0] == -2){
|
||||||
|
if(COMPRULE_RULE(m_compRules) && IsValidCompRule(COMPRULE_RULE(m_compRules)))
|
||||||
|
comp = ::ChooseComponent(COMPRULE_RULE(m_compRules), COMPRULE_COMPS(m_compRules));
|
||||||
|
else if(CGeneral::GetRandomNumberInRange(0, 3) < 2){
|
||||||
|
n = GetListOfComponentsNotUsedByRules(m_compRules, m_numComps, comps);
|
||||||
|
if(n)
|
||||||
|
comp = comps[(int)CGeneral::GetRandomNumberInRange(0, n)];
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
comp = ms_compsToUse[0];
|
||||||
|
ms_compsToUse[0] = -2;
|
||||||
|
}
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
CVehicleModelInfo::ChooseSecondComponent(void)
|
||||||
|
{
|
||||||
|
int32 comp;
|
||||||
|
int32 comps[8];
|
||||||
|
int32 n;
|
||||||
|
|
||||||
|
comp = -1;
|
||||||
|
if(ms_compsToUse[1] == -2){
|
||||||
|
if(COMPRULE2_RULE(m_compRules) && IsValidCompRule(COMPRULE2_RULE(m_compRules)))
|
||||||
|
comp = ::ChooseComponent(COMPRULE2_RULE(m_compRules), COMPRULE2_COMPS(m_compRules));
|
||||||
|
else if(COMPRULE_RULE(m_compRules) && IsValidCompRule(COMPRULE_RULE(m_compRules)) &&
|
||||||
|
CGeneral::GetRandomNumberInRange(0, 3) < 2){
|
||||||
|
|
||||||
|
n = GetListOfComponentsNotUsedByRules(m_compRules, m_numComps, comps);
|
||||||
|
if(n)
|
||||||
|
comp = comps[(int)CGeneral::GetRandomNumberInRange(0, n)];
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
comp = ms_compsToUse[1];
|
||||||
|
ms_compsToUse[1] = -2;
|
||||||
|
}
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct editableMatCBData
|
||||||
|
{
|
||||||
|
CVehicleModelInfo *vehicle;
|
||||||
|
int32 numMats1;
|
||||||
|
int32 numMats2;
|
||||||
|
};
|
||||||
|
|
||||||
|
RpMaterial*
|
||||||
|
CVehicleModelInfo::GetEditableMaterialListCB(RpMaterial *material, void *data)
|
||||||
|
{
|
||||||
|
static RwRGBA white = { 255, 255, 255, 255 };
|
||||||
|
RwRGBA *col;
|
||||||
|
editableMatCBData *cbdata;
|
||||||
|
|
||||||
|
cbdata = (editableMatCBData*)data;
|
||||||
|
col = RpMaterialGetColor(material);
|
||||||
|
if(col->red == 0x3C && col->green == 0xFF && col->blue == 0){
|
||||||
|
cbdata->vehicle->m_materials1[cbdata->numMats1++] = material;
|
||||||
|
RpMaterialSetColor(material, &white);
|
||||||
|
}else if(col->red == 0xFF && col->green == 0 && col->blue == 0xAF){
|
||||||
|
cbdata->vehicle->m_materials2[cbdata->numMats2++] = material;
|
||||||
|
RpMaterialSetColor(material, &white);
|
||||||
|
}
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
CVehicleModelInfo::GetEditableMaterialListCB(RpAtomic *atomic, void *data)
|
||||||
|
{
|
||||||
|
RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), GetEditableMaterialListCB, data);
|
||||||
|
return atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CVehicleModelInfo::FindEditableMaterialList(void)
|
||||||
|
{
|
||||||
|
editableMatCBData cbdata;
|
||||||
|
int32 i;
|
||||||
|
|
||||||
|
cbdata.vehicle = this;
|
||||||
|
cbdata.numMats1 = 0;
|
||||||
|
cbdata.numMats2 = 0;
|
||||||
|
RpClumpForAllAtomics(m_clump, GetEditableMaterialListCB, &cbdata);
|
||||||
|
for(i = 0; i < m_numComps; i++)
|
||||||
|
GetEditableMaterialListCB(m_comps[i], &cbdata);
|
||||||
|
m_materials1[cbdata.numMats1] = nil;
|
||||||
|
m_materials2[cbdata.numMats2] = nil;
|
||||||
|
m_currentColour1 = -1;
|
||||||
|
m_currentColour2 = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CVehicleModelInfo::SetVehicleColour(uint8 c1, uint8 c2)
|
||||||
|
{
|
||||||
|
RwRGBA col, *colp;
|
||||||
|
RwTexture *coltex;
|
||||||
|
RpMaterial **matp;
|
||||||
|
|
||||||
|
if(c1 != m_currentColour1){
|
||||||
|
col = ms_vehicleColourTable[c1];
|
||||||
|
coltex = ms_colourTextureTable[c1];
|
||||||
|
for(matp = m_materials1; *matp; matp++){
|
||||||
|
if(RpMaterialGetTexture(*matp) && RpMaterialGetTexture(*matp)->name[0] != '@'){
|
||||||
|
colp = RpMaterialGetColor(*matp);
|
||||||
|
colp->red = col.red;
|
||||||
|
colp->green = col.green;
|
||||||
|
colp->blue = col.blue;
|
||||||
|
}else
|
||||||
|
RpMaterialSetTexture(*matp, coltex);
|
||||||
|
}
|
||||||
|
m_currentColour1 = c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(c2 != m_currentColour2){
|
||||||
|
col = ms_vehicleColourTable[c2];
|
||||||
|
coltex = ms_colourTextureTable[c2];
|
||||||
|
for(matp = m_materials2; *matp; matp++){
|
||||||
|
if(RpMaterialGetTexture(*matp) && RpMaterialGetTexture(*matp)->name[0] != '@'){
|
||||||
|
colp = RpMaterialGetColor(*matp);
|
||||||
|
colp->red = col.red;
|
||||||
|
colp->green = col.green;
|
||||||
|
colp->blue = col.blue;
|
||||||
|
}else
|
||||||
|
RpMaterialSetTexture(*matp, coltex);
|
||||||
|
}
|
||||||
|
m_currentColour2 = c2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RpMaterial*
|
||||||
|
CVehicleModelInfo::HasSpecularMaterialCB(RpMaterial *material, void *data)
|
||||||
|
{
|
||||||
|
if(RpMaterialGetSurfaceProperties(material)->specular <= 0.0f)
|
||||||
|
return material;
|
||||||
|
*(bool*)data = true;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpMaterial*
|
||||||
|
CVehicleModelInfo::SetEnvironmentMapCB(RpMaterial *material, void *data)
|
||||||
|
{
|
||||||
|
float spec;
|
||||||
|
|
||||||
|
spec = RpMaterialGetSurfaceProperties(material)->specular;
|
||||||
|
if(spec <= 0.0f)
|
||||||
|
RpMatFXMaterialSetEffects(material, rpMATFXEFFECTNULL);
|
||||||
|
else{
|
||||||
|
if(RpMaterialGetTexture(material) == 0)
|
||||||
|
RpMaterialSetTexture(material, gpWhiteTexture);
|
||||||
|
RpMatFXMaterialSetEffects(material, rpMATFXEFFECTENVMAP);
|
||||||
|
spec *= 0.5f; // Tone down a bit for PC
|
||||||
|
RpMatFXMaterialSetupEnvMap(material, (RwTexture*)data, pMatFxIdentityFrame, false, spec);
|
||||||
|
}
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpAtomic*
|
||||||
|
CVehicleModelInfo::SetEnvironmentMapCB(RpAtomic *atomic, void *data)
|
||||||
|
{
|
||||||
|
bool hasSpec;
|
||||||
|
RpGeometry *geo;
|
||||||
|
|
||||||
|
geo = RpAtomicGetGeometry(atomic);
|
||||||
|
hasSpec = 0;
|
||||||
|
RpGeometryForAllMaterials(geo, HasSpecularMaterialCB, &hasSpec);
|
||||||
|
if(hasSpec){
|
||||||
|
RpGeometryForAllMaterials(geo, SetEnvironmentMapCB, data);
|
||||||
|
RpGeometrySetFlags(geo, RpGeometryGetFlags(geo) | rpGEOMETRYMODULATEMATERIALCOLOR);
|
||||||
|
RpMatFXAtomicEnableEffects(atomic);
|
||||||
|
// PS2 sets of PS2Manager lighting CB here
|
||||||
|
}
|
||||||
|
return atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CVehicleModelInfo::SetEnvironmentMap(void)
|
||||||
|
{
|
||||||
|
CSimpleModelInfo *wheelmi;
|
||||||
|
int32 i;
|
||||||
|
|
||||||
|
if(pMatFxIdentityFrame == nil){
|
||||||
|
pMatFxIdentityFrame = RwFrameCreate();
|
||||||
|
RwMatrixSetIdentity(RwFrameGetMatrix(pMatFxIdentityFrame));
|
||||||
|
RwFrameUpdateObjects(pMatFxIdentityFrame);
|
||||||
|
RwFrameGetLTM(pMatFxIdentityFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_envMap != ms_pEnvironmentMaps[0]){
|
||||||
|
m_envMap = ms_pEnvironmentMaps[0];
|
||||||
|
RpClumpForAllAtomics(m_clump, SetEnvironmentMapCB, m_envMap);
|
||||||
|
if(m_wheelId != -1){
|
||||||
|
wheelmi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(m_wheelId);
|
||||||
|
for(i = 0; i < wheelmi->m_numAtomics; i++)
|
||||||
|
SetEnvironmentMapCB(wheelmi->m_atomics[i], m_envMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CVehicleModelInfo::LoadEnvironmentMaps(void)
|
||||||
|
{
|
||||||
|
char *texnames[] = {
|
||||||
|
"reflection01", // only one used
|
||||||
|
"reflection02",
|
||||||
|
"reflection03",
|
||||||
|
"reflection04",
|
||||||
|
"reflection05",
|
||||||
|
"reflection06",
|
||||||
|
};
|
||||||
|
int32 txdslot;
|
||||||
|
int32 i;
|
||||||
|
|
||||||
|
txdslot = CTxdStore::FindTxdSlot("particle");
|
||||||
|
CTxdStore::PushCurrentTxd();
|
||||||
|
CTxdStore::SetCurrentTxd(txdslot);
|
||||||
|
for(i = 0; i < NUM_VEHICLE_ENVMAPS; i++){
|
||||||
|
ms_pEnvironmentMaps[i] = RwTextureRead(texnames[i], nil);
|
||||||
|
RwTextureSetFilterMode(ms_pEnvironmentMaps[i], rwFILTERLINEAR);
|
||||||
|
}
|
||||||
|
if(gpWhiteTexture == nil){
|
||||||
|
gpWhiteTexture = RwTextureRead("white", nil);
|
||||||
|
gpWhiteTexture->name[0] = '@';
|
||||||
|
RwTextureSetFilterMode(gpWhiteTexture, rwFILTERLINEAR);
|
||||||
|
}
|
||||||
|
CTxdStore::PopCurrentTxd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CVehicleModelInfo::ShutdownEnvironmentMaps(void)
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
|
||||||
|
// ignoring "initialised" as that's a PS2 thing only
|
||||||
|
RwTextureDestroy(gpWhiteTexture);
|
||||||
|
gpWhiteTexture = nil;
|
||||||
|
for(i = 0; i < NUM_VEHICLE_ENVMAPS; i++)
|
||||||
|
if(ms_pEnvironmentMaps[i])
|
||||||
|
RwTextureDestroy(ms_pEnvironmentMaps[i]);
|
||||||
|
RwFrameDestroy(pMatFxIdentityFrame);
|
||||||
|
pMatFxIdentityFrame = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x51FDC0, &CVehicleModelInfo::DeleteRwObject_, PATCH_JUMP);
|
||||||
|
InjectHook(0x51FCB0, &CVehicleModelInfo::CreateInstance_, PATCH_JUMP);
|
||||||
|
InjectHook(0x51FC60, &CVehicleModelInfo::SetClump_, PATCH_JUMP);
|
||||||
|
|
||||||
|
InjectHook(0x51FE10, &CVehicleModelInfo::CollapseFramesCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x51FE50, &CVehicleModelInfo::MoveObjectsCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x51FE70, &CVehicleModelInfo::HideDamagedAtomicCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x51FEF0, &CVehicleModelInfo::HasAlphaMaterialCB, PATCH_JUMP);
|
||||||
|
|
||||||
|
InjectHook(0x51FF10, &CVehicleModelInfo::SetAtomicRendererCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x520030, &CVehicleModelInfo::SetAtomicRendererCB_BigVehicle, PATCH_JUMP);
|
||||||
|
InjectHook(0x520230, &CVehicleModelInfo::SetAtomicRendererCB_Train, PATCH_JUMP);
|
||||||
|
InjectHook(0x520120, &CVehicleModelInfo::SetAtomicRendererCB_Boat, PATCH_JUMP);
|
||||||
|
InjectHook(0x520210, &CVehicleModelInfo::SetAtomicRendererCB_Heli, PATCH_JUMP);
|
||||||
|
InjectHook(0x5202C0, &CVehicleModelInfo::SetAtomicRenderCallbacks, PATCH_JUMP);
|
||||||
|
|
||||||
|
InjectHook(0x520340, &CVehicleModelInfo::SetAtomicFlagCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x520360, &CVehicleModelInfo::ClearAtomicFlagCB, PATCH_JUMP);
|
||||||
|
|
||||||
|
InjectHook(0x5204D0, &CVehicleModelInfo::PreprocessHierarchy, PATCH_JUMP);
|
||||||
|
|
||||||
|
InjectHook(0x520840, &CVehicleModelInfo::GetWheelPosn, PATCH_JUMP);
|
||||||
|
|
||||||
|
InjectHook(0x520880, IsValidCompRule, PATCH_JUMP);
|
||||||
|
InjectHook(0x520990, CountCompsInRule, PATCH_JUMP);
|
||||||
|
InjectHook(0x5209C0, ChooseComponent, PATCH_JUMP);
|
||||||
|
InjectHook(0x5208C0, GetListOfComponentsNotUsedByRules, PATCH_JUMP);
|
||||||
|
InjectHook(0x520AB0, &CVehicleModelInfo::ChooseComponent, PATCH_JUMP);
|
||||||
|
InjectHook(0x520BE0, &CVehicleModelInfo::ChooseSecondComponent, PATCH_JUMP);
|
||||||
|
|
||||||
|
InjectHook(0x520DC0, (RpAtomic *(*)(RpAtomic*, void*))CVehicleModelInfo::GetEditableMaterialListCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x520D30, (RpMaterial *(*)(RpMaterial*, void*))CVehicleModelInfo::GetEditableMaterialListCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x520DE0, &CVehicleModelInfo::FindEditableMaterialList, PATCH_JUMP);
|
||||||
|
InjectHook(0x520E70, &CVehicleModelInfo::SetVehicleColour, PATCH_JUMP);
|
||||||
|
|
||||||
|
InjectHook(0x521820, (RpAtomic *(*)(RpAtomic*, void*))CVehicleModelInfo::SetEnvironmentMapCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x5217A0, (RpMaterial *(*)(RpMaterial*, void*))CVehicleModelInfo::SetEnvironmentMapCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x521770, CVehicleModelInfo::HasSpecularMaterialCB, PATCH_JUMP);
|
||||||
|
InjectHook(0x521890, &CVehicleModelInfo::SetEnvironmentMap, PATCH_JUMP);
|
||||||
|
InjectHook(0x521680, CVehicleModelInfo::LoadEnvironmentMaps, PATCH_JUMP);
|
||||||
|
InjectHook(0x521720, CVehicleModelInfo::ShutdownEnvironmentMaps, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
115
src/modelinfo/VehicleModelInfo.h
Normal file
115
src/modelinfo/VehicleModelInfo.h
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ClumpModelInfo.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NUM_VEHICLE_POSITIONS = 10,
|
||||||
|
NUM_FIRST_MATERIALS = 26,
|
||||||
|
NUM_SECOND_MATERIALS = 26,
|
||||||
|
NUM_VEHICLE_COLOURS = 8,
|
||||||
|
NUM_VEHICLE_ENVMAPS = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ATOMIC_FLAG_OK = 0x1,
|
||||||
|
ATOMIC_FLAG_DAM = 0x2,
|
||||||
|
ATOMIC_FLAG_LEFT = 0x4,
|
||||||
|
ATOMIC_FLAG_RIGHT = 0x8,
|
||||||
|
ATOMIC_FLAG_FRONT = 0x10,
|
||||||
|
ATOMIC_FLAG_REAR = 0x20,
|
||||||
|
ATOMIC_FLAG_DRAWLAST = 0x40,
|
||||||
|
ATOMIC_FLAG_WINDSCREEN = 0x80,
|
||||||
|
ATOMIC_FLAG_ANGLECULL = 0x100,
|
||||||
|
ATOMIC_FLAG_REARDOOR = 0x200,
|
||||||
|
ATOMIC_FLAG_FRONTDOOR = 0x400,
|
||||||
|
ATOMIC_FLAG_NOCULL = 0x800,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VEHICLE_TYPE_CAR,
|
||||||
|
VEHICLE_TYPE_BOAT,
|
||||||
|
VEHICLE_TYPE_TRAIN,
|
||||||
|
VEHICLE_TYPE_HELI,
|
||||||
|
VEHICLE_TYPE_PLANE,
|
||||||
|
VEHICLE_TYPE_BIKE,
|
||||||
|
NUM_VEHICLE_TYPES
|
||||||
|
};
|
||||||
|
|
||||||
|
class CVehicleModelInfo : public CClumpModelInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint8 m_lastColour1;
|
||||||
|
uint8 m_lastColour2;
|
||||||
|
char m_gameName[32];
|
||||||
|
int32 m_vehicleType;
|
||||||
|
int32 m_wheelId;
|
||||||
|
float m_wheelScale;
|
||||||
|
int32 m_numDoors;
|
||||||
|
int32 m_handlingId;
|
||||||
|
int32 m_vehicleClass;
|
||||||
|
int32 m_level;
|
||||||
|
CVector m_positions[NUM_VEHICLE_POSITIONS];
|
||||||
|
uint32 m_compRules;
|
||||||
|
float m_bikeSteerAngle;
|
||||||
|
RpMaterial *m_materials1[NUM_FIRST_MATERIALS];
|
||||||
|
RpMaterial *m_materials2[NUM_SECOND_MATERIALS];
|
||||||
|
uint8 m_colours1[NUM_VEHICLE_COLOURS];
|
||||||
|
uint8 m_colours2[NUM_VEHICLE_COLOURS];
|
||||||
|
uint8 m_numColours;
|
||||||
|
uint8 m_bLastColorVariation; //
|
||||||
|
uint8 m_currentColour1;
|
||||||
|
uint8 m_currentColour2;
|
||||||
|
RwTexture *m_envMap;
|
||||||
|
RpAtomic *m_comps[6];
|
||||||
|
int32 m_numComps;
|
||||||
|
|
||||||
|
static int8 *ms_compsToUse; // [2];
|
||||||
|
static int8 *ms_compsUsed; // [2];
|
||||||
|
static RwTexture **ms_pEnvironmentMaps; // [NUM_VEHICLE_ENVMAPS]
|
||||||
|
static RwRGBA *ms_vehicleColourTable; // [256]
|
||||||
|
static RwTexture **ms_colourTextureTable; // [256]
|
||||||
|
static RwObjectNameIdAssocation *ms_vehicleDescs[NUM_VEHICLE_TYPES];
|
||||||
|
|
||||||
|
CVehicleModelInfo(void);
|
||||||
|
void DeleteRwObject(void);
|
||||||
|
RwObject *CreateInstance(void);
|
||||||
|
void SetClump(RpClump *);
|
||||||
|
|
||||||
|
static RwFrame *CollapseFramesCB(RwFrame *frame, void *data);
|
||||||
|
static RwObject *MoveObjectsCB(RwObject *object, void *data);
|
||||||
|
static RpAtomic *HideDamagedAtomicCB(RpAtomic *atomic, void *data);
|
||||||
|
static RpMaterial *HasAlphaMaterialCB(RpMaterial *material, void *data);
|
||||||
|
|
||||||
|
static RpAtomic *SetAtomicRendererCB(RpAtomic *atomic, void *data);
|
||||||
|
static RpAtomic *SetAtomicRendererCB_BigVehicle(RpAtomic *atomic, void *data);
|
||||||
|
static RpAtomic *SetAtomicRendererCB_Train(RpAtomic *atomic, void *data);
|
||||||
|
static RpAtomic *SetAtomicRendererCB_Boat(RpAtomic *atomic, void *data);
|
||||||
|
static RpAtomic *SetAtomicRendererCB_Heli(RpAtomic *atomic, void *data);
|
||||||
|
void SetAtomicRenderCallbacks(void);
|
||||||
|
|
||||||
|
static RpAtomic *SetAtomicFlagCB(RpAtomic *atomic, void *data);
|
||||||
|
static RpAtomic *ClearAtomicFlagCB(RpAtomic *atomic, void *data);
|
||||||
|
void SetVehicleComponentFlags(RwFrame *frame, uint32 flags);
|
||||||
|
void PreprocessHierarchy(void);
|
||||||
|
void GetWheelPosn(int32 n, CVector &pos);
|
||||||
|
|
||||||
|
int32 ChooseComponent(void);
|
||||||
|
int32 ChooseSecondComponent(void);
|
||||||
|
|
||||||
|
static RpMaterial *GetEditableMaterialListCB(RpMaterial *material, void *data);
|
||||||
|
static RpAtomic *GetEditableMaterialListCB(RpAtomic *atomic, void *data);
|
||||||
|
void FindEditableMaterialList(void);
|
||||||
|
void SetVehicleColour(uint8 c1, uint8 c2);
|
||||||
|
|
||||||
|
static RpAtomic *SetEnvironmentMapCB(RpAtomic *atomic, void *data);
|
||||||
|
static RpMaterial *SetEnvironmentMapCB(RpMaterial *material, void *data);
|
||||||
|
static RpMaterial *HasSpecularMaterialCB(RpMaterial *material, void *data);
|
||||||
|
void SetEnvironmentMap(void);
|
||||||
|
static void LoadEnvironmentMaps(void);
|
||||||
|
static void ShutdownEnvironmentMaps(void);
|
||||||
|
|
||||||
|
void DeleteRwObject_(void) { this->CVehicleModelInfo::DeleteRwObject(); }
|
||||||
|
RwObject *CreateInstance_(void) { return this->CVehicleModelInfo::CreateInstance(); }
|
||||||
|
void SetClump_(RpClump *clump) { this->CVehicleModelInfo::SetClump(clump); }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CVehicleModelInfo) == 0x1F8, "CVehicleModelInfo: error");
|
22
src/patcher.cpp
Normal file
22
src/patcher.cpp
Normal 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;
|
||||||
|
}
|
171
src/patcher.h
Normal file
171
src/patcher.h
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
#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
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PATCH_CALL,
|
||||||
|
PATCH_JUMP,
|
||||||
|
PATCH_NOTHING,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
III_10 = 1,
|
||||||
|
III_11,
|
||||||
|
III_STEAM,
|
||||||
|
VC_10,
|
||||||
|
VC_11,
|
||||||
|
VC_STEAM
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int gtaversion;
|
||||||
|
|
||||||
|
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, typename HT> inline void
|
||||||
|
InjectHook(AT address, HT hook, unsigned int nType=PATCH_NOTHING)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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();
|
||||||
|
};
|
||||||
|
|
||||||
|
#define STARTPATCHES static StaticPatcher Patcher([](){
|
||||||
|
#define ENDPATCHES });
|
39
src/render/2dEffect.h
Normal file
39
src/render/2dEffect.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
class C2dEffect
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Light {
|
||||||
|
float dist;
|
||||||
|
float outerRange;
|
||||||
|
float size;
|
||||||
|
float innerRange;
|
||||||
|
uint8 flash;
|
||||||
|
uint8 wet;
|
||||||
|
uint8 flare;
|
||||||
|
uint8 shadowIntens;
|
||||||
|
uint8 flag;
|
||||||
|
RwTexture *corona;
|
||||||
|
RwTexture *shadow;
|
||||||
|
};
|
||||||
|
struct Particle {
|
||||||
|
int particleType;
|
||||||
|
float dir[3];
|
||||||
|
float scale;
|
||||||
|
};
|
||||||
|
struct Attractor {
|
||||||
|
CVector dir;
|
||||||
|
uint8 flag;
|
||||||
|
uint8 probability;
|
||||||
|
};
|
||||||
|
|
||||||
|
CVector pos;
|
||||||
|
RwRGBA col;
|
||||||
|
uint8 type;
|
||||||
|
union {
|
||||||
|
Light light;
|
||||||
|
Particle particle;
|
||||||
|
Attractor attractor;
|
||||||
|
};
|
||||||
|
|
||||||
|
C2dEffect(void) {}
|
||||||
|
};
|
||||||
|
static_assert(sizeof(C2dEffect) == 0x34, "C2dEffect: error");
|
430
src/render/Clouds.cpp
Normal file
430
src/render/Clouds.cpp
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Sprite.h"
|
||||||
|
#include "General.h"
|
||||||
|
#include "Coronas.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
#include "TxdStore.h"
|
||||||
|
#include "Weather.h"
|
||||||
|
#include "Clock.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "Timecycle.h"
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include "Clouds.h"
|
||||||
|
|
||||||
|
#define SMALLSTRIPHEIGHT 4.0f
|
||||||
|
#define HORIZSTRIPHEIGHT 48.0f
|
||||||
|
|
||||||
|
RwTexture **gpCloudTex = (RwTexture**)0x9411C0; //[5];
|
||||||
|
|
||||||
|
float &CClouds::CloudRotation = *(float*)0x8F5F40;
|
||||||
|
uint32 &CClouds::IndividualRotation = *(uint32*)0x943078;
|
||||||
|
|
||||||
|
float &CClouds::ms_cameraRoll = *(float*)0x8F29CC;
|
||||||
|
float &CClouds::ms_horizonZ = *(float*)0x8F31C0;
|
||||||
|
CRGBA &CClouds::ms_colourTop = *(CRGBA*)0x94143C;
|
||||||
|
CRGBA &CClouds::ms_colourBottom = *(CRGBA*)0x8F2C38;
|
||||||
|
|
||||||
|
void
|
||||||
|
CClouds::Init(void)
|
||||||
|
{
|
||||||
|
CTxdStore::PushCurrentTxd();
|
||||||
|
CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("particle"));
|
||||||
|
gpCloudTex[0] = RwTextureRead("cloud1", nil);
|
||||||
|
gpCloudTex[1] = RwTextureRead("cloud2", nil);
|
||||||
|
gpCloudTex[2] = RwTextureRead("cloud3", nil);
|
||||||
|
gpCloudTex[3] = RwTextureRead("cloudhilit", nil);
|
||||||
|
gpCloudTex[4] = RwTextureRead("cloudmasked", nil);
|
||||||
|
CTxdStore::PopCurrentTxd();
|
||||||
|
CloudRotation = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClouds::Update(void)
|
||||||
|
{
|
||||||
|
float s = sin(TheCamera.Orientation - 0.85f);
|
||||||
|
CloudRotation += CWeather::Wind*s*0.0025f;
|
||||||
|
IndividualRotation += (CWeather::Wind*CTimer::GetTimeStep() + 0.3f) * 60.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CClouds::Render(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
float szx, szy;
|
||||||
|
RwV3d screenpos;
|
||||||
|
RwV3d worldpos;
|
||||||
|
|
||||||
|
CCoronas::SunBlockedByClouds = false;
|
||||||
|
|
||||||
|
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
|
||||||
|
CSprite::InitSpriteBuffer();
|
||||||
|
|
||||||
|
int minute = CClock::GetHours()*60 + CClock::GetMinutes();
|
||||||
|
RwV3d campos = *(RwV3d*)&TheCamera.GetPosition();
|
||||||
|
|
||||||
|
float coverage = CWeather::CloudCoverage <= CWeather::Foggyness ? CWeather::Foggyness : CWeather::CloudCoverage;
|
||||||
|
|
||||||
|
// Moon
|
||||||
|
int moonfadeout = abs(minute - 180); // fully visible at 3AM
|
||||||
|
if(moonfadeout < 180){ // fade in/out 3 hours
|
||||||
|
int brightness = (1.0f - coverage) * (180 - moonfadeout);
|
||||||
|
RwV3d pos = { 0.0f, -100.0f, 15.0f };
|
||||||
|
RwV3dAdd(&worldpos, &campos, &pos);
|
||||||
|
if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){
|
||||||
|
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[2]->raster);
|
||||||
|
if(CCoronas::bSmallMoon){
|
||||||
|
szx *= 4.0f;
|
||||||
|
szy *= 4.0f;
|
||||||
|
}else{
|
||||||
|
szx *= 10.0f;
|
||||||
|
szy *= 10.0f;
|
||||||
|
}
|
||||||
|
CSprite::RenderOneXLUSprite(screenpos.x, screenpos.y, screenpos.z,
|
||||||
|
szx, szy, brightness, brightness, brightness, 255, 1.0f/screenpos.z, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The R* logo
|
||||||
|
int starintens = 0;
|
||||||
|
if(CClock::GetHours() < 22 && CClock::GetHours() > 5)
|
||||||
|
starintens = 0;
|
||||||
|
else if(CClock::GetHours() > 22 || CClock::GetHours() < 5)
|
||||||
|
starintens = 255;
|
||||||
|
else if(CClock::GetHours() == 22)
|
||||||
|
starintens = 255 * CClock::GetMinutes()/60.0f;
|
||||||
|
else if(CClock::GetHours() == 5)
|
||||||
|
starintens = 255 * (60 - CClock::GetMinutes())/60.0f;
|
||||||
|
if(starintens != 0){
|
||||||
|
// R
|
||||||
|
static float StarCoorsX[9] = { 0.0f, 0.05f, 0.12f, 0.5f, 0.8f, 0.6f, 0.27f, 0.55f, 0.75f };
|
||||||
|
static float StarCoorsY[9] = { 0.0f, 0.45f, 0.9f, 1.0f, 0.85f, 0.52f, 0.48f, 0.35f, 0.2f };
|
||||||
|
static float StarSizes[9] = { 1.0f, 1.4f, 0.9f, 1.0f, 0.6f, 1.5f, 1.3f, 1.0f, 0.8f };
|
||||||
|
int brightness = (1.0f - coverage) * starintens;
|
||||||
|
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[0]->raster);
|
||||||
|
for(i = 0; i < 11; i++){
|
||||||
|
RwV3d pos = { 100.0f, 0.0f, 10.0f };
|
||||||
|
if(i >= 9) pos.x = -pos.x;
|
||||||
|
RwV3dAdd(&worldpos, &campos, &pos);
|
||||||
|
worldpos.y -= 90.0f*StarCoorsX[i%9];
|
||||||
|
worldpos.z += 80.0f*StarCoorsY[i%9];
|
||||||
|
if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){
|
||||||
|
float sz = 0.8f*StarSizes[i%9];
|
||||||
|
CSprite::RenderBufferedOneXLUSprite(screenpos.x, screenpos.y, screenpos.z,
|
||||||
|
szx*sz, szy*sz, brightness, brightness, brightness, 255, 1.0f/screenpos.z, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CSprite::FlushSpriteBuffer();
|
||||||
|
|
||||||
|
// *
|
||||||
|
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[0]->raster);
|
||||||
|
RwV3d pos = { 100.0f, 0.0f, 10.0f };
|
||||||
|
RwV3dAdd(&worldpos, &campos, &pos);
|
||||||
|
worldpos.y -= 90.0f;
|
||||||
|
if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){
|
||||||
|
brightness *= (CGeneral::GetRandomNumber()&127) / 640.0f + 0.5f;
|
||||||
|
CSprite::RenderOneXLUSprite(screenpos.x, screenpos.y, screenpos.z,
|
||||||
|
szx*5.0f, szy*5.0f, brightness, brightness, brightness, 255, 1.0f/screenpos.z, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Low clouds
|
||||||
|
static float LowCloudsX[12] = { 1.0f, 0.7f, 0.0f, -0.7f, -1.0f, -0.7f,
|
||||||
|
0.0f, 0.7f, 0.8f, -0.8f, 0.4f, -0.4f };
|
||||||
|
static float LowCloudsY[12] = { 0.0f, -0.7f, -1.0f, -0.7f, 0.0f, 0.7f,
|
||||||
|
1.0f, 0.7f, 0.4f, 0.4f, -0.8f, -0.8f };
|
||||||
|
static float LowCloudsZ[12] = { 0.0f, 1.0f, 0.5f, 0.0f, 1.0f, 0.3f,
|
||||||
|
0.9f, 0.4f, 1.3f, 1.4f, 1.2f, 1.7f };
|
||||||
|
float lowcloudintensity = 1.0f - coverage;
|
||||||
|
int r = CTimeCycle::GetLowCloudsRed() * lowcloudintensity;
|
||||||
|
int g = CTimeCycle::GetLowCloudsGreen() * lowcloudintensity;
|
||||||
|
int b = CTimeCycle::GetLowCloudsBlue() * lowcloudintensity;
|
||||||
|
for(int cloudtype = 0; cloudtype < 3; cloudtype++){
|
||||||
|
for(i = cloudtype; i < 12; i += 3){
|
||||||
|
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCloudTex[cloudtype]->raster);
|
||||||
|
RwV3d pos = { 800.0f*LowCloudsX[i], 800.0f*LowCloudsY[i], 60.0f*LowCloudsZ[i] };
|
||||||
|
worldpos.x = campos.x + pos.x;
|
||||||
|
worldpos.y = campos.y + pos.y;
|
||||||
|
worldpos.z = 40.0f + pos.z;
|
||||||
|
if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false))
|
||||||
|
CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(screenpos.x, screenpos.y, screenpos.z,
|
||||||
|
szx*320.0f, szy*40.0f, r, g, b, 255, 1.0f/screenpos.z, ms_cameraRoll, 255);
|
||||||
|
}
|
||||||
|
CSprite::FlushSpriteBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fluffy clouds
|
||||||
|
float rot_sin = sin(CloudRotation);
|
||||||
|
float rot_cos = cos(CloudRotation);
|
||||||
|
int fluffyalpha = 160 * (1.0f - CWeather::Foggyness);
|
||||||
|
if(fluffyalpha != 0){
|
||||||
|
static float CoorsOffsetX[37] = {
|
||||||
|
0.0f, 60.0f, 72.0f, 48.0f, 21.0f, 12.0f,
|
||||||
|
9.0f, -3.0f, -8.4f, -18.0f, -15.0f, -36.0f,
|
||||||
|
-40.0f, -48.0f, -60.0f, -24.0f, 100.0f, 100.0f,
|
||||||
|
100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f,
|
||||||
|
100.0f, 100.0f, -30.0f, -20.0f, 10.0f, 30.0f,
|
||||||
|
0.0f, -100.0f, -100.0f, -100.0f, -100.0f, -100.0f, -100.0f
|
||||||
|
};
|
||||||
|
static float CoorsOffsetY[37] = {
|
||||||
|
100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f,
|
||||||
|
100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f,
|
||||||
|
100.0f, 100.0f, 100.0f, 100.0f, -30.0f, 10.0f,
|
||||||
|
-25.0f, -5.0f, 28.0f, -10.0f, 10.0f, 0.0f,
|
||||||
|
15.0f, 40.0f, -100.0f, -100.0f, -100.0f, -100.0f,
|
||||||
|
-100.0f, -40.0f, -20.0f, 0.0f, 10.0f, 30.0f, 35.0f
|
||||||
|
};
|
||||||
|
static float CoorsOffsetZ[37] = {
|
||||||
|
2.0f, 1.0f, 0.0f, 0.3f, 0.7f, 1.4f,
|
||||||
|
1.7f, 0.24f, 0.7f, 1.3f, 1.6f, 1.0f,
|
||||||
|
1.2f, 0.3f, 0.7f, 1.4f, 0.0f, 0.1f,
|
||||||
|
0.5f, 0.4f, 0.55f, 0.75f, 1.0f, 1.4f,
|
||||||
|
1.7f, 2.0f, 2.0f, 2.3f, 1.9f, 2.4f,
|
||||||
|
2.0f, 2.0f, 1.5f, 1.2f, 1.7f, 1.5f, 2.1f
|
||||||
|
};
|
||||||
|
static bool bCloudOnScreen[37];
|
||||||
|
float hilight;
|
||||||
|
|
||||||
|
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
|
||||||
|
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
|
||||||
|
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCloudTex[4]->raster);
|
||||||
|
for(i = 0; i < 37; i++){
|
||||||
|
RwV3d pos = { 2.0f*CoorsOffsetX[i], 2.0f*CoorsOffsetY[i], 40.0f*CoorsOffsetZ[i] + 40.0f };
|
||||||
|
worldpos.x = pos.x*rot_cos + pos.y*rot_sin + campos.x;
|
||||||
|
worldpos.y = pos.x*rot_sin - pos.y*rot_cos + campos.y;
|
||||||
|
worldpos.z = pos.z;
|
||||||
|
|
||||||
|
if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){
|
||||||
|
float sundist = sqrt(sq(screenpos.x-CCoronas::SunScreenX) + sq(screenpos.y-CCoronas::SunScreenY));
|
||||||
|
int tr = CTimeCycle::GetFluffyCloudsTopRed();
|
||||||
|
int tg = CTimeCycle::GetFluffyCloudsTopGreen();
|
||||||
|
int tb = CTimeCycle::GetFluffyCloudsTopBlue();
|
||||||
|
int br = CTimeCycle::GetFluffyCloudsBottomRed();
|
||||||
|
int bg = CTimeCycle::GetFluffyCloudsBottomGreen();
|
||||||
|
int bb = CTimeCycle::GetFluffyCloudsBottomBlue();
|
||||||
|
if(sundist < SCREENW/2){
|
||||||
|
hilight = (1.0f - coverage) * (1.0f - sundist/(SCREENW/2));
|
||||||
|
tr = tr*(1.0f-hilight) + 255*hilight;
|
||||||
|
tg = tg*(1.0f-hilight) + 190*hilight;
|
||||||
|
tb = tb*(1.0f-hilight) + 190*hilight;
|
||||||
|
br = br*(1.0f-hilight) + 255*hilight;
|
||||||
|
bg = bg*(1.0f-hilight) + 190*hilight;
|
||||||
|
bb = bb*(1.0f-hilight) + 190*hilight;
|
||||||
|
if(sundist < SCREENW/10)
|
||||||
|
CCoronas::SunBlockedByClouds = true;
|
||||||
|
}else
|
||||||
|
hilight = 0.0f;
|
||||||
|
CSprite::RenderBufferedOneXLUSprite_Rotate_2Colours(screenpos.x, screenpos.y, screenpos.z,
|
||||||
|
szx*55.0f, szy*55.0f,
|
||||||
|
tr, tg, tb, br, bg, bb, 0.0f, -1.0f,
|
||||||
|
1.0f/screenpos.z,
|
||||||
|
IndividualRotation/65336.0f * 2*3.14f + ms_cameraRoll,
|
||||||
|
fluffyalpha);
|
||||||
|
bCloudOnScreen[i] = true;
|
||||||
|
}else
|
||||||
|
bCloudOnScreen[i] = false;
|
||||||
|
}
|
||||||
|
CSprite::FlushSpriteBuffer();
|
||||||
|
|
||||||
|
// Highlights
|
||||||
|
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCloudTex[3]->raster);
|
||||||
|
|
||||||
|
for(i = 0; i < 37; i++){
|
||||||
|
RwV3d pos = { 2.0f*CoorsOffsetX[i], 2.0f*CoorsOffsetY[i], 40.0f*CoorsOffsetZ[i] + 40.0f };
|
||||||
|
worldpos.x = campos.x*rot_cos + campos.y*rot_sin + pos.x;
|
||||||
|
worldpos.y = campos.x*rot_sin + campos.y*rot_cos + pos.y;
|
||||||
|
worldpos.z = pos.z;
|
||||||
|
if(bCloudOnScreen[i] && CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){
|
||||||
|
// BUG: this is stupid....would have to do this for each cloud individually
|
||||||
|
if(hilight > 0.0f){
|
||||||
|
CSprite::RenderBufferedOneXLUSprite_Rotate_Aspect(screenpos.x, screenpos.y, screenpos.z,
|
||||||
|
szx*30.0f, szy*30.0f,
|
||||||
|
200*hilight, 0, 0, 255, 1.0f/screenpos.z,
|
||||||
|
1.7f - CGeneral::GetATanOfXY(screenpos.x-CCoronas::SunScreenX, screenpos.y-CCoronas::SunScreenY) + CClouds::ms_cameraRoll, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CSprite::FlushSpriteBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rainbow
|
||||||
|
if(CWeather::Rainbow != 0.0f){
|
||||||
|
static uint8 BowRed[6] = { 30, 30, 30, 10, 0, 15 };
|
||||||
|
static uint8 BowGreen[6] = { 0, 15, 30, 30, 0, 0 };
|
||||||
|
static uint8 BowBlue[6] = { 0, 0, 0, 10, 30, 30 };
|
||||||
|
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[0]->raster);
|
||||||
|
for(i = 0; i < 6; i++){
|
||||||
|
RwV3d pos = { i*1.5f, 100.0f, 5.0f };
|
||||||
|
RwV3dAdd(&worldpos, &campos, &pos);
|
||||||
|
if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false))
|
||||||
|
CSprite::RenderBufferedOneXLUSprite(screenpos.x, screenpos.y, screenpos.z,
|
||||||
|
2.0f*szx, 50.0*szy,
|
||||||
|
BowRed[i]*CWeather::Rainbow, BowGreen[i]*CWeather::Rainbow, BowBlue[i]*CWeather::Rainbow,
|
||||||
|
255, 1.0f/screenpos.z, 255);
|
||||||
|
|
||||||
|
}
|
||||||
|
CSprite::FlushSpriteBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
|
||||||
|
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
UseDarkBackground(void)
|
||||||
|
{
|
||||||
|
return RwFrameGetLTM(RwCameraGetFrame(TheCamera.m_pRwCamera))->up.z < -0.9f ||
|
||||||
|
gbShowCollisionPolys;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClouds::RenderBackground(int16 topred, int16 topgreen, int16 topblue,
|
||||||
|
int16 botred, int16 botgreen, int16 botblue, int16 alpha)
|
||||||
|
{
|
||||||
|
RwMatrix *mat = RwFrameGetLTM(RwCameraGetFrame(TheCamera.m_pRwCamera));
|
||||||
|
float c = sqrt(mat->right.x * mat->right.x + mat->right.y * mat->right.y);
|
||||||
|
if(c > 1.0f)
|
||||||
|
c = 1.0f;
|
||||||
|
ms_cameraRoll = acos(c);
|
||||||
|
if(mat->right.z < 0.0f)
|
||||||
|
ms_cameraRoll = -ms_cameraRoll;
|
||||||
|
|
||||||
|
if(UseDarkBackground()){
|
||||||
|
ms_colourTop.r = 50;
|
||||||
|
ms_colourTop.g = 50;
|
||||||
|
ms_colourTop.b = 50;
|
||||||
|
ms_colourTop.a = 255;
|
||||||
|
if(gbShowCollisionPolys){
|
||||||
|
if(CTimer::GetFrameCounter() & 1){
|
||||||
|
ms_colourTop.r = 0;
|
||||||
|
ms_colourTop.g = 0;
|
||||||
|
ms_colourTop.b = 0;
|
||||||
|
}else{
|
||||||
|
ms_colourTop.r = 255;
|
||||||
|
ms_colourTop.g = 255;
|
||||||
|
ms_colourTop.b = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ms_colourBottom = ms_colourTop;
|
||||||
|
CRect r(0, 0, SCREENW, SCREENH);
|
||||||
|
CSprite2d::DrawRect(r, ms_colourBottom, ms_colourBottom, ms_colourTop, ms_colourTop);
|
||||||
|
}else{
|
||||||
|
ms_horizonZ = CSprite::CalcHorizonCoors();
|
||||||
|
|
||||||
|
// Draw top/bottom gradient
|
||||||
|
float gradheight = SCREENH/2.0f;
|
||||||
|
float topedge = ms_horizonZ - gradheight;
|
||||||
|
float botpos, toppos;
|
||||||
|
if(ms_horizonZ > 0.0f && topedge < SCREENH){
|
||||||
|
ms_colourTop.r = topred;
|
||||||
|
ms_colourTop.g = topgreen;
|
||||||
|
ms_colourTop.b = topblue;
|
||||||
|
ms_colourTop.a = alpha;
|
||||||
|
ms_colourBottom.r = botred;
|
||||||
|
ms_colourBottom.g = botgreen;
|
||||||
|
ms_colourBottom.b = botblue;
|
||||||
|
ms_colourBottom.a = alpha;
|
||||||
|
|
||||||
|
if(ms_horizonZ < SCREENH)
|
||||||
|
botpos = ms_horizonZ;
|
||||||
|
else{
|
||||||
|
float f = (ms_horizonZ - SCREENH)/gradheight;
|
||||||
|
ms_colourBottom.r = topred*f + (1.0f-f)*botred;
|
||||||
|
ms_colourBottom.g = topgreen*f + (1.0f-f)*botgreen;
|
||||||
|
ms_colourBottom.b = topblue*f + (1.0f-f)*botblue;
|
||||||
|
botpos = SCREENH;
|
||||||
|
}
|
||||||
|
if(topedge >= 0.0f)
|
||||||
|
toppos = topedge;
|
||||||
|
else{
|
||||||
|
float f = (0.0f - topedge)/gradheight;
|
||||||
|
ms_colourTop.r = botred*f + (1.0f-f)*topred;
|
||||||
|
ms_colourTop.g = botgreen*f + (1.0f-f)*topgreen;
|
||||||
|
ms_colourTop.b = botblue*f + (1.0f-f)*topblue;
|
||||||
|
toppos = 0.0f;
|
||||||
|
}
|
||||||
|
CSprite2d::DrawRect(CRect(0, toppos, SCREENW, botpos),
|
||||||
|
ms_colourBottom, ms_colourBottom, ms_colourTop, ms_colourTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw the small stripe (whatever it's supposed to be)
|
||||||
|
if(ms_horizonZ > -SMALLSTRIPHEIGHT && ms_horizonZ < SCREENH){
|
||||||
|
// Same colour as fog
|
||||||
|
ms_colourTop.r = (topred + 2 * botred) / 3;
|
||||||
|
ms_colourTop.g = (topgreen + 2 * botgreen) / 3;
|
||||||
|
ms_colourTop.b = (topblue + 2 * botblue) / 3;
|
||||||
|
CSprite2d::DrawRect(CRect(0, ms_horizonZ, SCREENW, ms_horizonZ+SMALLSTRIPHEIGHT),
|
||||||
|
ms_colourTop, ms_colourTop, ms_colourTop, ms_colourTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only top
|
||||||
|
if(topedge > 0.0f){
|
||||||
|
ms_colourTop.r = topred;
|
||||||
|
ms_colourTop.g = topgreen;
|
||||||
|
ms_colourTop.b = topblue;
|
||||||
|
ms_colourTop.a = alpha;
|
||||||
|
ms_colourBottom.r = topred;
|
||||||
|
ms_colourBottom.g = topgreen;
|
||||||
|
ms_colourBottom.b = topblue;
|
||||||
|
ms_colourBottom.a = alpha;
|
||||||
|
|
||||||
|
botpos = min(SCREENH, topedge);
|
||||||
|
CSprite2d::DrawRect(CRect(0, 0, SCREENW, botpos),
|
||||||
|
ms_colourBottom, ms_colourBottom, ms_colourTop, ms_colourTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set both to fog colour for RenderHorizon
|
||||||
|
ms_colourTop.r = (topred + 2 * botred) / 3;
|
||||||
|
ms_colourTop.g = (topgreen + 2 * botgreen) / 3;
|
||||||
|
ms_colourTop.b = (topblue + 2 * botblue) / 3;
|
||||||
|
ms_colourBottom.r = (topred + 2 * botred) / 3;
|
||||||
|
ms_colourBottom.g = (topgreen + 2 * botgreen) / 3;
|
||||||
|
ms_colourBottom.b = (topblue + 2 * botblue) / 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClouds::RenderHorizon(void)
|
||||||
|
{
|
||||||
|
if(UseDarkBackground())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ms_colourBottom.a = 230;
|
||||||
|
ms_colourTop.a = 80;
|
||||||
|
|
||||||
|
if(ms_horizonZ > SCREENH)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float z1 = min(ms_horizonZ + SMALLSTRIPHEIGHT, SCREENH);
|
||||||
|
CSprite2d::DrawRectXLU(CRect(0, ms_horizonZ, SCREENW, z1),
|
||||||
|
ms_colourBottom, ms_colourBottom, ms_colourTop, ms_colourTop);
|
||||||
|
|
||||||
|
// This is just weird
|
||||||
|
float a = SCREENH/400.0f * HORIZSTRIPHEIGHT +
|
||||||
|
SCREENH/300.0f * max(TheCamera.GetPosition().z, 0.0f);
|
||||||
|
float b = TheCamera.GetUp().z < 0.0f ?
|
||||||
|
SCREENH :
|
||||||
|
SCREENH * fabs(TheCamera.GetRight().z);
|
||||||
|
float z2 = z1 + (a + b)*TheCamera.LODDistMultiplier;
|
||||||
|
z2 = min(z2, SCREENH);
|
||||||
|
CSprite2d::DrawRect(CRect(0, z1, SCREENW, z2),
|
||||||
|
ms_colourBottom, ms_colourBottom, ms_colourTop, ms_colourTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x4F6C10, CClouds::Init, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F6CE0, CClouds::Update, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F6D90, CClouds::Render, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F7F00, CClouds::RenderBackground, PATCH_JUMP);
|
||||||
|
InjectHook(0x4F85F0, CClouds::RenderHorizon, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
20
src/render/Clouds.h
Normal file
20
src/render/Clouds.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CClouds
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static float &CloudRotation;
|
||||||
|
static uint32 &IndividualRotation;
|
||||||
|
|
||||||
|
static float &ms_cameraRoll;
|
||||||
|
static float &ms_horizonZ;
|
||||||
|
static CRGBA &ms_colourTop;
|
||||||
|
static CRGBA &ms_colourBottom;
|
||||||
|
|
||||||
|
static void Init(void);
|
||||||
|
static void Update(void);
|
||||||
|
static void Render(void);
|
||||||
|
static void RenderBackground(int16 topred, int16 topgreen, int16 topblue,
|
||||||
|
int16 botred, int16 botgreen, int16 botblue, int16 alpha);
|
||||||
|
static void RenderHorizon(void);
|
||||||
|
};
|
10
src/render/Coronas.cpp
Normal file
10
src/render/Coronas.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "Coronas.h"
|
||||||
|
|
||||||
|
RwTexture **gpCoronaTexture = (RwTexture**)0x5FAF44; //[9]
|
||||||
|
|
||||||
|
float &CCoronas::LightsMult = *(float*)0x5FB088; // 1.0
|
||||||
|
float &CCoronas::SunScreenX = *(float*)0x8F4358;
|
||||||
|
float &CCoronas::SunScreenY = *(float*)0x8F4354;
|
||||||
|
bool &CCoronas::bSmallMoon = *(bool*)0x95CD49;
|
||||||
|
bool &CCoronas::SunBlockedByClouds = *(bool*)0x95CD73;
|
13
src/render/Coronas.h
Normal file
13
src/render/Coronas.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern RwTexture **gpCoronaTexture; //[9]
|
||||||
|
|
||||||
|
class CCoronas
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static float &LightsMult;
|
||||||
|
static float &SunScreenY;
|
||||||
|
static float &SunScreenX;
|
||||||
|
static bool &bSmallMoon;
|
||||||
|
static bool &SunBlockedByClouds;
|
||||||
|
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user