diff options
author | Nikolay Korolev <nickvnuk@gmail.com> | 2020-03-28 13:24:55 +0100 |
---|---|---|
committer | Nikolay Korolev <nickvnuk@gmail.com> | 2020-03-28 13:24:55 +0100 |
commit | 9fb101fdd96c82f73f8b09a75a2f248e1ccc0f18 (patch) | |
tree | 6e220fddfcabc63c477335fb1ddccefe7b6d5e0d /src | |
parent | garages part 1 (diff) | |
parent | remove include <new> from common.h (diff) | |
download | re3-9fb101fdd96c82f73f8b09a75a2f248e1ccc0f18.tar re3-9fb101fdd96c82f73f8b09a75a2f248e1ccc0f18.tar.gz re3-9fb101fdd96c82f73f8b09a75a2f248e1ccc0f18.tar.bz2 re3-9fb101fdd96c82f73f8b09a75a2f248e1ccc0f18.tar.lz re3-9fb101fdd96c82f73f8b09a75a2f248e1ccc0f18.tar.xz re3-9fb101fdd96c82f73f8b09a75a2f248e1ccc0f18.tar.zst re3-9fb101fdd96c82f73f8b09a75a2f248e1ccc0f18.zip |
Diffstat (limited to '')
68 files changed, 6494 insertions, 2120 deletions
diff --git a/src/animation/AnimBlendAssociation.cpp b/src/animation/AnimBlendAssociation.cpp index ec42191b..246322ba 100644 --- a/src/animation/AnimBlendAssociation.cpp +++ b/src/animation/AnimBlendAssociation.cpp @@ -203,6 +203,15 @@ CAnimBlendAssociation::UpdateBlend(float timeDelta) return true; } +#include <new> + +class CAnimBlendAssociation_ : public CAnimBlendAssociation +{ +public: + CAnimBlendAssociation *ctor1(void) { return ::new (this) CAnimBlendAssociation(); } + CAnimBlendAssociation *ctor2(CAnimBlendAssociation &other) { return ::new (this) CAnimBlendAssociation(other); } + void dtor(void) { this->CAnimBlendAssociation::~CAnimBlendAssociation(); } +}; STARTPATCHES InjectHook(0x4016A0, &CAnimBlendAssociation::AllocateAnimBlendNodeArray, PATCH_JUMP); @@ -219,7 +228,7 @@ STARTPATCHES InjectHook(0x4031F0, &CAnimBlendAssociation::UpdateTime, PATCH_JUMP); InjectHook(0x4032B0, &CAnimBlendAssociation::UpdateBlend, PATCH_JUMP); - InjectHook(0x401460, &CAnimBlendAssociation::ctor1, PATCH_JUMP); - InjectHook(0x4014C0, &CAnimBlendAssociation::ctor2, PATCH_JUMP); - InjectHook(0x401520, &CAnimBlendAssociation::dtor, PATCH_JUMP); + InjectHook(0x401460, &CAnimBlendAssociation_::ctor1, PATCH_JUMP); + InjectHook(0x4014C0, &CAnimBlendAssociation_::ctor2, PATCH_JUMP); + InjectHook(0x401520, &CAnimBlendAssociation_::dtor, PATCH_JUMP); ENDPATCHES diff --git a/src/animation/AnimBlendAssociation.h b/src/animation/AnimBlendAssociation.h index aec28f56..d35db1db 100644 --- a/src/animation/AnimBlendAssociation.h +++ b/src/animation/AnimBlendAssociation.h @@ -85,9 +85,5 @@ public: static CAnimBlendAssociation *FromLink(CAnimBlendLink *l) { return (CAnimBlendAssociation*)((uint8*)l - offsetof(CAnimBlendAssociation, link)); } - - CAnimBlendAssociation *ctor1(void) { return ::new (this) CAnimBlendAssociation(); } - CAnimBlendAssociation *ctor2(CAnimBlendAssociation &other) { return ::new (this) CAnimBlendAssociation(other); } - void dtor(void) { this->CAnimBlendAssociation::~CAnimBlendAssociation(); } }; static_assert(sizeof(CAnimBlendAssociation) == 0x40, "CAnimBlendAssociation: error"); diff --git a/src/animation/AnimBlendClumpData.cpp b/src/animation/AnimBlendClumpData.cpp index 06625eb5..cc4281d6 100644 --- a/src/animation/AnimBlendClumpData.cpp +++ b/src/animation/AnimBlendClumpData.cpp @@ -36,9 +36,19 @@ CAnimBlendClumpData::ForAllFrames(void (*cb)(AnimBlendFrameData*, void*), void * cb(&frames[i], arg); } +#include <new> + +class CAnimBlendClumpData_ : public CAnimBlendClumpData +{ +public: + CAnimBlendClumpData *ctor(void) { return ::new (this) CAnimBlendClumpData(); } + void dtor(void) { this->CAnimBlendClumpData::~CAnimBlendClumpData(); } +}; + + STARTPATCHES - InjectHook(0x401880, &CAnimBlendClumpData::ctor, PATCH_JUMP); - InjectHook(0x4018B0, &CAnimBlendClumpData::dtor, PATCH_JUMP); + InjectHook(0x401880, &CAnimBlendClumpData_::ctor, PATCH_JUMP); + InjectHook(0x4018B0, &CAnimBlendClumpData_::dtor, PATCH_JUMP); InjectHook(0x4018F0, &CAnimBlendClumpData::SetNumberOfFrames, PATCH_JUMP); InjectHook(0x401930, &CAnimBlendClumpData::ForAllFrames, PATCH_JUMP); ENDPATCHES diff --git a/src/animation/AnimBlendClumpData.h b/src/animation/AnimBlendClumpData.h index df2fbc56..1c8c391d 100644 --- a/src/animation/AnimBlendClumpData.h +++ b/src/animation/AnimBlendClumpData.h @@ -49,9 +49,5 @@ public: void SetNumberOfBones(int n) { SetNumberOfFrames(n); } #endif void ForAllFrames(void (*cb)(AnimBlendFrameData*, void*), void *arg); - - - CAnimBlendClumpData *ctor(void) { return ::new (this) CAnimBlendClumpData(); } - void dtor(void) { this->CAnimBlendClumpData::~CAnimBlendClumpData(); } }; static_assert(sizeof(CAnimBlendClumpData) == 0x14, "CAnimBlendClumpData: error"); diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp index daa27e57..608a209a 100644 --- a/src/control/PathFind.cpp +++ b/src/control/PathFind.cpp @@ -11,19 +11,10 @@ CPathFind &ThePaths = *(CPathFind*)0x8F6754; WRAPPER bool CPedPath::CalcPedRoute(uint8, CVector, CVector, CVector*, int16*, int16) { EAXJMP(0x42E680); } -enum -{ - NodeTypeExtern = 1, - NodeTypeIntern = 2, - - ObjectFlag1 = 1, - ObjectEastWest = 2, - - MAX_DIST = INT16_MAX-1 -}; +#define MAX_DIST INT16_MAX-1 // object flags: -// 1 +// 1 UseInRoadBlock // 2 east/west road(?) CPathInfoForObject *&InfoForTileCars = *(CPathInfoForObject**)0x8F1A8C; @@ -218,14 +209,14 @@ CPathFind::PreparePathData(void) if(numIntern == 1 && numExtern == 2){ if(numLanes < 4){ if((i & 7) == 4){ // WHAT? - m_objectFlags[i] |= ObjectFlag1; + m_objectFlags[i] |= UseInRoadBlock; if(maxX > maxY) m_objectFlags[i] |= ObjectEastWest; else m_objectFlags[i] &= ~ObjectEastWest; } }else{ - m_objectFlags[i] |= ObjectFlag1; + m_objectFlags[i] |= UseInRoadBlock; if(maxX > maxY) m_objectFlags[i] |= ObjectEastWest; else diff --git a/src/control/PathFind.h b/src/control/PathFind.h index d42b8bb3..c51cb7c7 100644 --- a/src/control/PathFind.h +++ b/src/control/PathFind.h @@ -11,6 +11,15 @@ public: enum { + NodeTypeExtern = 1, + NodeTypeIntern = 2, + + UseInRoadBlock = 1, + ObjectEastWest = 2, +}; + +enum +{ PATH_CAR = 0, PATH_PED = 1, }; diff --git a/src/control/RoadBlocks.cpp b/src/control/RoadBlocks.cpp index ed092391..e39fe481 100644 --- a/src/control/RoadBlocks.cpp +++ b/src/control/RoadBlocks.cpp @@ -1,7 +1,37 @@ #include "common.h" #include "patcher.h" #include "RoadBlocks.h" +#include "PathFind.h" + +int16 &CRoadBlocks::NumRoadBlocks = *(int16*)0x95CC34; +int16 (&CRoadBlocks::RoadBlockObjects)[NUMROADBLOCKS] = *(int16(*)[NUMROADBLOCKS]) * (uintptr*)0x72B3A8; +bool (&CRoadBlocks::InOrOut)[NUMROADBLOCKS] = *(bool(*)[NUMROADBLOCKS]) * (uintptr*)0x733810; -WRAPPER void CRoadBlocks::Init(void) { EAXJMP(0x436F50); } WRAPPER void CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle*, int32, int16) { EAXJMP(0x4376A0); } -WRAPPER void CRoadBlocks::GenerateRoadBlocks(void) { EAXJMP(0x436FA0); }
\ No newline at end of file +WRAPPER void CRoadBlocks::GenerateRoadBlocks(void) { EAXJMP(0x436FA0); } + +void +CRoadBlocks::Init(void) +{ + NumRoadBlocks = 0; + for (int objId = 0; objId < ThePaths.m_numMapObjects; objId++) { + if (ThePaths.m_objectFlags[objId] & UseInRoadBlock) { + if (NumRoadBlocks < 600) { + InOrOut[NumRoadBlocks] = true; + RoadBlockObjects[NumRoadBlocks] = objId; + NumRoadBlocks++; + } else { +#ifndef MASTER + printf("Not enough room for the potential roadblocks\n"); +#endif + // FIX: Don't iterate loop after NUMROADBLOCKS + return; + } + } + } + +} + +STARTPATCHES + InjectHook(0x436F50, &CRoadBlocks::Init, PATCH_JUMP); +ENDPATCHES
\ No newline at end of file diff --git a/src/control/RoadBlocks.h b/src/control/RoadBlocks.h index b1bb3589..3f5868e7 100644 --- a/src/control/RoadBlocks.h +++ b/src/control/RoadBlocks.h @@ -6,6 +6,10 @@ class CVehicle; class CRoadBlocks { public: + static int16 (&NumRoadBlocks); + static int16 (&RoadBlockObjects)[NUMROADBLOCKS]; + static bool (&InOrOut)[NUMROADBLOCKS]; + static void Init(void); static void GenerateRoadBlockCopsForCar(CVehicle*, int32, int16); static void GenerateRoadBlocks(void); diff --git a/src/control/SceneEdit.cpp b/src/control/SceneEdit.cpp index 28b4ea6c..4c05e11b 100644 --- a/src/control/SceneEdit.cpp +++ b/src/control/SceneEdit.cpp @@ -2,5 +2,10 @@ #include "patcher.h" #include "SceneEdit.h" +int32 &CSceneEdit::m_bCameraFollowActor = *(int*)0x940590; +bool &CSceneEdit::m_bRecording = *(bool*)0x95CD1F; +CVector &CSceneEdit::m_vecCurrentPosition = *(CVector*)0x943064; +CVector &CSceneEdit::m_vecCamHeading = *(CVector*)0x942F8C; + WRAPPER void CSceneEdit::Update(void) { EAXJMP(0x585570); } WRAPPER void CSceneEdit::Init(void) { EAXJMP(0x585170); } diff --git a/src/control/SceneEdit.h b/src/control/SceneEdit.h index e9209b90..ec321b27 100644 --- a/src/control/SceneEdit.h +++ b/src/control/SceneEdit.h @@ -3,6 +3,11 @@ class CSceneEdit { public: + static int32 &m_bCameraFollowActor; + static bool &m_bRecording; + static CVector &m_vecCurrentPosition; + static CVector &m_vecCamHeading; + static void Update(void); static void Init(void); }; diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 42b75554..150b64cd 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -1,3 +1,4 @@ +#define WITHWINDOWS // for our script loading hack #include "common.h" #include "patcher.h" diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp new file mode 100644 index 00000000..4ddde360 --- /dev/null +++ b/src/core/Cam.cpp @@ -0,0 +1,4424 @@ +#include "common.h" +#include "patcher.h" +#include "main.h" +#include "Draw.h" +#include "World.h" +#include "Vehicle.h" +#include "Automobile.h" +#include "Ped.h" +#include "PlayerPed.h" +#include "CopPed.h" +#include "RpAnimBlend.h" +#include "ControllerConfig.h" +#include "Pad.h" +#include "Frontend.h" +#include "General.h" +#include "Renderer.h" +#include "Shadows.h" +#include "Hud.h" +#include "ZoneCull.h" +#include "SurfaceTable.h" +#include "WaterLevel.h" +#include "MBlur.h" +#include "SceneEdit.h" +#include "Debug.h" +#include "Camera.h" + +const float DefaultFOV = 70.0f; // beta: 80.0f + +bool PrintDebugCode = false; +int16 &DebugCamMode = *(int16*)0x95CCF2; + +void +CCam::Init(void) +{ + Mode = MODE_FOLLOWPED; + Front = CVector(0.0f, 0.0f, -1.0f); + Up = CVector(0.0f, 0.0f, 1.0f); + Rotating = 0; + m_iDoCollisionChecksOnFrameNum = 1; + m_iDoCollisionCheckEveryNumOfFrames = 9; + m_iFrameNumWereAt = 0; + m_bCollisionChecksOn = 1; + m_fRealGroundDist = 0.0f; + BetaSpeed = 0.0f; + AlphaSpeed = 0.0f; + DistanceSpeed = 0.0f; + f_max_role_angle = DEGTORAD(5.0f); + Distance = 30.0f; + DistanceSpeed = 0.0f; + m_pLastCarEntered = 0; + m_pLastPedLookedAt = 0; + ResetStatics = 1; + Beta = 0.0f; + m_bFixingBeta = 0; + CA_MIN_DISTANCE = 0.0f; + CA_MAX_DISTANCE = 0.0f; + LookingBehind = 0; + LookingLeft = 0; + LookingRight = 0; + m_fPlayerInFrontSyphonAngleOffSet = DEGTORAD(20.0f); + m_fSyphonModeTargetZOffSet = 0.5f; + m_fRadiusForDead = 1.5f; + DirectionWasLooking = LOOKING_FORWARD; + LookBehindCamWasInFront = 0; + f_Roll = 0.0f; + f_rollSpeed = 0.0f; + m_fCloseInPedHeightOffset = 0.0f; + m_fCloseInPedHeightOffsetSpeed = 0.0f; + m_fCloseInCarHeightOffset = 0.0f; + m_fCloseInCarHeightOffsetSpeed = 0.0f; + m_fPedBetweenCameraHeightOffset = 0.0f; + m_fTargetBeta = 0.0f; + m_fBufferedTargetBeta = 0.0f; + m_fBufferedTargetOrientation = 0.0f; + m_fBufferedTargetOrientationSpeed = 0.0f; + m_fDimensionOfHighestNearCar = 0.0f; + m_fRoadOffSet = 0.0f; +} + +void +CCam::Process(void) +{ + CVector CameraTarget; + float TargetSpeedVar = 0.0f; + float TargetOrientation = 0.0f; + + if(CamTargetEntity == nil) + CamTargetEntity = TheCamera.pTargetEntity; + + m_iFrameNumWereAt++; + if(m_iFrameNumWereAt > m_iDoCollisionCheckEveryNumOfFrames) + m_iFrameNumWereAt = 1; + m_bCollisionChecksOn = m_iFrameNumWereAt == m_iDoCollisionChecksOnFrameNum; + + if(m_bCamLookingAtVector){ + CameraTarget = m_cvecCamFixedModeVector; + }else if(CamTargetEntity->IsVehicle()){ + CameraTarget = CamTargetEntity->GetPosition(); + + if(CamTargetEntity->GetForward().x == 0.0f && CamTargetEntity->GetForward().y == 0.0f) + TargetOrientation = 0.0f; + else + TargetOrientation = CGeneral::GetATanOfXY(CamTargetEntity->GetForward().x, CamTargetEntity->GetForward().y); + + CVector Fwd(0.0f, 0.0f, 0.0f); + Fwd.x = CamTargetEntity->GetForward().x; + Fwd.y = CamTargetEntity->GetForward().y; + Fwd.Normalise(); + // Game normalizes again here manually. useless, so skipped + + float FwdSpeedX = ((CVehicle*)CamTargetEntity)->GetMoveSpeed().x * Fwd.x; + float FwdSpeedY = ((CVehicle*)CamTargetEntity)->GetMoveSpeed().y * Fwd.y; + if(FwdSpeedX + FwdSpeedY > 0.0f) + TargetSpeedVar = min(Sqrt(SQR(FwdSpeedX) + SQR(FwdSpeedY))/0.9f, 1.0f); + else + TargetSpeedVar = -min(Sqrt(SQR(FwdSpeedX) + SQR(FwdSpeedY))/1.8f, 0.5f); + SpeedVar = 0.895f*SpeedVar + 0.105*TargetSpeedVar; + }else{ + CameraTarget = CamTargetEntity->GetPosition(); + + if(CamTargetEntity->GetForward().x == 0.0f && CamTargetEntity->GetForward().y == 0.0f) + TargetOrientation = 0.0f; + else + TargetOrientation = CGeneral::GetATanOfXY(CamTargetEntity->GetForward().x, CamTargetEntity->GetForward().y); + TargetSpeedVar = 0.0f; + SpeedVar = 0.0f; + } + + switch(Mode){ + case MODE_TOPDOWN: + case MODE_GTACLASSIC: + Process_TopDown(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_BEHINDCAR: + Process_BehindCar(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_FOLLOWPED: + if(CCamera::m_bUseMouse3rdPerson) + Process_FollowPedWithMouse(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + else + Process_FollowPed(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; +// case MODE_AIMING: + case MODE_DEBUG: + Process_Debug(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_SNIPER: + Process_Sniper(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_ROCKETLAUNCHER: + Process_Rocket(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_MODELVIEW: + Process_ModelView(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; +// case MODE_BILL: + case MODE_SYPHON: + Process_Syphon(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_CIRCLE: + Process_Circle(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; +// case MODE_CHEESYZOOM: + case MODE_WHEELCAM: + Process_WheelCam(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_FIXED: + Process_Fixed(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_1STPERSON: + Process_1stPerson(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_FLYBY: + Process_FlyBy(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_CAM_ON_A_STRING: + Process_Cam_On_A_String(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_REACTION: + Process_ReactionCam(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_FOLLOW_PED_WITH_BIND: + Process_FollowPed_WithBinding(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_CHRIS: + Process_Chris_With_Binding_PlusRotation(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_BEHINDBOAT: + Process_BehindBoat(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_PLAYER_FALLEN_WATER: + Process_Player_Fallen_Water(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; +// case MODE_CAM_ON_TRAIN_ROOF: +// case MODE_CAM_RUNNING_SIDE_TRAIN: +// case MODE_BLOOD_ON_THE_TRACKS: +// case MODE_IM_THE_PASSENGER_WOOWOO: + case MODE_SYPHON_CRIM_IN_FRONT: + Process_Syphon_Crim_In_Front(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_PED_DEAD_BABY: + ProcessPedsDeadBaby(); + break; +// case MODE_PILLOWS_PAPS: +// case MODE_LOOK_AT_CARS: + case MODE_ARRESTCAM_ONE: + ProcessArrestCamOne(); + break; + case MODE_ARRESTCAM_TWO: + ProcessArrestCamTwo(); + break; + case MODE_M16_1STPERSON: + case MODE_HELICANNON_1STPERSON: // miami + Process_M16_1stPerson(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_SPECIAL_FIXED_FOR_SYPHON: + Process_SpecialFixedForSyphon(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_FIGHT_CAM: + Process_Fight_Cam(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_TOP_DOWN_PED: + Process_TopDownPed(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_SNIPER_RUNABOUT: + case MODE_ROCKETLAUNCHER_RUNABOUT: + case MODE_1STPERSON_RUNABOUT: + case MODE_M16_1STPERSON_RUNABOUT: + case MODE_FIGHT_CAM_RUNABOUT: + Process_1rstPersonPedOnPC(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + case MODE_EDITOR: + Process_Editor(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + break; + default: + Source = CVector(0.0f, 0.0f, 0.0f); + Front = CVector(0.0f, 1.0f, 0.0f); + Up = CVector(0.0f, 0.0f, 1.0f); + } + + CVector TargetToCam = Source - m_cvecTargetCoorsForFudgeInter; + float DistOnGround = TargetToCam.Magnitude2D(); + m_fTrueBeta = CGeneral::GetATanOfXY(TargetToCam.x, TargetToCam.y); + m_fTrueAlpha = CGeneral::GetATanOfXY(TargetToCam.z, DistOnGround); + if(TheCamera.m_uiTransitionState == 0) // TODO? what values are possible? enum? + KeepTrackOfTheSpeed(Source, m_cvecTargetCoorsForFudgeInter, Up, m_fTrueAlpha, m_fTrueBeta, FOV); + + // Look Behind, Left, Right + LookingBehind = false; + LookingLeft = false; + LookingRight = false; + SourceBeforeLookBehind = Source; + if(&TheCamera.Cams[TheCamera.ActiveCam] == this){ + if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_1STPERSON || Mode == MODE_BEHINDBOAT) && + CamTargetEntity->IsVehicle()){ + if(CPad::GetPad(0)->GetLookBehindForCar()){ + LookBehind(); + if(DirectionWasLooking != LOOKING_BEHIND) + TheCamera.m_bJust_Switched = true; + DirectionWasLooking = LOOKING_BEHIND; + }else if(CPad::GetPad(0)->GetLookLeft()){ + LookLeft(); + if(DirectionWasLooking != LOOKING_LEFT) + TheCamera.m_bJust_Switched = true; + DirectionWasLooking = LOOKING_LEFT; + }else if(CPad::GetPad(0)->GetLookRight()){ + LookRight(); + if(DirectionWasLooking != LOOKING_RIGHT) + TheCamera.m_bJust_Switched = true; + DirectionWasLooking = LOOKING_RIGHT; + }else{ + if(DirectionWasLooking != LOOKING_FORWARD) + TheCamera.m_bJust_Switched = true; + DirectionWasLooking = LOOKING_FORWARD; + } + } + if(Mode == MODE_FOLLOWPED && CamTargetEntity->IsPed()){ + if(CPad::GetPad(0)->GetLookBehindForPed()){ + LookBehind(); + if(DirectionWasLooking != LOOKING_BEHIND) + TheCamera.m_bJust_Switched = true; + DirectionWasLooking = LOOKING_BEHIND; + }else + DirectionWasLooking = LOOKING_FORWARD; + } + } + + if(Mode == MODE_SNIPER || Mode == MODE_ROCKETLAUNCHER || Mode == MODE_M16_1STPERSON || + Mode == MODE_1STPERSON || Mode == MODE_HELICANNON_1STPERSON || GetWeaponFirstPersonOn()) + ClipIfPedInFrontOfPlayer(); +} + +// MaxSpeed is a limit of how fast the value is allowed to change. 1.0 = to Target in up to 1ms +// Acceleration is how fast the speed will change to MaxSpeed. 1.0 = to MaxSpeed in 1ms +void +WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSpeed, float Acceleration, bool IsAngle) +{ + float Delta = Target - *CurrentValue; + + if(IsAngle){ + while(Delta >= PI) Delta -= 2*PI; + while(Delta < -PI) Delta += 2*PI; + } + + float TargetSpeed = Delta * MaxSpeed; + // Add or subtract absolute depending on sign, genius! +// if(TargetSpeed - *CurrentSpeed > 0.0f) +// *CurrentSpeed += Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); +// else +// *CurrentSpeed -= Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); + // this is simpler: + *CurrentSpeed += Acceleration * (TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); + + // Clamp speed if we overshot + if(TargetSpeed < 0.0f && *CurrentSpeed < TargetSpeed) + *CurrentSpeed = TargetSpeed; + else if(TargetSpeed > 0.0f && *CurrentSpeed > TargetSpeed) + *CurrentSpeed = TargetSpeed; + + *CurrentValue += *CurrentSpeed * min(10.0f, CTimer::GetTimeStep()); +} + +void +MakeAngleLessThan180(float &Angle) +{ + while(Angle >= PI) Angle -= 2*PI; + while(Angle < -PI) Angle += 2*PI; +} + +void +CCam::ProcessSpecialHeightRoutines(void) +{ + int i = 0; + bool StandingOnBoat = false; + static bool PreviouslyFailedRoadHeightCheck = false; + CVector CamToTarget, CamToPed; + float DistOnGround, BetaAngle; + CPed *Player; + int ClosestPed = 0; + bool FoundPed = false; + float ClosestPedDist, PedZDist; + CColPoint colPoint; + + CamToTarget = TheCamera.pTargetEntity->GetPosition() - TheCamera.GetGameCamPosition(); + DistOnGround = CamToTarget.Magnitude2D(); + BetaAngle = CGeneral::GetATanOfXY(CamToTarget.x, CamToTarget.y); + m_bTheHeightFixerVehicleIsATrain = false; + ClosestPedDist = 0.0f; + // CGeneral::GetATanOfXY(TheCamera.GetForward().x, TheCamera.GetForward().y); + Player = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + + if(DistOnGround > 10.0f) + DistOnGround = 10.0f; + + if(CamTargetEntity && CamTargetEntity->IsPed()){ + if(FindPlayerPed()->m_pCurSurface && FindPlayerPed()->m_pCurSurface->IsVehicle() && + ((CVehicle*)FindPlayerPed()->m_pCurSurface)->IsBoat()) + StandingOnBoat = true; + + // Move up the camera if there is a ped close to it + if(Mode == MODE_FOLLOWPED || Mode == MODE_FIGHT_CAM){ + // Find ped closest to camera + while(i < Player->m_numNearPeds){ + if(Player->m_nearPeds[i] && Player->m_nearPeds[i]->GetPedState() != PED_DEAD){ + CamToPed = Player->m_nearPeds[i]->GetPosition() - TheCamera.GetGameCamPosition(); + if(FoundPed){ + if(CamToPed.Magnitude2D() < ClosestPedDist){ + ClosestPed = i; + ClosestPedDist = CamToPed.Magnitude2D(); + } + }else{ + FoundPed = true; + ClosestPed = i; + ClosestPedDist = CamToPed.Magnitude2D(); + } + } + i++; + } + + if(FoundPed){ + float Offset = 0.0f; + CPed *Ped = Player->m_nearPeds[ClosestPed]; + CamToPed = Ped->GetPosition() - TheCamera.GetGameCamPosition(); + PedZDist = 0.0f; + float dist = CamToPed.Magnitude2D(); // should be same as ClosestPedDist + if(dist < 2.1f){ + // Ped is close to camera, move up + + // Z Distance between player and close ped + PedZDist = 0.0f; + if(Ped->bIsStanding) + PedZDist = Ped->GetPosition().z - Player->GetPosition().z; + // Ignore if too distant + if(PedZDist > 1.2f || PedZDist < -1.2f) + PedZDist = 0.0f; + + float DistScale = (2.1f - dist)/2.1f; + if(Mode == MODE_FOLLOWPED){ + if(TheCamera.PedZoomIndicator == 1.0f) + Offset = 0.45*DistScale + PedZDist; + if(TheCamera.PedZoomIndicator == 2.0f) + Offset = 0.35*DistScale + PedZDist; + if(TheCamera.PedZoomIndicator == 3.0f) + Offset = 0.25*DistScale + PedZDist; + if(Abs(CGeneral::GetRadianAngleBetweenPoints(CamToPed.x, CamToPed.y, CamToTarget.x, CamToTarget.y)) > HALFPI) + Offset += 0.3f; + m_fPedBetweenCameraHeightOffset = Offset + 1.3f; + PedZDist = 0.0f; + }else if(Mode == MODE_FIGHT_CAM) + m_fPedBetweenCameraHeightOffset = PedZDist + 1.3f + 0.5f; + }else + m_fPedBetweenCameraHeightOffset = 0.0f; + }else{ + PedZDist = 0.0f; + m_fPedBetweenCameraHeightOffset = 0.0f; + } + }else + PedZDist = 0.0f; + + + // Move camera up for vehicles in the way + if(m_bCollisionChecksOn && (Mode == MODE_FOLLOWPED || Mode == MODE_FIGHT_CAM)){ + bool FoundCar = false; + CEntity *vehicle = nil; + float TestDist = DistOnGround + 1.25f; + float HighestCar = 0.0f; + CVector TestBase = CamTargetEntity->GetPosition(); + CVector TestPoint; + TestBase.z -= 0.15f; + + TestPoint = TestBase - TestDist * CVector(Cos(BetaAngle), Sin(BetaAngle), 0.0f); + if(CWorld::ProcessLineOfSight(CamTargetEntity->GetPosition(), TestPoint, colPoint, vehicle, false, true, false, false, false, false) && + vehicle->IsVehicle()){ + float height = vehicle->GetColModel()->boundingBox.GetSize().z; + FoundCar = true; + HighestCar = height; + if(((CVehicle*)vehicle)->IsTrain()) + m_bTheHeightFixerVehicleIsATrain = true; + } + + TestPoint = TestBase - TestDist * CVector(Cos(BetaAngle+DEGTORAD(28.0f)), Sin(BetaAngle+DEGTORAD(28.0f)), 0.0f); + if(CWorld::ProcessLineOfSight(CamTargetEntity->GetPosition(), TestPoint, colPoint, vehicle, false, true, false, false, false, false) && + vehicle->IsVehicle()){ + float height = vehicle->GetColModel()->boundingBox.GetSize().z; + if(FoundCar){ + HighestCar = max(HighestCar, height); + }else{ + FoundCar = true; + HighestCar = height; + } + if(((CVehicle*)vehicle)->IsTrain()) + m_bTheHeightFixerVehicleIsATrain = true; + } + + TestPoint = TestBase - TestDist * CVector(Cos(BetaAngle-DEGTORAD(28.0f)), Sin(BetaAngle-DEGTORAD(28.0f)), 0.0f); + if(CWorld::ProcessLineOfSight(CamTargetEntity->GetPosition(), TestPoint, colPoint, vehicle, false, true, false, false, false, false) && + vehicle->IsVehicle()){ + float height = vehicle->GetColModel()->boundingBox.GetSize().z; + if(FoundCar){ + HighestCar = max(HighestCar, height); + }else{ + FoundCar = true; + HighestCar = height; + } + if(((CVehicle*)vehicle)->IsTrain()) + m_bTheHeightFixerVehicleIsATrain = true; + } + + if(FoundCar){ + m_fDimensionOfHighestNearCar = HighestCar + 0.1f; + if(Mode == MODE_FIGHT_CAM) + m_fDimensionOfHighestNearCar += 0.75f; + }else + m_fDimensionOfHighestNearCar = 0.0f; + } + + // Move up for road + if(Mode == MODE_FOLLOWPED || Mode == MODE_FIGHT_CAM || + Mode == MODE_SYPHON || Mode == MODE_SYPHON_CRIM_IN_FRONT || Mode == MODE_SPECIAL_FIXED_FOR_SYPHON){ + bool Inside = false; + bool OnRoad = false; + + switch(((CPhysical*)CamTargetEntity)->m_nSurfaceTouched) + case SURFACE_GRASS: + case SURFACE_DIRT: + case SURFACE_DIRTTRACK: + case SURFACE_STEEL: + case SURFACE_TIRE: + case SURFACE_STONE: + OnRoad = true; + + if(CCullZones::PlayerNoRain()) + Inside = true; + + if((m_bCollisionChecksOn || PreviouslyFailedRoadHeightCheck || OnRoad) && + m_fCloseInPedHeightOffset < 0.0001f && !Inside){ + CVector TestPoint; + CEntity *road; + float GroundZ = 0.0f; + bool FoundGround = false; + float RoofZ = 0.0f; + bool FoundRoof = false; + static float MinHeightAboveRoad = 0.9f; + + TestPoint = CamTargetEntity->GetPosition() - DistOnGround * CVector(Cos(BetaAngle), Sin(BetaAngle), 0.0f); + m_fRoadOffSet = 0.0f; + + if(CWorld::ProcessVerticalLine(TestPoint, -1000.0f, colPoint, road, true, false, false, false, false, false, nil)){ + FoundGround = true; + GroundZ = colPoint.point.z; + } + // Move up if too close to ground + if(FoundGround){ + if(TestPoint.z - GroundZ < MinHeightAboveRoad){ + m_fRoadOffSet = GroundZ + MinHeightAboveRoad - TestPoint.z; + PreviouslyFailedRoadHeightCheck = true; + }else{ + if(m_bCollisionChecksOn) + PreviouslyFailedRoadHeightCheck = false; + else + m_fRoadOffSet = 0.0f; + } + }else{ + if(CWorld::ProcessVerticalLine(TestPoint, 1000.0f, colPoint, road, true, false, false, false, false, false, nil)){ + FoundRoof = true; + RoofZ = colPoint.point.z; + } + if(FoundRoof){ + if(TestPoint.z - RoofZ < MinHeightAboveRoad){ + m_fRoadOffSet = RoofZ + MinHeightAboveRoad - TestPoint.z; + PreviouslyFailedRoadHeightCheck = true; + }else{ + if(m_bCollisionChecksOn) + PreviouslyFailedRoadHeightCheck = false; + else + m_fRoadOffSet = 0.0f; + } + } + } + } + } + + if(PreviouslyFailedRoadHeightCheck && m_fCloseInPedHeightOffset < 0.0001f){ + if(colPoint.surfaceB != SURFACE_TARMAC && + colPoint.surfaceB != SURFACE_GRASS && + colPoint.surfaceB != SURFACE_DIRT && + colPoint.surfaceB != SURFACE_DIRTTRACK && + colPoint.surfaceB != SURFACE_STONE){ + if(m_fRoadOffSet > 1.4f) + m_fRoadOffSet = 1.4f; + }else{ + if(Mode == MODE_FOLLOWPED){ + if(TheCamera.PedZoomIndicator == 1.0f) + m_fRoadOffSet += 0.2f; + if(TheCamera.PedZoomIndicator == 2.0f) + m_fRoadOffSet += 0.5f; + if(TheCamera.PedZoomIndicator == 3.0f) + m_fRoadOffSet += 0.95f; + } + } + } + } + + if(StandingOnBoat){ + m_fRoadOffSet = 0.0f; + m_fDimensionOfHighestNearCar = 1.0f; + m_fPedBetweenCameraHeightOffset = 0.0f; + } +} + +void +CCam::GetVectorsReadyForRW(void) +{ + CVector right; + Up = CVector(0.0f, 0.0f, 1.0f); + Front.Normalise(); + if(Front.x == 0.0f && Front.y == 0.0f){ + Front.x = 0.0001f; + Front.y = 0.0001f; + } + right = CrossProduct(Front, Up); + right.Normalise(); + Up = CrossProduct(right, Front); +} + +void +CCam::LookBehind(void) +{ + float Dist, DeltaBeta, TargetOrientation, Angle; + CVector TargetCoors, TargetFwd, TestCoors; + CColPoint colPoint; + CEntity *entity; + + TargetCoors = CamTargetEntity->GetPosition(); + Front = CamTargetEntity->GetPosition() - Source; + + if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_BEHINDBOAT) && CamTargetEntity->IsVehicle()){ + LookingBehind = true; + Dist = Mode == MODE_CAM_ON_A_STRING ? CA_MAX_DISTANCE : 15.5f; + TargetFwd = CamTargetEntity->GetForward(); + TargetFwd.Normalise(); + TargetOrientation = CGeneral::GetATanOfXY(TargetFwd.x, TargetFwd.y); + DeltaBeta = TargetOrientation - Beta; + while(DeltaBeta >= PI) DeltaBeta -= 2*PI; + while(DeltaBeta < -PI) DeltaBeta += 2*PI; + if(DirectionWasLooking == LOOKING_BEHIND) + LookBehindCamWasInFront = DeltaBeta <= -HALFPI || DeltaBeta >= HALFPI; + if(LookBehindCamWasInFront) + TargetOrientation += PI; + Source.x = Dist*Cos(TargetOrientation) + TargetCoors.x; + Source.y = Dist*Sin(TargetOrientation) + TargetCoors.y; + Source.z -= 1.0f; + if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.9f); + Source = colPoint.point; + } + Source.z += 1.0f; + Front = CamTargetEntity->GetPosition() - Source; + GetVectorsReadyForRW(); + } + if(Mode == MODE_1STPERSON && CamTargetEntity->IsVehicle()){ + LookingBehind = true; + RwCameraSetNearClipPlane(Scene.camera, 0.25f); + Front = CamTargetEntity->GetForward(); + Front.Normalise(); + if(((CVehicle*)CamTargetEntity)->IsBoat()) + Source.z -= 0.5f; + Source += 0.25f*Front; + Front = -Front; +#ifdef FIX_BUGS + // not sure if this is a bug... + GetVectorsReadyForRW(); +#endif + } + if(CamTargetEntity->IsPed()){ + Angle = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y) + PI; + Source.x = 4.5f*Cos(Angle) + TargetCoors.x; + Source.y = 4.5f*Sin(Angle) + TargetCoors.y; + Source.z = 1.15f + TargetCoors.z; + TestCoors = TargetCoors; + TestCoors.z = Source.z; + if(CWorld::ProcessLineOfSight(TestCoors, Source, colPoint, entity, true, true, false, true, false, true, true)){ + Source.x = colPoint.point.x; + Source.y = colPoint.point.y; + if((TargetCoors - Source).Magnitude2D() < 1.15f) + RwCameraSetNearClipPlane(Scene.camera, 0.05f); + } + Front = TargetCoors - Source; + GetVectorsReadyForRW(); + } +} + +void +CCam::LookLeft(void) +{ + float Dist, TargetOrientation; + CVector TargetCoors, TargetFwd; + CColPoint colPoint; + CEntity *entity; + + if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_BEHINDBOAT) && CamTargetEntity->IsVehicle()){ + LookingLeft = true; + TargetCoors = CamTargetEntity->GetPosition(); + Front = CamTargetEntity->GetPosition() - Source; + Dist = Mode == MODE_CAM_ON_A_STRING ? CA_MAX_DISTANCE : 9.0f; + TargetFwd = CamTargetEntity->GetForward(); + TargetFwd.Normalise(); + TargetOrientation = CGeneral::GetATanOfXY(TargetFwd.x, TargetFwd.y); + Source.x = Dist*Cos(TargetOrientation - HALFPI) + TargetCoors.x; + Source.y = Dist*Sin(TargetOrientation - HALFPI) + TargetCoors.y; + Source.z -= 1.0f; + if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + Source = colPoint.point; + } + Source.z += 1.0f; + Front = CamTargetEntity->GetPosition() - Source; + Front.z += 1.1f; + if(Mode == MODE_BEHINDBOAT) + Front.z += 1.2f; + GetVectorsReadyForRW(); + } + if(Mode == MODE_1STPERSON && CamTargetEntity->IsVehicle()){ + LookingLeft = true; + RwCameraSetNearClipPlane(Scene.camera, 0.25f); + if(((CVehicle*)CamTargetEntity)->IsBoat()) + Source.z -= 0.5f; + + Up = CamTargetEntity->GetUp(); + Up.Normalise(); + Front = CamTargetEntity->GetForward(); + Front.Normalise(); + Front = -CrossProduct(Front, Up); + Front.Normalise(); +#ifdef FIX_BUGS + // not sure if this is a bug... + GetVectorsReadyForRW(); +#endif + } +} + +void +CCam::LookRight(void) +{ + float Dist, TargetOrientation; + CVector TargetCoors, TargetFwd; + CColPoint colPoint; + CEntity *entity; + + if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_BEHINDBOAT) && CamTargetEntity->IsVehicle()){ + LookingRight = true; + TargetCoors = CamTargetEntity->GetPosition(); + Front = CamTargetEntity->GetPosition() - Source; + Dist = Mode == MODE_CAM_ON_A_STRING ? CA_MAX_DISTANCE : 9.0f; + TargetFwd = CamTargetEntity->GetForward(); + TargetFwd.Normalise(); + TargetOrientation = CGeneral::GetATanOfXY(TargetFwd.x, TargetFwd.y); + Source.x = Dist*Cos(TargetOrientation + HALFPI) + TargetCoors.x; + Source.y = Dist*Sin(TargetOrientation + HALFPI) + TargetCoors.y; + Source.z -= 1.0f; + if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + Source = colPoint.point; + } + Source.z += 1.0f; + Front = CamTargetEntity->GetPosition() - Source; + Front.z += 1.1f; + if(Mode == MODE_BEHINDBOAT) + Front.z += 1.2f; + GetVectorsReadyForRW(); + } + if(Mode == MODE_1STPERSON && CamTargetEntity->IsVehicle()){ + LookingRight = true; + RwCameraSetNearClipPlane(Scene.camera, 0.25f); + if(((CVehicle*)CamTargetEntity)->IsBoat()) + Source.z -= 0.5f; + + Up = CamTargetEntity->GetUp(); + Up.Normalise(); + Front = CamTargetEntity->GetForward(); + Front.Normalise(); + Front = CrossProduct(Front, Up); + Front.Normalise(); +#ifdef FIX_BUGS + // not sure if this is a bug... + GetVectorsReadyForRW(); +#endif + } +} + +void +CCam::ClipIfPedInFrontOfPlayer(void) +{ + float FwdAngle, PedAngle, DeltaAngle, fDist, Near; + CVector vDist; + CPed *Player; + bool found = false; + int ped = 0; + + // unused: TheCamera.pTargetEntity->GetPosition() - TheCamera.GetGameCamPosition(); + + FwdAngle = CGeneral::GetATanOfXY(TheCamera.GetForward().x, TheCamera.GetForward().y); + Player = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + while(ped < Player->m_numNearPeds && !found) + if(Player->m_nearPeds[ped] && Player->m_nearPeds[ped]->GetPedState() != PED_DEAD) + found = true; + else + ped++; + if(found){ + vDist = Player->m_nearPeds[ped]->GetPosition() - TheCamera.GetGameCamPosition(); + PedAngle = CGeneral::GetATanOfXY(vDist.x, vDist.y); + DeltaAngle = FwdAngle - PedAngle; + while(DeltaAngle >= PI) DeltaAngle -= 2*PI; + while(DeltaAngle < -PI) DeltaAngle += 2*PI; + if(Abs(DeltaAngle) < HALFPI){ + fDist = Sqrt(SQR(vDist.x) + SQR(vDist.y)); + if(fDist < 1.25f){ + Near = 0.9f - (1.25f - fDist); + if(Near < 0.05f) + Near = 0.05f; + RwCameraSetNearClipPlane(Scene.camera, Near); + } + } + } +} + +void +CCam::KeepTrackOfTheSpeed(const CVector &source, const CVector &target, const CVector &up, const float &alpha, const float &beta, const float &fov) +{ + static CVector PreviousSource = source; + static CVector PreviousTarget = target; + static CVector PreviousUp = up; + static float PreviousBeta = beta; + static float PreviousAlpha = alpha; + static float PreviousFov = fov; + + if(TheCamera.m_bJust_Switched){ + PreviousSource = source; + PreviousTarget = target; + PreviousUp = up; + } + + m_cvecSourceSpeedOverOneFrame = PreviousSource - source; + m_cvecTargetSpeedOverOneFrame = PreviousTarget - target; + m_cvecUpOverOneFrame = PreviousUp - up; + m_fFovSpeedOverOneFrame = fov - PreviousFov; + m_fBetaSpeedOverOneFrame = beta - PreviousBeta; + MakeAngleLessThan180(m_fBetaSpeedOverOneFrame); + m_fAlphaSpeedOverOneFrame = alpha - PreviousAlpha; + MakeAngleLessThan180(m_fAlphaSpeedOverOneFrame); + + PreviousSource = source; + PreviousTarget = target; + PreviousUp = up; + PreviousBeta = beta; + PreviousAlpha = alpha; + PreviousFov = fov; +} + +bool +CCam::Using3rdPersonMouseCam(void) +{ + return CCamera::m_bUseMouse3rdPerson && + (Mode == MODE_FOLLOWPED || + TheCamera.m_bPlayerIsInGarage && + FindPlayerPed() && FindPlayerPed()->m_nPedState != PED_DRIVING && + Mode != MODE_TOPDOWN && this->CamTargetEntity == FindPlayerPed()); +} + +bool +CCam::GetWeaponFirstPersonOn(void) +{ + CEntity *target = this->CamTargetEntity; + if (target && target->IsPed()) + return ((CPed*)target)->GetWeapon()->m_bAddRotOffset; + + return false; +} + +bool +CCam::IsTargetInWater(const CVector &CamCoors) +{ + if(CamTargetEntity == nil) + return false; + if(CamTargetEntity->IsPed()){ + if(!((CPed*)CamTargetEntity)->bIsInWater) + return false; + if(!((CPed*)CamTargetEntity)->bIsStanding) + return true; + return false; + } + return ((CPhysical*)CamTargetEntity)->bIsInWater; +} + +void +CCam::PrintMode(void) +{ + // Doesn't do anything + char buf[256]; + + if(PrintDebugCode){ + sprintf(buf, " "); + sprintf(buf, " "); + sprintf(buf, " "); + + static char *modes[] = { "None", + "Top Down", "GTA Classic", "Behind Car", "Follow Ped", + "Aiming", "Debug", "Sniper", "Rocket", "Model Viewer", "Bill", + "Syphon", "Circle", "Cheesy Zoom", "Wheel", "Fixed", + "1st Person", "Fly by", "on a String", "Reaction", + "Follow Ped with Bind", "Chris", "Behind Boat", + "Player fallen in Water", "Train Roof", "Train Side", + "Blood on the tracks", "Passenger", "Syphon Crim in Front", + "Dead Baby", "Pillow Paps", "Look at Cars", "Arrest One", + "Arrest Two", "M16", "Special fixed for Syphon", "Fight", + "Top Down Ped", + "Sniper run about", "Rocket run about", + "1st Person run about", "M16 run about", "Fight run about", + "Editor" + }; + sprintf(buf, "Cam: %s", modes[TheCamera.Cams[TheCamera.ActiveCam].Mode]); + CDebug::PrintAt(buf, 2, 5); + } + + if(DebugCamMode != MODE_NONE){ + switch(Mode){ + case MODE_FOLLOWPED: + sprintf(buf, "Debug:- Cam Choice1. No Locking, used as game default"); + break; + case MODE_REACTION: + sprintf(buf, "Debug:- Cam Choice2. Reaction Cam On A String "); + sprintf(buf, " Uses Locking Button LeftShoulder 1. "); // lie + break; + case MODE_FOLLOW_PED_WITH_BIND: + sprintf(buf, "Debug:- Cam Choice3. Game ReactionCam with Locking "); + sprintf(buf, " Uses Locking Button LeftShoulder 1. "); + break; + case MODE_CHRIS: + sprintf(buf, "Debug:- Cam Choice4. Chris's idea. "); + sprintf(buf, " Uses Locking Button LeftShoulder 1. "); + sprintf(buf, " Also control the camera using the right analogue stick."); + break; + } + } +} + +// This code is really bad. wtf R*? +CVector +CCam::DoAverageOnVector(const CVector &vec) +{ + int i; + CVector Average = { 0.0f, 0.0f, 0.0f }; + + if(ResetStatics){ + m_iRunningVectorArrayPos = 0; + m_iRunningVectorCounter = 1; + } + + // TODO: make this work with NUMBER_OF_VECTORS_FOR_AVERAGE != 2 + if(m_iRunningVectorCounter == 3){ + m_arrPreviousVectors[0] = m_arrPreviousVectors[1]; + m_arrPreviousVectors[1] = vec; + }else + m_arrPreviousVectors[m_iRunningVectorArrayPos] = vec; + + for(i = 0; i <= m_iRunningVectorArrayPos; i++) + Average += m_arrPreviousVectors[i]; + Average /= i; + + m_iRunningVectorArrayPos++; + m_iRunningVectorCounter++; + if(m_iRunningVectorArrayPos >= NUMBER_OF_VECTORS_FOR_AVERAGE) + m_iRunningVectorArrayPos = NUMBER_OF_VECTORS_FOR_AVERAGE-1; + if(m_iRunningVectorCounter > NUMBER_OF_VECTORS_FOR_AVERAGE+1) + m_iRunningVectorCounter = NUMBER_OF_VECTORS_FOR_AVERAGE+1; + + return Average; +} + +// Rotate Beta in direction opposite of BetaOffset in 5 deg. steps. +// Return the first angle for which Beta + BetaOffset + Angle has a clear view. +// i.e. BetaOffset is a safe zone so that Beta + Angle is really clear. +// If BetaOffset == 0, try both directions. +float +CCam::GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies) +{ + CColPoint point; + CEntity *ent = nil; + CVector ToSource; + float a; + + // This would be so much nicer if we just got the step variable before the loop...R* + + for(a = 0.0f; a <= PI; a += DEGTORAD(5.0f)){ + if(BetaOffset <= 0.0f){ + ToSource = CVector(Cos(Beta + BetaOffset + a), Sin(Beta + BetaOffset + a), 0.0f)*Dist; + if(!CWorld::ProcessLineOfSight(Target, Target + ToSource, + point, ent, checkBuildings, checkVehicles, checkPeds, + checkObjects, checkDummies, true, true)) + return a; + } + if(BetaOffset >= 0.0f){ + ToSource = CVector(Cos(Beta + BetaOffset - a), Sin(Beta + BetaOffset - a), 0.0f)*Dist; + if(!CWorld::ProcessLineOfSight(Target, Target + ToSource, + point, ent, checkBuildings, checkVehicles, checkPeds, + checkObjects, checkDummies, true, true)) + return -a; + } + } + return 0.0f; +} + +static float DefaultAcceleration = 0.045f; +static float DefaultMaxStep = 0.15f; + +void +CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + const float GroundDist = 1.85f; + + CVector TargetCoors, Dist, IdealSource; + float Length = 0.0f; + float LateralLeft = 0.0f; + float LateralRight = 0.0f; + float Center = 0.0f; + static bool PreviouslyObscured; + static bool PickedASide; + static float FixedTargetOrientation = 0.0f; + float AngleToGoTo = 0.0f; + float BetaOffsetAvoidBuildings = 0.45f; // ~25 deg + float BetaOffsetGoingBehind = 0.45f; + bool GoingBehind = false; + bool Obscured = false; + bool BuildingCheckObscured = false; + bool HackPlayerOnStoppingTrain = false; + static int TimeIndicatedWantedToGoDown = 0; + static bool StartedCountingForGoDown = false; + float DeltaBeta; + + m_bFixingBeta = false; + bBelowMinDist = false; + bBehindPlayerDesired = false; + +#ifdef FIX_BUGS + if(!CamTargetEntity->IsPed()) + return; +#endif + assert(CamTargetEntity->IsPed()); + + // CenterDist should be > LateralDist because we don't have an angle for safety in this case + float CenterDist, LateralDist; + float AngleToGoToSpeed; + if(m_fCloseInPedHeightOffset > 0.00001f){ + LateralDist = 0.55f; + CenterDist = 1.25f; + BetaOffsetAvoidBuildings = 0.9f; // ~50 deg + BetaOffsetGoingBehind = 0.9f; + AngleToGoToSpeed = 0.88254666f; + }else{ + LateralDist = 0.8f; + CenterDist = 1.35f; + if(TheCamera.PedZoomIndicator == 1.0f || TheCamera.PedZoomIndicator == 4.0f){ + LateralDist = 1.25f; + CenterDist = 1.6f; + } + AngleToGoToSpeed = 0.43254671f; + } + + FOV = DefaultFOV; + + if(ResetStatics){ + Rotating = false; + m_bCollisionChecksOn = true; + FixedTargetOrientation = 0.0f; + PreviouslyObscured = false; + PickedASide = false; + StartedCountingForGoDown = false; + AngleToGoTo = 0.0f; + // unused LastAngleWithNoPickedASide + } + + + TargetCoors = CameraTarget; + IdealSource = Source; + TargetCoors.z += m_fSyphonModeTargetZOffSet; + + TargetCoors = DoAverageOnVector(TargetCoors); + TargetCoors.z += m_fRoadOffSet; + + Dist.x = IdealSource.x - TargetCoors.x; + Dist.y = IdealSource.y - TargetCoors.y; + Length = Dist.Magnitude2D(); + + // Cam on a string. With a fixed distance. Zoom in/out is done later. + if(Length != 0.0f) + IdealSource = TargetCoors + CVector(Dist.x, Dist.y, 0.0f)/Length * GroundDist; + else + IdealSource = TargetCoors + CVector(1.0f, 1.0f, 0.0f); + + // TODO: what's transition beta? + if(TheCamera.m_bUseTransitionBeta && ResetStatics){ + CVector VecDistance; + IdealSource.x = TargetCoors.x + GroundDist*Cos(m_fTransitionBeta); + IdealSource.y = TargetCoors.y + GroundDist*Sin(m_fTransitionBeta); + Beta = CGeneral::GetATanOfXY(IdealSource.x - TargetCoors.x, IdealSource.y - TargetCoors.y); + }else + Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y); + + if(TheCamera.m_bCamDirectlyBehind){ + m_bCollisionChecksOn = true; + Beta = TargetOrientation + PI; + } + + if(FindPlayerVehicle()) + if(FindPlayerVehicle()->m_vehType == VEHICLE_TYPE_TRAIN) + HackPlayerOnStoppingTrain = true; + + if(TheCamera.m_bCamDirectlyInFront){ + m_bCollisionChecksOn = true; + Beta = TargetOrientation; + } + + while(Beta >= PI) Beta -= 2.0f * PI; + while(Beta < -PI) Beta += 2.0f * PI; + + // BUG? is this ever used? + // The values seem to be roughly m_fPedZoomValueSmooth + 1.85 + if(ResetStatics){ + if(TheCamera.PedZoomIndicator == 1.0) m_fRealGroundDist = 2.090556f; + if(TheCamera.PedZoomIndicator == 2.0) m_fRealGroundDist = 3.34973f; + if(TheCamera.PedZoomIndicator == 3.0) m_fRealGroundDist = 4.704914f; + if(TheCamera.PedZoomIndicator == 4.0) m_fRealGroundDist = 2.090556f; + } + // And what is this? It's only used for collision and rotation it seems + float RealGroundDist; + if(TheCamera.PedZoomIndicator == 1.0) RealGroundDist = 2.090556f; + if(TheCamera.PedZoomIndicator == 2.0) RealGroundDist = 3.34973f; + if(TheCamera.PedZoomIndicator == 3.0) RealGroundDist = 4.704914f; + if(TheCamera.PedZoomIndicator == 4.0) RealGroundDist = 2.090556f; + if(m_fCloseInPedHeightOffset > 0.00001f) + RealGroundDist = 1.7016f; + + + bool Shooting = false; + CPed *ped = (CPed*)CamTargetEntity; + if(ped->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) + if(CPad::GetPad(0)->GetWeapon()) + Shooting = true; + if(ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_DETONATOR || + ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT) + Shooting = false; + + + if(m_fCloseInPedHeightOffset > 0.00001f) + TargetCoors.z -= m_fRoadOffSet; + + // Figure out if and where we want to rotate + + if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){ + + // Center cam behind player + + GoingBehind = true; + m_bCollisionChecksOn = true; + float OriginalBeta = Beta; + // Set Beta behind player + Beta = TargetOrientation + PI; + TargetCoors.z -= 0.1f; + + AngleToGoTo = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false); + if(AngleToGoTo != 0.0f){ + if(AngleToGoTo < 0.0f) + AngleToGoTo -= AngleToGoToSpeed; + else + AngleToGoTo += AngleToGoToSpeed; + }else{ + float LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetGoingBehind, true, false, false, true, false); + float LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetGoingBehind, true, false, false, true, false); + if(LateralLeft == 0.0f && LateralRight != 0.0f) + AngleToGoTo += LateralRight; + else if(LateralLeft != 0.0f && LateralRight == 0.0f) + AngleToGoTo += LateralLeft; + } + + TargetCoors.z += 0.1f; + Beta = OriginalBeta; + + if(PickedASide){ + if(AngleToGoTo == 0.0f) + FixedTargetOrientation = TargetOrientation + PI; + Rotating = true; + }else{ + FixedTargetOrientation = TargetOrientation + PI + AngleToGoTo; + Rotating = true; + PickedASide = true; + } + }else{ + + // Rotate cam to avoid clipping into buildings + + TargetCoors.z -= 0.1f; + + Center = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false); + if(m_bCollisionChecksOn || PreviouslyObscured || Center != 0.0f || m_fCloseInPedHeightOffset > 0.00001f){ + if(Center != 0.0f){ + AngleToGoTo = Center; + }else{ + LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetAvoidBuildings, true, false, false, true, false); + LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetAvoidBuildings, true, false, false, true, false); + if(LateralLeft == 0.0f && LateralRight != 0.0f){ + AngleToGoTo += LateralRight; + if(m_fCloseInPedHeightOffset > 0.0f) + RwCameraSetNearClipPlane(Scene.camera, 0.7f); + }else if(LateralLeft != 0.0f && LateralRight == 0.0f){ + AngleToGoTo += LateralLeft; + if(m_fCloseInPedHeightOffset > 0.0f) + RwCameraSetNearClipPlane(Scene.camera, 0.7f); + } + } + if(LateralLeft != 0.0f || LateralRight != 0.0f || Center != 0.0f) + BuildingCheckObscured = true; + } + + TargetCoors.z += 0.1f; + } + + if(m_fCloseInPedHeightOffset > 0.00001f) + TargetCoors.z += m_fRoadOffSet; + + + // Have to fix to avoid collision + + if(AngleToGoTo != 0.0f){ + Obscured = true; + Rotating = true; + if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){ + if(!PickedASide) + FixedTargetOrientation = Beta + AngleToGoTo; // can this even happen? + }else + FixedTargetOrientation = Beta + AngleToGoTo; + + // This calculation is only really used to figure out how fast to rotate out of collision + + m_fAmountFractionObscured = 1.0f; + CVector PlayerPos = FindPlayerPed()->GetPosition(); + float RotationDist = (AngleToGoTo == Center ? CenterDist : LateralDist) * RealGroundDist; + // What's going on here? - AngleToGoTo? + CVector RotatedSource = PlayerPos + CVector(Cos(Beta - AngleToGoTo), Sin(Beta - AngleToGoTo), 0.0f) * RotationDist; + + CColPoint colpoint; + CEntity *entity; + if(CWorld::ProcessLineOfSight(PlayerPos, RotatedSource, colpoint, entity, true, false, false, true, false, false, false)){ + if((PlayerPos - RotatedSource).Magnitude() != 0.0f) + m_fAmountFractionObscured = (PlayerPos - colpoint.point).Magnitude() / (PlayerPos - RotatedSource).Magnitude(); + else + m_fAmountFractionObscured = 1.0f; + } + } + if(m_fAmountFractionObscured < 0.0f) m_fAmountFractionObscured = 0.0f; + if(m_fAmountFractionObscured > 1.0f) m_fAmountFractionObscured = 1.0f; + + + + // Figure out speed values for Beta rotation + + float Acceleration, MaxSpeed; + static float AccelerationMult = 0.35f; + static float MaxSpeedMult = 0.85f; + static float AccelerationMultClose = 0.7f; + static float MaxSpeedMultClose = 1.6f; + float BaseAcceleration = 0.025f; + float BaseMaxSpeed = 0.09f; + if(m_fCloseInPedHeightOffset > 0.00001f){ + if(AngleToGoTo == 0.0f){ + BaseAcceleration = 0.022f; + BaseMaxSpeed = 0.04f; + }else{ + BaseAcceleration = DefaultAcceleration; + BaseMaxSpeed = DefaultMaxStep; + } + } + if(AngleToGoTo == 0.0f){ + Acceleration = BaseAcceleration; + MaxSpeed = BaseMaxSpeed; + }else if(CPad::GetPad(0)->ForceCameraBehindPlayer() && !Shooting){ + Acceleration = 0.051f; + MaxSpeed = 0.18f; + }else if(m_fCloseInPedHeightOffset > 0.00001f){ + Acceleration = BaseAcceleration + AccelerationMultClose*sq(m_fAmountFractionObscured - 1.05f); + MaxSpeed = BaseMaxSpeed + MaxSpeedMultClose*sq(m_fAmountFractionObscured - 1.05f); + }else{ + Acceleration = DefaultAcceleration + AccelerationMult*sq(m_fAmountFractionObscured - 1.05f); + MaxSpeed = DefaultMaxStep + MaxSpeedMult*sq(m_fAmountFractionObscured - 1.05f); + } + static float AccelerationLimit = 0.3f; + static float MaxSpeedLimit = 0.65f; + if(Acceleration > AccelerationLimit) Acceleration = AccelerationLimit; + if(MaxSpeed > MaxSpeedLimit) MaxSpeed = MaxSpeedLimit; + + + int MoveState = ((CPed*)CamTargetEntity)->m_nMoveState; + if(MoveState != PEDMOVE_NONE && MoveState != PEDMOVE_STILL && + !CPad::GetPad(0)->ForceCameraBehindPlayer() && !Obscured && !Shooting){ + Rotating = false; + BetaSpeed = 0.0f; + } + + // Now do the Beta rotation + + float Distance = (IdealSource - TargetCoors).Magnitude2D(); + m_fDistanceBeforeChanges = Distance; + + if(Rotating){ + m_bFixingBeta = true; + + while(FixedTargetOrientation >= PI) FixedTargetOrientation -= 2*PI; + while(FixedTargetOrientation < -PI) FixedTargetOrientation += 2*PI; + + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + + +/* + // This is inlined WellBufferMe + DeltaBeta = FixedTargetOrientation - Beta; + while(DeltaBeta >= PI) DeltaBeta -= 2*PI; + while(DeltaBeta < -PI) DeltaBeta += 2*PI; + + float ReqSpeed = DeltaBeta * MaxSpeed; + // Add or subtract absolute depending on sign, genius! + if(ReqSpeed - BetaSpeed > 0.0f) + BetaSpeed += SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep(); + else + BetaSpeed -= SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep(); + // this would be simpler: + // BetaSpeed += SpeedStep * (ReqSpeed - BetaSpeed) * CTimer::ms_fTimeStep; + + if(ReqSpeed < 0.0f && BetaSpeed < ReqSpeed) + BetaSpeed = ReqSpeed; + else if(ReqSpeed > 0.0f && BetaSpeed > ReqSpeed) + BetaSpeed = ReqSpeed; + + Beta += BetaSpeed * min(10.0f, CTimer::GetTimeStep()); +*/ + WellBufferMe(FixedTargetOrientation, &Beta, &BetaSpeed, MaxSpeed, Acceleration, true); + + if(ResetStatics){ + Beta = FixedTargetOrientation; + BetaSpeed = 0.0f; + } + + Source.x = TargetCoors.x + Distance * Cos(Beta); + Source.y = TargetCoors.y + Distance * Sin(Beta); + + // Check if we can stop rotating + DeltaBeta = FixedTargetOrientation - Beta; + while(DeltaBeta >= PI) DeltaBeta -= 2*PI; + while(DeltaBeta < -PI) DeltaBeta += 2*PI; + if(Abs(DeltaBeta) < DEGTORAD(1.0f) && !bBehindPlayerDesired){ + // Stop rotation + PickedASide = false; + Rotating = false; + BetaSpeed = 0.0f; + } + } + + + if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront || + HackPlayerOnStoppingTrain || Rotating){ + if(TheCamera.m_bCamDirectlyBehind){ + Beta = TargetOrientation + PI; + Source.x = TargetCoors.x + Distance * Cos(Beta); + Source.y = TargetCoors.y + Distance * Sin(Beta); + } + if(TheCamera.m_bCamDirectlyInFront){ + Beta = TargetOrientation; + Source.x = TargetCoors.x + Distance * Cos(Beta); + Source.y = TargetCoors.y + Distance * Sin(Beta); + } + if(HackPlayerOnStoppingTrain){ + Beta = TargetOrientation + PI; + Source.x = TargetCoors.x + Distance * Cos(Beta); + Source.y = TargetCoors.y + Distance * Sin(Beta); + m_fDimensionOfHighestNearCar = 0.0f; + m_fCamBufferedHeight = 0.0f; + m_fCamBufferedHeightSpeed = 0.0f; + } + // Beta and Source already set in the rotation code + }else{ + Source = IdealSource; + BetaSpeed = 0.0f; + } + + // Subtract m_fRoadOffSet from both? + TargetCoors.z -= m_fRoadOffSet; + Source.z = IdealSource.z - m_fRoadOffSet; + + // Apply zoom now + // m_fPedZoomValueSmooth makes the cam go down the further out it is + // 0.25 -> 0.20 for nearest dist + // 1.50 -> -0.05 for mid dist + // 2.90 -> -0.33 for far dist + Source.z += (2.5f - TheCamera.m_fPedZoomValueSmooth)*0.2f - 0.25f; + // Zoom out camera + Front = TargetCoors - Source; + Front.Normalise(); + Source -= Front * TheCamera.m_fPedZoomValueSmooth; + // and then we move up again + // -0.375 + // 0.25 + // 0.95 + Source.z += (TheCamera.m_fPedZoomValueSmooth - 1.0f)*0.5f + m_fCloseInPedHeightOffset; + + + // Process height offset to avoid peds and cars + + float TargetZOffSet = m_fRoadOffSet + m_fDimensionOfHighestNearCar; + TargetZOffSet = max(TargetZOffSet, m_fPedBetweenCameraHeightOffset); + float TargetHeight = CameraTarget.z + TargetZOffSet - Source.z; + + if(TargetHeight > m_fCamBufferedHeight){ + // Have to go up + if(TargetZOffSet == m_fPedBetweenCameraHeightOffset && TargetZOffSet > m_fCamBufferedHeight) + WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.04f, false); + else if(TargetZOffSet == m_fRoadOffSet && TargetZOffSet > m_fCamBufferedHeight){ + // TODO: figure this out + bool foo = false; + switch(((CPhysical*)CamTargetEntity)->m_nSurfaceTouched) + case SURFACE_GRASS: + case SURFACE_DIRT: + case SURFACE_PAVEMENT: + case SURFACE_STEEL: + case SURFACE_TIRE: + case SURFACE_STONE: + foo = true; + if(foo) + WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.4f, 0.05f, false); + else + WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false); + }else + WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false); + StartedCountingForGoDown = false; + }else{ + // Have to go down + if(StartedCountingForGoDown){ + if(CTimer::GetTimeInMilliseconds() != TimeIndicatedWantedToGoDown){ + if(TargetHeight > 0.0f) + WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false); + else + WellBufferMe(0.0f, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false); + } + }else{ + StartedCountingForGoDown = true; + TimeIndicatedWantedToGoDown = CTimer::GetTimeInMilliseconds(); + } + } + + Source.z += m_fCamBufferedHeight; + + + // Clip Source if necessary + + bool ClipSource = m_fCloseInPedHeightOffset > 0.00001f && m_fCamBufferedHeight > 0.001f; + if(GoingBehind || ResetStatics || ClipSource){ + CColPoint colpoint; + CEntity *entity; + if(CWorld::ProcessLineOfSight(TargetCoors, Source, colpoint, entity, true, false, false, true, false, true, true)){ + Source = colpoint.point; + if((TargetCoors - Source).Magnitude2D() < 1.0f) + RwCameraSetNearClipPlane(Scene.camera, 0.05f); + } + } + + TargetCoors.z += min(1.0f, m_fCamBufferedHeight/2.0f); + m_cvecTargetCoorsForFudgeInter = TargetCoors; + + Front = TargetCoors - Source; + m_fRealGroundDist = Front.Magnitude2D(); + m_fMinDistAwayFromCamWhenInterPolating = m_fRealGroundDist; + Front.Normalise(); + GetVectorsReadyForRW(); + TheCamera.m_bCamDirectlyBehind = false; + TheCamera.m_bCamDirectlyInFront = false; + PreviouslyObscured = BuildingCheckObscured; + + ResetStatics = false; +} + +static float fBaseDist = 1.7f; +static float fAngleDist = 2.0f; +static float fFalloff = 3.0f; +static float fStickSens = 0.01f; +static float fTweakFOV = 1.05f; +static float fTranslateCamUp = 0.8f; +static int16 nFadeControlThreshhold = 45; +static float fDefaultAlphaOrient = -0.22f; + +void +CCam::Process_FollowPedWithMouse(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + FOV = DefaultFOV; + + if(!CamTargetEntity->IsPed()) + return; + + CVector TargetCoors; + float CamDist; + CColPoint colPoint; + CEntity *entity; + + if(ResetStatics){ + Rotating = false; + m_bCollisionChecksOn = true; + CPad::GetPad(0)->ClearMouseHistory(); + ResetStatics = false; + } + + bool OnTrain = FindPlayerVehicle() && FindPlayerVehicle()->IsTrain(); + + // Look around + bool UseMouse = false; + float MouseX = CPad::GetPad(0)->GetMouseX(); + float MouseY = CPad::GetPad(0)->GetMouseY(); + float LookLeftRight, LookUpDown; + if((MouseX != 0.0f || MouseY != 0.0f) && !CPad::GetPad(0)->ArePlayerControlsDisabled()){ + UseMouse = true; + LookLeftRight = -2.5f*MouseX; + LookUpDown = 4.0f*MouseY; + }else{ + LookLeftRight = -CPad::GetPad(0)->LookAroundLeftRight(); + LookUpDown = CPad::GetPad(0)->LookAroundUpDown(); + } + float AlphaOffset, BetaOffset; + if(UseMouse){ + BetaOffset = LookLeftRight * TheCamera.m_fMouseAccelHorzntl * FOV/80.0f; + AlphaOffset = LookUpDown * TheCamera.m_fMouseAccelVertical * FOV/80.0f; + }else{ + BetaOffset = LookLeftRight * fStickSens * (0.5f/7.0f) * FOV/80.0f * CTimer::GetTimeStep(); + AlphaOffset = LookUpDown * fStickSens * (0.3f/7.0f) * FOV/80.0f * CTimer::GetTimeStep(); + } + + if(TheCamera.GetFading() && TheCamera.GetFadingDirection() == FADE_IN && nFadeControlThreshhold < CDraw::FadeValue || + CDraw::FadeValue > 200){ + if(Alpha < fDefaultAlphaOrient-0.05f) + AlphaOffset = 0.05f; + else if(Alpha < fDefaultAlphaOrient) + AlphaOffset = fDefaultAlphaOrient - Alpha; + else if(Alpha > fDefaultAlphaOrient+0.05f) + AlphaOffset = -0.05f; + else if(Alpha > fDefaultAlphaOrient) + AlphaOffset = fDefaultAlphaOrient - Alpha; + else + AlphaOffset = 0.0f; + } + + Alpha += AlphaOffset; + Beta += BetaOffset; + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + if(Alpha > DEGTORAD(45.0f)) Alpha = DEGTORAD(45.0f); + if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f); + + TargetCoors = CameraTarget; + TargetCoors.z += fTranslateCamUp; + TargetCoors = DoAverageOnVector(TargetCoors); + + if(Alpha > fBaseDist) // comparing an angle against a distance? + CamDist = fBaseDist + Cos(min(Alpha*fFalloff, HALFPI))*fAngleDist; + else + CamDist = fBaseDist + Cos(Alpha)*fAngleDist; + + if(TheCamera.m_bUseTransitionBeta) + Beta = -CGeneral::GetATanOfXY(-Cos(m_fTransitionBeta), -Sin(m_fTransitionBeta)); + + if(TheCamera.m_bCamDirectlyBehind) + Beta = TheCamera.m_PedOrientForBehindOrInFront; + if(TheCamera.m_bCamDirectlyInFront) + Beta = TheCamera.m_PedOrientForBehindOrInFront + PI; + if(OnTrain) + Beta = TargetOrientation; + + Front.x = Cos(Alpha) * Cos(Beta); + Front.y = Cos(Alpha) * Sin(Beta); + Front.z = Sin(Alpha); + Source = TargetCoors - Front*CamDist; + m_cvecTargetCoorsForFudgeInter = TargetCoors; + + // Clip Source and fix near clip + CWorld::pIgnoreEntity = CamTargetEntity; + entity = nil; + if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, true, true, true, false, false, true)){ + float PedColDist = (TargetCoors - colPoint.point).Magnitude(); + float ColCamDist = CamDist - PedColDist; + if(entity->IsPed() && ColCamDist > 1.0f){ + // Ped in the way but not clipping through + if(CWorld::ProcessLineOfSight(colPoint.point, Source, colPoint, entity, true, true, true, true, false, false, true)){ + PedColDist = (TargetCoors - colPoint.point).Magnitude(); + Source = colPoint.point; + if(PedColDist < 0.9f + 0.3f) + RwCameraSetNearClipPlane(Scene.camera, max(PedColDist-0.3f, 0.05f)); + }else{ + RwCameraSetNearClipPlane(Scene.camera, min(ColCamDist-0.35f, 0.9f)); + } + }else{ + Source = colPoint.point; + if(PedColDist < 0.9f + 0.3f) + RwCameraSetNearClipPlane(Scene.camera, max(PedColDist-0.3f, 0.05f)); + } + } + CWorld::pIgnoreEntity = nil; + + float ViewPlaneHeight = Tan(DEGTORAD(FOV) / 2.0f); + float ViewPlaneWidth = ViewPlaneHeight * CDraw::FindAspectRatio() * fTweakFOV; + float Near = RwCameraGetNearClipPlane(Scene.camera); + float radius = ViewPlaneWidth*Near; + entity = CWorld::TestSphereAgainstWorld(Source + Front*Near, radius, nil, true, true, false, true, false, false); + int i = 0; + while(entity){ + CVector CamToCol = gaTempSphereColPoints[0].point - Source; + float frontDist = DotProduct(CamToCol, Front); + float dist = (CamToCol - Front*frontDist).Magnitude() / ViewPlaneWidth; + + // Try to decrease near clip + dist = max(min(Near, dist), 0.1f); + if(dist < Near) + RwCameraSetNearClipPlane(Scene.camera, dist); + + // Move forward a bit + if(dist == 0.1f) + Source += (TargetCoors - Source)*0.3f; + +#ifndef FIX_BUGS + // this is totally wrong... + radius = Tan(FOV / 2.0f) * Near; +#endif + // Keep testing + entity = CWorld::TestSphereAgainstWorld(Source + Front*Near, radius, nil, true, true, false, true, false, false); + + i++; + if(i > 5) + entity = nil; + } + + if(CamTargetEntity->m_rwObject){ + // what's going on here? + if(RpAnimBlendClumpGetAssociation(CamTargetEntity->GetClump(), ANIM_WEAPON_PUMP) || + RpAnimBlendClumpGetAssociation(CamTargetEntity->GetClump(), ANIM_WEAPON_THROW) || + RpAnimBlendClumpGetAssociation(CamTargetEntity->GetClump(), ANIM_WEAPON_THROWU) || + RpAnimBlendClumpGetAssociation(CamTargetEntity->GetClump(), ANIM_WEAPON_START_THROW)){ + CPed *player = FindPlayerPed(); + float PlayerDist = (Source - player->GetPosition()).Magnitude(); + if(PlayerDist < 2.75f) + Near = PlayerDist/2.75f * 0.9f - 0.3f; + RwCameraSetNearClipPlane(Scene.camera, max(Near, 0.1f)); + } + } + + TheCamera.m_bCamDirectlyInFront = false; + TheCamera.m_bCamDirectlyBehind = false; + + GetVectorsReadyForRW(); + + if(((CPed*)CamTargetEntity)->CanStrafeOrMouseControl() && CDraw::FadeValue < 250 && + (TheCamera.GetFadingDirection() != FADE_OUT || CDraw::FadeValue <= 100)){ + float Heading = Front.Heading(); + ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Heading; + ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Heading; + TheCamera.pTargetEntity->SetHeading(Heading); + TheCamera.pTargetEntity->GetMatrix().UpdateRW(); + } +} + +void +CCam::Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + FOV = DefaultFOV; + + if(!CamTargetEntity->IsVehicle()) + return; + + CVector TargetCoors = CameraTarget; + TargetCoors.z -= 0.2f; + CA_MAX_DISTANCE = 9.95f; + CA_MIN_DISTANCE = 8.5f; + + CVector Dist = Source - TargetCoors; + float Length = Dist.Magnitude2D(); + m_fDistanceBeforeChanges = Length; + if(Length < 0.002f) + Length = 0.002f; + Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y); + if(Length > CA_MAX_DISTANCE){ + Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE; + Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE; + }else if(Length < CA_MIN_DISTANCE){ + Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE; + Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE; + } + TargetCoors.z += 0.8f; + + WorkOutCamHeightWeeCar(TargetCoors, TargetOrientation); + RotCamIfInFrontCar(TargetCoors, TargetOrientation); + FixCamIfObscured(TargetCoors, 1.2f, TargetOrientation); + + Front = TargetCoors - Source; + m_cvecTargetCoorsForFudgeInter = TargetCoors; + ResetStatics = false; + GetVectorsReadyForRW(); +} + +void +CCam::WorkOutCamHeightWeeCar(CVector &TargetCoors, float TargetOrientation) +{ + CColPoint colpoint; + CEntity *ent; + float TargetZOffSet = 0.0f; + static bool PreviouslyFailedRoadHeightCheck = false; + static float RoadHeightFix = 0.0f; + static float RoadHeightFixSpeed = 0.0f; + + if(ResetStatics){ + RoadHeightFix = 0.0f; + RoadHeightFixSpeed = 0.0f; + Alpha = DEGTORAD(25.0f); + AlphaSpeed = 0.0f; + } + float AlphaTarget = DEGTORAD(25.0f); + if(CCullZones::CamNoRain() || CCullZones::PlayerNoRain()) + AlphaTarget = DEGTORAD(14.0f); + WellBufferMe(AlphaTarget, &Alpha, &AlphaSpeed, 0.1f, 0.05f, true); + Source.z = TargetCoors.z + CA_MAX_DISTANCE*Sin(Alpha); + + if(FindPlayerVehicle()){ + m_fRoadOffSet = 0.0f; + bool FoundRoad = false; + bool FoundRoof = false; + float RoadZ = 0.0f; + float RoofZ = 0.0f; + + if(CWorld::ProcessVerticalLine(Source, -1000.0f, colpoint, ent, true, false, false, false, false, false, nil) && + ent->IsBuilding()){ + FoundRoad = true; + RoadZ = colpoint.point.z; + } + + if(FoundRoad){ + if(Source.z - RoadZ < 0.9f){ + PreviouslyFailedRoadHeightCheck = true; + TargetZOffSet = RoadZ + 0.9f - Source.z; + }else{ + if(m_bCollisionChecksOn) + PreviouslyFailedRoadHeightCheck = false; + else + TargetZOffSet = 0.0f; + } + }else{ + if(CWorld::ProcessVerticalLine(Source, 1000.0f, colpoint, ent, true, false, false, false, false, false, nil) && + ent->IsBuilding()){ + FoundRoof = true; + RoofZ = colpoint.point.z; + } + if(FoundRoof){ + if(Source.z - RoofZ < 0.9f){ + PreviouslyFailedRoadHeightCheck = true; + TargetZOffSet = RoofZ + 0.9f - Source.z; + }else{ + if(m_bCollisionChecksOn) + PreviouslyFailedRoadHeightCheck = false; + else + TargetZOffSet = 0.0f; + } + } + } + } + + if(TargetZOffSet > RoadHeightFix) + RoadHeightFix = TargetZOffSet; + else + WellBufferMe(TargetZOffSet, &RoadHeightFix, &RoadHeightFixSpeed, 0.27f, 0.1f, false); + + if((colpoint.surfaceB == SURFACE_DEFAULT || colpoint.surfaceB >= SURFACE_METAL6) && + colpoint.surfaceB != SURFACE_STEEL && colpoint.surfaceB != SURFACE_STONE && + RoadHeightFix > 1.4f) + RoadHeightFix = 1.4f; + + Source.z += RoadHeightFix; +} + +void +CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight) +{ + static float LastTargetAlphaWithCollisionOn = 0.0f; + static float LastTopAlphaSpeed = 0.0f; + static float LastAlphaSpeedStep = 0.0f; + static bool PreviousNearCheckNearClipSmall = false; + + bool CamClear = true; + float ModeAlpha = 0.0f; + + if(ResetStatics){ + LastTargetAlphaWithCollisionOn = 0.0f; + LastTopAlphaSpeed = 0.0f; + LastAlphaSpeedStep = 0.0f; + PreviousNearCheckNearClipSmall = false; + } + + float TopAlphaSpeed = 0.15f; + float AlphaSpeedStep = 0.015f; + + float zoomvalue = TheCamera.CarZoomValueSmooth; + if(zoomvalue < 0.1f) + zoomvalue = 0.1f; + if(TheCamera.CarZoomIndicator == 1.0f) + ModeAlpha = CGeneral::GetATanOfXY(23.0f, zoomvalue); // near + else if(TheCamera.CarZoomIndicator == 2.0f) + ModeAlpha = CGeneral::GetATanOfXY(10.8f, zoomvalue); // mid + else if(TheCamera.CarZoomIndicator == 3.0f) + ModeAlpha = CGeneral::GetATanOfXY(7.0f, zoomvalue); // far + + + float Length = (Source - TargetCoors).Magnitude2D(); + if(m_bCollisionChecksOn){ // there's another variable (on PC) but it's uninitialised + CVector Forward = CamTargetEntity->GetForward(); + float CarAlpha = CGeneral::GetATanOfXY(Forward.Magnitude2D(), Forward.z); + // this shouldn't be necessary.... + while(CarAlpha >= PI) CarAlpha -= 2*PI; + while(CarAlpha < -PI) CarAlpha += 2*PI; + + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + + float deltaBeta = Beta - TargetOrientation; + while(deltaBeta >= PI) deltaBeta -= 2*PI; + while(deltaBeta < -PI) deltaBeta += 2*PI; + + float BehindCarNess = Cos(deltaBeta); // 1 if behind car, 0 if side, -1 if in front + CarAlpha = -CarAlpha * BehindCarNess; + if(CarAlpha < -0.01f) + CarAlpha = -0.01f; + + float DeltaAlpha = CarAlpha - Alpha; + while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI; + while(DeltaAlpha < -PI) DeltaAlpha += 2*PI; + // What's this?? wouldn't it make more sense to clamp? + float AngleLimit = DEGTORAD(1.8f); + if(DeltaAlpha < -AngleLimit) + DeltaAlpha += AngleLimit; + else if(DeltaAlpha > AngleLimit) + DeltaAlpha -= AngleLimit; + else + DeltaAlpha = 0.0f; + + // Now the collision + + float TargetAlpha = 0.0f; + bool FoundRoofCenter = false; + bool FoundRoofSide1 = false; + bool FoundRoofSide2 = false; + bool FoundCamRoof = false; + bool FoundCamGround = false; + float CamRoof = 0.0f; + float CarBottom = TargetCoors.z - TargetHeight/2.0f; + + // Check car center + float CarRoof = CWorld::FindRoofZFor3DCoord(TargetCoors.x, TargetCoors.y, CarBottom, &FoundRoofCenter); + + // Check sides of the car + Forward = CamTargetEntity->GetForward(); // we actually still have that... + Forward.Normalise(); // shouldn't be necessary + float CarSideAngle = CGeneral::GetATanOfXY(Forward.x, Forward.y) + PI/2.0f; + float SideX = 2.5f * Cos(CarSideAngle); + float SideY = 2.5f * Sin(CarSideAngle); + CWorld::FindRoofZFor3DCoord(TargetCoors.x + SideX, TargetCoors.y + SideY, CarBottom, &FoundRoofSide1); + CWorld::FindRoofZFor3DCoord(TargetCoors.x - SideX, TargetCoors.y - SideY, CarBottom, &FoundRoofSide2); + + // Now find out at what height we'd like to place the camera + float CamGround = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, TargetCoors.z + Length*Sin(Alpha + ModeAlpha) + m_fCloseInCarHeightOffset, &FoundCamGround); + float CamTargetZ = 0.0f; + if(FoundCamGround){ + // This is the normal case + CamRoof = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamGround + TargetHeight, &FoundCamRoof); + CamTargetZ = CamGround + TargetHeight*1.5f + 0.1f; + }else{ + FoundCamRoof = false; + CamTargetZ = TargetCoors.z; + } + + if(FoundRoofCenter && !FoundCamRoof && (FoundRoofSide1 || FoundRoofSide2)){ + // Car is under something but camera isn't + // This seems weird... + TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, CarRoof - CamTargetZ - 1.5f); + CamClear = false; + } + if(FoundCamRoof){ + // Camera is under something + float roof = FoundRoofCenter ? min(CamRoof, CarRoof) : CamRoof; + // Same weirdness again? + TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, roof - CamTargetZ - 1.5f); + CamClear = false; + } + while(TargetAlpha >= PI) TargetAlpha -= 2*PI; + while(TargetAlpha < -PI) TargetAlpha += 2*PI; + if(TargetAlpha < DEGTORAD(-7.0f)) + TargetAlpha = DEGTORAD(-7.0f); + + // huh? + if(TargetAlpha > ModeAlpha) + CamClear = true; + // Camera is contrained by collision in some way + PreviousNearCheckNearClipSmall = false; + if(!CamClear){ + PreviousNearCheckNearClipSmall = true; + RwCameraSetNearClipPlane(Scene.camera, 0.9f); + + DeltaAlpha = TargetAlpha - (Alpha + ModeAlpha); + while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI; + while(DeltaAlpha < -PI) DeltaAlpha += 2*PI; + + TopAlphaSpeed = 0.3f; + AlphaSpeedStep = 0.03f; + } + + // Now do things if CamClear...but what is that anyway? + float CamZ = TargetCoors.z + Length*Sin(Alpha + DeltaAlpha + ModeAlpha) + m_fCloseInCarHeightOffset; + bool FoundGround, FoundRoof; + float CamGround2 = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, CamZ, &FoundGround); + if(FoundGround){ + if(CamClear) + if(CamZ - CamGround2 < 1.5f){ + PreviousNearCheckNearClipSmall = true; + RwCameraSetNearClipPlane(Scene.camera, 0.9f); + + float a; + if(Length == 0.0f || CamGround2 + 1.5f - TargetCoors.z == 0.0f) + a = Alpha; + else + a = CGeneral::GetATanOfXY(Length, CamGround2 + 1.5f - TargetCoors.z); + while(a > PI) a -= 2*PI; + while(a < -PI) a += 2*PI; + DeltaAlpha = a - Alpha; + } + }else{ + if(CamClear){ + float CamRoof2 = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamZ, &FoundRoof); + if(FoundRoof && CamZ - CamRoof2 < 1.5f){ + PreviousNearCheckNearClipSmall = true; + RwCameraSetNearClipPlane(Scene.camera, 0.9f); + + if(CamRoof2 > TargetCoors.z + 3.5f) + CamRoof2 = TargetCoors.z + 3.5f; + + float a; + if(Length == 0.0f || CamRoof2 + 1.5f - TargetCoors.z == 0.0f) + a = Alpha; + else + a = CGeneral::GetATanOfXY(Length, CamRoof2 + 1.5f - TargetCoors.z); + while(a > PI) a -= 2*PI; + while(a < -PI) a += 2*PI; + DeltaAlpha = a - Alpha; + } + } + } + + LastTargetAlphaWithCollisionOn = DeltaAlpha + Alpha; + LastTopAlphaSpeed = TopAlphaSpeed; + LastAlphaSpeedStep = AlphaSpeedStep; + }else{ + if(PreviousNearCheckNearClipSmall) + RwCameraSetNearClipPlane(Scene.camera, 0.9f); + } + + WellBufferMe(LastTargetAlphaWithCollisionOn, &Alpha, &AlphaSpeed, LastTopAlphaSpeed, LastAlphaSpeedStep, true); + + Source.z = TargetCoors.z + Sin(Alpha + ModeAlpha)*Length + m_fCloseInCarHeightOffset; +} + +// Rotate cam behind the car when the car is moving forward +bool +CCam::RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation) +{ + bool MovingForward = false; + CPhysical *phys = (CPhysical*)CamTargetEntity; + + float ForwardSpeed = DotProduct(phys->GetForward(), phys->GetSpeed(CVector(0.0f, 0.0f, 0.0f))); + if(ForwardSpeed > 0.02f) + MovingForward = true; + + float Dist = (Source - TargetCoors).Magnitude2D(); + + float DeltaBeta = TargetOrientation - Beta; + while(DeltaBeta >= PI) DeltaBeta -= 2*PI; + while(DeltaBeta < -PI) DeltaBeta += 2*PI; + + if(Abs(DeltaBeta) > DEGTORAD(20.0f) && MovingForward && TheCamera.m_uiTransitionState == 0) + m_bFixingBeta = true; + + CPad *pad = CPad::GetPad(0); + if(!(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight())) + if(DirectionWasLooking != LOOKING_FORWARD) + TheCamera.m_bCamDirectlyBehind = true; + + if(!m_bFixingBeta && !TheCamera.m_bUseTransitionBeta && !TheCamera.m_bCamDirectlyBehind && !TheCamera.m_bCamDirectlyInFront) + return false; + + bool SetBeta = false; + if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront || TheCamera.m_bUseTransitionBeta) + if(&TheCamera.Cams[TheCamera.ActiveCam] == this) + SetBeta = true; + + if(m_bFixingBeta || SetBeta){ + WellBufferMe(TargetOrientation, &Beta, &BetaSpeed, 0.15f, 0.007f, true); + + if(TheCamera.m_bCamDirectlyBehind && &TheCamera.Cams[TheCamera.ActiveCam] == this) + Beta = TargetOrientation; + if(TheCamera.m_bCamDirectlyInFront && &TheCamera.Cams[TheCamera.ActiveCam] == this) + Beta = TargetOrientation + PI; + if(TheCamera.m_bUseTransitionBeta && &TheCamera.Cams[TheCamera.ActiveCam] == this) + Beta = m_fTransitionBeta; + + Source.x = TargetCoors.x - Cos(Beta)*Dist; + Source.y = TargetCoors.y - Sin(Beta)*Dist; + + // Check if we're done + DeltaBeta = TargetOrientation - Beta; + while(DeltaBeta >= PI) DeltaBeta -= 2*PI; + while(DeltaBeta < -PI) DeltaBeta += 2*PI; + if(Abs(DeltaBeta) < DEGTORAD(2.0f)) + m_bFixingBeta = false; + } + TheCamera.m_bCamDirectlyBehind = false; + TheCamera.m_bCamDirectlyInFront = false; + return true; +} + +// Move the cam to avoid clipping through buildings +bool +CCam::FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation) +{ + CVector Target = TargetCoors; + bool UseEntityPos = false; + CVector EntityPos; + static CColPoint colPoint; + static bool LastObscured = false; + + if(Mode == MODE_BEHINDCAR) + Target.z += TargetHeight/2.0f; + if(Mode == MODE_CAM_ON_A_STRING){ + UseEntityPos = true; + Target.z += TargetHeight/2.0f; + EntityPos = CamTargetEntity->GetPosition(); + } + + CVector TempSource = Source; + + bool Obscured1 = false; + bool Obscured2 = false; + bool Fix1 = false; + float Dist1 = 0.0f; + float Dist2 = 0.0f; + CEntity *ent; + if(m_bCollisionChecksOn || LastObscured){ + Obscured1 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true); + if(Obscured1){ + Dist1 = (Target - colPoint.point).Magnitude2D(); + Fix1 = true; + if(UseEntityPos) + Obscured1 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true); + }else if(m_bFixingBeta){ + float d = (TempSource - Target).Magnitude(); + TempSource.x = Target.x - d*Cos(TargetOrientation); + TempSource.y = Target.y - d*Sin(TargetOrientation); + + // same check again + Obscured2 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true); + if(Obscured2){ + Dist2 = (Target - colPoint.point).Magnitude2D(); + if(UseEntityPos) + Obscured2 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true); + } + } + LastObscured = Obscured1 || Obscured2; + } + + // nothing to do + if(!LastObscured) + return false; + + if(Fix1){ + Source.x = Target.x - Cos(Beta)*Dist1; + Source.y = Target.y - Sin(Beta)*Dist1; + if(Mode == MODE_BEHINDCAR) + Source = colPoint.point; + }else{ + WellBufferMe(Dist2, &m_fDistanceBeforeChanges, &DistanceSpeed, 0.2f, 0.025f, false); + Source.x = Target.x - Cos(Beta)*m_fDistanceBeforeChanges; + Source.y = Target.y - Sin(Beta)*m_fDistanceBeforeChanges; + } + + if(ResetStatics){ + m_fDistanceBeforeChanges = (Source - Target).Magnitude2D(); + DistanceSpeed = 0.0f; + Source.x = colPoint.point.x; + Source.y = colPoint.point.y; + } + return true; +} + +void +CCam::Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + if(!CamTargetEntity->IsVehicle()) + return; + + FOV = DefaultFOV; + + if(ResetStatics){ + AlphaSpeed = 0.0f; + if(TheCamera.m_bIdleOn) + TheCamera.m_uiTimeWeEnteredIdle = CTimer::GetTimeInMilliseconds(); + } + + CBaseModelInfo *mi = CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex()); + CVector Dimensions = mi->GetColModel()->boundingBox.max - mi->GetColModel()->boundingBox.min; + float BaseDist = Dimensions.Magnitude2D(); + + CVector TargetCoors = CameraTarget; + TargetCoors.z += Dimensions.z - 0.1f; // final + Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y); + while(Alpha >= PI) Alpha -= 2*PI; + while(Alpha < -PI) Alpha += 2*PI; + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + + m_fDistanceBeforeChanges = (Source - TargetCoors).Magnitude2D(); + + Cam_On_A_String_Unobscured(TargetCoors, BaseDist); + WorkOutCamHeight(TargetCoors, TargetOrientation, Dimensions.z); + RotCamIfInFrontCar(TargetCoors, TargetOrientation); + FixCamIfObscured(TargetCoors, Dimensions.z, TargetOrientation); + FixCamWhenObscuredByVehicle(TargetCoors); + + m_cvecTargetCoorsForFudgeInter = TargetCoors; + Front = TargetCoors - Source; + Front.Normalise(); + GetVectorsReadyForRW(); + ResetStatics = false; +} + +// Basic Cam on a string algorithm +void +CCam::Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist) +{ + CA_MAX_DISTANCE = BaseDist + 0.1f + TheCamera.CarZoomValueSmooth; + CA_MIN_DISTANCE = min(BaseDist*0.6f, 3.5f); + + CVector Dist = Source - TargetCoors; + + if(ResetStatics) + Source = TargetCoors + Dist*(CA_MAX_DISTANCE + 1.0f); + + float Length = Dist.Magnitude2D(); + if(Length < 0.001f){ + // This probably shouldn't happen. reset view + CVector Forward = CamTargetEntity->GetForward(); + Forward.z = 0.0f; + Forward.Normalise(); + Source = TargetCoors - Forward*CA_MAX_DISTANCE; + Dist = Source - TargetCoors; + Length = Dist.Magnitude2D(); + } + + if(Length > CA_MAX_DISTANCE){ + Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE; + Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE; + }else if(Length < CA_MIN_DISTANCE){ + Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE; + Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE; + } +} + +void +CCam::FixCamWhenObscuredByVehicle(const CVector &TargetCoors) +{ + // BUG? is this never reset + static float HeightFixerCarsObscuring = 0.0f; + static float HeightFixerCarsObscuringSpeed = 0.0f; + CColPoint colPoint; + CEntity *entity; + + float HeightTarget = 0.0f; + if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, false, true, false, false, false, false, false)){ + CBaseModelInfo *mi = CModelInfo::GetModelInfo(entity->GetModelIndex()); + HeightTarget = mi->GetColModel()->boundingBox.max.z + 1.0f + TargetCoors.z - Source.z; + if(HeightTarget < 0.0f) + HeightTarget = 0.0f; + } + WellBufferMe(HeightTarget, &HeightFixerCarsObscuring, &HeightFixerCarsObscuringSpeed, 0.2f, 0.025f, false); + Source.z += HeightFixerCarsObscuring; +} + +void +CCam::Process_TopDown(const CVector &CameraTarget, float TargetOrientation, float SpeedVar, float TargetSpeedVar) +{ + FOV = DefaultFOV; + + if(!CamTargetEntity->IsVehicle()) + return; + + float Dist; + float HeightTarget = 0.0f; + static float AdjustHeightTargetMoveBuffer = 0.0f; + static float AdjustHeightTargetMoveSpeed = 0.0f; + static float NearClipDistance = 1.5f; + const float FarClipDistance = 200.0f; + CVector TargetFront, Target; + CVector TestSource, TestTarget; + CColPoint colPoint; + CEntity *entity; + + TargetFront = CameraTarget; + TargetFront.x += 18.0f*CamTargetEntity->GetForward().x*SpeedVar; + TargetFront.y += 18.0f*CamTargetEntity->GetForward().y*SpeedVar; + + if(ResetStatics){ + AdjustHeightTargetMoveBuffer = 0.0f; + AdjustHeightTargetMoveSpeed = 0.0f; + } + + float f = Pow(0.8f, 4.0f); + Target = f*CameraTarget + (1.0f-f)*TargetFront; + if(Mode == MODE_GTACLASSIC) + SpeedVar = TargetSpeedVar; + Source = Target + CVector(0.0f, 0.0f, (40.0f*SpeedVar + 30.0f)*0.8f); + // What is this? looks horrible + if(Mode == MODE_GTACLASSIC) + Source.x += (uint8)(100.0f*CameraTarget.x)/500.0f; + + TestSource = Source; + TestTarget = TestSource; + TestTarget.z = Target.z; + if(CWorld::ProcessLineOfSight(TestTarget, TestSource, colPoint, entity, true, false, false, false, false, false, false)){ + if(Source.z < colPoint.point.z+3.0f) + HeightTarget = colPoint.point.z+3.0f - Source.z; + }else{ + TestSource = Source; + TestTarget = TestSource; + TestTarget.z += 10.0f; + if(CWorld::ProcessLineOfSight(TestTarget, TestSource, colPoint, entity, true, false, false, false, false, false, false)) + if(Source.z < colPoint.point.z+3.0f) + HeightTarget = colPoint.point.z+3.0f - Source.z; + } + WellBufferMe(HeightTarget, &AdjustHeightTargetMoveBuffer, &AdjustHeightTargetMoveSpeed, 0.2f, 0.02f, false); + Source.z += AdjustHeightTargetMoveBuffer; + + if(RwCameraGetFarClipPlane(Scene.camera) > FarClipDistance) + RwCameraSetFarClipPlane(Scene.camera, FarClipDistance); + RwCameraSetNearClipPlane(Scene.camera, NearClipDistance); + + Front = CVector(-0.01f, -0.01f, -1.0f); // look down + Front.Normalise(); + Dist = (Source - CameraTarget).Magnitude(); + m_cvecTargetCoorsForFudgeInter = Dist*Front + Source; + Up = CVector(0.0f, 1.0f, 0.0f); + + ResetStatics = false; +} + +void +CCam::AvoidWallsTopDownPed(const CVector &TargetCoors, const CVector &Offset, float *Adjuster, float *AdjusterSpeed, float yDistLimit) +{ + float Target = 0.0f; + float MaxSpeed = 0.13f; + float Acceleration = 0.015f; + float SpeedMult; + float dy; + CVector TestPoint2; + CVector TestPoint1; + CColPoint colPoint; + CEntity *entity; + + TestPoint2 = TargetCoors + Offset; + TestPoint1 = TargetCoors; + TestPoint1.z = TestPoint2.z; + if(CWorld::ProcessLineOfSight(TestPoint1, TestPoint2, colPoint, entity, true, false, false, false, false, false, false)){ + // What is this even? + dy = TestPoint1.y - colPoint.point.y; + if(dy > yDistLimit) + dy = yDistLimit; + SpeedMult = yDistLimit - Abs(dy/yDistLimit); + + Target = 2.5f; + MaxSpeed += SpeedMult*0.3f; + Acceleration += SpeedMult*0.03f; + } + WellBufferMe(Target, Adjuster, AdjusterSpeed, MaxSpeed, Acceleration, false); +} + +void +CCam::Process_TopDownPed(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + if(!CamTargetEntity->IsPed()) + return; + + float Dist; + float HeightTarget; + static int NumPedPosCountsSoFar = 0; + static float PedAverageSpeed = 0.0f; + static float AdjustHeightTargetMoveBuffer = 0.0f; + static float AdjustHeightTargetMoveSpeed = 0.0f; + static float PedSpeedSoFar = 0.0f; + static float FarClipDistance = 200.0f; + static float NearClipDistance = 1.5f; + static float TargetAdjusterForSouth = 0.0f; + static float TargetAdjusterSpeedForSouth = 0.0f; + static float TargetAdjusterForNorth = 0.0f; + static float TargetAdjusterSpeedForNorth = 0.0f; + static float TargetAdjusterForEast = 0.0f; + static float TargetAdjusterSpeedForEast = 0.0f; + static float TargetAdjusterForWest = 0.0f; + static float TargetAdjusterSpeedForWest = 0.0f; + static CVector PreviousPlayerMoveSpeedVec; + CVector TargetCoors, PlayerMoveSpeed; + CVector TestSource, TestTarget; + CColPoint colPoint; + CEntity *entity; + + FOV = DefaultFOV; + TargetCoors = CameraTarget; + PlayerMoveSpeed = ((CPed*)CamTargetEntity)->GetMoveSpeed(); + + if(ResetStatics){ + PreviousPlayerMoveSpeedVec = PlayerMoveSpeed; + AdjustHeightTargetMoveBuffer = 0.0f; + AdjustHeightTargetMoveSpeed = 0.0f; + NumPedPosCountsSoFar = 0; + PedSpeedSoFar = 0.0f; + PedAverageSpeed = 0.0f; + TargetAdjusterForWest = 0.0f; + TargetAdjusterSpeedForWest = 0.0f; + TargetAdjusterForEast = 0.0f; + TargetAdjusterSpeedForEast = 0.0f; + TargetAdjusterForNorth = 0.0f; + TargetAdjusterSpeedForNorth = 0.0f; + TargetAdjusterForSouth = 0.0f; + TargetAdjusterSpeedForSouth = 0.0f; + } + + if(RwCameraGetFarClipPlane(Scene.camera) > FarClipDistance) + RwCameraSetFarClipPlane(Scene.camera, FarClipDistance); + RwCameraSetNearClipPlane(Scene.camera, NearClipDistance); + + // Average ped speed + NumPedPosCountsSoFar++; + PedSpeedSoFar += PlayerMoveSpeed.Magnitude(); + if(NumPedPosCountsSoFar == 5){ + PedAverageSpeed = 0.4f*PedAverageSpeed + 0.6*(PedSpeedSoFar/5.0f); + NumPedPosCountsSoFar = 0; + PedSpeedSoFar = 0.0f; + } + PreviousPlayerMoveSpeedVec = PlayerMoveSpeed; + + // Zoom out depending on speed + if(PedAverageSpeed > 0.01f && PedAverageSpeed <= 0.04f) + HeightTarget = 2.5f; + else if(PedAverageSpeed > 0.04f && PedAverageSpeed <= 0.145f) + HeightTarget = 4.5f; + else if(PedAverageSpeed > 0.145f) + HeightTarget = 7.0f; + else + HeightTarget = 0.0f; + + // Zoom out if locked on target is far away + if(FindPlayerPed()->m_pPointGunAt){ + Dist = (FindPlayerPed()->m_pPointGunAt->GetPosition() - CameraTarget).Magnitude2D(); + if(Dist > 6.0f) + HeightTarget = max(HeightTarget, Dist/22.0f*37.0f); + } + + Source = TargetCoors + CVector(0.0f, -1.0f, 9.0f); + + // Collision checks + entity = nil; + TestSource = TargetCoors + CVector(0.0f, -1.0f, 9.0f); + TestTarget = TestSource; + TestTarget.z = TargetCoors.z; + if(CWorld::ProcessLineOfSight(TestTarget, TestSource, colPoint, entity, true, false, false, false, false, false, false)){ + if(TargetCoors.z+9.0f+HeightTarget < colPoint.point.z+3.0f) + HeightTarget = colPoint.point.z+3.0f - (TargetCoors.z+9.0f); + }else{ + TestSource = TargetCoors + CVector(0.0f, -1.0f, 9.0f); + TestTarget = TestSource; + TestSource.z += HeightTarget; + TestTarget.z = TestSource.z + 10.0f; + if(CWorld::ProcessLineOfSight(TestTarget, TestSource, colPoint, entity, true, false, false, false, false, false, false)){ + if(TargetCoors.z+9.0f+HeightTarget < colPoint.point.z+3.0f) + HeightTarget = colPoint.point.z+3.0f - (TargetCoors.z+9.0f); + } + } + + WellBufferMe(HeightTarget, &AdjustHeightTargetMoveBuffer, &AdjustHeightTargetMoveSpeed, 0.3f, 0.03f, false); + Source.z += AdjustHeightTargetMoveBuffer; + + // Wall checks + AvoidWallsTopDownPed(TargetCoors, CVector(0.0f, -3.0f, 3.0f), &TargetAdjusterForSouth, &TargetAdjusterSpeedForSouth, 1.0f); + Source.y += TargetAdjusterForSouth; + AvoidWallsTopDownPed(TargetCoors, CVector(0.0f, 3.0f, 3.0f), &TargetAdjusterForNorth, &TargetAdjusterSpeedForNorth, 1.0f); + Source.y -= TargetAdjusterForNorth; + // BUG: east and west flipped + AvoidWallsTopDownPed(TargetCoors, CVector(3.0f, 0.0f, 3.0f), &TargetAdjusterForWest, &TargetAdjusterSpeedForWest, 1.0f); + Source.x -= TargetAdjusterForWest; + AvoidWallsTopDownPed(TargetCoors, CVector(-3.0f, 0.0f, 3.0f), &TargetAdjusterForEast, &TargetAdjusterSpeedForEast, 1.0f); + Source.x += TargetAdjusterForEast; + + TargetCoors.y = Source.y + 1.0f; + TargetCoors.y += TargetAdjusterForSouth; + TargetCoors.x += TargetAdjusterForEast; + TargetCoors.x -= TargetAdjusterForWest; + + Front = TargetCoors - Source; + Front.Normalise(); +#ifdef FIX_BUGS + if(Front.x == 0.0f && Front.y == 0.0f) + Front.y = 0.0001f; +#else + // someone used = instead of == in the above check by accident + Front.x = 0.0f; +#endif + m_cvecTargetCoorsForFudgeInter = TargetCoors; + Up = CrossProduct(Front, CVector(-1.0f, 0.0f, 0.0f)); + Up.Normalise(); + + ResetStatics = false; +} + +// Identical to M16 +void +CCam::Process_Rocket(const CVector &CameraTarget, float, float, float) +{ + if(!CamTargetEntity->IsPed()) + return; + + static bool FailedTestTwelveFramesAgo = false; + RwV3d HeadPos; + CVector TargetCoors; + + FOV = DefaultFOV; + TargetCoors = CameraTarget; + + if(ResetStatics){ + Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI; + Alpha = 0.0f; + m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI; + FailedTestTwelveFramesAgo = false; + // static DPadVertical unused + // static DPadHorizontal unused + m_bCollisionChecksOn = true; + ResetStatics = false; + } + + ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&HeadPos, PED_HEAD); + Source = HeadPos; + Source.z += 0.1f; + Source.x -= 0.19f*Cos(m_fInitialPlayerOrientation); + Source.y -= 0.19f*Sin(m_fInitialPlayerOrientation); + + // Look around + bool UseMouse = false; + float MouseX = CPad::GetPad(0)->GetMouseX(); + float MouseY = CPad::GetPad(0)->GetMouseY(); + float LookLeftRight, LookUpDown; + if(MouseX != 0.0f || MouseY != 0.0f){ + UseMouse = true; + LookLeftRight = -3.0f*MouseX; + LookUpDown = 4.0f*MouseY; + }else{ + LookLeftRight = -CPad::GetPad(0)->SniperModeLookLeftRight(); + LookUpDown = CPad::GetPad(0)->SniperModeLookUpDown(); + } + if(UseMouse){ + Beta += TheCamera.m_fMouseAccelHorzntl * LookLeftRight * FOV/80.0f; + Alpha += TheCamera.m_fMouseAccelVertical * LookUpDown * FOV/80.0f; + }else{ + float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f; + float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f; + Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep(); + Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep(); + } + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f); + if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f); + + TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x; + TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y; + TargetCoors.z = 3.0f * Sin(Alpha) + Source.z; + Front = TargetCoors - Source; + Front.Normalise(); + Source += Front*0.4f; + + if(m_bCollisionChecksOn){ + if(!CWorld::GetIsLineOfSightClear(TargetCoors, Source, true, true, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + FailedTestTwelveFramesAgo = true; + }else{ + CVector TestPoint; + TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta + DEGTORAD(35.0f)) + Source.x; + TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta + DEGTORAD(35.0f)) + Source.y; + TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z; + if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + FailedTestTwelveFramesAgo = true; + }else{ + TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta - DEGTORAD(35.0f)) + Source.x; + TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta - DEGTORAD(35.0f)) + Source.y; + TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z; + if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + FailedTestTwelveFramesAgo = true; + }else + FailedTestTwelveFramesAgo = false; + } + } + } + + if(FailedTestTwelveFramesAgo) + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + Source -= Front*0.4f; + + GetVectorsReadyForRW(); + float Rotation = CGeneral::GetATanOfXY(Front.x, Front.y) - HALFPI; + ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Rotation; + ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Rotation; +} + +// Identical to Rocket +void +CCam::Process_M16_1stPerson(const CVector &CameraTarget, float, float, float) +{ + if(!CamTargetEntity->IsPed()) + return; + + static bool FailedTestTwelveFramesAgo = false; + RwV3d HeadPos; + CVector TargetCoors; + + FOV = DefaultFOV; + TargetCoors = CameraTarget; + + if(ResetStatics){ + Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI; + Alpha = 0.0f; + m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI; + FailedTestTwelveFramesAgo = false; + // static DPadVertical unused + // static DPadHorizontal unused + m_bCollisionChecksOn = true; + ResetStatics = false; + } + + ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&HeadPos, PED_HEAD); + Source = HeadPos; + Source.z += 0.1f; + Source.x -= 0.19f*Cos(m_fInitialPlayerOrientation); + Source.y -= 0.19f*Sin(m_fInitialPlayerOrientation); + + // Look around + bool UseMouse = false; + float MouseX = CPad::GetPad(0)->GetMouseX(); + float MouseY = CPad::GetPad(0)->GetMouseY(); + float LookLeftRight, LookUpDown; + if(MouseX != 0.0f || MouseY != 0.0f){ + UseMouse = true; + LookLeftRight = -3.0f*MouseX; + LookUpDown = 4.0f*MouseY; + }else{ + LookLeftRight = -CPad::GetPad(0)->SniperModeLookLeftRight(); + LookUpDown = CPad::GetPad(0)->SniperModeLookUpDown(); + } + if(UseMouse){ + Beta += TheCamera.m_fMouseAccelHorzntl * LookLeftRight * FOV/80.0f; + Alpha += TheCamera.m_fMouseAccelVertical * LookUpDown * FOV/80.0f; + }else{ + float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f; + float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f; + Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep(); + Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep(); + } + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f); + if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f); + + TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x; + TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y; + TargetCoors.z = 3.0f * Sin(Alpha) + Source.z; + Front = TargetCoors - Source; + Front.Normalise(); + Source += Front*0.4f; + + if(m_bCollisionChecksOn){ + if(!CWorld::GetIsLineOfSightClear(TargetCoors, Source, true, true, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + FailedTestTwelveFramesAgo = true; + }else{ + CVector TestPoint; + TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta + DEGTORAD(35.0f)) + Source.x; + TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta + DEGTORAD(35.0f)) + Source.y; + TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z; + if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + FailedTestTwelveFramesAgo = true; + }else{ + TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta - DEGTORAD(35.0f)) + Source.x; + TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta - DEGTORAD(35.0f)) + Source.y; + TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z; + if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + FailedTestTwelveFramesAgo = true; + }else + FailedTestTwelveFramesAgo = false; + } + } + } + + if(FailedTestTwelveFramesAgo) + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + Source -= Front*0.4f; + + GetVectorsReadyForRW(); + float Rotation = CGeneral::GetATanOfXY(Front.x, Front.y) - HALFPI; + ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Rotation; + ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Rotation; +} + +void +CCam::Process_1stPerson(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + static float DontLookThroughWorldFixer = 0.0f; + CVector TargetCoors; + + FOV = DefaultFOV; + TargetCoors = CameraTarget; + if(CamTargetEntity->m_rwObject == nil) + return; + + if(ResetStatics){ + Beta = TargetOrientation; + Alpha = 0.0f; + m_fInitialPlayerOrientation = TargetOrientation; + if(CamTargetEntity->IsPed()){ + Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI; + Alpha = 0.0f; + m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI; + } + DontLookThroughWorldFixer = 0.0f; + } + + if(CamTargetEntity->IsPed()){ + static bool FailedTestTwelveFramesAgo = false; + RwV3d HeadPos; + + TargetCoors = CameraTarget; + + if(ResetStatics){ + Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI; + Alpha = 0.0f; + m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI; + FailedTestTwelveFramesAgo = false; + // static DPadVertical unused + // static DPadHorizontal unused + m_bCollisionChecksOn = true; + ResetStatics = false; + } + + ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&HeadPos, PED_HEAD); + Source = HeadPos; + Source.z += 0.1f; + Source.x -= 0.19f*Cos(m_fInitialPlayerOrientation); + Source.y -= 0.19f*Sin(m_fInitialPlayerOrientation); + + float LookLeftRight, LookUpDown; + LookLeftRight = -CPad::GetPad(0)->LookAroundLeftRight(); + LookUpDown = CPad::GetPad(0)->LookAroundUpDown(); + float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f; + float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f; + Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep(); + Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep(); + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f); + if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f); + + TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x; + TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y; + TargetCoors.z = 3.0f * Sin(Alpha) + Source.z; + Front = TargetCoors - Source; + Front.Normalise(); + Source += Front*0.4f; + + if(m_bCollisionChecksOn){ + if(!CWorld::GetIsLineOfSightClear(TargetCoors, Source, true, true, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + FailedTestTwelveFramesAgo = true; + }else{ + CVector TestPoint; + TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta + DEGTORAD(35.0f)) + Source.x; + TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta + DEGTORAD(35.0f)) + Source.y; + TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z; + if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + FailedTestTwelveFramesAgo = true; + }else{ + TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta - DEGTORAD(35.0f)) + Source.x; + TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta - DEGTORAD(35.0f)) + Source.y; + TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z; + if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + FailedTestTwelveFramesAgo = true; + }else + FailedTestTwelveFramesAgo = false; + } + } + } + + if(FailedTestTwelveFramesAgo) + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + Source -= Front*0.4f; + + GetVectorsReadyForRW(); + float Rotation = CGeneral::GetATanOfXY(Front.x, Front.y) - HALFPI; + ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Rotation; + ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Rotation; + }else{ + assert(CamTargetEntity->IsVehicle()); + CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex()); + CVector CamPos = mi->m_vehicleType == VEHICLE_TYPE_BOAT ? mi->m_positions[BOAT_POS_FRONTSEAT] : mi->m_positions[CAR_POS_FRONTSEAT]; + CamPos.x = 0.0f; + CamPos.y += -0.08f; + CamPos.z += 0.62f; + FOV = 60.0f; + Source = Multiply3x3(CamTargetEntity->GetMatrix(), CamPos); + Source += CamTargetEntity->GetPosition(); + if(((CVehicle*)CamTargetEntity)->IsBoat()) + Source.z += 0.5f; + + if(((CVehicle*)CamTargetEntity)->IsUpsideDown()){ + if(DontLookThroughWorldFixer < 0.5f) + DontLookThroughWorldFixer += 0.03f; + else + DontLookThroughWorldFixer = 0.5f; + }else{ + if(DontLookThroughWorldFixer < 0.0f) +#ifdef FIX_BUGS + DontLookThroughWorldFixer += 0.03f; +#else + DontLookThroughWorldFixer -= 0.03f; +#endif + else + DontLookThroughWorldFixer = 0.0f; + } + Source.z += DontLookThroughWorldFixer; + Front = CamTargetEntity->GetForward(); + Front.Normalise(); + Up = CamTargetEntity->GetUp(); + Up.Normalise(); + CVector Right = CrossProduct(Front, Up); + Right.Normalise(); + Up = CrossProduct(Right, Front); + Up.Normalise(); + } + + ResetStatics = false; +} + +static CVector vecHeadCamOffset(0.06f, 0.05f, 0.0f); + +void +CCam::Process_1rstPersonPedOnPC(const CVector&, float TargetOrientation, float, float) +{ + // static int DontLookThroughWorldFixer = 0; // unused + static CVector InitialHeadPos; + + if(Mode != MODE_SNIPER_RUNABOUT) + FOV = DefaultFOV; + TheCamera.m_1rstPersonRunCloseToAWall = false; + if(CamTargetEntity->m_rwObject == nil) + return; + + if(CamTargetEntity->IsPed()){ + // static bool FailedTestTwelveFramesAgo = false; // unused + RwV3d HeadPos = vecHeadCamOffset; + CVector TargetCoors; + + // needs fix for SKINNING + RwFrame *frm = ((CPed*)CamTargetEntity)->GetNodeFrame(PED_HEAD); + while(frm){ + RwV3dTransformPoints(&HeadPos, &HeadPos, 1, RwFrameGetMatrix(frm)); + frm = RwFrameGetParent(frm); + if(frm == RpClumpGetFrame(CamTargetEntity->GetClump())) + frm = nil; + } + + if(ResetStatics){ + Beta = TargetOrientation; + Alpha = 0.0f; + m_fInitialPlayerOrientation = TargetOrientation; + if(CamTargetEntity->IsPed()){ // useless check + Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI; + Alpha = 0.0f; + m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI; + // FailedTestTwelveFramesAgo = false; + m_bCollisionChecksOn = true; + } + // DontLookThroughWorldFixer = false; + m_vecBufferedPlayerBodyOffset = HeadPos; + InitialHeadPos = HeadPos; + } + + m_vecBufferedPlayerBodyOffset.y = HeadPos.y; + + if(TheCamera.m_bHeadBob){ + m_vecBufferedPlayerBodyOffset.x = + TheCamera.m_fGaitSwayBuffer * m_vecBufferedPlayerBodyOffset.x + + (1.0f-TheCamera.m_fGaitSwayBuffer) * HeadPos.x; + m_vecBufferedPlayerBodyOffset.z = + TheCamera.m_fGaitSwayBuffer * m_vecBufferedPlayerBodyOffset.z + + (1.0f-TheCamera.m_fGaitSwayBuffer) * HeadPos.z; + HeadPos = RwV3d(CamTargetEntity->GetMatrix() * m_vecBufferedPlayerBodyOffset); + }else{ + float HeadDelta = (HeadPos - InitialHeadPos).Magnitude2D(); + CVector Fwd = CamTargetEntity->GetForward(); + Fwd.z = 0.0f; + Fwd.Normalise(); + HeadPos = RwV3d(HeadDelta*1.23f*Fwd + CamTargetEntity->GetPosition()); + HeadPos.z += 0.59f; + } + Source = HeadPos; + + // unused: + // ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&MidPos, PED_MID); + // Source - MidPos; + + // Look around + bool UseMouse = false; + float MouseX = CPad::GetPad(0)->GetMouseX(); + float MouseY = CPad::GetPad(0)->GetMouseY(); + float LookLeftRight, LookUpDown; + if(MouseX != 0.0f || MouseY != 0.0f){ + UseMouse = true; + LookLeftRight = -3.0f*MouseX; + LookUpDown = 4.0f*MouseY; + }else{ + LookLeftRight = -CPad::GetPad(0)->LookAroundLeftRight(); + LookUpDown = CPad::GetPad(0)->LookAroundUpDown(); + } + if(UseMouse){ + Beta += TheCamera.m_fMouseAccelHorzntl * LookLeftRight * FOV/80.0f; + Alpha += TheCamera.m_fMouseAccelVertical * LookUpDown * FOV/80.0f; + }else{ + float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f; + float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f; + Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep(); + Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep(); + } + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f); + if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f); + + TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x; + TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y; + TargetCoors.z = 3.0f * Sin(Alpha) + Source.z; + Front = TargetCoors - Source; + Front.Normalise(); + Source += Front*0.4f; + + TheCamera.m_AlphaForPlayerAnim1rstPerson = Alpha; + + GetVectorsReadyForRW(); + + float Heading = Front.Heading(); + ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Heading; + ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Heading; + TheCamera.pTargetEntity->SetHeading(Heading); + TheCamera.pTargetEntity->GetMatrix().UpdateRW(); + + if(Mode == MODE_SNIPER_RUNABOUT){ + // no mouse wheel FOV buffering here like in normal sniper mode + if(CPad::GetPad(0)->SniperZoomIn() || CPad::GetPad(0)->SniperZoomOut()){ + if(CPad::GetPad(0)->SniperZoomOut()) + FOV *= (255.0f*CTimer::GetTimeStep() + 10000.0f) / 10000.0f; + else + FOV /= (255.0f*CTimer::GetTimeStep() + 10000.0f) / 10000.0f; + } + + TheCamera.SetMotionBlur(180, 255, 180, 120, MBLUR_SNIPER); + + if(FOV > DefaultFOV) + FOV = DefaultFOV; + if(FOV < 15.0f) + FOV = 15.0f; + } + } + + ResetStatics = false; + RwCameraSetNearClipPlane(Scene.camera, 0.05f); +} + +void +CCam::Process_Sniper(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + if(CamTargetEntity->m_rwObject == nil) + return; + +#ifdef FIX_BUGS + if(!CamTargetEntity->IsPed()) + return; +#endif + + static bool FailedTestTwelveFramesAgo = false; + RwV3d HeadPos; + CVector TargetCoors; + TargetCoors = CameraTarget; + + static float TargetFOV = 0.0f; + + if(ResetStatics){ + Beta = TargetOrientation; + Alpha = 0.0f; + m_fInitialPlayerOrientation = TargetOrientation; + FailedTestTwelveFramesAgo = false; + // static DPadVertical unused + // static DPadHorizontal unused + m_bCollisionChecksOn = true; + FOVSpeed = 0.0f; + TargetFOV = FOV; + ResetStatics = false; + } + + ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&HeadPos, PED_HEAD); + Source = HeadPos; + Source.z += 0.1f; + Source.x -= 0.19f*Cos(m_fInitialPlayerOrientation); + Source.y -= 0.19f*Sin(m_fInitialPlayerOrientation); + + // Look around + bool UseMouse = false; + float MouseX = CPad::GetPad(0)->GetMouseX(); + float MouseY = CPad::GetPad(0)->GetMouseY(); + float LookLeftRight, LookUpDown; + if(MouseX != 0.0f || MouseY != 0.0f){ + UseMouse = true; + LookLeftRight = -3.0f*MouseX; + LookUpDown = 4.0f*MouseY; + }else{ + LookLeftRight = -CPad::GetPad(0)->SniperModeLookLeftRight(); + LookUpDown = CPad::GetPad(0)->SniperModeLookUpDown(); + } + if(UseMouse){ + Beta += TheCamera.m_fMouseAccelHorzntl * LookLeftRight * FOV/80.0f; + Alpha += TheCamera.m_fMouseAccelVertical * LookUpDown * FOV/80.0f; + }else{ + float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f; + float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f; + Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep(); + Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep(); + } + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f); + if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f); + + TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x; + TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y; + TargetCoors.z = 3.0f * Sin(Alpha) + Source.z; + + UseMouse = false; + int ZoomInButton = ControlsManager.GetMouseButtonAssociatedWithAction(PED_SNIPER_ZOOM_IN); + int ZoomOutButton = ControlsManager.GetMouseButtonAssociatedWithAction(PED_SNIPER_ZOOM_OUT); + // TODO: enum? this should be mouse wheel up and down + if(ZoomInButton == 4 || ZoomInButton == 5 || ZoomOutButton == 4 || ZoomOutButton == 5){ + if(CPad::GetPad(0)->GetMouseWheelUp() || CPad::GetPad(0)->GetMouseWheelDown()){ + if(CPad::GetPad(0)->SniperZoomIn()){ + TargetFOV = FOV - 10.0f; + UseMouse = true; + } + if(CPad::GetPad(0)->SniperZoomOut()){ + TargetFOV = FOV + 10.0f; + UseMouse = true; + } + } + } + if((CPad::GetPad(0)->SniperZoomIn() || CPad::GetPad(0)->SniperZoomOut()) && !UseMouse){ + if(CPad::GetPad(0)->SniperZoomOut()){ + FOV *= (255.0f*CTimer::GetTimeStep() + 10000.0f) / 10000.0f; + TargetFOV = FOV; + FOVSpeed = 0.0f; + }else{ + FOV /= (255.0f*CTimer::GetTimeStep() + 10000.0f) / 10000.0f; + TargetFOV = FOV; + FOVSpeed = 0.0f; + } + }else{ + if(Abs(TargetFOV - FOV) > 0.5f) + WellBufferMe(TargetFOV, &FOV, &FOVSpeed, 0.5f, 0.25f, false); + else + FOVSpeed = 0.0f; + } + + TheCamera.SetMotionBlur(180, 255, 180, 120, MBLUR_SNIPER); + + if(FOV > DefaultFOV) + FOV = DefaultFOV; + if(FOV < 15.0f) + FOV = 15.0f; + + Front = TargetCoors - Source; + Front.Normalise(); + Source += Front*0.4f; + + if(m_bCollisionChecksOn){ + if(!CWorld::GetIsLineOfSightClear(TargetCoors, Source, true, true, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + FailedTestTwelveFramesAgo = true; + }else{ + CVector TestPoint; + TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta + DEGTORAD(35.0f)) + Source.x; + TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta + DEGTORAD(35.0f)) + Source.y; + TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z; + if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + FailedTestTwelveFramesAgo = true; + }else{ + TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta - DEGTORAD(35.0f)) + Source.x; + TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta - DEGTORAD(35.0f)) + Source.y; + TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z; + if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){ + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + FailedTestTwelveFramesAgo = true; + }else + FailedTestTwelveFramesAgo = false; + } + } + } + + if(FailedTestTwelveFramesAgo) + RwCameraSetNearClipPlane(Scene.camera, 0.4f); + Source -= Front*0.4f; + + GetVectorsReadyForRW(); + float Rotation = CGeneral::GetATanOfXY(Front.x, Front.y) - HALFPI; + ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Rotation; + ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Rotation; +} + +void +CCam::Process_Syphon(const CVector &CameraTarget, float, float, float) +{ + FOV = DefaultFOV; + + if(!CamTargetEntity->IsPed()) + return; + + static bool CameraObscured = false; + // unused FailedClippingTestPrevously + static float BetaOffset = DEGTORAD(18.0f); + // unused AngleToGoTo + // unused AngleToGoToSpeed + // unused DistBetweenPedAndPlayerPreviouslyOn + static float HeightDown = -0.5f; + static float PreviousDistForInter; + CVector TargetCoors; + CVector2D vDist; + float fDist, fAimingDist; + float TargetAlpha; + CColPoint colPoint; + CEntity *entity; + + TargetCoors = CameraTarget; + + if(TheCamera.Cams[TheCamera.ActiveCam].Mode != MODE_SYPHON) + return; + + vDist = Source - TargetCoors; + fDist = vDist.Magnitude(); + if(fDist == 0.0f) + Source = TargetCoors + CVector(1.0f, 1.0f, 0.0f); + else + Source = TargetCoors + CVector(vDist.x/fDist * 1.7f, vDist.y/fDist * 1.7f, 0.0f); + if(fDist > 1.7f) + fDist = 1.7f; + + Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y); + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + + float NewBeta = CGeneral::GetATanOfXY(TheCamera.m_cvecAimingTargetCoors.x - TargetCoors.x, TheCamera.m_cvecAimingTargetCoors.y - TargetCoors.y) + PI; + if(ResetStatics){ + CameraObscured = false; + float TestBeta1 = NewBeta - BetaOffset - Beta; + float TestBeta2 = NewBeta + BetaOffset - Beta; + MakeAngleLessThan180(TestBeta1); + MakeAngleLessThan180(TestBeta2); + if(Abs(TestBeta1) < Abs(TestBeta2)) + BetaOffset = -BetaOffset; + // some unuseds + ResetStatics = false; + } + Beta = NewBeta + BetaOffset; + Source = TargetCoors; + Source.x += 1.7f*Cos(Beta); + Source.y += 1.7f*Sin(Beta); + TargetCoors.z += m_fSyphonModeTargetZOffSet; + fAimingDist = (TheCamera.m_cvecAimingTargetCoors - TargetCoors).Magnitude2D(); + if(fAimingDist < 6.5f) + fAimingDist = 6.5f; + TargetAlpha = CGeneral::GetATanOfXY(fAimingDist, TheCamera.m_cvecAimingTargetCoors.z - TargetCoors.z); + while(TargetAlpha >= PI) TargetAlpha -= 2*PI; + while(TargetAlpha < -PI) TargetAlpha += 2*PI; + + // inlined + WellBufferMe(-TargetAlpha, &Alpha, &AlphaSpeed, 0.07f, 0.015f, true); + + Source.z += fDist*Sin(Alpha) + fDist*0.2f; + if(Source.z < TargetCoors.z + HeightDown) + Source.z = TargetCoors.z + HeightDown; + + CameraObscured = CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true); + // PreviousDistForInter unused + if(CameraObscured){ + PreviousDistForInter = (TargetCoors - colPoint.point).Magnitude2D(); + Source = colPoint.point; + }else + PreviousDistForInter = 1.7f; + + m_cvecTargetCoorsForFudgeInter = TargetCoors; + Front = TargetCoors - Source; + m_fMinDistAwayFromCamWhenInterPolating = Front.Magnitude2D(); + if(m_fMinDistAwayFromCamWhenInterPolating < 1.1f) + RwCameraSetNearClipPlane(Scene.camera, max(m_fMinDistAwayFromCamWhenInterPolating - 0.35f, 0.05f)); + Front.Normalise(); + GetVectorsReadyForRW(); +} + +void +CCam::Process_Syphon_Crim_In_Front(const CVector &CameraTarget, float, float, float) +{ + FOV = DefaultFOV; + + if(!CamTargetEntity->IsPed()) + return; + + CVector TargetCoors = CameraTarget; + CVector vDist; + float fDist, TargetDist; + float zOffset; + float AimingAngle; + CColPoint colPoint; + CEntity *entity; + + TargetDist = TheCamera.m_fPedZoomValueSmooth * 0.5f + 4.0f; + vDist = Source - TargetCoors; + fDist = vDist.Magnitude2D(); + zOffset = TargetDist - 2.65f; + if(zOffset < 0.0f) + zOffset = 0.0f; + if(zOffset == 0.0f) + Source = TargetCoors + CVector(1.0f, 1.0f, zOffset); + else + Source = TargetCoors + CVector(vDist.x/fDist*TargetDist, vDist.y/fDist*TargetDist, zOffset); + + AimingAngle = CGeneral::GetATanOfXY(TheCamera.m_cvecAimingTargetCoors.x - TargetCoors.x, TheCamera.m_cvecAimingTargetCoors.y - TargetCoors.y); + while(AimingAngle >= PI) AimingAngle -= 2*PI; + while(AimingAngle < -PI) AimingAngle += 2*PI; + + if(TheCamera.PlayerWeaponMode.Mode == MODE_SYPHON) + Beta = AimingAngle + m_fPlayerInFrontSyphonAngleOffSet; + + Source.x = TargetCoors.x; + Source.y = TargetCoors.y; + Source.x += Cos(Beta) * TargetDist; + Source.y += Sin(Beta) * TargetDist; + + if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true)){ + Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y); + fDist = (TargetCoors - colPoint.point).Magnitude2D(); + Source.x = TargetCoors.x; + Source.y = TargetCoors.y; + Source.x += Cos(Beta) * fDist; + Source.y += Sin(Beta) * fDist; + } + + TargetCoors = CameraTarget; + TargetCoors.z += m_fSyphonModeTargetZOffSet; + m_cvecTargetCoorsForFudgeInter = TargetCoors; + Front = TargetCoors - Source; + GetVectorsReadyForRW(); +} + +void +CCam::Process_BehindBoat(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + if(!CamTargetEntity->IsVehicle()){ + ResetStatics = false; + return; + } + + CVector TargetCoors = CameraTarget; + float DeltaBeta = 0.0f; + static CColPoint colPoint; + CEntity *entity; + static float TargetWhenChecksWereOn = 0.0f; + static float CenterObscuredWhenChecksWereOn = 0.0f; + static float WaterZAddition = 2.75f; + float WaterLevel = 0.0f; + float s, c; + float Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y); + FOV = DefaultFOV; + + if(ResetStatics){ + CenterObscuredWhenChecksWereOn = 0.0f; + TargetWhenChecksWereOn = 0.0f; + Beta = TargetOrientation + PI; + } + + CWaterLevel::GetWaterLevelNoWaves(TargetCoors.x, TargetCoors.y, TargetCoors.z, &WaterLevel); + WaterLevel += WaterZAddition; + static float FixerForGoingBelowGround = 0.4f; + if(-FixerForGoingBelowGround < TargetCoors.z-WaterLevel) + WaterLevel += TargetCoors.z-WaterLevel - FixerForGoingBelowGround; + + bool Obscured; + if(m_bCollisionChecksOn || ResetStatics){ + CVector TestPoint; + // Weird calculations here, also casting bool to float... + c = Cos(TargetOrientation); + s = Sin(TargetOrientation); + TestPoint = TheCamera.CarZoomValueSmooth * CVector(-c, -s, 0.0f) + + (TheCamera.CarZoomValueSmooth+7.0f) * CVector(-c, -s, 0.0f) + + TargetCoors; + TestPoint.z = WaterLevel + TheCamera.CarZoomValueSmooth; + float Test1 = CWorld::GetIsLineOfSightClear(TestPoint, TargetCoors, true, false, false, true, false, true, true); + + c = Cos(TargetOrientation + 0.8f); + s = Sin(TargetOrientation + DEGTORAD(40.0f)); + TestPoint = TheCamera.CarZoomValueSmooth * CVector(-c, -s, 0.0f) + + (TheCamera.CarZoomValueSmooth+7.0f) * CVector(-c, -s, 0.0f) + + TargetCoors; + TestPoint.z = WaterLevel + TheCamera.CarZoomValueSmooth; + float Test2 = CWorld::GetIsLineOfSightClear(TestPoint, TargetCoors, true, false, false, true, false, true, true); + + c = Cos(TargetOrientation - 0.8); + s = Sin(TargetOrientation - DEGTORAD(40.0f)); + TestPoint = TheCamera.CarZoomValueSmooth * CVector(-c, -s, 0.0f) + + (TheCamera.CarZoomValueSmooth+7.0f) * CVector(-c, -s, 0.0f) + + TargetCoors; + TestPoint.z = WaterLevel + TheCamera.CarZoomValueSmooth; + float Test3 = CWorld::GetIsLineOfSightClear(TestPoint, TargetCoors, true, false, false, true, false, true, true); + + if(Test2 == 0.0f){ + DeltaBeta = TargetOrientation - Beta - DEGTORAD(40.0f); + if(ResetStatics) + Beta = TargetOrientation - DEGTORAD(40.0f); + }else if(Test3 == 0.0f){ + DeltaBeta = TargetOrientation - Beta + DEGTORAD(40.0f); + if(ResetStatics) + Beta = TargetOrientation + DEGTORAD(40.0f); + }else if(Test1 == 0.0f){ + DeltaBeta = 0.0f; + }else if(Test2 != 0.0f && Test3 != 0.0f && Test1 != 0.0f){ + if(ResetStatics) + Beta = TargetOrientation; + DeltaBeta = TargetOrientation - Beta; + } + + c = Cos(Beta); + s = Sin(Beta); + TestPoint.x = TheCamera.CarZoomValueSmooth * -c + + (TheCamera.CarZoomValueSmooth + 7.0f) * -c + + TargetCoors.x; + TestPoint.y = TheCamera.CarZoomValueSmooth * -s + + (TheCamera.CarZoomValueSmooth + 7.0f) * -s + + TargetCoors.y; + TestPoint.z = WaterLevel + TheCamera.CarZoomValueSmooth; + Obscured = CWorld::ProcessLineOfSight(TestPoint, TargetCoors, colPoint, entity, true, false, false, true, false, true, true); + CenterObscuredWhenChecksWereOn = Obscured; + + // now DeltaBeta == TargetWhenChecksWereOn - Beta, which we need for WellBufferMe below + TargetWhenChecksWereOn = DeltaBeta + Beta; + }else{ + // DeltaBeta = TargetWhenChecksWereOn - Beta; // unneeded since we don't inline WellBufferMe + Obscured = CenterObscuredWhenChecksWereOn != 0.0f; + } + + if(Obscured){ + CWorld::ProcessLineOfSight(Source, TargetCoors, colPoint, entity, true, false, false, true, false, true, true); + Source = colPoint.point; + }else{ + // inlined + WellBufferMe(TargetWhenChecksWereOn, &Beta, &BetaSpeed, 0.07f, 0.015f, true); + + s = Sin(Beta); + c = Cos(Beta); + Source = TheCamera.CarZoomValueSmooth * CVector(-c, -s, 0.0f) + + (TheCamera.CarZoomValueSmooth+7.0f) * CVector(-c, -s, 0.0f) + + TargetCoors; + Source.z = WaterLevel + TheCamera.CarZoomValueSmooth; + } + + if(TheCamera.CarZoomValueSmooth < 0.05f){ + static float AmountUp = 2.2f; + TargetCoors.z += AmountUp * (0.0f - TheCamera.CarZoomValueSmooth); + } + TargetCoors.z += TheCamera.CarZoomValueSmooth + 0.5f; + m_cvecTargetCoorsForFudgeInter = TargetCoors; + Front = TargetCoors - Source; + GetVectorsReadyForRW(); + ResetStatics = false; +} + +void +CCam::Process_Fight_Cam(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + if(!CamTargetEntity->IsPed()) + return; + + FOV = DefaultFOV; + float BetaLeft, BetaRight, DeltaBetaLeft, DeltaBetaRight; + float BetaFix; + float Dist; + float BetaMaxSpeed = 0.015f; + float BetaAcceleration = 0.007f; + static bool PreviouslyFailedBuildingChecks = false; + float TargetCamHeight; + CVector TargetCoors; + + m_fMinDistAwayFromCamWhenInterPolating = 4.0f; + Front = Source - CameraTarget; + Beta = CGeneral::GetATanOfXY(Front.x, Front.y); + while(TargetOrientation >= PI) TargetOrientation -= 2*PI; + while(TargetOrientation < -PI) TargetOrientation += 2*PI; + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + + // Figure out Beta + BetaLeft = TargetOrientation - HALFPI; + BetaRight = TargetOrientation + HALFPI; + DeltaBetaLeft = Beta - BetaLeft; + DeltaBetaRight = Beta - BetaRight; + while(DeltaBetaLeft >= PI) DeltaBetaLeft -= 2*PI; + while(DeltaBetaLeft < -PI) DeltaBetaLeft += 2*PI; + while(DeltaBetaRight >= PI) DeltaBetaRight -= 2*PI; + while(DeltaBetaRight < -PI) DeltaBetaRight += 2*PI; + + if(ResetStatics){ + if(Abs(DeltaBetaLeft) < Abs(DeltaBetaRight)) + m_fTargetBeta = DeltaBetaLeft; + else + m_fTargetBeta = DeltaBetaRight; + m_fBufferedTargetOrientation = TargetOrientation; + m_fBufferedTargetOrientationSpeed = 0.0f; + m_bCollisionChecksOn = true; + BetaSpeed = 0.0f; + }else if(CPad::GetPad(0)->WeaponJustDown()){ + if(Abs(DeltaBetaLeft) < Abs(DeltaBetaRight)) + m_fTargetBeta = DeltaBetaLeft; + else + m_fTargetBeta = DeltaBetaRight; + } + + // Check collisions + BetaFix = 0.0f; + Dist = Front.Magnitude2D(); + if(m_bCollisionChecksOn || PreviouslyFailedBuildingChecks){ + BetaFix = GetPedBetaAngleForClearView(CameraTarget, Dist+0.25f, 0.0f, true, false, false, true, false); + if(BetaFix == 0.0f){ + BetaFix = GetPedBetaAngleForClearView(CameraTarget, Dist+0.5f, DEGTORAD(24.0f), true, false, false, true, false); + if(BetaFix == 0.0f) + BetaFix = GetPedBetaAngleForClearView(CameraTarget, Dist+0.5f, -DEGTORAD(24.0f), true, false, false, true, false); + } + } + if(BetaFix != 0.0f){ + BetaMaxSpeed = 0.1f; + PreviouslyFailedBuildingChecks = true; + BetaAcceleration = 0.025f; + m_fTargetBeta = Beta + BetaFix; + } + WellBufferMe(m_fTargetBeta, &Beta, &BetaSpeed, BetaMaxSpeed, BetaAcceleration, true); + + Source = CameraTarget + 4.0f*CVector(Cos(Beta), Sin(Beta), 0.0f); + Source.z -= 0.5f; + + WellBufferMe(TargetOrientation, &m_fBufferedTargetOrientation, &m_fBufferedTargetOrientationSpeed, 0.07f, 0.004f, true); + TargetCoors = CameraTarget + 0.5f*CVector(Cos(m_fBufferedTargetOrientation), Sin(m_fBufferedTargetOrientation), 0.0f); + + TargetCamHeight = CameraTarget.z - Source.z + max(m_fPedBetweenCameraHeightOffset, m_fRoadOffSet + m_fDimensionOfHighestNearCar) - 0.5f; + if(TargetCamHeight > m_fCamBufferedHeight) + WellBufferMe(TargetCamHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.15f, 0.04f, false); + else + WellBufferMe(0.0f, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.08f, 0.0175f, false); + Source.z += m_fCamBufferedHeight; + + m_cvecTargetCoorsForFudgeInter = TargetCoors; + Front = TargetCoors - Source; + Front.Normalise(); + GetVectorsReadyForRW(); + + ResetStatics = false; +} + +/* +// Spline format is this, but game doesn't seem to use any kind of struct: +struct Spline +{ + float numFrames; + struct { + float time; + float f[3]; // CVector for Vector spline + } frames[1]; // numFrames +}; +*/ + +// These two functions are pretty ugly + +#define MS(t) (uint32)((t)*1000.0f) + +void +FindSplinePathPositionFloat(float *out, float *spline, uint32 time, uint32 &marker) +{ + // marker is at time + uint32 numFrames = spline[0]; + uint32 timeDelta = MS(spline[marker] - spline[marker-4]); + uint32 endTime = MS(spline[4*(numFrames-1) + 1]); + if(time < endTime){ + bool canAdvance = true; + if((marker-1)/4 > numFrames){ + canAdvance = false; + marker = 4*(numFrames-1) + 1; + } + // skipping over small time deltas apparently? + while(timeDelta <= 75 && canAdvance){ + marker += 4; + if((marker-1)/4 > numFrames){ + canAdvance = false; + marker = 4*(numFrames-1) + 1; + } + timeDelta = (spline[marker] - spline[marker-4]) * 1000.0f; + } + } + float a = ((float)time - (float)MS(spline[marker-4])) / (float)MS(spline[marker] - spline[marker-4]); + a = clamp(a, 0.0f, 1.0f); + float b = 1.0f - a; + *out = b*b*b * spline[marker-3] + + 3.0f*a*b*b * spline[marker-1] + + 3.0f*a*a*b * spline[marker+2] + + a*a*a * spline[marker+1]; +} + +void +FindSplinePathPositionVector(CVector *out, float *spline, uint32 time, uint32 &marker) +{ + // marker is at time + uint32 numFrames = spline[0]; + uint32 timeDelta = MS(spline[marker] - spline[marker-10]); + uint32 endTime = MS(spline[10*(numFrames-1) + 1]); + if(time < endTime){ + bool canAdvance = true; + if((marker-1)/10 > numFrames){ + canAdvance = false; + marker = 10*(numFrames-1) + 1; + } + // skipping over small time deltas apparently? + while(timeDelta <= 75 && canAdvance){ + marker += 10; + if((marker-1)/10 > numFrames){ + canAdvance = false; + marker = 10*(numFrames-1) + 1; + } + timeDelta = (spline[marker] - spline[marker-10]) * 1000.0f; + } + } + + if((marker-1)/10 > numFrames){ + printf("Arraymarker %i \n", marker); + printf("Path zero %i \n", numFrames); + } + + float a = ((float)time - (float)MS(spline[marker-10])) / (float)MS(spline[marker] - spline[marker-10]); + a = clamp(a, 0.0f, 1.0f); + float b = 1.0f - a; + out->x = + b*b*b * spline[marker-9] + + 3.0f*a*b*b * spline[marker-3] + + 3.0f*a*a*b * spline[marker+4] + + a*a*a * spline[marker+1]; + out->y = + b*b*b * spline[marker-8] + + 3.0f*a*b*b * spline[marker-2] + + 3.0f*a*a*b * spline[marker+5] + + a*a*a * spline[marker+2]; + out->z = + b*b*b * spline[marker-7] + + 3.0f*a*b*b * spline[marker-1] + + 3.0f*a*a*b * spline[marker+6] + + a*a*a * spline[marker+3]; + *out += TheCamera.m_vecCutSceneOffset; +} + +void +CCam::Process_FlyBy(const CVector&, float, float, float) +{ + float UpAngle = 0.0f; + static float FirstFOVValue = 0.0f; + static float PsuedoFOV; + static uint32 ArrayMarkerFOV; + static uint32 ArrayMarkerUp; + static uint32 ArrayMarkerSource; + static uint32 ArrayMarkerFront; + + if(TheCamera.m_bcutsceneFinished) + return; + + Up = CVector(0.0f, 0.0f, 1.0f); + if(TheCamera.m_bStartingSpline) + m_fTimeElapsedFloat += CTimer::GetTimeStepInMilliseconds(); + else{ + m_fTimeElapsedFloat = 0.0f; + m_uiFinishTime = MS(TheCamera.m_arrPathArray[2].m_arr_PathData[10*((int)TheCamera.m_arrPathArray[2].m_arr_PathData[0]-1) + 1]); + TheCamera.m_bStartingSpline = true; + FirstFOVValue = TheCamera.m_arrPathArray[0].m_arr_PathData[2]; + PsuedoFOV = TheCamera.m_arrPathArray[0].m_arr_PathData[2]; + ArrayMarkerFOV = 5; + ArrayMarkerUp = 5; + ArrayMarkerSource = 11; + ArrayMarkerFront = 11; + } + + float fTime = m_fTimeElapsedFloat; + uint32 uiFinishTime = m_uiFinishTime; + uint32 uiTime = fTime; + if(uiTime < uiFinishTime){ + TheCamera.m_fPositionAlongSpline = (float) uiTime / uiFinishTime; + + while(uiTime >= (TheCamera.m_arrPathArray[2].m_arr_PathData[ArrayMarkerSource] - TheCamera.m_arrPathArray[2].m_arr_PathData[1])*1000.0f) + ArrayMarkerSource += 10; + FindSplinePathPositionVector(&Source, TheCamera.m_arrPathArray[2].m_arr_PathData, uiTime, ArrayMarkerSource); + + while(uiTime >= (TheCamera.m_arrPathArray[3].m_arr_PathData[ArrayMarkerFront] - TheCamera.m_arrPathArray[3].m_arr_PathData[1])*1000.0f) + ArrayMarkerFront += 10; + FindSplinePathPositionVector(&Front, TheCamera.m_arrPathArray[3].m_arr_PathData, uiTime, ArrayMarkerFront); + + while(uiTime >= (TheCamera.m_arrPathArray[1].m_arr_PathData[ArrayMarkerUp] - TheCamera.m_arrPathArray[1].m_arr_PathData[1])*1000.0f) + ArrayMarkerUp += 4; + FindSplinePathPositionFloat(&UpAngle, TheCamera.m_arrPathArray[1].m_arr_PathData, uiTime, ArrayMarkerUp); + UpAngle = DEGTORAD(UpAngle) + HALFPI; + Up.x = Cos(UpAngle); + Up.z = Sin(UpAngle); + + while(uiTime >= (TheCamera.m_arrPathArray[0].m_arr_PathData[ArrayMarkerFOV] - TheCamera.m_arrPathArray[0].m_arr_PathData[1])*1000.0f) + ArrayMarkerFOV += 4; + FindSplinePathPositionFloat(&PsuedoFOV, TheCamera.m_arrPathArray[0].m_arr_PathData, uiTime, ArrayMarkerFOV); + + m_cvecTargetCoorsForFudgeInter = Front; + Front = Front - Source; + Front.Normalise(); + CVector Left = CrossProduct(Up, Front); + Up = CrossProduct(Front, Left); + Up.Normalise(); + FOV = PsuedoFOV; + }else{ + // end + ArrayMarkerSource = (TheCamera.m_arrPathArray[2].m_arr_PathData[0] - 1)*10 + 1; + ArrayMarkerFront = (TheCamera.m_arrPathArray[3].m_arr_PathData[0] - 1)*10 + 1; + ArrayMarkerUp = (TheCamera.m_arrPathArray[1].m_arr_PathData[0] - 1)*4 + 1; + ArrayMarkerFOV = (TheCamera.m_arrPathArray[0].m_arr_PathData[0] - 1)*4 + 1; + + FindSplinePathPositionVector(&Source, TheCamera.m_arrPathArray[2].m_arr_PathData, uiTime, ArrayMarkerSource); + FindSplinePathPositionVector(&Front, TheCamera.m_arrPathArray[3].m_arr_PathData, uiTime, ArrayMarkerFront); + FindSplinePathPositionFloat(&UpAngle, TheCamera.m_arrPathArray[1].m_arr_PathData, uiTime, ArrayMarkerUp); + UpAngle = DEGTORAD(UpAngle) + HALFPI; + Up.x = Cos(UpAngle); + Up.z = Sin(UpAngle); + FindSplinePathPositionFloat(&PsuedoFOV, TheCamera.m_arrPathArray[0].m_arr_PathData, uiTime, ArrayMarkerFOV); + + TheCamera.m_fPositionAlongSpline = 1.0f; + ArrayMarkerFOV = 0; + ArrayMarkerUp = 0; + ArrayMarkerSource = 0; + ArrayMarkerFront = 0; + + m_cvecTargetCoorsForFudgeInter = Front; + Front = Front - Source; + Front.Normalise(); + CVector Left = CrossProduct(Up, Front); + Up = CrossProduct(Front, Left); + Up.Normalise(); + FOV = PsuedoFOV; + } +} + +void +CCam::Process_WheelCam(const CVector&, float, float, float) +{ + FOV = DefaultFOV; + + if(CamTargetEntity->IsPed()){ + // what? ped with wheels or what? + Source = Multiply3x3(CamTargetEntity->GetMatrix(), CVector(-0.3f, -0.5f, 0.1f)); + Source += CamTargetEntity->GetPosition(); + Front = CVector(1.0f, 0.0f, 0.0f); + }else{ + Source = Multiply3x3(CamTargetEntity->GetMatrix(), CVector(-1.4f, -2.3f, 0.3f)); + Source += CamTargetEntity->GetPosition(); + Front = CamTargetEntity->GetForward(); + } + + CVector NewUp(0.0f, 0.0f, 1.0f); + CVector Left = CrossProduct(Front, NewUp); + Left.Normalise(); + NewUp = CrossProduct(Left, Front); + + float Roll = Cos((CTimer::GetTimeInMilliseconds()&0x1FFFF)/(float)0x1FFFF * TWOPI); + Up = Cos(Roll*0.4f)*NewUp + Sin(Roll*0.4f)*Left; +} + +void +CCam::Process_Fixed(const CVector &CameraTarget, float, float, float) +{ + Source = m_cvecCamFixedModeSource; + Front = CameraTarget - Source; + m_cvecTargetCoorsForFudgeInter = CameraTarget; + GetVectorsReadyForRW(); + + Up = CVector(0.0f, 0.0f, 1.0f) + m_cvecCamFixedModeUpOffSet; + Up.Normalise(); + CVector Right = CrossProduct(Front, Up); + Right.Normalise(); + Up = CrossProduct(Right, Front); + + FOV = DefaultFOV; + if(TheCamera.m_bUseSpecialFovTrain) + FOV = TheCamera.m_fFovForTrain; + + if(CMenuManager::m_ControlMethod == 0 && Using3rdPersonMouseCam()){ + CPed *player = FindPlayerPed(); + if(player && player->CanStrafeOrMouseControl()){ + float Heading = Front.Heading(); + ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Heading; + ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Heading; + TheCamera.pTargetEntity->SetHeading(Heading); + TheCamera.pTargetEntity->GetMatrix().UpdateRW(); + } + } +} + +void +CCam::Process_Player_Fallen_Water(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + CColPoint colPoint; + CEntity *entity = nil; + + FOV = DefaultFOV; + Source = CameraTarget; + Source.x += -4.5f*Cos(TargetOrientation); + Source.y += -4.5f*Sin(TargetOrientation); + Source.z = m_vecLastAboveWaterCamPosition.z + 4.0f; + + m_cvecTargetCoorsForFudgeInter = CameraTarget; + Front = CameraTarget - Source; + Front.Normalise(); + if(CWorld::ProcessLineOfSight(CameraTarget, Source, colPoint, entity, true, false, false, true, false, true, true)) + Source = colPoint.point; + GetVectorsReadyForRW(); + Front = CameraTarget - Source; + Front.Normalise(); +} + +// unused +void +CCam::Process_Circle(const CVector &CameraTarget, float, float, float) +{ + FOV = DefaultFOV; + + Front.x = Cos(0.7f) * Cos((CTimer::GetTimeInMilliseconds()&0xFFF)/(float)0xFFF * TWOPI); + Front.y = Cos(0.7f) * Sin((CTimer::GetTimeInMilliseconds()&0xFFF)/(float)0xFFF * TWOPI); + Front.z = -Sin(0.7f); + Source = CameraTarget - 4.0f*Front; + Source.z += 1.0f; + GetVectorsReadyForRW(); +} + +void +CCam::Process_SpecialFixedForSyphon(const CVector &CameraTarget, float, float, float) +{ + Source = m_cvecCamFixedModeSource; + m_cvecTargetCoorsForFudgeInter = CameraTarget; + m_cvecTargetCoorsForFudgeInter.z += m_fSyphonModeTargetZOffSet; + Front = CameraTarget - Source; + Front.z += m_fSyphonModeTargetZOffSet; + + GetVectorsReadyForRW(); + + Up += m_cvecCamFixedModeUpOffSet; + Up.Normalise(); + CVector Left = CrossProduct(Up, Front); + Left.Normalise(); + Front = CrossProduct(Left, Up); + Front.Normalise(); + FOV = DefaultFOV; +} + +#ifdef IMPROVED_CAMERA + +#define KEYJUSTDOWN(k) ControlsManager.GetIsKeyboardKeyJustDown((RsKeyCodes)k) +#define KEYDOWN(k) ControlsManager.GetIsKeyboardKeyDown((RsKeyCodes)k) +#define CTRLJUSTDOWN(key) \ + ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYJUSTDOWN((RsKeyCodes)key) || \ + (KEYJUSTDOWN(rsLCTRL) || KEYJUSTDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key)) +#define CTRLDOWN(key) ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key)) + + +void +CCam::Process_Debug(const CVector&, float, float, float) +{ + static float Speed = 0.0f; + static float PanSpeedX = 0.0f; + static float PanSpeedY = 0.0f; + CVector TargetCoors; + + RwCameraSetNearClipPlane(Scene.camera, 0.9f); + FOV = DefaultFOV; + Alpha += DEGTORAD(CPad::GetPad(1)->GetLeftStickY()) / 50.0f; + Beta += DEGTORAD(CPad::GetPad(1)->GetLeftStickX())*1.5f / 19.0f; + if(CPad::GetPad(0)->GetLeftMouse()){ + Alpha += DEGTORAD(CPad::GetPad(0)->GetMouseY()/2.0f); + Beta -= DEGTORAD(CPad::GetPad(0)->GetMouseX()/2.0f); + } + + TargetCoors.x = Source.x + Cos(Alpha) * Cos(Beta) * 3.0f; + TargetCoors.y = Source.y + Cos(Alpha) * Sin(Beta) * 3.0f; + TargetCoors.z = Source.z + Sin(Alpha) * 3.0f; + + if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f); + if(Alpha < DEGTORAD(-89.5f)) Alpha = DEGTORAD(-89.5f); + + if(CPad::GetPad(1)->GetSquare() || KEYDOWN('W')) + Speed += 0.1f; + else if(CPad::GetPad(1)->GetCross() || KEYDOWN('S')) + Speed -= 0.1f; + else + Speed = 0.0f; + if(Speed > 70.0f) Speed = 70.0f; + if(Speed < -70.0f) Speed = -70.0f; + + + if(KEYDOWN(rsRIGHT) || KEYDOWN('D')) + PanSpeedX += 0.1f; + else if(KEYDOWN(rsLEFT) || KEYDOWN('A')) + PanSpeedX -= 0.1f; + else + PanSpeedX = 0.0f; + if(PanSpeedX > 70.0f) PanSpeedX = 70.0f; + if(PanSpeedX < -70.0f) PanSpeedX = -70.0f; + + + if(KEYDOWN(rsUP)) + PanSpeedY += 0.1f; + else if(KEYDOWN(rsDOWN)) + PanSpeedY -= 0.1f; + else + PanSpeedY = 0.0f; + if(PanSpeedY > 70.0f) PanSpeedY = 70.0f; + if(PanSpeedY < -70.0f) PanSpeedY = -70.0f; + + + Front = TargetCoors - Source; + Front.Normalise(); + Source = Source + Front*Speed; + + Up = CVector{ 0.0f, 0.0f, 1.0f }; + CVector Right = CrossProduct(Front, Up); + Up = CrossProduct(Right, Front); + Source = Source + Up*PanSpeedY + Right*PanSpeedX; + + if(Source.z < -450.0f) + Source.z = -450.0f; + + if(CPad::GetPad(1)->GetRightShoulder2JustDown() || KEYJUSTDOWN(rsENTER)){ + if(FindPlayerVehicle()) + FindPlayerVehicle()->Teleport(Source); + else + CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition() = Source; + } + + // stay inside sectors + while(CWorld::GetSectorX(Source.x) > 95.0f) + Source.x -= 1.0f; + while(CWorld::GetSectorX(Source.x) < 5.0f) + Source.x += 1.0f; + while(CWorld::GetSectorY(Source.y) > 95.0f) + Source.y -= 1.0f; + while(CWorld::GetSectorY(Source.y) < 5.0f) + Source.y += 1.0f; + GetVectorsReadyForRW(); + + CPad::GetPad(0)->DisablePlayerControls = PLAYERCONTROL_DISABLED_1; + + if(CPad::GetPad(1)->GetLeftShockJustDown() && gbBigWhiteDebugLightSwitchedOn) + CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &Source, + 12.0f, 0.0f, 0.0f, -12.0f, + 128, 128, 128, 128, 1000.0f, false, 1.0f); + + if(CHud::m_Wants_To_Draw_Hud){ + char str[256]; + sprintf(str, "CamX: %f CamY: %f CamZ: %f", Source.x, Source.y, Source.z); + sprintf(str, "Frontx: %f, Fronty: %f, Frontz: %f ", Front.x, Front.y, Front.z); + sprintf(str, "Look@: %f, Look@: %f, Look@: %f ", Front.x + Source.x, Front.y + Source.y, Front.z + Source.z); + } +} +#else +void +CCam::Process_Debug(const CVector&, float, float, float) +{ + static float Speed = 0.0f; + CVector TargetCoors; + + RwCameraSetNearClipPlane(Scene.camera, 0.9f); + FOV = DefaultFOV; + Alpha += DEGTORAD(CPad::GetPad(1)->GetLeftStickY()) / 50.0f; + Beta += DEGTORAD(CPad::GetPad(1)->GetLeftStickX())*1.5f / 19.0f; + + TargetCoors.x = Source.x + Cos(Alpha) * Cos(Beta) * 3.0f; + TargetCoors.y = Source.y + Cos(Alpha) * Sin(Beta) * 3.0f; + TargetCoors.z = Source.z + Sin(Alpha) * 3.0f; + + if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f); + if(Alpha < DEGTORAD(-89.5f)) Alpha = DEGTORAD(-89.5f); + + if(CPad::GetPad(1)->GetSquare() || CPad::GetPad(1)->GetLeftMouse()) + Speed += 0.1f; + else if(CPad::GetPad(1)->GetCross() || CPad::GetPad(1)->GetRightMouse()) + Speed -= 0.1f; + else + Speed = 0.0f; + if(Speed > 70.0f) Speed = 70.0f; + if(Speed < -70.0f) Speed = -70.0f; + + Front = TargetCoors - Source; + Front.Normalise(); + Source = Source + Front*Speed; + + if(Source.z < -450.0f) + Source.z = -450.0f; + + if(CPad::GetPad(1)->GetRightShoulder2JustDown()){ + if(FindPlayerVehicle()) + FindPlayerVehicle()->Teleport(Source); + else + CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition() = Source; + + } + + // stay inside sectors + while(CWorld::GetSectorX(Source.x) > 95.0f) + Source.x -= 1.0f; + while(CWorld::GetSectorX(Source.x) < 5.0f) + Source.x += 1.0f; + while(CWorld::GetSectorY(Source.y) > 95.0f) + Source.y -= 1.0f; + while(CWorld::GetSectorY(Source.y) < 5.0f) + Source.y += 1.0f; + GetVectorsReadyForRW(); + + if(CPad::GetPad(1)->GetLeftShockJustDown() && gbBigWhiteDebugLightSwitchedOn) + CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &Source, + 12.0f, 0.0f, 0.0f, -12.0f, + 128, 128, 128, 128, 1000.0f, false, 1.0f); + + if(CHud::m_Wants_To_Draw_Hud){ + char str[256]; + sprintf(str, "CamX: %f CamY: %f CamZ: %f", Source.x, Source.y, Source.z); + sprintf(str, "Frontx: %f, Fronty: %f, Frontz: %f ", Front.x, Front.y, Front.z); + sprintf(str, "Look@: %f, Look@: %f, Look@: %f ", Front.x + Source.x, Front.y + Source.y, Front.z + Source.z); + } +} +#endif + +void +CCam::Process_Editor(const CVector&, float, float, float) +{ + static float Speed = 0.0f; + CVector TargetCoors; + + if(ResetStatics){ + Source = CVector(796.0f, -937.0, 40.0f); + CamTargetEntity = nil; + } + ResetStatics = false; + + RwCameraSetNearClipPlane(Scene.camera, 0.9f); + FOV = DefaultFOV; + Alpha += DEGTORAD(CPad::GetPad(1)->GetLeftStickY()) / 50.0f; + Beta += DEGTORAD(CPad::GetPad(1)->GetLeftStickX())*1.5f / 19.0f; + + if(CamTargetEntity && CSceneEdit::m_bCameraFollowActor){ + TargetCoors = CamTargetEntity->GetPosition(); + }else if(CSceneEdit::m_bRecording){ + TargetCoors.x = Source.x + Cos(Alpha) * Cos(Beta) * 7.0f; + TargetCoors.y = Source.y + Cos(Alpha) * Sin(Beta) * 7.0f; + TargetCoors.z = Source.z + Sin(Alpha) * 7.0f; + }else + TargetCoors = CSceneEdit::m_vecCamHeading + Source; + CSceneEdit::m_vecCurrentPosition = TargetCoors; + CSceneEdit::m_vecCamHeading = TargetCoors - Source; + + if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f); + if(Alpha < DEGTORAD(-89.5f)) Alpha = DEGTORAD(-89.5f); + + if(CPad::GetPad(1)->GetSquare() || CPad::GetPad(1)->GetLeftMouse()) + Speed += 0.1f; + else if(CPad::GetPad(1)->GetCross() || CPad::GetPad(1)->GetRightMouse()) + Speed -= 0.1f; + else + Speed = 0.0f; + if(Speed > 70.0f) Speed = 70.0f; + if(Speed < -70.0f) Speed = -70.0f; + + Front = TargetCoors - Source; + Front.Normalise(); + Source = Source + Front*Speed; + + if(Source.z < -450.0f) + Source.z = -450.0f; + + if(CPad::GetPad(1)->GetRightShoulder2JustDown()){ + if(FindPlayerVehicle()) + FindPlayerVehicle()->Teleport(Source); + else + CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition() = Source; + + } + + // stay inside sectors + while(CWorld::GetSectorX(Source.x) > 95.0f) + Source.x -= 1.0f; + while(CWorld::GetSectorX(Source.x) < 5.0f) + Source.x += 1.0f; + while(CWorld::GetSectorY(Source.y) > 95.0f) + Source.y -= 1.0f; + while(CWorld::GetSectorY(Source.y) < 5.0f) + Source.y += 1.0f; + GetVectorsReadyForRW(); + + if(CPad::GetPad(1)->GetLeftShockJustDown() && gbBigWhiteDebugLightSwitchedOn) + CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &Source, + 12.0f, 0.0f, 0.0f, -12.0f, + 128, 128, 128, 128, 1000.0f, false, 1.0f); + + if(CHud::m_Wants_To_Draw_Hud){ + char str[256]; + sprintf(str, "CamX: %f CamY: %f CamZ: %f", Source.x, Source.y, Source.z); + sprintf(str, "Frontx: %f, Fronty: %f, Frontz: %f ", Front.x, Front.y, Front.z); + sprintf(str, "Look@: %f, Look@: %f, Look@: %f ", Front.x + Source.x, Front.y + Source.y, Front.z + Source.z); + } +} + +void +CCam::Process_ModelView(const CVector &CameraTarget, float, float, float) +{ + CVector TargetCoors = CameraTarget; + float Angle = Atan2(Front.x, Front.y); + FOV = DefaultFOV; + + Angle += CPad::GetPad(0)->GetLeftStickX()/1280.0f; + if(Distance < 10.0f) + Distance += CPad::GetPad(0)->GetLeftStickY()/1000.0f; + else + Distance += CPad::GetPad(0)->GetLeftStickY() * ((Distance - 10.0f)/20.0f + 1.0f) / 1000.0f; + if(Distance < 1.5f) + Distance = 1.5f; + + Front.x = Cos(0.3f) * Sin(Angle); + Front.y = Cos(0.3f) * Cos(Angle); + Front.z = -Sin(0.3f); + Source = CameraTarget - Distance*Front; + + GetVectorsReadyForRW(); +} + +void +CCam::ProcessPedsDeadBaby(void) +{ + float Distance = 0.0f; + static bool SafeToRotate = false; + CVector TargetDist, TestPoint; + + FOV = DefaultFOV; + TargetDist = Source - CamTargetEntity->GetPosition(); + Distance = TargetDist.Magnitude(); + Beta = CGeneral::GetATanOfXY(TargetDist.x, TargetDist.y); + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + + if(ResetStatics){ + TestPoint = CamTargetEntity->GetPosition() + + CVector(4.0f * Cos(Alpha) * Cos(Beta), + 4.0f * Cos(Alpha) * Sin(Beta), + 4.0f * Sin(Alpha)); + bool Safe1 = CWorld::GetIsLineOfSightClear(TestPoint, CamTargetEntity->GetPosition(), true, false, false, true, false, true, true); + + TestPoint = CamTargetEntity->GetPosition() + + CVector(4.0f * Cos(Alpha) * Cos(Beta + DEGTORAD(120.0f)), + 4.0f * Cos(Alpha) * Sin(Beta + DEGTORAD(120.0f)), + 4.0f * Sin(Alpha)); + bool Safe2 = CWorld::GetIsLineOfSightClear(TestPoint, CamTargetEntity->GetPosition(), true, false, false, true, false, true, true); + + TestPoint = CamTargetEntity->GetPosition() + + CVector(4.0f * Cos(Alpha) * Cos(Beta - DEGTORAD(120.0f)), + 4.0f * Cos(Alpha) * Sin(Beta - DEGTORAD(120.0f)), + 4.0f * Sin(Alpha)); + bool Safe3 = CWorld::GetIsLineOfSightClear(TestPoint, CamTargetEntity->GetPosition(), true, false, false, true, false, true, true); + + SafeToRotate = Safe1 && Safe2 && Safe3; + + ResetStatics = false; + } + + if(SafeToRotate) + WellBufferMe(Beta + DEGTORAD(175.0f), &Beta, &BetaSpeed, 0.015f, 0.007f, true); + + WellBufferMe(DEGTORAD(89.5f), &Alpha, &AlphaSpeed, 0.015f, 0.07f, true); + WellBufferMe(35.0f, &Distance, &DistanceSpeed, 0.006f, 0.007f, false); + + Source = CamTargetEntity->GetPosition() + + CVector(Distance * Cos(Alpha) * Cos(Beta), + Distance * Cos(Alpha) * Sin(Beta), + Distance * Sin(Alpha)); + m_cvecTargetCoorsForFudgeInter = CamTargetEntity->GetPosition(); + Front = CamTargetEntity->GetPosition() - Source; + Front.Normalise(); + GetVectorsReadyForRW(); +} + +bool +CCam::ProcessArrestCamOne(void) +{ + FOV = 45.0f; + if(ResetStatics) + return true; + +#ifdef FIX_BUGS + if(!CamTargetEntity->IsPed()) + return true; +#endif + + bool found; + float Ground; + CVector PlayerCoors = TheCamera.pTargetEntity->GetPosition(); + CVector CopCoors = ((CPlayerPed*)TheCamera.pTargetEntity)->m_pArrestingCop->GetPosition(); + Beta = CGeneral::GetATanOfXY(PlayerCoors.x - CopCoors.x, PlayerCoors.y - CopCoors.y); + + Source = PlayerCoors + 9.5f*CVector(Cos(Beta), Sin(Beta), 0.0f); + Source.z += 6.0f; + Ground = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, Source.z, &found); + if(!found){ + Ground = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, Source.z, &found); + if(!found) + return false; + } + Source.z = Ground + 0.25f; + if(!CWorld::GetIsLineOfSightClear(Source, CopCoors, true, true, false, true, false, true, true)){ + Beta += DEGTORAD(115.0f); + Source = PlayerCoors + 9.5f*CVector(Cos(Beta), Sin(Beta), 0.0f); + Source.z += 6.0f; + Ground = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, Source.z, &found); + if(!found){ + Ground = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, Source.z, &found); + if(!found) + return false; + } + Source.z = Ground + 0.25f; + + CopCoors.z += 0.35f; + Front = CopCoors - Source; + if(!CWorld::GetIsLineOfSightClear(Source, CopCoors, true, true, false, true, false, true, true)) + return false; + } + CopCoors.z += 0.35f; + m_cvecTargetCoorsForFudgeInter = CopCoors; + Front = CopCoors - Source; + ResetStatics = false; + GetVectorsReadyForRW(); + return true; +} + +bool +CCam::ProcessArrestCamTwo(void) +{ + CPed *player = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + if(!ResetStatics) + return true; + ResetStatics = false; + + CVector TargetCoors, ToCamera; + float BetaOffset; + float SourceX, SourceY; + CCam *ActiveCam = &TheCamera.Cams[TheCamera.ActiveCam]; + if(&ActiveCam[1] == this){ + SourceX = TheCamera.Cams[(TheCamera.ActiveCam + 1) % 2].Source.x; + SourceY = TheCamera.Cams[(TheCamera.ActiveCam + 1) % 2].Source.y; + }else{ + SourceX = ActiveCam[1].Source.x; + SourceY = ActiveCam[1].Source.y; + } + + for(int i = 0; i <= 1; i++){ + int Dir = i == 0 ? 1 : -1; + + TargetCoors = player->GetPosition(); + Beta = CGeneral::GetATanOfXY(TargetCoors.x-SourceX, TargetCoors.y-SourceY); + BetaOffset = DEGTORAD(Dir*80); + Source = TargetCoors + 11.5f*CVector(Cos(Beta+BetaOffset), Sin(Beta+BetaOffset), 0.0f); + + ToCamera = Source - TargetCoors; + ToCamera.Normalise(); + TargetCoors.x += 0.4f*ToCamera.x; + TargetCoors.y += 0.4f*ToCamera.y; + if(CWorld::GetIsLineOfSightClear(Source, TargetCoors, true, true, false, true, false, true, true)){ + Source.z += 5.5f; + TargetCoors += CVector(-0.8f*ToCamera.x, -0.8f*ToCamera.y, 2.2f); + m_cvecTargetCoorsForFudgeInter = TargetCoors; + Front = TargetCoors - Source; + ResetStatics = false; + GetVectorsReadyForRW(); + return true; + } + } + return false; +} + + +/* + * Unused PS2 cams + */ + +void +CCam::Process_Chris_With_Binding_PlusRotation(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + static float AngleToBinned = 0.0f; + static float StartingAngleLastChange = 0.0f; + static float FixedTargetOrientation = 0.0f; + static float DeadZoneReachedOnePrevious; + + FOV = DefaultFOV; // missing in game + + bool FixOrientation = true; + if(ResetStatics){ + Rotating = false; + DeadZoneReachedOnePrevious = 0.0f; + FixedTargetOrientation = 0.0f; + ResetStatics = false; + } + + CVector TargetCoors = CameraTarget; + + float StickX = CPad::GetPad(0)->GetRightStickX(); + float StickY = CPad::GetPad(0)->GetRightStickY(); + float StickAngle; + if(StickX != 0.0 || StickY != 0.0f) // BUG: game checks StickX twice + StickAngle = CGeneral::GetATanOfXY(StickX, StickY); // result unused? + else + FixOrientation = false; + + CVector Dist = Source - TargetCoors; + Source.z = TargetCoors.z + 0.75f; + float Length = Dist.Magnitude2D(); + if(Length > 2.5f){ + Source.x = TargetCoors.x + Dist.x/Length * 2.5f; + Source.y = TargetCoors.y + Dist.y/Length * 2.5f; + }else if(Length < 2.4f){ + Source.x = TargetCoors.x + Dist.x/Length * 2.4f; + Source.y = TargetCoors.y + Dist.y/Length * 2.4f; + } + + Beta = CGeneral::GetATanOfXY(Dist.x, Dist.y); + if(CPad::GetPad(0)->GetLeftShoulder1()){ + FixedTargetOrientation = TargetOrientation; + Rotating = true; + } + + if(FixOrientation){ + Rotating = true; + FixedTargetOrientation = StickX/128.0f + Beta - PI; + } + + if(Rotating){ + Dist = Source - TargetCoors; + Length = Dist.Magnitude2D(); + // inlined + WellBufferMe(FixedTargetOrientation+PI, &Beta, &BetaSpeed, 0.1f, 0.06f, true); + + Source.x = TargetCoors.x + Length*Cos(Beta); + Source.y = TargetCoors.y + Length*Sin(Beta); + + float DeltaBeta = FixedTargetOrientation+PI - Beta; + while(DeltaBeta >= PI) DeltaBeta -= 2*PI; + while(DeltaBeta < -PI) DeltaBeta += 2*PI; + if(Abs(DeltaBeta) < 0.06f) + Rotating = false; + } + + Front = TargetCoors - Source; + Front.Normalise(); + CVector Front2 = Front; + Front2.Normalise(); // What? + // FIX: the meaning of this value must have changed somehow + Source -= Front2 * TheCamera.m_fPedZoomValueSmooth*1.5f; +// Source += Front2 * TheCamera.m_fPedZoomValueSmooth; + + GetVectorsReadyForRW(); +} + +void +CCam::Process_ReactionCam(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + static float AngleToBinned = 0.0f; + static float StartingAngleLastChange = 0.0f; + static float FixedTargetOrientation; + static float DeadZoneReachedOnePrevious; + static uint32 TimeOfLastChange; + uint32 Time; + bool DontBind = false; // BUG: left uninitialized + + FOV = DefaultFOV; // missing in game + + if(ResetStatics){ + Rotating = false; + DeadZoneReachedOnePrevious = 0.0f; + FixedTargetOrientation = 0.0f; + ResetStatics = false; + DontBind = false; + } + + CVector TargetCoors = CameraTarget; + + CVector Dist = Source - TargetCoors; + Source.z = TargetCoors.z + 0.75f; + float Length = Dist.Magnitude2D(); + if(Length > 2.5f){ + Source.x = TargetCoors.x + Dist.x/Length * 2.5f; + Source.y = TargetCoors.y + Dist.y/Length * 2.5f; + }else if(Length < 2.4f){ + Source.x = TargetCoors.x + Dist.x/Length * 2.4f; + Source.y = TargetCoors.y + Dist.y/Length * 2.4f; + } + + Beta = CGeneral::GetATanOfXY(Dist.x, Dist.y); + + float StickX = CPad::GetPad(0)->GetLeftStickX(); + float StickY = CPad::GetPad(0)->GetLeftStickY(); + float StickAngle; + if(StickX != 0.0 || StickY != 0.0f){ + StickAngle = CGeneral::GetATanOfXY(StickX, StickY); + while(StickAngle >= PI) StickAngle -= 2*PI; + while(StickAngle < -PI) StickAngle += 2*PI; + }else + StickAngle = 1000.0f; + + if(Abs(StickAngle-AngleToBinned) > DEGTORAD(15.0f)){ + DontBind = true; + Time = CTimer::GetTimeInMilliseconds(); + } + + if(CTimer::GetTimeInMilliseconds()-TimeOfLastChange > 200){ + if(Abs(HALFPI-StickAngle) > DEGTORAD(50.0f)){ + FixedTargetOrientation = TargetOrientation; + Rotating = true; + TimeOfLastChange = CTimer::GetTimeInMilliseconds(); + } + } + + // These two together don't make much sense. + // Only prevents rotation for one frame + AngleToBinned = StickAngle; + if(DontBind) + TimeOfLastChange = Time; + + if(Rotating){ + Dist = Source - TargetCoors; + Length = Dist.Magnitude2D(); + // inlined + WellBufferMe(FixedTargetOrientation+PI, &Beta, &BetaSpeed, 0.1f, 0.06f, true); + + Source.x = TargetCoors.x + Length*Cos(Beta); + Source.y = TargetCoors.y + Length*Sin(Beta); + + float DeltaBeta = FixedTargetOrientation+PI - Beta; + while(DeltaBeta >= PI) DeltaBeta -= 2*PI; + while(DeltaBeta < -PI) DeltaBeta += 2*PI; + if(Abs(DeltaBeta) < 0.06f) + Rotating = false; + } + + Front = TargetCoors - Source; + Front.Normalise(); + CVector Front2 = Front; + Front2.Normalise(); // What? + // FIX: the meaning of this value must have changed somehow + Source -= Front2 * TheCamera.m_fPedZoomValueSmooth*1.5f; +// Source += Front2 * TheCamera.m_fPedZoomValueSmooth; + + GetVectorsReadyForRW(); +} + +void +CCam::Process_FollowPed_WithBinding(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + static float AngleToBinned = 0.0f; + static float StartingAngleLastChange = 0.0f; + static float FixedTargetOrientation; + static float DeadZoneReachedOnePrevious; + static uint32 TimeOfLastChange; + uint32 Time; + bool DontBind = false; + + FOV = DefaultFOV; // missing in game + + if(ResetStatics){ + Rotating = false; + DeadZoneReachedOnePrevious = 0.0f; + FixedTargetOrientation = 0.0f; + ResetStatics = false; + } + + CVector TargetCoors = CameraTarget; + + CVector Dist = Source - TargetCoors; + Source.z = TargetCoors.z + 0.75f; + float Length = Dist.Magnitude2D(); + if(Length > 2.5f){ + Source.x = TargetCoors.x + Dist.x/Length * 2.5f; + Source.y = TargetCoors.y + Dist.y/Length * 2.5f; + }else if(Length < 2.4f){ + Source.x = TargetCoors.x + Dist.x/Length * 2.4f; + Source.y = TargetCoors.y + Dist.y/Length * 2.4f; + } + + Beta = CGeneral::GetATanOfXY(Dist.x, Dist.y); + + float StickX = CPad::GetPad(0)->GetLeftStickX(); + float StickY = CPad::GetPad(0)->GetLeftStickY(); + float StickAngle; + if(StickX != 0.0 || StickY != 0.0f){ + StickAngle = CGeneral::GetATanOfXY(StickX, StickY); + while(StickAngle >= PI) StickAngle -= 2*PI; + while(StickAngle < -PI) StickAngle += 2*PI; + }else + StickAngle = 1000.0f; + + if(Abs(StickAngle-AngleToBinned) > DEGTORAD(15.0f)){ + DontBind = true; + Time = CTimer::GetTimeInMilliseconds(); + } + + if(CTimer::GetTimeInMilliseconds()-TimeOfLastChange > 200){ + if(Abs(HALFPI-StickAngle) > DEGTORAD(50.0f)){ + FixedTargetOrientation = TargetOrientation; + Rotating = true; + TimeOfLastChange = CTimer::GetTimeInMilliseconds(); + } + } + + if(CPad::GetPad(0)->GetLeftShoulder1JustDown()){ + FixedTargetOrientation = TargetOrientation; + Rotating = true; + TimeOfLastChange = CTimer::GetTimeInMilliseconds(); + } + + // These two together don't make much sense. + // Only prevents rotation for one frame + AngleToBinned = StickAngle; + if(DontBind) + TimeOfLastChange = Time; + + if(Rotating){ + Dist = Source - TargetCoors; + Length = Dist.Magnitude2D(); + // inlined + WellBufferMe(FixedTargetOrientation+PI, &Beta, &BetaSpeed, 0.1f, 0.06f, true); + + Source.x = TargetCoors.x + Length*Cos(Beta); + Source.y = TargetCoors.y + Length*Sin(Beta); + + float DeltaBeta = FixedTargetOrientation+PI - Beta; + while(DeltaBeta >= PI) DeltaBeta -= 2*PI; + while(DeltaBeta < -PI) DeltaBeta += 2*PI; + if(Abs(DeltaBeta) < 0.06f) + Rotating = false; + } + + Front = TargetCoors - Source; + Front.Normalise(); + CVector Front2 = Front; + Front2.Normalise(); // What? + // FIX: the meaning of this value must have changed somehow + Source -= Front2 * TheCamera.m_fPedZoomValueSmooth*1.5f; +// Source += Front2 * TheCamera.m_fPedZoomValueSmooth; + + GetVectorsReadyForRW(); +} + +STARTPATCHES + InjectHook(0x456F40, WellBufferMe, PATCH_JUMP); + InjectHook(0x458410, &CCam::Init, PATCH_JUMP); + InjectHook(0x4582F0, &CCam::GetVectorsReadyForRW, PATCH_JUMP); + InjectHook(0x457710, &CCam::DoAverageOnVector, PATCH_JUMP); + InjectHook(0x458060, &CCam::GetPedBetaAngleForClearView, PATCH_JUMP); + InjectHook(0x457210, &CCam::Cam_On_A_String_Unobscured, PATCH_JUMP); + InjectHook(0x457A80, &CCam::FixCamWhenObscuredByVehicle, PATCH_JUMP); + InjectHook(0x457B90, &CCam::FixCamIfObscured, PATCH_JUMP); + InjectHook(0x465DA0, &CCam::RotCamIfInFrontCar, PATCH_JUMP); + InjectHook(0x4662D0, &CCam::WorkOutCamHeightWeeCar, PATCH_JUMP); + InjectHook(0x466650, &CCam::WorkOutCamHeight, PATCH_JUMP); + InjectHook(0x458600, &CCam::LookBehind, PATCH_JUMP); + InjectHook(0x458C40, &CCam::LookLeft, PATCH_JUMP); + InjectHook(0x458FB0, &CCam::LookRight, PATCH_JUMP); + InjectHook(0x4574C0, &CCam::ClipIfPedInFrontOfPlayer, PATCH_JUMP); + InjectHook(0x459300, &CCam::KeepTrackOfTheSpeed, PATCH_JUMP); + InjectHook(0x458580, &CCam::IsTargetInWater, PATCH_JUMP); + InjectHook(0x4570C0, &CCam::AvoidWallsTopDownPed, PATCH_JUMP); + InjectHook(0x4595B0, &CCam::PrintMode, PATCH_JUMP); + + InjectHook(0x467400, &CCam::ProcessSpecialHeightRoutines, PATCH_JUMP); + InjectHook(0x4596A0, &CCam::Process, PATCH_JUMP); + InjectHook(0x45E3A0, &CCam::Process_FollowPed, PATCH_JUMP); + InjectHook(0x45FF70, &CCam::Process_FollowPedWithMouse, PATCH_JUMP); + InjectHook(0x45BE60, &CCam::Process_BehindCar, PATCH_JUMP); + InjectHook(0x45C090, &CCam::Process_Cam_On_A_String, PATCH_JUMP); + InjectHook(0x463EB0, &CCam::Process_TopDown, PATCH_JUMP); + InjectHook(0x464390, &CCam::Process_TopDownPed, PATCH_JUMP); + InjectHook(0x461AF0, &CCam::Process_Rocket, PATCH_JUMP); + InjectHook(0x460E00, &CCam::Process_M16_1stPerson, PATCH_JUMP); + InjectHook(0x459FA0, &CCam::Process_1stPerson, PATCH_JUMP); + InjectHook(0x462420, &CCam::Process_Sniper, PATCH_JUMP); + InjectHook(0x463130, &CCam::Process_Syphon, PATCH_JUMP); + InjectHook(0x463A70, &CCam::Process_Syphon_Crim_In_Front, PATCH_JUMP); + InjectHook(0x45B470, &CCam::Process_BehindBoat, PATCH_JUMP); + InjectHook(0x45D2F0, &CCam::Process_Fight_Cam, PATCH_JUMP); + InjectHook(0x45DC20, &CCam::Process_FlyBy, PATCH_JUMP); + InjectHook(0x464D10, &CCam::Process_WheelCam, PATCH_JUMP); + InjectHook(0x45DA20, &CCam::Process_Fixed, PATCH_JUMP); + InjectHook(0x461940, &CCam::Process_Player_Fallen_Water, PATCH_JUMP); + InjectHook(0x45C400, &CCam::Process_Circle, PATCH_JUMP); + InjectHook(0x462FC0, &CCam::Process_SpecialFixedForSyphon, PATCH_JUMP); + InjectHook(0x45CCC0, &CCam::Process_Debug, PATCH_JUMP); + InjectHook(0x4656C0, &CCam::ProcessPedsDeadBaby, PATCH_JUMP); + InjectHook(0x465000, &CCam::ProcessArrestCamOne, PATCH_JUMP); + InjectHook(0x4653C0, &CCam::ProcessArrestCamTwo, PATCH_JUMP); + + InjectHook(0x456CE0, &FindSplinePathPositionFloat, PATCH_JUMP); + InjectHook(0x4569A0, &FindSplinePathPositionVector, PATCH_JUMP); + + InjectHook(0x473250, &CCamera::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 75e52c5f..3f7ed286 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -13,8 +13,6 @@ #include "MBlur.h" #include "Camera.h" -const float DefaultFOV = 70.0f; // beta: 80.0f - CCamera &TheCamera = *(CCamera*)0x6FACF8; bool &CCamera::m_bUseMouse3rdPerson = *(bool *)0x5F03D8; @@ -38,6 +36,15 @@ CCamera::GetFading() return m_bFading; } +int +CCamera::GetFadingDirection() +{ + if(m_bFading) + return m_iFadingDirection == FADE_IN ? FADE_IN : FADE_OUT; + else + return FADE_NONE; +} + bool CCamera::IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat) { @@ -182,1148 +189,6 @@ CCamera::ClearPlayerWeaponMode() PlayerWeaponMode.Duration = 0.0f; } - -/* - * - * CCam - * - */ - - -// MaxSpeed is a limit of how fast the value is allowed to change. 1.0 = to Target in up to 1ms -// Acceleration is how fast the speed will change to MaxSpeed. 1.0 = to MaxSpeed in 1ms -void -WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSpeed, float Acceleration, bool IsAngle) -{ - float Delta = Target - *CurrentValue; - - if(IsAngle){ - while(Delta >= PI) Delta -= 2*PI; - while(Delta < -PI) Delta += 2*PI; - } - - float TargetSpeed = Delta * MaxSpeed; - // Add or subtract absolute depending on sign, genius! -// if(TargetSpeed - *CurrentSpeed > 0.0f) -// *CurrentSpeed += Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); -// else -// *CurrentSpeed -= Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); - // this is simpler: - *CurrentSpeed += Acceleration * (TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); - - // Clamp speed if we overshot - if(TargetSpeed < 0.0f && *CurrentSpeed < TargetSpeed) - *CurrentSpeed = TargetSpeed; - else if(TargetSpeed > 0.0f && *CurrentSpeed > TargetSpeed) - *CurrentSpeed = TargetSpeed; - - *CurrentValue += *CurrentSpeed * min(10.0f, CTimer::GetTimeStep()); -} - -void -CCam::GetVectorsReadyForRW(void) -{ - CVector right; - Up = CVector(0.0f, 0.0f, 1.0f); - Front.Normalise(); - if(Front.x == 0.0f && Front.y == 0.0f){ - Front.x = 0.0001f; - Front.y = 0.0001f; - } - right = CrossProduct(Front, Up); - right.Normalise(); - Up = CrossProduct(right, Front); -} - -// This code is really bad. wtf R*? -CVector -CCam::DoAverageOnVector(const CVector &vec) -{ - int i; - CVector Average = { 0.0f, 0.0f, 0.0f }; - - if(ResetStatics){ - m_iRunningVectorArrayPos = 0; - m_iRunningVectorCounter = 1; - } - - // TODO: make this work with NUMBER_OF_VECTORS_FOR_AVERAGE != 2 - if(m_iRunningVectorCounter == 3){ - m_arrPreviousVectors[0] = m_arrPreviousVectors[1]; - m_arrPreviousVectors[1] = vec; - }else - m_arrPreviousVectors[m_iRunningVectorArrayPos] = vec; - - for(i = 0; i <= m_iRunningVectorArrayPos; i++) - Average += m_arrPreviousVectors[i]; - Average /= i; - - m_iRunningVectorArrayPos++; - m_iRunningVectorCounter++; - if(m_iRunningVectorArrayPos >= NUMBER_OF_VECTORS_FOR_AVERAGE) - m_iRunningVectorArrayPos = NUMBER_OF_VECTORS_FOR_AVERAGE-1; - if(m_iRunningVectorCounter > NUMBER_OF_VECTORS_FOR_AVERAGE+1) - m_iRunningVectorCounter = NUMBER_OF_VECTORS_FOR_AVERAGE+1; - - return Average; -} - -// Rotate Beta in direction opposite of BetaOffset in 5 deg. steps. -// Return the first angle for which Beta + BetaOffset + Angle has a clear view. -// i.e. BetaOffset is a safe zone so that Beta + Angle is really clear. -// If BetaOffset == 0, try both directions. -float -CCam::GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies) -{ - CColPoint point; - CEntity *ent = nil; - CVector ToSource; - float a; - - // This would be so much nicer if we just got the step variable before the loop...R* - - for(a = 0.0f; a <= PI; a += DEGTORAD(5.0f)){ - if(BetaOffset <= 0.0f){ - ToSource = CVector(Cos(Beta + BetaOffset + a), Sin(Beta + BetaOffset + a), 0.0f)*Dist; - if(!CWorld::ProcessLineOfSight(Target, Target + ToSource, - point, ent, checkBuildings, checkVehicles, checkPeds, - checkObjects, checkDummies, true, true)) - return a; - } - if(BetaOffset >= 0.0f){ - ToSource = CVector(Cos(Beta + BetaOffset - a), Sin(Beta + BetaOffset - a), 0.0f)*Dist; - if(!CWorld::ProcessLineOfSight(Target, Target + ToSource, - point, ent, checkBuildings, checkVehicles, checkPeds, - checkObjects, checkDummies, true, true)) - return -a; - } - } - return 0.0f; -} - -static float DefaultAcceleration = 0.045f; -static float DefaultMaxStep = 0.15f; - -void -CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float) -{ - const float GroundDist = 1.85f; - - CVector TargetCoors, Dist, IdealSource; - float Length = 0.0f; - float LateralLeft = 0.0f; - float LateralRight = 0.0f; - float Center = 0.0f; - static bool PreviouslyObscured; - static bool PickedASide; - static float FixedTargetOrientation = 0.0f; - float AngleToGoTo = 0.0f; - float BetaOffsetAvoidBuildings = 0.45f; // ~25 deg - float BetaOffsetGoingBehind = 0.45f; - bool GoingBehind = false; - bool Obscured = false; - bool BuildingCheckObscured = false; - bool HackPlayerOnStoppingTrain = false; - static int TimeIndicatedWantedToGoDown = 0; - static bool StartedCountingForGoDown = false; - float DeltaBeta; - - m_bFixingBeta = false; - bBelowMinDist = false; - bBehindPlayerDesired = false; - - assert(CamTargetEntity->IsPed()); - - // CenterDist should be > LateralDist because we don't have an angle for safety in this case - float CenterDist, LateralDist; - float AngleToGoToSpeed; - if(m_fCloseInPedHeightOffsetSpeed > 0.00001f){ - LateralDist = 0.55f; - CenterDist = 1.25f; - BetaOffsetAvoidBuildings = 0.9f; // ~50 deg - BetaOffsetGoingBehind = 0.9f; - AngleToGoToSpeed = 0.88254666f; - }else{ - LateralDist = 0.8f; - CenterDist = 1.35f; - if(TheCamera.PedZoomIndicator == 1.0f || TheCamera.PedZoomIndicator == 4.0f){ - LateralDist = 1.25f; - CenterDist = 1.6f; - } - AngleToGoToSpeed = 0.43254671f; - } - - FOV = DefaultFOV; - - if(ResetStatics){ - Rotating = false; - m_bCollisionChecksOn = true; - FixedTargetOrientation = 0.0f; - PreviouslyObscured = false; - PickedASide = false; - StartedCountingForGoDown = false; - AngleToGoTo = 0.0f; - // unused LastAngleWithNoPickedASide - } - - - TargetCoors = CameraTarget; - IdealSource = Source; - TargetCoors.z += m_fSyphonModeTargetZOffSet; - - CVector TempTargetCoors; - TempTargetCoors = DoAverageOnVector(TargetCoors); - TargetCoors = TempTargetCoors; - // Add this unknown offset, but later it's removed again - TargetCoors.z += m_fUnknownZOffSet; - - Dist.x = IdealSource.x - TargetCoors.x; - Dist.y = IdealSource.y - TargetCoors.y; - Length = Dist.Magnitude2D(); - - // Cam on a string. With a fixed distance. Zoom in/out is done later. - if(Length != 0.0f) - IdealSource = TargetCoors + CVector(Dist.x, Dist.y, 0.0f)/Length * GroundDist; - else - IdealSource = TargetCoors + CVector(1.0f, 1.0f, 0.0f); - - // TODO: what's transition beta? - if(TheCamera.m_bUseTransitionBeta && ResetStatics){ - CVector VecDistance; - IdealSource.x = TargetCoors.x + GroundDist*Cos(m_fTransitionBeta); - IdealSource.y = TargetCoors.y + GroundDist*Sin(m_fTransitionBeta); - Beta = CGeneral::GetATanOfXY(IdealSource.x - TargetCoors.x, IdealSource.y - TargetCoors.y); - }else - Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y); - - if(TheCamera.m_bCamDirectlyBehind){ - m_bCollisionChecksOn = true; - Beta = TargetOrientation + PI; - } - - if(FindPlayerVehicle()) - if(FindPlayerVehicle()->m_vehType == VEHICLE_TYPE_TRAIN) - HackPlayerOnStoppingTrain = true; - - if(TheCamera.m_bCamDirectlyInFront){ - m_bCollisionChecksOn = true; - Beta = TargetOrientation; - } - - while(Beta >= PI) Beta -= 2.0f * PI; - while(Beta < -PI) Beta += 2.0f * PI; - - // BUG? is this ever used? - // The values seem to be roughly m_fPedZoomValueSmooth + 1.85 - if(ResetStatics){ - if(TheCamera.PedZoomIndicator == 1.0f) m_fRealGroundDist = 2.090556f; - if(TheCamera.PedZoomIndicator == 2.0f) m_fRealGroundDist = 3.34973f; - if(TheCamera.PedZoomIndicator == 3.0f) m_fRealGroundDist = 4.704914f; - if(TheCamera.PedZoomIndicator == 4.0f) m_fRealGroundDist = 2.090556f; - } - // And what is this? It's only used for collision and rotation it seems - float RealGroundDist; - if(TheCamera.PedZoomIndicator == 1.0f) RealGroundDist = 2.090556f; - if(TheCamera.PedZoomIndicator == 2.0f) RealGroundDist = 3.34973f; - if(TheCamera.PedZoomIndicator == 3.0f) RealGroundDist = 4.704914f; - if(TheCamera.PedZoomIndicator == 4.0f) RealGroundDist = 2.090556f; - if(m_fCloseInPedHeightOffset > 0.00001f) - RealGroundDist = 1.7016f; - - - bool Shooting = false; - CPed *ped = (CPed*)CamTargetEntity; - if(ped->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) - if(CPad::GetPad(0)->GetWeapon()) - Shooting = true; - if(ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_DETONATOR || - ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT) - Shooting = false; - - - if(m_fCloseInPedHeightOffset > 0.00001f) - TargetCoors.z -= m_fUnknownZOffSet; - - // Figure out if and where we want to rotate - - if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){ - - // Center cam behind player - - GoingBehind = true; - m_bCollisionChecksOn = true; - float OriginalBeta = Beta; - // Set Beta behind player - Beta = TargetOrientation + PI; - TargetCoors.z -= 0.1f; - - AngleToGoTo = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false); - if(AngleToGoTo != 0.0f){ - if(AngleToGoTo < 0.0f) - AngleToGoTo -= AngleToGoToSpeed; - else - AngleToGoTo += AngleToGoToSpeed; - }else{ - float LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetGoingBehind, true, false, false, true, false); - float LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetGoingBehind, true, false, false, true, false); - if(LateralLeft == 0.0f && LateralRight != 0.0f) - AngleToGoTo += LateralRight; - else if(LateralLeft != 0.0f && LateralRight == 0.0f) - AngleToGoTo += LateralLeft; - } - - TargetCoors.z += 0.1f; - Beta = OriginalBeta; - - if(PickedASide){ - if(AngleToGoTo == 0.0f) - FixedTargetOrientation = TargetOrientation + PI; - Rotating = true; - }else{ - FixedTargetOrientation = TargetOrientation + PI + AngleToGoTo; - Rotating = true; - PickedASide = true; - } - }else{ - - // Rotate cam to avoid clipping into buildings - - TargetCoors.z -= 0.1f; - - Center = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false); - if(m_bCollisionChecksOn || PreviouslyObscured || Center != 0.0f || m_fCloseInPedHeightOffset > 0.00001f){ - if(Center != 0.0f){ - AngleToGoTo = Center; - }else{ - LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetAvoidBuildings, true, false, false, true, false); - LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetAvoidBuildings, true, false, false, true, false); - if(LateralLeft == 0.0f && LateralRight != 0.0f){ - AngleToGoTo += LateralRight; - if(m_fCloseInPedHeightOffset > 0.0f) - RwCameraSetNearClipPlane(Scene.camera, 0.7f); - }else if(LateralLeft != 0.0f && LateralRight == 0.0f){ - AngleToGoTo += LateralLeft; - if(m_fCloseInPedHeightOffset > 0.0f) - RwCameraSetNearClipPlane(Scene.camera, 0.7f); - } - } - if(LateralLeft != 0.0f || LateralRight != 0.0f || Center != 0.0f) - BuildingCheckObscured = true; - } - - TargetCoors.z += 0.1f; - } - - if(m_fCloseInPedHeightOffset > 0.00001f) - TargetCoors.z += m_fUnknownZOffSet; - - - // Have to fix to avoid collision - - if(AngleToGoTo != 0.0f){ - Obscured = true; - Rotating = true; - if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){ - if(!PickedASide) - FixedTargetOrientation = Beta + AngleToGoTo; // can this even happen? - }else - FixedTargetOrientation = Beta + AngleToGoTo; - - // This calculation is only really used to figure out how fast to rotate out of collision - - m_fAmountFractionObscured = 1.0f; - CVector PlayerPos = FindPlayerPed()->GetPosition(); - float RotationDist = (AngleToGoTo == Center ? CenterDist : LateralDist) * RealGroundDist; - // What's going on here? - AngleToGoTo? - CVector RotatedSource = PlayerPos + CVector(Cos(Beta - AngleToGoTo), Sin(Beta - AngleToGoTo), 0.0f) * RotationDist; - - CColPoint colpoint; - CEntity *entity; - if(CWorld::ProcessLineOfSight(PlayerPos, RotatedSource, colpoint, entity, true, false, false, true, false, false, false)){ - if((PlayerPos - RotatedSource).Magnitude() != 0.0f) - m_fAmountFractionObscured = (PlayerPos - colpoint.point).Magnitude() / (PlayerPos - RotatedSource).Magnitude(); - else - m_fAmountFractionObscured = 1.0f; - } - } - if(m_fAmountFractionObscured < 0.0f) m_fAmountFractionObscured = 0.0f; - if(m_fAmountFractionObscured > 1.0f) m_fAmountFractionObscured = 1.0f; - - - - // Figure out speed values for Beta rotation - - float Acceleration, MaxSpeed; - static float AccelerationMult = 0.35f; - static float MaxSpeedMult = 0.85f; - static float AccelerationMultClose = 0.7f; - static float MaxSpeedMultClose = 1.6f; - float BaseAcceleration = 0.025f; - float BaseMaxSpeed = 0.09f; - if(m_fCloseInPedHeightOffset > 0.00001f){ - if(AngleToGoTo == 0.0f){ - BaseAcceleration = 0.022f; - BaseMaxSpeed = 0.04f; - }else{ - BaseAcceleration = DefaultAcceleration; - BaseMaxSpeed = DefaultMaxStep; - } - } - if(AngleToGoTo == 0.0f){ - Acceleration = BaseAcceleration; - MaxSpeed = BaseMaxSpeed; - }else if(CPad::GetPad(0)->ForceCameraBehindPlayer() && !Shooting){ - Acceleration = 0.051f; - MaxSpeed = 0.18f; - }else if(m_fCloseInPedHeightOffset > 0.00001f){ - Acceleration = BaseAcceleration + AccelerationMultClose*sq(m_fAmountFractionObscured - 1.05f); - MaxSpeed = BaseMaxSpeed + MaxSpeedMultClose*sq(m_fAmountFractionObscured - 1.05f); - }else{ - Acceleration = DefaultAcceleration + AccelerationMult*sq(m_fAmountFractionObscured - 1.05f); - MaxSpeed = DefaultMaxStep + MaxSpeedMult*sq(m_fAmountFractionObscured - 1.05f); - } - static float AccelerationLimit = 0.3f; - static float MaxSpeedLimit = 0.65f; - if(Acceleration > AccelerationLimit) Acceleration = AccelerationLimit; - if(MaxSpeed > MaxSpeedLimit) MaxSpeed = MaxSpeedLimit; - - - int MoveState = ((CPed*)CamTargetEntity)->m_nMoveState; - if(MoveState != PEDMOVE_NONE && MoveState != PEDMOVE_STILL && - !CPad::GetPad(0)->ForceCameraBehindPlayer() && !Obscured && !Shooting){ - Rotating = false; - BetaSpeed = 0.0f; - } - - // Now do the Beta rotation - - float Distance = (IdealSource - TargetCoors).Magnitude2D(); - m_fDistanceBeforeChanges = Distance; - - if(Rotating){ - m_bFixingBeta = true; - - while(FixedTargetOrientation >= PI) FixedTargetOrientation -= 2*PI; - while(FixedTargetOrientation < -PI) FixedTargetOrientation += 2*PI; - - while(Beta >= PI) Beta -= 2*PI; - while(Beta < -PI) Beta += 2*PI; - - -/* - // This is inlined WellBufferMe - DeltaBeta = FixedTargetOrientation - Beta; - while(DeltaBeta >= PI) DeltaBeta -= 2*PI; - while(DeltaBeta < -PI) DeltaBeta += 2*PI; - - float ReqSpeed = DeltaBeta * MaxSpeed; - // Add or subtract absolute depending on sign, genius! - if(ReqSpeed - BetaSpeed > 0.0f) - BetaSpeed += SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep(); - else - BetaSpeed -= SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep(); - // this would be simpler: - // BetaSpeed += SpeedStep * (ReqSpeed - BetaSpeed) * CTimer::ms_fTimeStep; - - if(ReqSpeed < 0.0f && BetaSpeed < ReqSpeed) - BetaSpeed = ReqSpeed; - else if(ReqSpeed > 0.0f && BetaSpeed > ReqSpeed) - BetaSpeed = ReqSpeed; - - Beta += BetaSpeed * min(10.0f, CTimer::GetTimeStep()); -*/ - WellBufferMe(FixedTargetOrientation, &Beta, &BetaSpeed, MaxSpeed, Acceleration, true); - - if(ResetStatics){ - Beta = FixedTargetOrientation; - BetaSpeed = 0.0f; - } - - Source.x = TargetCoors.x + Distance * Cos(Beta); - Source.y = TargetCoors.y + Distance * Sin(Beta); - - // Check if we can stop rotating - DeltaBeta = FixedTargetOrientation - Beta; - while(DeltaBeta >= PI) DeltaBeta -= 2*PI; - while(DeltaBeta < -PI) DeltaBeta += 2*PI; - if(Abs(DeltaBeta) < DEGTORAD(1.0f) && !bBehindPlayerDesired){ - // Stop rotation - PickedASide = false; - Rotating = false; - BetaSpeed = 0.0f; - } - } - - - if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront || - HackPlayerOnStoppingTrain || Rotating){ - if(TheCamera.m_bCamDirectlyBehind){ - Beta = TargetOrientation + PI; - Source.x = TargetCoors.x + Distance * Cos(Beta); - Source.y = TargetCoors.y + Distance * Sin(Beta); - } - if(TheCamera.m_bCamDirectlyInFront){ - Beta = TargetOrientation; - Source.x = TargetCoors.x + Distance * Cos(Beta); - Source.y = TargetCoors.y + Distance * Sin(Beta); - } - if(HackPlayerOnStoppingTrain){ - Beta = TargetOrientation + PI; - Source.x = TargetCoors.x + Distance * Cos(Beta); - Source.y = TargetCoors.y + Distance * Sin(Beta); - m_fDimensionOfHighestNearCar = 0.0f; - m_fCamBufferedHeight = 0.0f; - m_fCamBufferedHeightSpeed = 0.0f; - } - // Beta and Source already set in the rotation code - }else{ - Source = IdealSource; - BetaSpeed = 0.0f; - } - - // Subtract m_fUnknownZOffSet from both? - TargetCoors.z -= m_fUnknownZOffSet; - Source.z = IdealSource.z - m_fUnknownZOffSet; - - // Apply zoom now - // m_fPedZoomValueSmooth makes the cam go down the further out it is - // 0.25 -> 0.20 for nearest dist - // 1.50 -> -0.05 for mid dist - // 2.90 -> -0.33 for far dist - Source.z += (2.5f - TheCamera.m_fPedZoomValueSmooth)*0.2f - 0.25f; - // Zoom out camera - Front = TargetCoors - Source; - Front.Normalise(); - Source -= Front * TheCamera.m_fPedZoomValueSmooth; - // and then we move up again - // -0.375 - // 0.25 - // 0.95 - Source.z += (TheCamera.m_fPedZoomValueSmooth - 1.0f)*0.5f + m_fCloseInPedHeightOffset; - - - // Process height offset to avoid peds and cars - - float TargetZOffSet = m_fUnknownZOffSet + m_fDimensionOfHighestNearCar; - TargetZOffSet = max(TargetZOffSet, m_fPedBetweenCameraHeightOffset); - float TargetHeight = CameraTarget.z + TargetZOffSet - Source.z; - - if(TargetHeight > m_fCamBufferedHeight){ - // Have to go up - if(TargetZOffSet == m_fPedBetweenCameraHeightOffset && TargetZOffSet > m_fCamBufferedHeight) - WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.04f, false); - else if(TargetZOffSet == m_fUnknownZOffSet && TargetZOffSet > m_fCamBufferedHeight){ - // TODO: figure this out - bool foo = false; - switch(((CPhysical*)CamTargetEntity)->m_nSurfaceTouched) - case SURFACE_GRASS: - case SURFACE_DIRT: - case SURFACE_PAVEMENT: - case SURFACE_STEEL: - case SURFACE_TIRE: - case SURFACE_STONE: - foo = true; - if(foo) - WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.4f, 0.05f, false); - else - WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false); - }else - WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false); - StartedCountingForGoDown = false; - }else{ - // Have to go down - if(StartedCountingForGoDown){ - if(CTimer::GetTimeInMilliseconds() != TimeIndicatedWantedToGoDown){ - if(TargetHeight > 0.0f) - WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false); - else - WellBufferMe(0.0f, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false); - } - }else{ - StartedCountingForGoDown = true; - TimeIndicatedWantedToGoDown = CTimer::GetTimeInMilliseconds(); - } - } - - Source.z += m_fCamBufferedHeight; - - - // Clip Source if necessary - - bool ClipSource = m_fCloseInPedHeightOffset > 0.00001f && m_fCamBufferedHeight > 0.001f; - if(GoingBehind || ResetStatics || ClipSource){ - CColPoint colpoint; - CEntity *entity; - if(CWorld::ProcessLineOfSight(TargetCoors, Source, colpoint, entity, true, false, false, true, false, true, true)){ - Source = colpoint.point; - if((TargetCoors - Source).Magnitude2D() < 1.0f) - RwCameraSetNearClipPlane(Scene.camera, 0.05f); - } - } - - TargetCoors.z += min(1.0f, m_fCamBufferedHeight/2.0f); - m_cvecTargetCoorsForFudgeInter = TargetCoors; - - Front = TargetCoors - Source; - m_fRealGroundDist = Front.Magnitude2D(); - m_fMinDistAwayFromCamWhenInterPolating = m_fRealGroundDist; - Front.Normalise(); - GetVectorsReadyForRW(); - TheCamera.m_bCamDirectlyBehind = false; - TheCamera.m_bCamDirectlyInFront = false; - PreviouslyObscured = BuildingCheckObscured; - - ResetStatics = false; -} - -void -CCam::Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float) -{ - FOV = DefaultFOV; - - if(!CamTargetEntity->IsVehicle()) - return; - - CVector TargetCoors = CameraTarget; - TargetCoors.z -= 0.2f; - CA_MAX_DISTANCE = 9.95f; - CA_MIN_DISTANCE = 8.5f; - - CVector Dist = Source - TargetCoors; - float Length = Dist.Magnitude2D(); - m_fDistanceBeforeChanges = Length; - if(Length < 0.002f) - Length = 0.002f; - Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y); - if(Length > CA_MAX_DISTANCE){ - Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE; - Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE; - }else if(Length < CA_MIN_DISTANCE){ - Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE; - Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE; - } - TargetCoors.z += 0.8f; - - WorkOutCamHeightWeeCar(TargetCoors, TargetOrientation); - RotCamIfInFrontCar(TargetCoors, TargetOrientation); - FixCamIfObscured(TargetCoors, 1.2f, TargetOrientation); - - Front = TargetCoors - Source; - m_cvecTargetCoorsForFudgeInter = TargetCoors; - ResetStatics = false; - GetVectorsReadyForRW(); -} - -void -CCam::WorkOutCamHeightWeeCar(CVector &TargetCoors, float TargetOrientation) -{ - CColPoint colpoint; - CEntity *ent; - float TargetZOffSet = 0.0f; - static bool PreviouslyFailedRoadHeightCheck = false; - static float RoadHeightFix = 0.0f; - static float RoadHeightFixSpeed = 0.0f; - - if(ResetStatics){ - RoadHeightFix = 0.0f; - RoadHeightFixSpeed = 0.0f; - Alpha = DEGTORAD(25.0f); - AlphaSpeed = 0.0f; - } - float AlphaTarget = DEGTORAD(25.0f); - if(CCullZones::CamNoRain() || CCullZones::PlayerNoRain()) - AlphaTarget = DEGTORAD(14.0f); - WellBufferMe(AlphaTarget, &Alpha, &AlphaSpeed, 0.1f, 0.05f, true); - Source.z = TargetCoors.z + CA_MAX_DISTANCE*Sin(Alpha); - - if(FindPlayerVehicle()){ - m_fUnknownZOffSet = 0.0f; - bool FoundRoad = false; - bool FoundRoof = false; - float RoadZ = 0.0f; - float RoofZ = 0.0f; - - if(CWorld::ProcessVerticalLine(Source, -1000.0f, colpoint, ent, true, false, false, false, false, false, nil) && - ent->IsBuilding()){ - FoundRoad = true; - RoadZ = colpoint.point.z; - } - - if(FoundRoad){ - if(Source.z - RoadZ < 0.9f){ - PreviouslyFailedRoadHeightCheck = true; - TargetZOffSet = RoadZ + 0.9f - Source.z; - }else{ - if(m_bCollisionChecksOn) - PreviouslyFailedRoadHeightCheck = false; - else - TargetZOffSet = 0.0f; - } - }else{ - if(CWorld::ProcessVerticalLine(Source, 1000.0f, colpoint, ent, true, false, false, false, false, false, nil) && - ent->IsBuilding()){ - FoundRoof = true; - RoofZ = colpoint.point.z; - } - if(FoundRoof){ - if(Source.z - RoofZ < 0.9f){ - PreviouslyFailedRoadHeightCheck = true; - TargetZOffSet = RoofZ + 0.9f - Source.z; - }else{ - if(m_bCollisionChecksOn) - PreviouslyFailedRoadHeightCheck = false; - else - TargetZOffSet = 0.0f; - } - } - } - } - - if(TargetZOffSet > RoadHeightFix) - RoadHeightFix = TargetZOffSet; - else - WellBufferMe(TargetZOffSet, &RoadHeightFix, &RoadHeightFixSpeed, 0.27f, 0.1f, false); - - if((colpoint.surfaceB == SURFACE_DEFAULT || colpoint.surfaceB >= SURFACE_METAL6) && - colpoint.surfaceB != SURFACE_STEEL && colpoint.surfaceB != SURFACE_STONE && - RoadHeightFix > 1.4f) - RoadHeightFix = 1.4f; - - Source.z += RoadHeightFix; -} - -void -CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight) -{ - static float LastTargetAlphaWithCollisionOn = 0.0f; - static float LastTopAlphaSpeed = 0.0f; - static float LastAlphaSpeedStep = 0.0f; - static bool PreviousNearCheckNearClipSmall = false; - - bool CamClear = true; - float ModeAlpha = 0.0f; - - if(ResetStatics){ - LastTargetAlphaWithCollisionOn = 0.0f; - LastTopAlphaSpeed = 0.0f; - LastAlphaSpeedStep = 0.0f; - PreviousNearCheckNearClipSmall = false; - } - - float TopAlphaSpeed = 0.15f; - float AlphaSpeedStep = 0.015f; - - float zoomvalue = TheCamera.CarZoomValueSmooth; - if(zoomvalue < 0.1f) - zoomvalue = 0.1f; - if(TheCamera.CarZoomIndicator == 1.0f) - ModeAlpha = CGeneral::GetATanOfXY(23.0f, zoomvalue); // near - else if(TheCamera.CarZoomIndicator == 2.0f) - ModeAlpha = CGeneral::GetATanOfXY(10.8f, zoomvalue); // mid - else if(TheCamera.CarZoomIndicator == 3.0f) - ModeAlpha = CGeneral::GetATanOfXY(7.0f, zoomvalue); // far - - - float Length = (Source - TargetCoors).Magnitude2D(); - if(m_bCollisionChecksOn){ // there's another variable (on PC) but it's uninitialised - CVector Forward = CamTargetEntity->GetForward(); - float CarAlpha = CGeneral::GetATanOfXY(Forward.Magnitude2D(), Forward.z); - // this shouldn't be necessary.... - while(CarAlpha >= PI) CarAlpha -= 2*PI; - while(CarAlpha < -PI) CarAlpha += 2*PI; - - while(Beta >= PI) Beta -= 2*PI; - while(Beta < -PI) Beta += 2*PI; - - float deltaBeta = Beta - TargetOrientation; - while(deltaBeta >= PI) deltaBeta -= 2*PI; - while(deltaBeta < -PI) deltaBeta += 2*PI; - - float BehindCarNess = Cos(deltaBeta); // 1 if behind car, 0 if side, -1 if in front - CarAlpha = -CarAlpha * BehindCarNess; - if(CarAlpha < -0.01f) - CarAlpha = -0.01f; - - float DeltaAlpha = CarAlpha - Alpha; - while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI; - while(DeltaAlpha < -PI) DeltaAlpha += 2*PI; - // What's this?? wouldn't it make more sense to clamp? - float AngleLimit = DEGTORAD(1.8f); - if(DeltaAlpha < -AngleLimit) - DeltaAlpha += AngleLimit; - else if(DeltaAlpha > AngleLimit) - DeltaAlpha -= AngleLimit; - else - DeltaAlpha = 0.0f; - - // Now the collision - - float TargetAlpha = 0.0f; - bool FoundRoofCenter = false; - bool FoundRoofSide1 = false; - bool FoundRoofSide2 = false; - bool FoundCamRoof = false; - bool FoundCamGround = false; - float CamRoof = 0.0f; - float CarBottom = TargetCoors.z - TargetHeight/2.0f; - - // Check car center - float CarRoof = CWorld::FindRoofZFor3DCoord(TargetCoors.x, TargetCoors.y, CarBottom, &FoundRoofCenter); - - // Check sides of the car - Forward = CamTargetEntity->GetForward(); // we actually still have that... - Forward.Normalise(); // shouldn't be necessary - float CarSideAngle = CGeneral::GetATanOfXY(Forward.x, Forward.y) + PI/2.0f; - float SideX = 2.5f * Cos(CarSideAngle); - float SideY = 2.5f * Sin(CarSideAngle); - CWorld::FindRoofZFor3DCoord(TargetCoors.x + SideX, TargetCoors.y + SideY, CarBottom, &FoundRoofSide1); - CWorld::FindRoofZFor3DCoord(TargetCoors.x - SideX, TargetCoors.y - SideY, CarBottom, &FoundRoofSide2); - - // Now find out at what height we'd like to place the camera - float CamGround = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, TargetCoors.z + Length*Sin(Alpha + ModeAlpha) + m_fCloseInCarHeightOffset, &FoundCamGround); - float CamTargetZ = 0.0f; - if(FoundCamGround){ - // This is the normal case - CamRoof = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamGround + TargetHeight, &FoundCamRoof); - CamTargetZ = CamGround + TargetHeight*1.5f + 0.1f; - }else{ - FoundCamRoof = false; - CamTargetZ = TargetCoors.z; - } - - if(FoundRoofCenter && !FoundCamRoof && (FoundRoofSide1 || FoundRoofSide2)){ - // Car is under something but camera isn't - // This seems weird... - TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, CarRoof - CamTargetZ - 1.5f); - CamClear = false; - } - if(FoundCamRoof){ - // Camera is under something - float roof = FoundRoofCenter ? min(CamRoof, CarRoof) : CamRoof; - // Same weirdness again? - TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, roof - CamTargetZ - 1.5f); - CamClear = false; - } - while(TargetAlpha >= PI) TargetAlpha -= 2*PI; - while(TargetAlpha < -PI) TargetAlpha += 2*PI; - if(TargetAlpha < DEGTORAD(-7.0f)) - TargetAlpha = DEGTORAD(-7.0f); - - // huh? - if(TargetAlpha > ModeAlpha) - CamClear = true; - // Camera is contrained by collision in some way - PreviousNearCheckNearClipSmall = false; - if(!CamClear){ - PreviousNearCheckNearClipSmall = true; - RwCameraSetNearClipPlane(Scene.camera, 0.9f); - - DeltaAlpha = TargetAlpha - (Alpha + ModeAlpha); - while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI; - while(DeltaAlpha < -PI) DeltaAlpha += 2*PI; - - TopAlphaSpeed = 0.3f; - AlphaSpeedStep = 0.03f; - } - - // Now do things if CamClear...but what is that anyway? - float CamZ = TargetCoors.z + Length*Sin(Alpha + DeltaAlpha + ModeAlpha) + m_fCloseInCarHeightOffset; - bool FoundGround, FoundRoof; - float CamGround2 = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, CamZ, &FoundGround); - if(FoundGround){ - if(CamClear) - if(CamZ - CamGround2 < 1.5f){ - PreviousNearCheckNearClipSmall = true; - RwCameraSetNearClipPlane(Scene.camera, 0.9f); - - float a; - if(Length == 0.0f || CamGround2 + 1.5f - TargetCoors.z == 0.0f) - a = Alpha; - else - a = CGeneral::GetATanOfXY(Length, CamGround2 + 1.5f - TargetCoors.z); - while(a > PI) a -= 2*PI; - while(a < -PI) a += 2*PI; - DeltaAlpha = a - Alpha; - } - }else{ - if(CamClear){ - float CamRoof2 = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamZ, &FoundRoof); - if(FoundRoof && CamZ - CamRoof2 < 1.5f){ - PreviousNearCheckNearClipSmall = true; - RwCameraSetNearClipPlane(Scene.camera, 0.9f); - - if(CamRoof2 > TargetCoors.z + 3.5f) - CamRoof2 = TargetCoors.z + 3.5f; - - float a; - if(Length == 0.0f || CamRoof2 + 1.5f - TargetCoors.z == 0.0f) - a = Alpha; - else - a = CGeneral::GetATanOfXY(Length, CamRoof2 + 1.5f - TargetCoors.z); - while(a > PI) a -= 2*PI; - while(a < -PI) a += 2*PI; - DeltaAlpha = a - Alpha; - } - } - } - - LastTargetAlphaWithCollisionOn = DeltaAlpha + Alpha; - LastTopAlphaSpeed = TopAlphaSpeed; - LastAlphaSpeedStep = AlphaSpeedStep; - }else{ - if(PreviousNearCheckNearClipSmall) - RwCameraSetNearClipPlane(Scene.camera, 0.9f); - } - - WellBufferMe(LastTargetAlphaWithCollisionOn, &Alpha, &AlphaSpeed, LastTopAlphaSpeed, LastAlphaSpeedStep, true); - - Source.z = TargetCoors.z + Sin(Alpha + ModeAlpha)*Length + m_fCloseInCarHeightOffset; -} - -// Rotate cam behind the car when the car is moving forward -bool -CCam::RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation) -{ - bool MovingForward = false; - CPhysical *phys = (CPhysical*)CamTargetEntity; - - float ForwardSpeed = DotProduct(phys->GetForward(), phys->GetSpeed(CVector(0.0f, 0.0f, 0.0f))); - if(ForwardSpeed > 0.02f) - MovingForward = true; - - float Dist = (Source - TargetCoors).Magnitude2D(); - - float DeltaBeta = TargetOrientation - Beta; - while(DeltaBeta >= PI) DeltaBeta -= 2*PI; - while(DeltaBeta < -PI) DeltaBeta += 2*PI; - - if(Abs(DeltaBeta) > DEGTORAD(20.0f) && MovingForward && TheCamera.m_uiTransitionState == 0) - m_bFixingBeta = true; - - CPad *pad = CPad::GetPad(0); - if(!(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight())) - if(DirectionWasLooking != LOOKING_FORWARD) - TheCamera.m_bCamDirectlyBehind = true; - - if(!m_bFixingBeta && !TheCamera.m_bUseTransitionBeta && !TheCamera.m_bCamDirectlyBehind && !TheCamera.m_bCamDirectlyInFront) - return false; - - bool SetBeta = false; - if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront || TheCamera.m_bUseTransitionBeta) - if(&TheCamera.Cams[TheCamera.ActiveCam] == this) - SetBeta = true; - - if(m_bFixingBeta || SetBeta){ - WellBufferMe(TargetOrientation, &Beta, &BetaSpeed, 0.15f, 0.007f, true); - - if(TheCamera.m_bCamDirectlyBehind && &TheCamera.Cams[TheCamera.ActiveCam] == this) - Beta = TargetOrientation; - if(TheCamera.m_bCamDirectlyInFront && &TheCamera.Cams[TheCamera.ActiveCam] == this) - Beta = TargetOrientation + PI; - if(TheCamera.m_bUseTransitionBeta && &TheCamera.Cams[TheCamera.ActiveCam] == this) - Beta = m_fTransitionBeta; - - Source.x = TargetCoors.x - Cos(Beta)*Dist; - Source.y = TargetCoors.y - Sin(Beta)*Dist; - - // Check if we're done - DeltaBeta = TargetOrientation - Beta; - while(DeltaBeta >= PI) DeltaBeta -= 2*PI; - while(DeltaBeta < -PI) DeltaBeta += 2*PI; - if(Abs(DeltaBeta) < DEGTORAD(2.0f)) - m_bFixingBeta = false; - } - TheCamera.m_bCamDirectlyBehind = false; - TheCamera.m_bCamDirectlyInFront = false; - return true; -} - -// Move the cam to avoid clipping through buildings -bool -CCam::FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation) -{ - CVector Target = TargetCoors; - bool UseEntityPos = false; - CVector EntityPos; - static CColPoint colPoint; - static bool LastObscured = false; - - if(Mode == MODE_BEHINDCAR) - Target.z += TargetHeight/2.0f; - if(Mode == MODE_CAM_ON_A_STRING){ - UseEntityPos = true; - Target.z += TargetHeight/2.0f; - EntityPos = CamTargetEntity->GetPosition(); - } - - CVector TempSource = Source; - - bool Obscured1 = false; - bool Obscured2 = false; - bool Fix1 = false; - float Dist1 = 0.0f; - float Dist2 = 0.0f; - CEntity *ent; - if(m_bCollisionChecksOn || LastObscured){ - Obscured1 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true); - if(Obscured1){ - Dist1 = (Target - colPoint.point).Magnitude2D(); - Fix1 = true; - if(UseEntityPos) - Obscured1 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true); - }else if(m_bFixingBeta){ - float d = (TempSource - Target).Magnitude(); - TempSource.x = Target.x - d*Cos(TargetOrientation); - TempSource.y = Target.y - d*Sin(TargetOrientation); - - // same check again - Obscured2 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true); - if(Obscured2){ - Dist2 = (Target - colPoint.point).Magnitude2D(); - if(UseEntityPos) - Obscured2 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true); - } - } - LastObscured = Obscured1 || Obscured2; - } - - // nothing to do - if(!LastObscured) - return false; - - if(Fix1){ - Source.x = Target.x - Cos(Beta)*Dist1; - Source.y = Target.y - Sin(Beta)*Dist1; - if(Mode == MODE_BEHINDCAR) - Source = colPoint.point; - }else{ - WellBufferMe(Dist2, &m_fDistanceBeforeChanges, &DistanceSpeed, 0.2f, 0.025f, false); - Source.x = Target.x - Cos(Beta)*m_fDistanceBeforeChanges; - Source.y = Target.y - Sin(Beta)*m_fDistanceBeforeChanges; - } - - if(ResetStatics){ - m_fDistanceBeforeChanges = (Source - Target).Magnitude2D(); - DistanceSpeed = 0.0f; - Source.x = colPoint.point.x; - Source.y = colPoint.point.y; - } - return true; -} - -void -CCam::Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float) -{ - if(!CamTargetEntity->IsVehicle()) - return; - - FOV = DefaultFOV; - - if(ResetStatics){ - AlphaSpeed = 0.0f; - if(TheCamera.m_bIdleOn) - TheCamera.m_uiTimeWeEnteredIdle = CTimer::GetTimeInMilliseconds(); - } - - CBaseModelInfo *mi = CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex()); - CVector Dimensions = mi->GetColModel()->boundingBox.max - mi->GetColModel()->boundingBox.min; - float BaseDist = Dimensions.Magnitude2D(); - - CVector TargetCoors = CameraTarget; - TargetCoors.z += Dimensions.z - 0.1f; // final - Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y); - while(Alpha >= PI) Alpha -= 2*PI; - while(Alpha < -PI) Alpha += 2*PI; - while(Beta >= PI) Beta -= 2*PI; - while(Beta < -PI) Beta += 2*PI; - - m_fDistanceBeforeChanges = (Source - TargetCoors).Magnitude2D(); - - Cam_On_A_String_Unobscured(TargetCoors, BaseDist); - WorkOutCamHeight(TargetCoors, TargetOrientation, Dimensions.z); - RotCamIfInFrontCar(TargetCoors, TargetOrientation); - FixCamIfObscured(TargetCoors, Dimensions.z, TargetOrientation); - FixCamWhenObscuredByVehicle(TargetCoors); - - m_cvecTargetCoorsForFudgeInter = TargetCoors; - Front = TargetCoors - Source; - Front.Normalise(); - GetVectorsReadyForRW(); - ResetStatics = false; -} - -// Basic Cam on a string algorithm -void -CCam::Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist) -{ - CA_MAX_DISTANCE = BaseDist + 0.1f + TheCamera.CarZoomValueSmooth; - CA_MIN_DISTANCE = min(BaseDist*0.6f, 3.5f); - - CVector Dist = Source - TargetCoors; - - if(ResetStatics) - Source = TargetCoors + Dist*(CA_MAX_DISTANCE + 1.0f); - - float Length = Dist.Magnitude2D(); - if(Length < 0.001f){ - // This probably shouldn't happen. reset view - CVector Forward = CamTargetEntity->GetForward(); - Forward.z = 0.0f; - Forward.Normalise(); - Source = TargetCoors - Forward*CA_MAX_DISTANCE; - Dist = Source - TargetCoors; - Length = Dist.Magnitude2D(); - } - - if(Length > CA_MAX_DISTANCE){ - Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE; - Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE; - }else if(Length < CA_MIN_DISTANCE){ - Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE; - Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE; - } -} - -void -CCam::FixCamWhenObscuredByVehicle(const CVector &TargetCoors) -{ - // BUG? is this never reset - static float HeightFixerCarsObscuring = 0.0f; - static float HeightFixerCarsObscuringSpeed = 0.0f; - CColPoint colPoint; - CEntity *entity; - - float HeightTarget = 0.0f; - if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, false, true, false, false, false, false, false)){ - CBaseModelInfo *mi = CModelInfo::GetModelInfo(entity->GetModelIndex()); - HeightTarget = mi->GetColModel()->boundingBox.max.z + 1.0f + TargetCoors.z - Source.z; - if(HeightTarget < 0.0f) - HeightTarget = 0.0f; - } - WellBufferMe(HeightTarget, &HeightFixerCarsObscuring, &HeightFixerCarsObscuringSpeed, 0.2f, 0.025f, false); - Source.z += HeightFixerCarsObscuring; -} - -bool -CCam::Using3rdPersonMouseCam() -{ - return CCamera::m_bUseMouse3rdPerson && - (Mode == MODE_FOLLOWPED || - TheCamera.m_bPlayerIsInGarage && - FindPlayerPed() && FindPlayerPed()->m_nPedState != PED_DRIVING && - Mode != MODE_TOPDOWN && this->CamTargetEntity == FindPlayerPed()); -} - -bool -CCam::GetWeaponFirstPersonOn() -{ - CEntity *target = this->CamTargetEntity; - if (target && target->IsPed()) - return ((CPed*)target)->GetWeapon()->m_bAddRotOffset; - - return false; -} - float CCamera::Find3rdPersonQuickAimPitch(void) { @@ -1478,22 +343,4 @@ STARTPATCHES InjectHook(0x46B560, &CCamera::FinishCutscene, PATCH_JUMP); InjectHook(0x46FF30, &CCamera::SetZoomValueFollowPedScript, PATCH_JUMP); InjectHook(0x46FF90, &CCamera::SetZoomValueCamStringScript, PATCH_JUMP); - - - InjectHook(0x456F40, WellBufferMe, PATCH_JUMP); - InjectHook(0x4582F0, &CCam::GetVectorsReadyForRW, PATCH_JUMP); - InjectHook(0x457710, &CCam::DoAverageOnVector, PATCH_JUMP); - InjectHook(0x458060, &CCam::GetPedBetaAngleForClearView, PATCH_JUMP); - InjectHook(0x457210, &CCam::Cam_On_A_String_Unobscured, PATCH_JUMP); - InjectHook(0x457A80, &CCam::FixCamWhenObscuredByVehicle, PATCH_JUMP); - InjectHook(0x457B90, &CCam::FixCamIfObscured, PATCH_JUMP); - InjectHook(0x465DA0, &CCam::RotCamIfInFrontCar, PATCH_JUMP); - InjectHook(0x4662D0, &CCam::WorkOutCamHeightWeeCar, PATCH_JUMP); - InjectHook(0x466650, &CCam::WorkOutCamHeight, PATCH_JUMP); - - InjectHook(0x45E3A0, &CCam::Process_FollowPed, PATCH_JUMP); - InjectHook(0x45BE60, &CCam::Process_BehindCar, PATCH_JUMP); - InjectHook(0x45C090, &CCam::Process_Cam_On_A_String, PATCH_JUMP); - - InjectHook(0x473250, &CCamera::dtor, PATCH_JUMP); ENDPATCHES diff --git a/src/core/Camera.h b/src/core/Camera.h index 980af5c1..982620a3 100644 --- a/src/core/Camera.h +++ b/src/core/Camera.h @@ -5,6 +5,8 @@ class CEntity; class CPed; class CAutomobile; +extern int16 &DebugCamMode; + #define NUMBER_OF_VECTORS_FOR_AVERAGE 2 struct CCam @@ -66,17 +68,17 @@ struct CCam bool m_bTheHeightFixerVehicleIsATrain; bool LookBehindCamWasInFront; bool LookingBehind; - bool LookingLeft; // 32 + bool LookingLeft; bool LookingRight; bool ResetStatics; //for interpolation type stuff to work bool Rotating; int16 Mode; // CameraMode - uint32 m_uiFinishTime; // 52 + uint32 m_uiFinishTime; int m_iDoCollisionChecksOnFrameNum; int m_iDoCollisionCheckEveryNumOfFrames; - int m_iFrameNumWereAt; // 64 + int m_iFrameNumWereAt; int m_iRunningVectorArrayPos; int m_iRunningVectorCounter; int DirectionWasLooking; @@ -85,9 +87,9 @@ struct CCam float f_Roll; //used for adding a slight roll to the camera in the float f_rollSpeed; float m_fSyphonModeTargetZOffSet; - float m_fUnknownZOffSet; + float m_fRoadOffSet; float m_fAmountFractionObscured; - float m_fAlphaSpeedOverOneFrame; // 100 + float m_fAlphaSpeedOverOneFrame; float m_fBetaSpeedOverOneFrame; float m_fBufferedTargetBeta; float m_fBufferedTargetOrientation; @@ -95,7 +97,7 @@ struct CCam float m_fCamBufferedHeight; float m_fCamBufferedHeightSpeed; float m_fCloseInPedHeightOffset; - float m_fCloseInPedHeightOffsetSpeed; // 132 + float m_fCloseInPedHeightOffsetSpeed; float m_fCloseInCarHeightOffset; float m_fCloseInCarHeightOffsetSpeed; float m_fDimensionOfHighestNearCar; @@ -103,7 +105,7 @@ struct CCam float m_fFovSpeedOverOneFrame; float m_fMinDistAwayFromCamWhenInterPolating; float m_fPedBetweenCameraHeightOffset; - float m_fPlayerInFrontSyphonAngleOffSet; // 164 + float m_fPlayerInFrontSyphonAngleOffSet; float m_fRadiusForDead; float m_fRealGroundDist; //used for follow ped mode float m_fTargetBeta; @@ -111,7 +113,7 @@ struct CCam float m_fTransitionBeta; float m_fTrueBeta; - float m_fTrueAlpha; // 200 + float m_fTrueAlpha; float m_fInitialPlayerOrientation; //used for first person float Alpha; @@ -120,34 +122,25 @@ struct CCam float FOVSpeed; float Beta; float BetaSpeed; - float Distance; // 232 + float Distance; 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 + CVector m_cvecSourceSpeedOverOneFrame; + CVector m_cvecTargetSpeedOverOneFrame; + CVector m_cvecUpOverOneFrame; + + CVector m_cvecTargetCoorsForFudgeInter; + CVector m_cvecCamFixedModeVector; + CVector m_cvecCamFixedModeSource; + CVector m_cvecCamFixedModeUpOffSet; + CVector m_vecLastAboveWaterCamPosition; //helper for when the player has gone under the water + CVector m_vecBufferedPlayerBodyOffset; // The three vectors that determine this camera for this frame - CVector Front; // 432 // Direction of looking in + CVector Front; // Direction of looking in CVector Source; // Coors in world space CVector SourceBeforeLookBehind; CVector Up; // Just that @@ -162,6 +155,10 @@ struct CCam bool m_bFirstPersonRunAboutActive; + CCam(void) { Init(); } + void Init(void); + void Process(void); + void ProcessSpecialHeightRoutines(void); void GetVectorsReadyForRW(void); CVector DoAverageOnVector(const CVector &vec); float GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies); @@ -171,13 +168,59 @@ struct CCam bool FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation); void Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist); void FixCamWhenObscuredByVehicle(const CVector &TargetCoors); - bool Using3rdPersonMouseCam(); - bool GetWeaponFirstPersonOn(); - - void Process_Debug(float *vec, float a, float b, float c); + void LookBehind(void); + void LookLeft(void); + void LookRight(void); + void ClipIfPedInFrontOfPlayer(void); + void KeepTrackOfTheSpeed(const CVector &source, const CVector &target, const CVector &up, const float &alpha, const float &beta, const float &fov); + bool Using3rdPersonMouseCam(void); + bool GetWeaponFirstPersonOn(void); + bool IsTargetInWater(const CVector &CamCoors); + void AvoidWallsTopDownPed(const CVector &TargetCoors, const CVector &Offset, float *Adjuster, float *AdjusterSpeed, float yDistLimit); + void PrintMode(void); + + void Process_Debug(const CVector&, float, float, float); + void Process_Editor(const CVector&, float, float, float); + void Process_ModelView(const CVector &CameraTarget, float, float, float); void Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float); + void Process_FollowPedWithMouse(const CVector &CameraTarget, float TargetOrientation, float, float); void Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float); void Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float); + void Process_TopDown(const CVector &CameraTarget, float TargetOrientation, float SpeedVar, float TargetSpeedVar); + void Process_TopDownPed(const CVector &CameraTarget, float TargetOrientation, float, float); + void Process_Rocket(const CVector &CameraTarget, float, float, float); + void Process_M16_1stPerson(const CVector &CameraTarget, float, float, float); + void Process_1stPerson(const CVector &CameraTarget, float, float, float); + void Process_1rstPersonPedOnPC(const CVector &CameraTarget, float TargetOrientation, float, float); + void Process_Sniper(const CVector &CameraTarget, float, float, float); + void Process_Syphon(const CVector &CameraTarget, float, float, float); + void Process_Syphon_Crim_In_Front(const CVector &CameraTarget, float, float, float); + void Process_BehindBoat(const CVector &CameraTarget, float TargetOrientation, float, float); + void Process_Fight_Cam(const CVector &CameraTarget, float TargetOrientation, float, float); + void Process_FlyBy(const CVector&, float, float, float); + void Process_WheelCam(const CVector&, float, float, float); + void Process_Fixed(const CVector &CameraTarget, float, float, float); + void Process_Player_Fallen_Water(const CVector &CameraTarget, float TargetOrientation, float, float); + void Process_Circle(const CVector &CameraTarget, float, float, float); + void Process_SpecialFixedForSyphon(const CVector &CameraTarget, float, float, float); + void ProcessPedsDeadBaby(void); + bool ProcessArrestCamOne(void); + bool ProcessArrestCamTwo(void); + + /* Some of the unused PS2 cams */ + void Process_Chris_With_Binding_PlusRotation(const CVector &CameraTarget, float, float, float); + void Process_ReactionCam(const CVector &CameraTarget, float TargetOrientation, float, float); + void Process_FollowPed_WithBinding(const CVector &CameraTarget, float TargetOrientation, float, float); + // TODO: + // CCam::Process_CushyPillows_Arse + // CCam::Process_Look_At_Cars + // CCam::Process_CheesyZoom + // CCam::Process_Aiming + // CCam::Process_Bill // same as BehindCar due to unused variables + // CCam::Process_Im_The_Passenger_Woo_Woo + // CCam::Process_Blood_On_The_Tracks + // CCam::Process_Cam_Running_Side_Train + // CCam::Process_Cam_On_Train_Roof }; static_assert(sizeof(CCam) == 0x1A4, "CCam: wrong size"); static_assert(offsetof(CCam, Alpha) == 0xA8, "CCam: error"); @@ -223,6 +266,7 @@ enum FADE_OUT = 0, FADE_IN, + FADE_NONE }; enum @@ -445,8 +489,8 @@ uint32 unknown; uint32 m_fScriptTimeForInterPolation; -int16 m_iFadingDirection; -int m_iModeObbeCamIsInForCar; + int16 m_iFadingDirection; + int m_iModeObbeCamIsInForCar; int16 m_iModeToGoTo; int16 m_iMusicFadingDirection; int16 m_iTypeOfSwitch; @@ -493,6 +537,7 @@ int m_iModeObbeCamIsInForCar; void TakeControlNoEntity(const CVector&, int16, int32); void SetCamPositionForFixedMode(const CVector&, const CVector&); bool GetFading(); + int GetFadingDirection(); void Init(); void SetRwCamera(RwCamera*); @@ -525,8 +570,12 @@ 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(offsetof(CCamera, pToGarageWeAreIn) == 0x690, "CCamera: error"); +static_assert(offsetof(CCamera, m_PreviousCameraPosition) == 0x6B0, "CCamera: error"); static_assert(offsetof(CCamera, m_vecCutSceneOffset) == 0x6F8, "CCamera: error"); +static_assert(offsetof(CCamera, m_arrPathArray) == 0x7a8, "CCamera: error"); static_assert(sizeof(CCamera) == 0xE9D8, "CCamera: wrong size"); + extern CCamera &TheCamera; -void CamShakeNoPos(CCamera*, float);
\ No newline at end of file +void CamShakeNoPos(CCamera*, float); diff --git a/src/core/CdStream.cpp b/src/core/CdStream.cpp index 57b1cbe2..a400c039 100644 --- a/src/core/CdStream.cpp +++ b/src/core/CdStream.cpp @@ -43,6 +43,7 @@ BOOL _gbCdStreamOverlapped; BOOL _gbCdStreamAsync; DWORD _gdwCdStreamFlags; +DWORD WINAPI CdStreamThread(LPVOID lpThreadParameter); void CdStreamInitThread(void) diff --git a/src/core/CdStream.h b/src/core/CdStream.h index 55507aa8..9ef71b65 100644 --- a/src/core/CdStream.h +++ b/src/core/CdStream.h @@ -39,7 +39,6 @@ int32 CdStreamSync(int32 channel); void AddToQueue(Queue *queue, int32 item); int32 GetFirstInQueue(Queue *queue); void RemoveFirstInQueue(Queue *queue); -DWORD WINAPI CdStreamThread(LPVOID lpThreadParameter); bool CdStreamAddImage(char const *path); char *CdStreamGetImageName(int32 cd); void CdStreamRemoveImages(void); diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp index fc8428be..94ef769e 100644 --- a/src/core/Collision.cpp +++ b/src/core/Collision.cpp @@ -2061,6 +2061,19 @@ CColModel::operator=(const CColModel &other) return *this; } +#include <new> +struct CColLine_ : public CColLine +{ + CColLine *ctor(CVector *p0, CVector *p1) { return ::new (this) CColLine(*p0, *p1); } +}; + +struct CColModel_ : public CColModel +{ + CColModel *ctor(void) { return ::new (this) CColModel(); } + void dtor(void) { this->CColModel::~CColModel(); } +}; + + STARTPATCHES InjectHook(0x4B9C30, (CMatrix& (*)(const CMatrix &src, CMatrix &dst))Invert, PATCH_JUMP); @@ -2099,15 +2112,15 @@ STARTPATCHES InjectHook(0x411E40, (void (CColSphere::*)(float, const CVector&, uint8, uint8))&CColSphere::Set, PATCH_JUMP); InjectHook(0x40B2A0, &CColBox::Set, PATCH_JUMP); - InjectHook(0x40B320, &CColLine::ctor, PATCH_JUMP); + InjectHook(0x40B320, &CColLine_::ctor, PATCH_JUMP); InjectHook(0x40B350, &CColLine::Set, PATCH_JUMP); InjectHook(0x411E70, &CColTriangle::Set, PATCH_JUMP); InjectHook(0x411EA0, &CColTrianglePlane::Set, PATCH_JUMP); InjectHook(0x412140, &CColTrianglePlane::GetNormal, PATCH_JUMP); - InjectHook(0x411680, &CColModel::ctor, PATCH_JUMP); - InjectHook(0x4116E0, &CColModel::dtor, PATCH_JUMP); + InjectHook(0x411680, &CColModel_::ctor, PATCH_JUMP); + InjectHook(0x4116E0, &CColModel_::dtor, PATCH_JUMP); InjectHook(0x411D80, &CColModel::RemoveCollisionVolumes, PATCH_JUMP); InjectHook(0x411CB0, &CColModel::CalculateTrianglePlanes, PATCH_JUMP); InjectHook(0x411D10, &CColModel::RemoveTrianglePlanes, PATCH_JUMP); diff --git a/src/core/Collision.h b/src/core/Collision.h index 9597a181..429fc17f 100644 --- a/src/core/Collision.h +++ b/src/core/Collision.h @@ -35,8 +35,6 @@ struct CColLine 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 @@ -106,8 +104,6 @@ struct CColModel void SetLinkPtr(CLink<CColModel*>*); void GetTrianglePoint(CVector &v, int i) const; - CColModel *ctor(void) { return ::new (this) CColModel(); } - void dtor(void) { this->CColModel::~CColModel(); } CColModel& operator=(const CColModel& other); }; diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp index 92c51182..541257c6 100644 --- a/src/core/ControllerConfig.cpp +++ b/src/core/ControllerConfig.cpp @@ -417,6 +417,11 @@ void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonDown(int32 button, i case 13: pad->PCTempJoyState.DPadUp = 255; break; +#ifdef REGISTER_START_BUTTON + case 12: + pad->PCTempJoyState.Start = 255; + break; +#endif case 11: pad->PCTempJoyState.RightShock = 255; break; @@ -839,6 +844,11 @@ void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonUp(int32 button, int case 13: pad->PCTempJoyState.DPadUp = 0; break; +#ifdef REGISTER_START_BUTTON + case 12: + pad->PCTempJoyState.Start = 0; + break; +#endif case 11: pad->PCTempJoyState.RightShock = 0; break; diff --git a/src/core/CutsceneMgr.cpp b/src/core/CutsceneMgr.cpp index 3df81b2b..c13aa3a8 100644 --- a/src/core/CutsceneMgr.cpp +++ b/src/core/CutsceneMgr.cpp @@ -1,3 +1,4 @@ +#define WITHWINDOWS // just for VK_SPACE #include "common.h" #include "patcher.h" #include "General.h" @@ -27,79 +28,79 @@ const struct { { "BET", STREAMED_SOUND_BANK_INTRO }, { "L1_LG", STREAMED_SOUND_CUTSCENE_LUIGI1_LG }, { "L2_DSB", STREAMED_SOUND_CUTSCENE_LUIGI2_DSB }, - { "L3_DM", STREAMED_SOUND_CUTSCENE_LUIGI3_DM },
- { "L4_PAP", STREAMED_SOUND_CUTSCENE_LUIGI4_PAP },
- { "L5_TFB", STREAMED_SOUND_CUTSCENE_LUIGI5_TFB },
- { "J0_DM2", STREAMED_SOUND_CUTSCENE_JOEY0_DM2 },
- { "J1_LFL", STREAMED_SOUND_CUTSCENE_JOEY1_LFL },
- { "J2_KCL", STREAMED_SOUND_CUTSCENE_JOEY2_KCL },
- { "J3_VH", STREAMED_SOUND_CUTSCENE_JOEY3_VH },
- { "J4_ETH", STREAMED_SOUND_CUTSCENE_JOEY4_ETH },
- { "J5_DST", STREAMED_SOUND_CUTSCENE_JOEY5_DST },
- { "J6_TBJ", STREAMED_SOUND_CUTSCENE_JOEY6_TBJ },
- { "T1_TOL", STREAMED_SOUND_CUTSCENE_TONI1_TOL },
- { "T2_TPU", STREAMED_SOUND_CUTSCENE_TONI2_TPU },
- { "T3_MAS", STREAMED_SOUND_CUTSCENE_TONI3_MAS },
- { "T4_TAT", STREAMED_SOUND_CUTSCENE_TONI4_TAT },
- { "T5_BF", STREAMED_SOUND_CUTSCENE_TONI5_BF },
- { "S0_MAS", STREAMED_SOUND_CUTSCENE_SAL0_MAS },
- { "S1_PF", STREAMED_SOUND_CUTSCENE_SAL1_PF },
- { "S2_CTG", STREAMED_SOUND_CUTSCENE_SAL2_CTG },
- { "S3_RTC", STREAMED_SOUND_CUTSCENE_SAL3_RTC },
- { "S5_LRQ", STREAMED_SOUND_CUTSCENE_SAL5_LRQ },
- { "S4_BDBA", STREAMED_SOUND_CUTSCENE_SAL4_BDBA },
- { "S4_BDBB", STREAMED_SOUND_CUTSCENE_SAL4_BDBB },
- { "S2_CTG2", STREAMED_SOUND_CUTSCENE_SAL2_CTG2 },
- { "S4_BDBD", STREAMED_SOUND_CUTSCENE_SAL4_BDBD },
- { "S5_LRQB", STREAMED_SOUND_CUTSCENE_SAL5_LRQB },
- { "S5_LRQC", STREAMED_SOUND_CUTSCENE_SAL5_LRQC },
- { "A1_SS0", STREAMED_SOUND_CUTSCENE_ASUKA_1_SSO },
- { "A2_PP", STREAMED_SOUND_CUTSCENE_ASUKA_2_PP },
- { "A3_SS", STREAMED_SOUND_CUTSCENE_ASUKA_3_SS },
- { "A4_PDR", STREAMED_SOUND_CUTSCENE_ASUKA_4_PDR },
- { "A5_K2FT", STREAMED_SOUND_CUTSCENE_ASUKA_5_K2FT},
- { "K1_KBO", STREAMED_SOUND_CUTSCENE_KENJI1_KBO },
- { "K2_GIS", STREAMED_SOUND_CUTSCENE_KENJI2_GIS },
- { "K3_DS", STREAMED_SOUND_CUTSCENE_KENJI3_DS },
- { "K4_SHI", STREAMED_SOUND_CUTSCENE_KENJI4_SHI },
- { "K5_SD", STREAMED_SOUND_CUTSCENE_KENJI5_SD },
- { "R0_PDR2", STREAMED_SOUND_CUTSCENE_RAY0_PDR2 },
- { "R1_SW", STREAMED_SOUND_CUTSCENE_RAY1_SW },
- { "R2_AP", STREAMED_SOUND_CUTSCENE_RAY2_AP },
- { "R3_ED", STREAMED_SOUND_CUTSCENE_RAY3_ED },
- { "R4_GF", STREAMED_SOUND_CUTSCENE_RAY4_GF },
- { "R5_PB", STREAMED_SOUND_CUTSCENE_RAY5_PB },
- { "R6_MM", STREAMED_SOUND_CUTSCENE_RAY6_MM },
- { "D1_STOG", STREAMED_SOUND_CUTSCENE_DONALD1_STOG },
- { "D2_KK", STREAMED_SOUND_CUTSCENE_DONALD2_KK },
- { "D3_ADO", STREAMED_SOUND_CUTSCENE_DONALD3_ADO },
- { "D5_ES", STREAMED_SOUND_CUTSCENE_DONALD5_ES },
- { "D7_MLD", STREAMED_SOUND_CUTSCENE_DONALD7_MLD },
- { "D4_GTA", STREAMED_SOUND_CUTSCENE_DONALD4_GTA },
- { "D4_GTA2", STREAMED_SOUND_CUTSCENE_DONALD4_GTA2 },
- { "D6_STS", STREAMED_SOUND_CUTSCENE_DONALD6_STS },
- { "A6_BAIT", STREAMED_SOUND_CUTSCENE_ASUKA6_BAIT },
- { "A7_ETG", STREAMED_SOUND_CUTSCENE_ASUKA7_ETG },
- { "A8_PS", STREAMED_SOUND_CUTSCENE_ASUKA8_PS },
- { "A9_ASD", STREAMED_SOUND_CUTSCENE_ASUKA9_ASD },
- { "K4_SHI2", STREAMED_SOUND_CUTSCENE_KENJI4_SHI2 },
- { "C1_TEX", STREAMED_SOUND_CUTSCENE_CATALINA1_TEX },
- { "EL_PH1", STREAMED_SOUND_CUTSCENE_ELBURRO1_PH1 },
- { "EL_PH2", STREAMED_SOUND_CUTSCENE_ELBURRO2_PH2 },
- { "EL_PH3", STREAMED_SOUND_CUTSCENE_ELBURRO3_PH3 },
- { "EL_PH4", STREAMED_SOUND_CUTSCENE_ELBURRO4_PH4 },
- { "YD_PH1", STREAMED_SOUND_CUTSCENE_YARDIE_PH1 },
- { "YD_PH2", STREAMED_SOUND_CUTSCENE_YARDIE_PH2 },
- { "YD_PH3", STREAMED_SOUND_CUTSCENE_YARDIE_PH3 },
- { "YD_PH4", STREAMED_SOUND_CUTSCENE_YARDIE_PH4 },
- { "HD_PH1", STREAMED_SOUND_CUTSCENE_HOODS_PH1 },
- { "HD_PH2", STREAMED_SOUND_CUTSCENE_HOODS_PH2 },
- { "HD_PH3", STREAMED_SOUND_CUTSCENE_HOODS_PH3 },
- { "HD_PH4", STREAMED_SOUND_CUTSCENE_HOODS_PH4 },
- { "HD_PH5", STREAMED_SOUND_CUTSCENE_HOODS_PH5 },
- { "MT_PH1", STREAMED_SOUND_CUTSCENE_MARTY_PH1 },
- { "MT_PH2", STREAMED_SOUND_CUTSCENE_MARTY_PH2 },
- { "MT_PH3", STREAMED_SOUND_CUTSCENE_MARTY_PH3 },
+ { "L3_DM", STREAMED_SOUND_CUTSCENE_LUIGI3_DM }, + { "L4_PAP", STREAMED_SOUND_CUTSCENE_LUIGI4_PAP }, + { "L5_TFB", STREAMED_SOUND_CUTSCENE_LUIGI5_TFB }, + { "J0_DM2", STREAMED_SOUND_CUTSCENE_JOEY0_DM2 }, + { "J1_LFL", STREAMED_SOUND_CUTSCENE_JOEY1_LFL }, + { "J2_KCL", STREAMED_SOUND_CUTSCENE_JOEY2_KCL }, + { "J3_VH", STREAMED_SOUND_CUTSCENE_JOEY3_VH }, + { "J4_ETH", STREAMED_SOUND_CUTSCENE_JOEY4_ETH }, + { "J5_DST", STREAMED_SOUND_CUTSCENE_JOEY5_DST }, + { "J6_TBJ", STREAMED_SOUND_CUTSCENE_JOEY6_TBJ }, + { "T1_TOL", STREAMED_SOUND_CUTSCENE_TONI1_TOL }, + { "T2_TPU", STREAMED_SOUND_CUTSCENE_TONI2_TPU }, + { "T3_MAS", STREAMED_SOUND_CUTSCENE_TONI3_MAS }, + { "T4_TAT", STREAMED_SOUND_CUTSCENE_TONI4_TAT }, + { "T5_BF", STREAMED_SOUND_CUTSCENE_TONI5_BF }, + { "S0_MAS", STREAMED_SOUND_CUTSCENE_SAL0_MAS }, + { "S1_PF", STREAMED_SOUND_CUTSCENE_SAL1_PF }, + { "S2_CTG", STREAMED_SOUND_CUTSCENE_SAL2_CTG }, + { "S3_RTC", STREAMED_SOUND_CUTSCENE_SAL3_RTC }, + { "S5_LRQ", STREAMED_SOUND_CUTSCENE_SAL5_LRQ }, + { "S4_BDBA", STREAMED_SOUND_CUTSCENE_SAL4_BDBA }, + { "S4_BDBB", STREAMED_SOUND_CUTSCENE_SAL4_BDBB }, + { "S2_CTG2", STREAMED_SOUND_CUTSCENE_SAL2_CTG2 }, + { "S4_BDBD", STREAMED_SOUND_CUTSCENE_SAL4_BDBD }, + { "S5_LRQB", STREAMED_SOUND_CUTSCENE_SAL5_LRQB }, + { "S5_LRQC", STREAMED_SOUND_CUTSCENE_SAL5_LRQC }, + { "A1_SS0", STREAMED_SOUND_CUTSCENE_ASUKA_1_SSO }, + { "A2_PP", STREAMED_SOUND_CUTSCENE_ASUKA_2_PP }, + { "A3_SS", STREAMED_SOUND_CUTSCENE_ASUKA_3_SS }, + { "A4_PDR", STREAMED_SOUND_CUTSCENE_ASUKA_4_PDR }, + { "A5_K2FT", STREAMED_SOUND_CUTSCENE_ASUKA_5_K2FT}, + { "K1_KBO", STREAMED_SOUND_CUTSCENE_KENJI1_KBO }, + { "K2_GIS", STREAMED_SOUND_CUTSCENE_KENJI2_GIS }, + { "K3_DS", STREAMED_SOUND_CUTSCENE_KENJI3_DS }, + { "K4_SHI", STREAMED_SOUND_CUTSCENE_KENJI4_SHI }, + { "K5_SD", STREAMED_SOUND_CUTSCENE_KENJI5_SD }, + { "R0_PDR2", STREAMED_SOUND_CUTSCENE_RAY0_PDR2 }, + { "R1_SW", STREAMED_SOUND_CUTSCENE_RAY1_SW }, + { "R2_AP", STREAMED_SOUND_CUTSCENE_RAY2_AP }, + { "R3_ED", STREAMED_SOUND_CUTSCENE_RAY3_ED }, + { "R4_GF", STREAMED_SOUND_CUTSCENE_RAY4_GF }, + { "R5_PB", STREAMED_SOUND_CUTSCENE_RAY5_PB }, + { "R6_MM", STREAMED_SOUND_CUTSCENE_RAY6_MM }, + { "D1_STOG", STREAMED_SOUND_CUTSCENE_DONALD1_STOG }, + { "D2_KK", STREAMED_SOUND_CUTSCENE_DONALD2_KK }, + { "D3_ADO", STREAMED_SOUND_CUTSCENE_DONALD3_ADO }, + { "D5_ES", STREAMED_SOUND_CUTSCENE_DONALD5_ES }, + { "D7_MLD", STREAMED_SOUND_CUTSCENE_DONALD7_MLD }, + { "D4_GTA", STREAMED_SOUND_CUTSCENE_DONALD4_GTA }, + { "D4_GTA2", STREAMED_SOUND_CUTSCENE_DONALD4_GTA2 }, + { "D6_STS", STREAMED_SOUND_CUTSCENE_DONALD6_STS }, + { "A6_BAIT", STREAMED_SOUND_CUTSCENE_ASUKA6_BAIT }, + { "A7_ETG", STREAMED_SOUND_CUTSCENE_ASUKA7_ETG }, + { "A8_PS", STREAMED_SOUND_CUTSCENE_ASUKA8_PS }, + { "A9_ASD", STREAMED_SOUND_CUTSCENE_ASUKA9_ASD }, + { "K4_SHI2", STREAMED_SOUND_CUTSCENE_KENJI4_SHI2 }, + { "C1_TEX", STREAMED_SOUND_CUTSCENE_CATALINA1_TEX }, + { "EL_PH1", STREAMED_SOUND_CUTSCENE_ELBURRO1_PH1 }, + { "EL_PH2", STREAMED_SOUND_CUTSCENE_ELBURRO2_PH2 }, + { "EL_PH3", STREAMED_SOUND_CUTSCENE_ELBURRO3_PH3 }, + { "EL_PH4", STREAMED_SOUND_CUTSCENE_ELBURRO4_PH4 }, + { "YD_PH1", STREAMED_SOUND_CUTSCENE_YARDIE_PH1 }, + { "YD_PH2", STREAMED_SOUND_CUTSCENE_YARDIE_PH2 }, + { "YD_PH3", STREAMED_SOUND_CUTSCENE_YARDIE_PH3 }, + { "YD_PH4", STREAMED_SOUND_CUTSCENE_YARDIE_PH4 }, + { "HD_PH1", STREAMED_SOUND_CUTSCENE_HOODS_PH1 }, + { "HD_PH2", STREAMED_SOUND_CUTSCENE_HOODS_PH2 }, + { "HD_PH3", STREAMED_SOUND_CUTSCENE_HOODS_PH3 }, + { "HD_PH4", STREAMED_SOUND_CUTSCENE_HOODS_PH4 }, + { "HD_PH5", STREAMED_SOUND_CUTSCENE_HOODS_PH5 }, + { "MT_PH1", STREAMED_SOUND_CUTSCENE_MARTY_PH1 }, + { "MT_PH2", STREAMED_SOUND_CUTSCENE_MARTY_PH2 }, + { "MT_PH3", STREAMED_SOUND_CUTSCENE_MARTY_PH3 }, { "MT_PH4", STREAMED_SOUND_CUTSCENE_MARTY_PH4 }, { NULL, NULL } }; @@ -128,135 +129,135 @@ CVector &CCutsceneMgr::ms_cutsceneOffset = *(CVector*)0x8F2C0C; float &CCutsceneMgr::ms_cutsceneTimer = *(float*)0x941548; uint32 &CCutsceneMgr::ms_cutsceneLoadStatus = *(uint32*)0x95CB40; -RpAtomic *
-CalculateBoundingSphereRadiusCB(RpAtomic *atomic, void *data)
-{
- float radius = RpAtomicGetBoundingSphereMacro(atomic)->radius;
- RwV3d center = RpAtomicGetBoundingSphereMacro(atomic)->center;
-
- for (RwFrame *frame = RpAtomicGetFrame(atomic); RwFrameGetParent(frame); frame = RwFrameGetParent(frame))
- RwV3dTransformPoints(¢er, ¢er, 1, RwFrameGetMatrix(frame));
-
- float size = RwV3dLength(¢er) + radius;
- if (size > *(float *)data)
- *(float *)data = size;
- return atomic;
+RpAtomic * +CalculateBoundingSphereRadiusCB(RpAtomic *atomic, void *data) +{ + float radius = RpAtomicGetBoundingSphereMacro(atomic)->radius; + RwV3d center = RpAtomicGetBoundingSphereMacro(atomic)->center; + + for (RwFrame *frame = RpAtomicGetFrame(atomic); RwFrameGetParent(frame); frame = RwFrameGetParent(frame)) + RwV3dTransformPoints(¢er, ¢er, 1, RwFrameGetMatrix(frame)); + + float size = RwV3dLength(¢er) + radius; + if (size > *(float *)data) + *(float *)data = size; + return atomic; } void CCutsceneMgr::Initialise(void) -{
- ms_numCutsceneObjs = 0;
- ms_loaded = false;
- ms_running = false;
- ms_animLoaded = false;
- ms_cutsceneProcessing = false;
- ms_useLodMultiplier = false;
-
- ms_pCutsceneDir = new CDirectory(CUTSCENEDIRSIZE);
+{ + ms_numCutsceneObjs = 0; + ms_loaded = false; + ms_running = false; + ms_animLoaded = false; + ms_cutsceneProcessing = false; + ms_useLodMultiplier = false; + + ms_pCutsceneDir = new CDirectory(CUTSCENEDIRSIZE); ms_pCutsceneDir->ReadDirFile("ANIM\\CUTS.DIR"); } -void
-CCutsceneMgr::Shutdown(void)
-{
- delete ms_pCutsceneDir;
+void +CCutsceneMgr::Shutdown(void) +{ + delete ms_pCutsceneDir; } -void
-CCutsceneMgr::LoadCutsceneData(const char *szCutsceneName)
-{
- int file;
- uint32 size;
- uint32 offset;
- CPlayerPed *pPlayerPed;
-
- ms_cutsceneProcessing = true;
- if (!strcasecmp(szCutsceneName, "jb"))
- ms_useLodMultiplier = true;
- CTimer::Stop();
-
- ms_pCutsceneDir->numEntries = 0;
- ms_pCutsceneDir->ReadDirFile("ANIM\\CUTS.DIR");
-
- CStreaming::RemoveUnusedModelsInLoadedList();
- CGame::DrasticTidyUpMemory();
-
- strcpy(ms_cutsceneName, szCutsceneName);
- file = CFileMgr::OpenFile("ANIM\\CUTS.IMG", "rb");
-
- // Load animations
- sprintf(gString, "%s.IFP", szCutsceneName);
- if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
- CStreaming::MakeSpaceFor(size << 11);
- CStreaming::ImGonnaUseStreamingMemory();
- CFileMgr::Seek(file, offset << 11, SEEK_SET);
- CAnimManager::LoadAnimFile(file, false);
- ms_cutsceneAssociations.CreateAssociations(szCutsceneName);
- CStreaming::IHaveUsedStreamingMemory();
- ms_animLoaded = true;
- } else {
- ms_animLoaded = false;
- }
-
- // Load camera data
- sprintf(gString, "%s.DAT", szCutsceneName);
- if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
- CFileMgr::Seek(file, offset << 11, SEEK_SET);
- TheCamera.LoadPathSplines(file);
- }
-
- CFileMgr::CloseFile(file);
-
- if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
- DMAudio.ChangeMusicMode(MUSICMODE_CUTSCENE);
- int trackId = FindCutsceneAudioTrackId(szCutsceneName);
- if (trackId != -1) {
- printf("Start preload audio %s\n", szCutsceneName);
- DMAudio.PreloadCutSceneMusic(trackId);
- printf("End preload audio %s\n", szCutsceneName);
- }
- }
-
- ms_cutsceneTimer = 0.0f;
- ms_loaded = true;
- ms_cutsceneOffset = CVector(0.0f, 0.0f, 0.0f);
-
- pPlayerPed = FindPlayerPed();
- CTimer::Update();
-
- pPlayerPed->m_pWanted->ClearQdCrimes();
- pPlayerPed->bIsVisible = false;
- pPlayerPed->m_fCurrentStamina = pPlayerPed->m_fMaxStamina;
- CPad::GetPad(0)->DisablePlayerControls |= PLAYERCONTROL_DISABLED_80;
- CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(true);
+void +CCutsceneMgr::LoadCutsceneData(const char *szCutsceneName) +{ + int file; + uint32 size; + uint32 offset; + CPlayerPed *pPlayerPed; + + ms_cutsceneProcessing = true; + if (!strcasecmp(szCutsceneName, "jb")) + ms_useLodMultiplier = true; + CTimer::Stop(); + + ms_pCutsceneDir->numEntries = 0; + ms_pCutsceneDir->ReadDirFile("ANIM\\CUTS.DIR"); + + CStreaming::RemoveUnusedModelsInLoadedList(); + CGame::DrasticTidyUpMemory(); + + strcpy(ms_cutsceneName, szCutsceneName); + file = CFileMgr::OpenFile("ANIM\\CUTS.IMG", "rb"); + + // Load animations + sprintf(gString, "%s.IFP", szCutsceneName); + if (ms_pCutsceneDir->FindItem(gString, offset, size)) { + CStreaming::MakeSpaceFor(size << 11); + CStreaming::ImGonnaUseStreamingMemory(); + CFileMgr::Seek(file, offset << 11, SEEK_SET); + CAnimManager::LoadAnimFile(file, false); + ms_cutsceneAssociations.CreateAssociations(szCutsceneName); + CStreaming::IHaveUsedStreamingMemory(); + ms_animLoaded = true; + } else { + ms_animLoaded = false; + } + + // Load camera data + sprintf(gString, "%s.DAT", szCutsceneName); + if (ms_pCutsceneDir->FindItem(gString, offset, size)) { + CFileMgr::Seek(file, offset << 11, SEEK_SET); + TheCamera.LoadPathSplines(file); + } + + CFileMgr::CloseFile(file); + + if (CGeneral::faststricmp(ms_cutsceneName, "end")) { + DMAudio.ChangeMusicMode(MUSICMODE_CUTSCENE); + int trackId = FindCutsceneAudioTrackId(szCutsceneName); + if (trackId != -1) { + printf("Start preload audio %s\n", szCutsceneName); + DMAudio.PreloadCutSceneMusic(trackId); + printf("End preload audio %s\n", szCutsceneName); + } + } + + ms_cutsceneTimer = 0.0f; + ms_loaded = true; + ms_cutsceneOffset = CVector(0.0f, 0.0f, 0.0f); + + pPlayerPed = FindPlayerPed(); + CTimer::Update(); + + pPlayerPed->m_pWanted->ClearQdCrimes(); + pPlayerPed->bIsVisible = false; + pPlayerPed->m_fCurrentStamina = pPlayerPed->m_fMaxStamina; + CPad::GetPad(0)->DisablePlayerControls |= PLAYERCONTROL_DISABLED_80; + CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(true); } -void
-CCutsceneMgr::SetHeadAnim(const char *animName, CObject *pObject)
-{
- CCutsceneHead *pCutsceneHead = (CCutsceneHead*)pObject;
- char szAnim[CUTSCENENAMESIZE * 2];
-
- sprintf(szAnim, "%s_%s", ms_cutsceneName, animName);
- pCutsceneHead->PlayAnimation(szAnim);
+void +CCutsceneMgr::SetHeadAnim(const char *animName, CObject *pObject) +{ + CCutsceneHead *pCutsceneHead = (CCutsceneHead*)pObject; + char szAnim[CUTSCENENAMESIZE * 2]; + + sprintf(szAnim, "%s_%s", ms_cutsceneName, animName); + pCutsceneHead->PlayAnimation(szAnim); } -void
-CCutsceneMgr::FinishCutscene()
-{
- CCutsceneMgr::ms_cutsceneTimer = TheCamera.GetCutSceneFinishTime() * 0.001f;
- TheCamera.FinishCutscene();
-
- FindPlayerPed()->bIsVisible = true;
- CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false);
+void +CCutsceneMgr::FinishCutscene() +{ + CCutsceneMgr::ms_cutsceneTimer = TheCamera.GetCutSceneFinishTime() * 0.001f; + TheCamera.FinishCutscene(); + + FindPlayerPed()->bIsVisible = true; + CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false); } void CCutsceneMgr::SetupCutsceneToStart(void) { - TheCamera.SetCamCutSceneOffSet(ms_cutsceneOffset);
- TheCamera.TakeControlWithSpline(JUMP_CUT);
+ TheCamera.SetCamCutSceneOffSet(ms_cutsceneOffset); + TheCamera.TakeControlWithSpline(JUMP_CUT); TheCamera.SetWideScreenOn(); ms_cutsceneOffset.z++; @@ -273,9 +274,9 @@ CCutsceneMgr::SetupCutsceneToStart(void) } } - CTimer::Update();
- CTimer::Update();
- ms_running = true;
+ CTimer::Update(); + CTimer::Update(); + ms_running = true; ms_cutsceneTimer = 0.0f; } @@ -297,14 +298,14 @@ CCutsceneMgr::SetCutsceneAnim(const char *animName, CObject *pObject) pAnimBlendClumpData->link.Prepend(&pNewAnim->link); } -CCutsceneHead *
-CCutsceneMgr::AddCutsceneHead(CObject *pObject, int modelId)
-{
- CCutsceneHead *pHead = new CCutsceneHead(pObject);
- pHead->SetModelIndex(modelId);
- CWorld::Add(pHead);
- ms_pCutsceneObjects[ms_numCutsceneObjs++] = pHead;
- return pHead;
+CCutsceneHead * +CCutsceneMgr::AddCutsceneHead(CObject *pObject, int modelId) +{ + CCutsceneHead *pHead = new CCutsceneHead(pObject); + pHead->SetModelIndex(modelId); + CWorld::Add(pHead); + ms_pCutsceneObjects[ms_numCutsceneObjs++] = pHead; + return pHead; } CCutsceneObject * @@ -333,89 +334,89 @@ CCutsceneMgr::CreateCutsceneObject(int modelId) pCutsceneObject = new CCutsceneObject(); pCutsceneObject->SetModelIndex(modelId); - ms_pCutsceneObjects[ms_numCutsceneObjs++] = pCutsceneObject;
+ ms_pCutsceneObjects[ms_numCutsceneObjs++] = pCutsceneObject; return pCutsceneObject; } -void
-CCutsceneMgr::DeleteCutsceneData(void)
-{
- if (!ms_loaded) return;
-
- ms_cutsceneProcessing = false;
- ms_useLodMultiplier = false;
-
- for (--ms_numCutsceneObjs; ms_numCutsceneObjs >= 0; ms_numCutsceneObjs--) {
- CWorld::Remove(ms_pCutsceneObjects[ms_numCutsceneObjs]);
- ms_pCutsceneObjects[ms_numCutsceneObjs]->DeleteRwObject();
- delete ms_pCutsceneObjects[ms_numCutsceneObjs];
- }
- ms_numCutsceneObjs = 0;
-
- if (ms_animLoaded)
- CAnimManager::RemoveLastAnimFile();
-
- ms_animLoaded = false;
- TheCamera.RestoreWithJumpCut();
- TheCamera.SetWideScreenOff();
- ms_running = false;
- ms_loaded = false;
-
- FindPlayerPed()->bIsVisible = true;
- CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_80;
- CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false);
-
- if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
- DMAudio.StopCutSceneMusic();
- if (CGeneral::faststricmp(ms_cutsceneName, "bet"))
- DMAudio.ChangeMusicMode(MUSICMODE_GAME);
- }
- CTimer::Stop();
- //TheCamera.GetScreenFadeStatus() == 2; // what for??
- CGame::DrasticTidyUpMemory();
- CTimer::Update();
+void +CCutsceneMgr::DeleteCutsceneData(void) +{ + if (!ms_loaded) return; + + ms_cutsceneProcessing = false; + ms_useLodMultiplier = false; + + for (--ms_numCutsceneObjs; ms_numCutsceneObjs >= 0; ms_numCutsceneObjs--) { + CWorld::Remove(ms_pCutsceneObjects[ms_numCutsceneObjs]); + ms_pCutsceneObjects[ms_numCutsceneObjs]->DeleteRwObject(); + delete ms_pCutsceneObjects[ms_numCutsceneObjs]; + } + ms_numCutsceneObjs = 0; + + if (ms_animLoaded) + CAnimManager::RemoveLastAnimFile(); + + ms_animLoaded = false; + TheCamera.RestoreWithJumpCut(); + TheCamera.SetWideScreenOff(); + ms_running = false; + ms_loaded = false; + + FindPlayerPed()->bIsVisible = true; + CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_80; + CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false); + + if (CGeneral::faststricmp(ms_cutsceneName, "end")) { + DMAudio.StopCutSceneMusic(); + if (CGeneral::faststricmp(ms_cutsceneName, "bet")) + DMAudio.ChangeMusicMode(MUSICMODE_GAME); + } + CTimer::Stop(); + //TheCamera.GetScreenFadeStatus() == 2; // what for?? + CGame::DrasticTidyUpMemory(); + CTimer::Update(); } -void
-CCutsceneMgr::Update(void)
-{
- enum {
- CUTSCENE_LOADING_0 = 0,
- CUTSCENE_LOADING_AUDIO,
- CUTSCENE_LOADING_2,
- CUTSCENE_LOADING_3,
- CUTSCENE_LOADING_4
- };
-
- switch (ms_cutsceneLoadStatus) {
- case CUTSCENE_LOADING_AUDIO:
- SetupCutsceneToStart();
- if (CGeneral::faststricmp(ms_cutsceneName, "end"))
- DMAudio.PlayPreloadedCutSceneMusic();
- ms_cutsceneLoadStatus++;
- break;
- case CUTSCENE_LOADING_2:
- case CUTSCENE_LOADING_3:
- ms_cutsceneLoadStatus++;
- break;
- case CUTSCENE_LOADING_4:
- ms_cutsceneLoadStatus = CUTSCENE_LOADING_0;
- break;
- default:
- break;
- }
-
- if (!ms_running) return;
-
- ms_cutsceneTimer += CTimer::GetTimeStepNonClipped() * 0.02f;
- if (CGeneral::faststricmp(ms_cutsceneName, "end") && TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FLYBY && ms_cutsceneLoadStatus == CUTSCENE_LOADING_0) {
- if (CPad::GetPad(0)->GetCrossJustDown()
- || (CGame::playingIntro && CPad::GetPad(0)->GetStartJustDown())
- || CPad::GetPad(0)->GetLeftMouseJustDown()
- || CPad::GetPad(0)->GetEnterJustDown()
- || CPad::GetPad(0)->GetCharJustDown(VK_SPACE))
- FinishCutscene();
- }
+void +CCutsceneMgr::Update(void) +{ + enum { + CUTSCENE_LOADING_0 = 0, + CUTSCENE_LOADING_AUDIO, + CUTSCENE_LOADING_2, + CUTSCENE_LOADING_3, + CUTSCENE_LOADING_4 + }; + + switch (ms_cutsceneLoadStatus) { + case CUTSCENE_LOADING_AUDIO: + SetupCutsceneToStart(); + if (CGeneral::faststricmp(ms_cutsceneName, "end")) + DMAudio.PlayPreloadedCutSceneMusic(); + ms_cutsceneLoadStatus++; + break; + case CUTSCENE_LOADING_2: + case CUTSCENE_LOADING_3: + ms_cutsceneLoadStatus++; + break; + case CUTSCENE_LOADING_4: + ms_cutsceneLoadStatus = CUTSCENE_LOADING_0; + break; + default: + break; + } + + if (!ms_running) return; + + ms_cutsceneTimer += CTimer::GetTimeStepNonClipped() * 0.02f; + if (CGeneral::faststricmp(ms_cutsceneName, "end") && TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FLYBY && ms_cutsceneLoadStatus == CUTSCENE_LOADING_0) { + if (CPad::GetPad(0)->GetCrossJustDown() + || (CGame::playingIntro && CPad::GetPad(0)->GetStartJustDown()) + || CPad::GetPad(0)->GetLeftMouseJustDown() + || CPad::GetPad(0)->GetEnterJustDown() + || CPad::GetPad(0)->GetCharJustDown(VK_SPACE)) + FinishCutscene(); + } } bool CCutsceneMgr::HasCutsceneFinished(void) { return TheCamera.GetPositionAlongSpline() == 1.0f; } diff --git a/src/core/Debug.cpp b/src/core/Debug.cpp index bdcbaf04..2b713198 100644 --- a/src/core/Debug.cpp +++ b/src/core/Debug.cpp @@ -89,3 +89,49 @@ CDebug::DebugDisplayTextBuffer() } #endif } + + +// custom + +CDebug::ScreenStr CDebug::ms_aScreenStrs[MAX_SCREEN_STRS]; +int CDebug::ms_nScreenStrs; + +void +CDebug::DisplayScreenStrings() +{ + int i; + + + CFont::SetPropOn(); + CFont::SetBackgroundOff(); + CFont::SetScale(1.0f, 1.0f); + CFont::SetCentreOff(); + CFont::SetRightJustifyOff(); + CFont::SetJustifyOff(); + CFont::SetRightJustifyWrap(0.0f); + CFont::SetWrapx(9999.0f); + CFont::SetBackGroundOnlyTextOff(); + CFont::SetFontStyle(FONT_BANK); + + for(i = 0; i < ms_nScreenStrs; i++){ + AsciiToUnicode(ms_aScreenStrs[i].str, gUString); + CFont::SetColor(CRGBA(0, 0, 0, 255)); + CFont::PrintString(ms_aScreenStrs[i].x, ms_aScreenStrs[i].y, gUString); + CFont::SetColor(CRGBA(255, 255, 255, 255)); + CFont::PrintString(ms_aScreenStrs[i].x+1, ms_aScreenStrs[i].y+1, gUString); + } + CFont::DrawFonts(); + + ms_nScreenStrs = 0; +} + +void +CDebug::PrintAt(const char *str, int x, int y) +{ + if(ms_nScreenStrs >= MAX_SCREEN_STRS) + return; + strncpy(ms_aScreenStrs[ms_nScreenStrs].str, str, 256); + ms_aScreenStrs[ms_nScreenStrs].x = x*12; + ms_aScreenStrs[ms_nScreenStrs].y = y*22; + ms_nScreenStrs++; +} diff --git a/src/core/Debug.h b/src/core/Debug.h index 444a0cf5..d169a0b4 100644 --- a/src/core/Debug.h +++ b/src/core/Debug.h @@ -6,15 +6,29 @@ class CDebug { MAX_LINES = 15, MAX_STR_LEN = 80, + + MAX_SCREEN_STRS = 100, }; static int16 ms_nCurrentTextLine; static char ms_aTextBuffer[MAX_LINES][MAX_STR_LEN]; + // custom + struct ScreenStr { + int x, y; + char str[256]; + }; + static ScreenStr ms_aScreenStrs[MAX_SCREEN_STRS]; + static int ms_nScreenStrs; + public: static void DebugInitTextBuffer(); static void DebugDisplayTextBuffer(); static void DebugAddText(const char *str); + + // custom + static void PrintAt(const char *str, int x, int y); + static void DisplayScreenStrings(); }; extern bool gbDebugStuffInRelease; diff --git a/src/core/EventList.cpp b/src/core/EventList.cpp index caf0cb3f..4364359a 100644 --- a/src/core/EventList.cpp +++ b/src/core/EventList.cpp @@ -5,10 +5,13 @@ #include "World.h" #include "Wanted.h" #include "EventList.h" +#include "Messages.h" +#include "Text.h" +#include "main.h" int32 CEventList::ms_nFirstFreeSlotIndex; -//CEvent gaEvent[NUMEVENTS]; -CEvent *gaEvent = (CEvent*)0x6EF830; +CEvent gaEvent[NUMEVENTS]; +//CEvent *gaEvent = (CEvent*)0x6EF830; enum { @@ -207,8 +210,20 @@ CEventList::ReportCrimeForEvent(eEventType type, int32 crimeId, bool copsDontCar default: crime = CRIME_NONE; break; } - if(crime == CRIME_NONE) - return; +#ifdef VC_PED_PORTS + if (crime == CRIME_HIT_PED && ((CPed*)crimeId)->IsPointerValid() && + FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 && ((CPed*)crimeId)->m_ped_flagE2) { + + if(!((CPed*)crimeId)->DyingOrDead()) { + sprintf(gString, "$50 Good Citizen Bonus!"); + AsciiToUnicode(gString, gUString); + CMessages::AddBigMessage(gUString, 5000, 0); + CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 50; + } + } else +#endif + if(crime == CRIME_NONE) + return; CVector playerPedCoors = FindPlayerPed()->GetPosition(); CVector playerCoors = FindPlayerCoors(); diff --git a/src/core/EventList.h b/src/core/EventList.h index 2799fca4..1c03c9d6 100644 --- a/src/core/EventList.h +++ b/src/core/EventList.h @@ -63,4 +63,4 @@ public: static void ReportCrimeForEvent(eEventType type, int32, bool); }; -extern CEvent *gaEvent;
\ No newline at end of file +extern CEvent gaEvent[NUMEVENTS];
\ No newline at end of file diff --git a/src/core/Fire.cpp b/src/core/Fire.cpp index f83ad2c8..c98c808d 100644 --- a/src/core/Fire.cpp +++ b/src/core/Fire.cpp @@ -1,19 +1,289 @@ #include "common.h" #include "patcher.h" +#include "Vector.h" +#include "PlayerPed.h" +#include "Entity.h" +#include "PointLights.h" +#include "Particle.h" +#include "Timer.h" +#include "Vehicle.h" +#include "Shadows.h" +#include "Automobile.h" +#include "World.h" +#include "General.h" +#include "EventList.h" +#include "DamageManager.h" +#include "Ped.h" #include "Fire.h" CFireManager &gFireManager = *(CFireManager*)0x8F31D0; -WRAPPER void CFire::Extinguish(void) { EAXJMP(0x479D40); } -WRAPPER void CFireManager::Update(void) { EAXJMP(0x479310); } -WRAPPER CFire* CFireManager::FindFurthestFire_NeverMindFireMen(CVector coors, float, float) { EAXJMP(0x479430); } +CFire::CFire() +{ + m_bIsOngoing = false; + m_bIsScriptFire = false; + m_bPropagationFlag = true; + m_bAudioSet = true; + m_vecPos = CVector(0.0f, 0.0f, 0.0f); + m_pEntity = nil; + m_pSource = nil; + m_nFiremenPuttingOut = 0; + m_nExtinguishTime = 0; + m_nStartTime = 0; + field_20 = 1; + m_nNextTimeToAddFlames = 0; + m_fStrength = 0.8f; +} -uint32 CFireManager::GetTotalActiveFires() const +CFire::~CFire() {} + +void +CFire::ProcessFire(void) { - return m_nTotalFires; + float fDamagePlayer; + float fDamagePeds; + float fDamageVehicle; + int8 nRandNumber; + float fGreen; + float fRed; + CVector lightpos; + CVector firePos; + CPed *ped = (CPed *)m_pEntity; + CVehicle *veh = (CVehicle*)m_pEntity; + + if (m_pEntity) { + m_vecPos = m_pEntity->GetPosition(); + + if (((CPed *)m_pEntity)->IsPed()) { + if (ped->m_pFire != this) { + Extinguish(); + return; + } + if (ped->m_nMoveState != PEDMOVE_RUN) + m_vecPos.z -= 1.0f; + if (ped->bInVehicle && ped->m_pMyVehicle) { + if (ped->m_pMyVehicle->IsCar()) + ped->m_pMyVehicle->m_fHealth = 75.0f; + } else if (m_pEntity == (CPed *)FindPlayerPed()) { + fDamagePlayer = 1.2f * CTimer::GetTimeStep(); + + ((CPlayerPed *)m_pEntity)->InflictDamage( + (CPlayerPed *)m_pSource, WEAPONTYPE_FLAMETHROWER, + fDamagePlayer, PEDPIECE_TORSO, 0); + } else { + fDamagePeds = 1.2f * CTimer::GetTimeStep(); + + if (((CPlayerPed *)m_pEntity)->InflictDamage( + (CPlayerPed *)m_pSource, WEAPONTYPE_FLAMETHROWER, + fDamagePeds, PEDPIECE_TORSO, 0)) { + m_pEntity->bRenderScorched = true; + } + } + } else if (m_pEntity->IsVehicle()) { + if (veh->m_pCarFire != this) { + Extinguish(); + return; + } + if (!m_bIsScriptFire) { + fDamageVehicle = 1.2f * CTimer::GetTimeStep(); + veh->InflictDamage((CVehicle *)m_pSource, WEAPONTYPE_FLAMETHROWER, fDamageVehicle); + } + } + } + if (!FindPlayerVehicle() && !FindPlayerPed()->m_pFire && !(FindPlayerPed()->bFireProof) + && ((FindPlayerPed()->GetPosition() - m_vecPos).MagnitudeSqr() < 2.0f)) { + FindPlayerPed()->DoStuffToGoOnFire(); + gFireManager.StartFire(FindPlayerPed(), m_pSource, 0.8f, 1); + } + if (CTimer::GetTimeInMilliseconds() > m_nNextTimeToAddFlames) { + m_nNextTimeToAddFlames = CTimer::GetTimeInMilliseconds() + 80; + firePos = m_vecPos; + + if (veh && veh->IsVehicle() && veh->IsCar()) { + CVehicleModelInfo *mi = ((CVehicleModelInfo*)CModelInfo::GetModelInfo(veh->GetModelIndex())); + CVector ModelInfo = mi->m_positions[CAR_POS_HEADLIGHTS]; + ModelInfo = m_pEntity->GetMatrix() * ModelInfo; + + firePos.x = ModelInfo.x; + firePos.y = ModelInfo.y; + firePos.z = ModelInfo.z + 0.15f; + } + + CParticle::AddParticle(PARTICLE_CARFLAME, firePos, + CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.0125f, 0.1f) * m_fStrength), + 0, m_fStrength, 0, 0, 0, 0); + + rand(); rand(); rand(); /* unsure why these three rands are called */ + + CParticle::AddParticle(PARTICLE_CARFLAME_SMOKE, firePos, + CVector(0.0f, 0.0f, 0.0f), 0, 0.0f, 0, 0, 0, 0); + } + if (CTimer::GetTimeInMilliseconds() < m_nExtinguishTime || m_bIsScriptFire) { + if (CTimer::GetTimeInMilliseconds() > m_nStartTime) + m_nStartTime = CTimer::GetTimeInMilliseconds() + 400; + + nRandNumber = CGeneral::GetRandomNumber() & 127; + lightpos.x = m_vecPos.x; + lightpos.y = m_vecPos.y; + lightpos.z = m_vecPos.z + 5.0f; + + if (!m_pEntity) { + CShadows::StoreStaticShadow((uint32)this, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &lightpos, + 7.0f, 0.0f, 0.0f, -7.0f, 0, nRandNumber / 2, nRandNumber / 2, + 0, 10.0f, 1.0f, 40.0f, 0, 0.0f); + } + fGreen = nRandNumber / 128; + fRed = nRandNumber / 128; + + CPointLights::AddLight(0, m_vecPos, CVector(0.0f, 0.0f, 0.0f), + 12.0f, fRed, fGreen, 0, 0, 0); + } else { + Extinguish(); + } } -CFire* CFireManager::FindNearestFire(CVector vecPos, float* pDistance) +void +CFire::ReportThisFire(void) +{ + gFireManager.m_nTotalFires++; + CEventList::RegisterEvent(EVENT_FIRE, m_vecPos, 1000); +} + +void +CFire::Extinguish(void) +{ + if (m_bIsOngoing) { + if (!m_bIsScriptFire) + gFireManager.m_nTotalFires--; + + m_nExtinguishTime = 0; + m_bIsOngoing = false; + + if (m_pEntity) { + if (m_pEntity->IsPed()) { + ((CPed *)m_pEntity)->RestorePreviousState(); + ((CPed *)m_pEntity)->m_pFire = nil; + } else if (m_pEntity->IsVehicle()) { + ((CVehicle *)m_pEntity)->m_pCarFire = nil; + } + m_pEntity = nil; + } + } +} + +void +CFireManager::StartFire(CVector pos, float size, bool propagation) +{ + CFire *fire = GetNextFreeFire(); + + if (fire) { + fire->m_bIsOngoing = true; + fire->m_bIsScriptFire = false; + fire->m_bPropagationFlag = propagation; + fire->m_bAudioSet = true; + fire->m_vecPos = pos; + fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + 10000; + fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400; + fire->m_pEntity = nil; + fire->m_pSource = nil; + fire->m_nNextTimeToAddFlames = 0; + fire->ReportThisFire(); + fire->m_fStrength = size; + } +} + +CFire * +CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, bool propagation) +{ + CPed *ped = (CPed *)entityOnFire; + CVehicle *veh = (CVehicle *)entityOnFire; + + if (entityOnFire->IsPed()) { + if (ped->m_pFire) + return nil; + if (!ped->IsPedInControl()) + return nil; + } else if (entityOnFire->IsVehicle()) { + if (veh->m_pCarFire) + return nil; + if (veh->IsCar() && ((CAutomobile *)veh)->Damage.GetEngineStatus() >= 225) + return nil; + } + CFire *fire = GetNextFreeFire(); + + if (fire) { + if (entityOnFire->IsPed()) { + ped->m_pFire = fire; + if (ped != FindPlayerPed()) { + if (fleeFrom) { + ped->SetFlee(fleeFrom, 10000); + } else { + CVector2D pos = entityOnFire->GetPosition(); + ped->SetFlee(pos, 10000); + ped->m_fleeFrom = nil; + } + ped->bDrawLast = false; + ped->SetMoveState(PEDMOVE_SPRINT); + ped->SetMoveAnim(); + ped->m_nPedState = PED_ON_FIRE; + } + if (fleeFrom) { + if (ped->m_nPedType == PEDTYPE_COP) { + CEventList::RegisterEvent(EVENT_COP_SET_ON_FIRE, EVENT_ENTITY_PED, + entityOnFire, (CPed *)fleeFrom, 10000); + } else { + CEventList::RegisterEvent(EVENT_PED_SET_ON_FIRE, EVENT_ENTITY_PED, + entityOnFire, (CPed *)fleeFrom, 10000); + } + } + } else { + if (entityOnFire->IsVehicle()) { + veh->m_pCarFire = fire; + if (fleeFrom) { + CEventList::RegisterEvent(EVENT_CAR_SET_ON_FIRE, EVENT_ENTITY_VEHICLE, + entityOnFire, (CPed *)fleeFrom, 10000); + } + } + } + + fire->m_bIsOngoing = true; + fire->m_bIsScriptFire = false; + fire->m_vecPos = entityOnFire->GetPosition(); + + if (entityOnFire && entityOnFire->IsPed() && ped->IsPlayer()) { + fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + 3333; + } else if (entityOnFire->IsVehicle()) { + fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(4000, 5000); + } else { + fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(10000, 11000); + } + fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400; + fire->m_pEntity = entityOnFire; + + entityOnFire->RegisterReference(&fire->m_pEntity); + fire->m_pSource = fleeFrom; + + if (fleeFrom) + fleeFrom->RegisterReference(&fire->m_pSource); + fire->ReportThisFire(); + fire->m_nNextTimeToAddFlames = 0; + fire->m_fStrength = strength; + fire->m_bPropagationFlag = propagation; + fire->m_bAudioSet = true; + } + return fire; +} + +void +CFireManager::Update(void) +{ + for (int i = 0; i < NUM_FIRES; i++) { + if (m_aFires[i].m_bIsOngoing) + m_aFires[i].ProcessFire(); + } +} + +CFire* CFireManager::FindNearestFire(CVector vecPos, float *pDistance) { for (int i = 0; i < MAX_FIREMEN_ATTENDING; i++) { int fireId = -1; @@ -38,6 +308,44 @@ CFire* CFireManager::FindNearestFire(CVector vecPos, float* pDistance) return nil; } +CFire * +CFireManager::FindFurthestFire_NeverMindFireMen(CVector coords, float minRange, float maxRange) +{ + int furthestFire = -1; + float lastFireDist = 0.0f; + float fireDist; + + for (int i = 0; i < NUM_FIRES; i++) { + if (m_aFires[i].m_bIsOngoing && !m_aFires[i].m_bIsScriptFire) { + fireDist = (m_aFires[i].m_vecPos - coords).Magnitude2D(); + if (fireDist > minRange && fireDist < maxRange && fireDist > lastFireDist) { + lastFireDist = fireDist; + furthestFire = i; + } + } + } + if (furthestFire == -1) + return nil; + else + return &m_aFires[furthestFire]; +} + +CFire * +CFireManager::GetNextFreeFire(void) +{ + for (int i = 0; i < NUM_FIRES; i++) { + if (!m_aFires[i].m_bIsOngoing && !m_aFires[i].m_bIsScriptFire) + return &m_aFires[i]; + } + return nil; +} + +uint32 +CFireManager::GetTotalActiveFires(void) const +{ + return m_nTotalFires; +} + void CFireManager::ExtinguishPoint(CVector point, float range) { @@ -49,16 +357,100 @@ CFireManager::ExtinguishPoint(CVector point, float range) } } -WRAPPER void CFireManager::StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32) { EAXJMP(0x479590); } -WRAPPER void CFireManager::StartFire(CVector, float, uint8) { EAXJMP(0x479500); } -WRAPPER int32 CFireManager::StartScriptFire(const CVector& pos, CEntity* culprit, float, uint8) { EAXJMP(0x479E60); } -WRAPPER bool CFireManager::IsScriptFireExtinguish(int16) { EAXJMP(0x479FC0); } -WRAPPER void CFireManager::RemoveScriptFire(int16) { EAXJMP(0x479FE0); } -WRAPPER void CFireManager::RemoveAllScriptFires(void) { EAXJMP(0x47A000); } -WRAPPER void CFireManager::SetScriptFireAudio(int16, bool) { EAXJMP(0x47A040); } +int32 +CFireManager::StartScriptFire(const CVector &pos, CEntity *target, float strength, bool propagation) +{ + CFire *fire; + CPed *ped = (CPed *)target; + CVehicle *veh = (CVehicle *)target; + + if (target) { + if (target->IsPed()) { + if (ped->m_pFire) + ped->m_pFire->Extinguish(); + } else if (target->IsVehicle()) { + if (veh->m_pCarFire) + veh->m_pCarFire->Extinguish(); + if (veh->IsCar() && ((CAutomobile *)veh)->Damage.GetEngineStatus() >= 225) { + ((CAutomobile *)veh)->Damage.SetEngineStatus(215); + } + } + } + + fire = GetNextFreeFire(); + fire->m_bIsOngoing = true; + fire->m_bIsScriptFire = true; + fire->m_bPropagationFlag = propagation; + fire->m_bAudioSet = true; + fire->m_vecPos = pos; + fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400; + fire->m_pEntity = target; + + if (target) + target->RegisterReference(&fire->m_pEntity); + fire->m_pSource = nil; + fire->m_nNextTimeToAddFlames = 0; + fire->m_fStrength = strength; + if (target) { + if (target->IsPed()) { + ped->m_pFire = fire; + if (target != (CVehicle *)FindPlayerPed()) { + CVector2D pos = target->GetPosition(); + ped->SetFlee(pos, 10000); + ped->SetMoveAnim(); + ped->m_nPedState = PED_ON_FIRE; + } + } else if (target->IsVehicle()) { + veh->m_pCarFire = fire; + } + } + return fire - m_aFires; +} + +bool +CFireManager::IsScriptFireExtinguish(int16 index) +{ + return !m_aFires[index].m_bIsOngoing; +} + +void +CFireManager::RemoveAllScriptFires(void) +{ + for (int i = 0; i < NUM_FIRES; i++) { + if (m_aFires[i].m_bIsScriptFire) { + m_aFires[i].Extinguish(); + m_aFires[i].m_bIsScriptFire = false; + } + } +} + +void +CFireManager::RemoveScriptFire(int16 index) +{ + m_aFires[index].Extinguish(); + m_aFires[index].m_bIsScriptFire = false; +} + +void +CFireManager::SetScriptFireAudio(int16 index, bool state) +{ + m_aFires[index].m_bAudioSet = state; +} STARTPATCHES - InjectHook(0x479DB0, &CFireManager::ExtinguishPoint, PATCH_JUMP); + InjectHook(0x4798D0, &CFire::ProcessFire, PATCH_JUMP); + InjectHook(0x4798B0, &CFire::ReportThisFire, PATCH_JUMP); + InjectHook(0x479D40, &CFire::Extinguish, PATCH_JUMP); + InjectHook(0x479500, (void(CFireManager::*)(CVector pos, float size, bool propagation))&CFireManager::StartFire, PATCH_JUMP); + InjectHook(0x479590, (CFire *(CFireManager::*)(CEntity *, CEntity *, float, bool))&CFireManager::StartFire, PATCH_JUMP); + InjectHook(0x479310, &CFireManager::Update, PATCH_JUMP); + InjectHook(0x479430, &CFireManager::FindFurthestFire_NeverMindFireMen, PATCH_JUMP); InjectHook(0x479340, &CFireManager::FindNearestFire, PATCH_JUMP); + InjectHook(0x4792E0, &CFireManager::GetNextFreeFire, PATCH_JUMP); + InjectHook(0x479DB0, &CFireManager::ExtinguishPoint, PATCH_JUMP); + InjectHook(0x479E60, &CFireManager::StartScriptFire, PATCH_JUMP); + InjectHook(0x479FC0, &CFireManager::IsScriptFireExtinguish, PATCH_JUMP); + InjectHook(0x47A000, &CFireManager::RemoveAllScriptFires, PATCH_JUMP); + InjectHook(0x479FE0, &CFireManager::RemoveScriptFire, PATCH_JUMP); + InjectHook(0x47A040, &CFireManager::SetScriptFireAudio, PATCH_JUMP); ENDPATCHES - diff --git a/src/core/Fire.h b/src/core/Fire.h index 624bf608..a4599d11 100644 --- a/src/core/Fire.h +++ b/src/core/Fire.h @@ -7,18 +7,22 @@ class CFire public: bool m_bIsOngoing; bool m_bIsScriptFire; - bool m_bPropogationFlag; + bool m_bPropagationFlag; bool m_bAudioSet; CVector m_vecPos; CEntity *m_pEntity; CEntity *m_pSource; - int m_nExtinguishTime; - int m_nStartTime; - int field_20; - int field_24; + uint32 m_nExtinguishTime; + uint32 m_nStartTime; + int32 field_20; + uint32 m_nNextTimeToAddFlames; uint32 m_nFiremenPuttingOut; - float field_2C; + float m_fStrength; + CFire(); + ~CFire(); + void ProcessFire(void); + void ReportThisFire(void); void Extinguish(void); }; @@ -27,20 +31,21 @@ class CFireManager enum { MAX_FIREMEN_ATTENDING = 2, }; - uint32 m_nTotalFires; public: + uint32 m_nTotalFires; CFire m_aFires[NUM_FIRES]; - void StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32); - void StartFire(CVector, float, uint8); + void StartFire(CVector pos, float size, bool propagation); + CFire *StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, bool propagation); void Update(void); - CFire *FindFurthestFire_NeverMindFireMen(CVector coors, float, float); - CFire *FindNearestFire(CVector, float*); + CFire *FindFurthestFire_NeverMindFireMen(CVector coords, float minRange, float maxRange); + CFire *FindNearestFire(CVector vecPos, float *pDistance); + CFire *GetNextFreeFire(void); uint32 GetTotalActiveFires() const; - void ExtinguishPoint(CVector, float); - int32 StartScriptFire(const CVector& pos, CEntity* culprit, float, uint8); - bool IsScriptFireExtinguish(int16); - void RemoveScriptFire(int16); + void ExtinguishPoint(CVector point, float range); + int32 StartScriptFire(const CVector &pos, CEntity *target, float strength, bool propagation); + bool IsScriptFireExtinguish(int16 index); void RemoveAllScriptFires(void); - void SetScriptFireAudio(int16, bool); + void RemoveScriptFire(int16 index); + void SetScriptFireAudio(int16 index, bool state); }; extern CFireManager &gFireManager; diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 4c2f3afa..aff8a3ec 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -181,6 +181,7 @@ ScaleAndCenterX(float x) #endif #define isPlainTextScreen(screen) (screen == MENUPAGE_BRIEFS || screen == MENUPAGE_STATS) + #ifdef PS2_LIKE_MENU #define ChangeScreen(screen, option, updateDelay, withReverseAlpha) \ do { \ @@ -235,67 +236,100 @@ ScaleAndCenterX(float x) m_nHoverOption = HOVEROPTION_NOT_HOVERING; \ } while(0) -#define ScrollUpListByOne() \ - do { \ - if (m_nSelectedListRow == m_nFirstVisibleRowOnList) { \ - if (m_nFirstVisibleRowOnList > 0) { \ - m_nSelectedListRow--; \ - m_nFirstVisibleRowOnList--; \ - m_nCurListItemY -= LIST_HEIGHT / m_nTotalListRow; \ - } \ - } else { \ - m_nSelectedListRow--; \ - } \ - } while(0) +// --- Functions not in the game/inlined starts -#define ScrollDownListByOne() \ - do { \ - if (m_nSelectedListRow == m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1) { \ - if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { \ - m_nSelectedListRow++; \ - m_nFirstVisibleRowOnList++; \ - m_nCurListItemY += LIST_HEIGHT / m_nTotalListRow; \ - } \ - } else { \ - if (m_nSelectedListRow < m_nTotalListRow - 1) { \ - m_nSelectedListRow++; \ - } \ - } \ - } while(0) +inline void +CMenuManager::ScrollUpListByOne() +{ + if (m_nSelectedListRow == m_nFirstVisibleRowOnList) { + if (m_nFirstVisibleRowOnList > 0) { + m_nSelectedListRow--; + m_nFirstVisibleRowOnList--; + m_nCurListItemY -= LIST_HEIGHT / m_nTotalListRow; + } + } else { + m_nSelectedListRow--; + } +} -#define PageUpList(playSoundOnSuccess) \ - do { \ - if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { \ - if (m_nFirstVisibleRowOnList > 0) { \ - if(playSoundOnSuccess) \ - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); \ - \ - m_nFirstVisibleRowOnList = max(0, m_nFirstVisibleRowOnList - MAX_VISIBLE_LIST_ROW); \ - m_nSelectedListRow = min(m_nSelectedListRow, m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1); \ - } else { \ - m_nFirstVisibleRowOnList = 0; \ - m_nSelectedListRow = 0; \ - } \ - m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; \ - } \ - } while(0) +inline void +CMenuManager::ScrollDownListByOne() +{ + if (m_nSelectedListRow == m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1) { + if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { + m_nSelectedListRow++; + m_nFirstVisibleRowOnList++; + m_nCurListItemY += LIST_HEIGHT / m_nTotalListRow; + } + } else { + if (m_nSelectedListRow < m_nTotalListRow - 1) { + m_nSelectedListRow++; + } + } +} -#define PageDownList(playSoundOnSuccess) \ - do { \ - if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { \ - if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { \ - if(playSoundOnSuccess) \ - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); \ - \ - m_nFirstVisibleRowOnList = min(m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW, m_nTotalListRow - MAX_VISIBLE_LIST_ROW); \ - m_nSelectedListRow = max(m_nSelectedListRow, m_nFirstVisibleRowOnList); \ - } else { \ - m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW; \ - m_nSelectedListRow = m_nTotalListRow - 1; \ - } \ - m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; \ - } \ - } while(0) +inline void +CMenuManager::PageUpList(bool playSoundOnSuccess) +{ + if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { + if (m_nFirstVisibleRowOnList > 0) { + if(playSoundOnSuccess) + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); + + m_nFirstVisibleRowOnList = max(0, m_nFirstVisibleRowOnList - MAX_VISIBLE_LIST_ROW); + m_nSelectedListRow = min(m_nSelectedListRow, m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1); + } else { + m_nFirstVisibleRowOnList = 0; + m_nSelectedListRow = 0; + } + m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; + } +} + +inline void +CMenuManager::PageDownList(bool playSoundOnSuccess) +{ + if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { + if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { + if(playSoundOnSuccess) + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); + + m_nFirstVisibleRowOnList = min(m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW, m_nTotalListRow - MAX_VISIBLE_LIST_ROW); + m_nSelectedListRow = max(m_nSelectedListRow, m_nFirstVisibleRowOnList); + } else { + m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW; + m_nSelectedListRow = m_nTotalListRow - 1; + } + m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; + } +} + +inline void +CMenuManager::ThingsToDoBeforeLeavingPage() +{ + if ((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && strcmp(m_aSkinName, m_PrefsSkinFile) != 0) { + CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile); + } else if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) { + if (m_nPrefsAudio3DProviderIndex != -1) + m_nPrefsAudio3DProviderIndex = DMAudio.GetCurrent3DProviderIndex(); +#ifdef TIDY_UP_PBP + DMAudio.StopFrontEndTrack(); + OutputDebugString("FRONTEND AUDIO TRACK STOPPED"); +#endif + } else if (m_nCurrScreen == MENUPAGE_GRAPHICS_SETTINGS) { + m_nDisplayVideoMode = m_nPrefsVideoMode; + } + + if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { + CPlayerSkin::EndFrontendSkinEdit(); + } + + if ((m_nCurrScreen == MENUPAGE_SKIN_SELECT) || (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS)) { + m_nTotalListRow = 0; + } +} + +// ------ Functions not in the game/inlined ends void CMenuManager::BuildStatLine(char *text, void *stat, uint8 aFloat, void *stat2) @@ -1173,7 +1207,6 @@ void CMenuManager::DrawFrontEnd() bbNames[5] = { "FESZ_QU",MENUPAGE_EXIT }; bbTabCount = 6; } - m_nCurrScreen = MENUPAGE_NEW_GAME; } else { if (bbTabCount != 8) { bbNames[0] = { "FEB_STA",MENUPAGE_STATS }; @@ -1186,8 +1219,8 @@ void CMenuManager::DrawFrontEnd() bbNames[7] = { "FESZ_QU",MENUPAGE_EXIT }; bbTabCount = 8; } - m_nCurrScreen = MENUPAGE_STATS; } + m_nCurrScreen = bbNames[0].screenId; bottomBarActive = true; curBottomBarOption = 0; } @@ -1285,7 +1318,6 @@ void CMenuManager::DrawFrontEndNormal() eFrontendSprites currentSprite; switch (m_nCurrScreen) { case MENUPAGE_STATS: - case MENUPAGE_NEW_GAME: case MENUPAGE_START_MENU: case MENUPAGE_PAUSE_MENU: case MENUPAGE_EXIT: @@ -1315,7 +1347,7 @@ void CMenuManager::DrawFrontEndNormal() currentSprite = FE_ICONCONTROLS; break; default: - /* actually MENUPAGE_NEW_GAME too*/ + /*case MENUPAGE_NEW_GAME: */ /*case MENUPAGE_BRIEFS: */ currentSprite = FE_ICONBRIEF; break; @@ -1324,16 +1356,16 @@ void CMenuManager::DrawFrontEndNormal() m_aFrontEndSprites[currentSprite].Draw(CRect(MENU_X_LEFT_ALIGNED(50.0f), MENU_Y(50.0f), MENU_X_RIGHT_ALIGNED(50.0f), SCREEN_SCALE_FROM_BOTTOM(95.0f)), CRGBA(255, 255, 255, m_nMenuFadeAlpha > 255 ? 255 : m_nMenuFadeAlpha)); if (m_nMenuFadeAlpha < 255) { - static int LastFade = 0; + static uint32 LastFade = 0; if (m_nMenuFadeAlpha <= 0 && reverseAlpha) { reverseAlpha = false; ChangeScreen(pendingScreen, pendingOption, true, false); - } else if(CTimer::GetTimeInMillisecondsPauseMode() - LastFade > 10){ + } else { if (!reverseAlpha) - m_nMenuFadeAlpha += 20; + m_nMenuFadeAlpha += min((CTimer::GetTimeInMillisecondsPauseMode() - LastFade) / 33.0f, 1.0f) * 20.0f; else - m_nMenuFadeAlpha = max(m_nMenuFadeAlpha - 30, 0); + m_nMenuFadeAlpha = max(0, m_nMenuFadeAlpha - min((CTimer::GetTimeInMillisecondsPauseMode() - LastFade) / 33.0f, 1.0f) * 30.0f); LastFade = CTimer::GetTimeInMillisecondsPauseMode(); } @@ -1537,12 +1569,18 @@ void CMenuManager::DrawFrontEndNormal() } if (m_nMenuFadeAlpha < 255) { - static int LastFade = 0; + static uint32 LastFade = 0; + // Famous transparent menu bug. 33.0f = 1000.f/30.f (original frame limiter fps) +#ifdef FIX_BUGS + m_nMenuFadeAlpha += min((CTimer::GetTimeInMillisecondsPauseMode() - LastFade) / 33.0f, 1.0f) * 20.0f; + LastFade = CTimer::GetTimeInMillisecondsPauseMode(); +#else if(CTimer::GetTimeInMillisecondsPauseMode() - LastFade > 10){ m_nMenuFadeAlpha += 20; LastFade = CTimer::GetTimeInMillisecondsPauseMode(); } +#endif if (m_nMenuFadeAlpha > 255){ m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); @@ -1950,7 +1988,7 @@ WRAPPER void CMenuManager::Process(void) { EAXJMP(0x485100); } #else void CMenuManager::Process(void) { - m_bMenuNotProcessed = false; + m_bMenuStateChanged = false; if (!m_bSaveMenuActive && TheCamera.GetScreenFadeStatus() != FADE_0) return; @@ -2701,6 +2739,8 @@ CMenuManager::ProcessButtonPresses(void) if (CPad::GetPad(0)->GetEnterJustDown() || CPad::GetPad(0)->GetCrossJustDown()) { DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); bottomBarActive = false; + + // If there's a menu change with fade ongoing, finish it now if (reverseAlpha) m_nMenuFadeAlpha = 0; return; @@ -3116,51 +3156,43 @@ CMenuManager::ProcessButtonPresses(void) if (goBack) { CMenuManager::ResetHelperText(); DMAudio.PlayFrontEndSound(SOUND_FRONTEND_EXIT, 0); - if (m_nCurrScreen == MENUPAGE_PAUSE_MENU && !m_bGameNotLoaded && !m_bMenuNotProcessed){ - if (CMenuManager::m_PrefsVsyncDisp != CMenuManager::m_PrefsVsync) { - CMenuManager::m_PrefsVsync = CMenuManager::m_PrefsVsyncDisp; - } - CMenuManager::RequestFrontEndShutDown(); - } else if (m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT -#ifdef PS2_SAVE_DIALOG - || m_nCurrScreen == MENUPAGE_SAVE -#endif - ) { - CMenuManager::RequestFrontEndShutDown(); - } else if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) { - DMAudio.StopFrontEndTrack(); - OutputDebugString("FRONTEND AUDIO TRACK STOPPED"); - } - - int oldScreen = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_PreviousPage[1] : aScreens[m_nCurrScreen].m_PreviousPage[0]; - int oldOption = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_ParentEntry[1] : aScreens[m_nCurrScreen].m_ParentEntry[0]; - #ifdef PS2_LIKE_MENU - if (bottomBarActive){ - bottomBarActive = false; - if (!m_bGameNotLoaded) { + if (m_nCurrScreen == MENUPAGE_PAUSE_MENU || bottomBarActive) { +#else + if (m_nCurrScreen == MENUPAGE_PAUSE_MENU) { +#endif + if (!m_bGameNotLoaded && !m_bMenuStateChanged) { if (CMenuManager::m_PrefsVsyncDisp != CMenuManager::m_PrefsVsync) { CMenuManager::m_PrefsVsync = CMenuManager::m_PrefsVsyncDisp; } CMenuManager::RequestFrontEndShutDown(); } + + // We're already resuming, we don't need further processing. +#if defined(FIX_BUGS) || defined(PS2_LIKE_MENU) return; +#endif + } +#ifdef PS2_LIKE_MENU + else if (m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT || m_nCurrScreen == MENUPAGE_SAVE) { +#else + else if (m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT) { +#endif + CMenuManager::RequestFrontEndShutDown(); + } + // It's now in ThingsToDoBeforeLeavingPage() +#ifndef TIDY_UP_PBP + else if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) { + DMAudio.StopFrontEndTrack(); + OutputDebugString("FRONTEND AUDIO TRACK STOPPED"); } #endif + int oldScreen = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_PreviousPage[1] : aScreens[m_nCurrScreen].m_PreviousPage[0]; + int oldOption = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_ParentEntry[1] : aScreens[m_nCurrScreen].m_ParentEntry[0]; + if (oldScreen != -1) { - if ((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && strcmp(m_aSkinName, m_PrefsSkinFile) != 0) { - CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile); - } - if ((m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) && (m_nPrefsAudio3DProviderIndex != -1)) { - m_nPrefsAudio3DProviderIndex = DMAudio.GetCurrent3DProviderIndex(); - } - if (m_nCurrScreen == MENUPAGE_GRAPHICS_SETTINGS) { - m_nDisplayVideoMode = m_nPrefsVideoMode; - } - if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { - CPlayerSkin::EndFrontendSkinEdit(); - } + ThingsToDoBeforeLeavingPage(); #ifdef PS2_LIKE_MENU if (!bottomBarActive && @@ -3168,10 +3200,8 @@ CMenuManager::ProcessButtonPresses(void) bottomBarActive = true; } else #endif + { ChangeScreen(oldScreen, oldOption, true, true); - - if ((m_nPrevScreen == MENUPAGE_SKIN_SELECT) || (m_nPrevScreen == MENUPAGE_KEYBOARD_CONTROLS)) { - m_nTotalListRow = 0; } // We will go back for sure at this point, why process other things?! @@ -3512,11 +3542,16 @@ WRAPPER void CMenuManager::SwitchMenuOnAndOff() { EAXJMP(0x488790); } #else void CMenuManager::SwitchMenuOnAndOff() { - if (!!(CPad::GetPad(0)->NewState.Start && !CPad::GetPad(0)->OldState.Start) - || m_bShutDownFrontEndRequested || m_bStartUpFrontEndRequested) { + bool menuWasActive = !!m_bMenuActive; - if (!m_bMenuActive) - m_bMenuActive = true; + // Reminder: You need REGISTER_START_BUTTON defined to make it work. + if (CPad::GetPad(0)->GetStartJustDown() +#ifdef FIX_BUGS + && !m_bGameNotLoaded +#endif + || m_bShutDownFrontEndRequested || m_bStartUpFrontEndRequested) { + + m_bMenuActive = !m_bMenuActive; if (m_bShutDownFrontEndRequested) m_bMenuActive = false; @@ -3525,8 +3560,13 @@ void CMenuManager::SwitchMenuOnAndOff() if (m_bMenuActive) { CTimer::StartUserPause(); - } - else { + } else { +#ifdef PS2_LIKE_MENU + bottomBarActive = false; +#endif +#ifdef FIX_BUGS + ThingsToDoBeforeLeavingPage(); +#endif ShutdownJustMenu(); SaveSettings(); m_bStartUpFrontEndRequested = false; @@ -3553,7 +3593,7 @@ void CMenuManager::SwitchMenuOnAndOff() PcSaveHelper.PopulateSlotInfo(); m_nCurrOption = 0; } -/* // Unused? +/* // PS2 leftover? if (m_nCurrScreen != MENUPAGE_SOUND_SETTINGS && gMusicPlaying) { DMAudio.StopFrontEndTrack(); @@ -3561,8 +3601,8 @@ void CMenuManager::SwitchMenuOnAndOff() gMusicPlaying = 0; } */ - if (!m_bMenuActive) - m_bMenuNotProcessed = true; + if (m_bMenuActive != menuWasActive) + m_bMenuStateChanged = true; m_bStartUpFrontEndRequested = false; m_bShutDownFrontEndRequested = false; diff --git a/src/core/Frontend.h b/src/core/Frontend.h index 6d7327d3..3dbed164 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -403,7 +403,7 @@ public: int32 m_nHelperTextMsgId; bool m_bLanguageLoaded; bool m_bMenuActive; - bool m_bMenuNotProcessed; + bool m_bMenuStateChanged; bool m_bWaitingForNewKeyBind; bool m_bStartGameLoading; bool m_bFirstTime; @@ -540,8 +540,14 @@ public: void WaitForUserCD(); void PrintController(); - // New content: - uint8 GetNumberOfMenuOptions(); + // New (not in function or inlined in the game) + void ThingsToDoBeforeLeavingPage(); + void ScrollUpListByOne(); + void ScrollDownListByOne(); + void PageUpList(bool); + void PageDownList(bool); + + // uint8 GetNumberOfMenuOptions(); }; static_assert(sizeof(CMenuManager) == 0x564, "CMenuManager: error"); diff --git a/src/core/General.h b/src/core/General.h index a7b240c2..f32846eb 100644 --- a/src/core/General.h +++ b/src/core/General.h @@ -1,5 +1,7 @@ #pragma once +#include <ctype.h> + class CGeneral { public: diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index 51102c7b..87f45b9f 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -5,6 +5,10 @@ #pragma warning( pop ) #include "common.h" +#ifdef XINPUT +#include <Xinput.h> +#pragma comment( lib, "Xinput9_1_0.lib" ) +#endif #include "patcher.h" #include "Pad.h" #include "ControllerConfig.h" @@ -547,12 +551,78 @@ void CPad::AddToPCCheatString(char c) #undef _CHEATCMP } +#ifdef XINPUT +void CPad::AffectFromXinput(uint32 pad) +{ + XINPUT_STATE xstate; + memset(&xstate, 0, sizeof(XINPUT_STATE)); + if (XInputGetState(pad, &xstate) == ERROR_SUCCESS) + { + PCTempJoyState.Circle = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_B) ? 255 : 0; + PCTempJoyState.Cross = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_A) ? 255 : 0; + PCTempJoyState.Square = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_X) ? 255 : 0; + PCTempJoyState.Triangle = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_Y) ? 255 : 0; + PCTempJoyState.DPadDown = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) ? 255 : 0; + PCTempJoyState.DPadLeft = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) ? 255 : 0; + PCTempJoyState.DPadRight = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) ? 255 : 0; + PCTempJoyState.DPadUp = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) ? 255 : 0; + PCTempJoyState.LeftShock = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) ? 255 : 0; + PCTempJoyState.LeftShoulder1 = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) ? 255 : 0; + PCTempJoyState.LeftShoulder2 = xstate.Gamepad.bLeftTrigger; + PCTempJoyState.RightShock = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) ? 255 : 0; + PCTempJoyState.RightShoulder1 = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) ? 255 : 0; + PCTempJoyState.RightShoulder2 = xstate.Gamepad.bRightTrigger; + + PCTempJoyState.Select = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) ? 255 : 0; + PCTempJoyState.Start = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_START) ? 255 : 0; + + float lx = (float)xstate.Gamepad.sThumbLX / (float)0x7FFF; + float ly = (float)xstate.Gamepad.sThumbLY / (float)0x7FFF; + float rx = (float)xstate.Gamepad.sThumbRX / (float)0x7FFF; + float ry = (float)xstate.Gamepad.sThumbRY / (float)0x7FFF; + + if (Abs(lx) > 0.3f || Abs(ly) > 0.3f) { + PCTempJoyState.LeftStickX = (int32)(lx * 128.0f); + PCTempJoyState.LeftStickY = (int32)(-ly * 128.0f); + } + + if (Abs(rx) > 0.3f || Abs(ry) > 0.3f) { + PCTempJoyState.RightStickX = (int32)(rx * 128.0f); + PCTempJoyState.RightStickY = (int32)(ry * 128.0f); + } + + XINPUT_VIBRATION VibrationState; + + memset(&VibrationState, 0, sizeof(XINPUT_VIBRATION)); + + uint16 iLeftMotor = (uint16)((float)ShakeFreq / 255.0f * (float)0xffff); + uint16 iRightMotor = (uint16)((float)ShakeFreq / 255.0f * (float)0xffff); + + if (ShakeDur < CTimer::GetTimeStepInMilliseconds()) + ShakeDur = 0; + else + ShakeDur -= CTimer::GetTimeStepInMilliseconds(); + if (ShakeDur == 0) ShakeFreq = 0; + + VibrationState.wLeftMotorSpeed = iLeftMotor; + VibrationState.wRightMotorSpeed = iRightMotor; + + XInputSetState(pad, &VibrationState); + } +} +#endif + void CPad::UpdatePads(void) { bool bUpdate = true; GetPad(0)->UpdateMouse(); +#ifdef XINPUT + GetPad(0)->AffectFromXinput(0); + GetPad(1)->AffectFromXinput(1); +#else CapturePad(0); +#endif ControlsManager.ClearSimButtonPressCheckers(); @@ -565,10 +635,13 @@ void CPad::UpdatePads(void) if ( bUpdate ) { GetPad(0)->Update(0); + GetPad(1)->Update(0); } - + +#if defined(MASTER) && !defined(XINPUT) GetPad(1)->NewState.Clear(); GetPad(1)->OldState.Clear(); +#endif OldKeyState = NewKeyState; NewKeyState = TempKeyState; diff --git a/src/core/Pad.h b/src/core/Pad.h index a231900e..84919f32 100644 --- a/src/core/Pad.h +++ b/src/core/Pad.h @@ -247,6 +247,10 @@ public: static char *EditString(char *pStr, int32 nSize); static int32 *EditCodesForControls(int32 *pRsKeys, int32 nSize); +#ifdef XINPUT + void AffectFromXinput(uint32 pad); +#endif + // mouse bool GetLeftMouseJustDown() { return !!(NewMouseControllerState.LMB && !OldMouseControllerState.LMB); } bool GetRightMouseJustDown() { return !!(NewMouseControllerState.RMB && !OldMouseControllerState.RMB); } @@ -399,6 +403,8 @@ public: bool GetLeftShoulder2JustDown() { return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); } bool GetRightShoulder1JustDown() { return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); } bool GetRightShoulder2JustDown() { return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); } + bool GetLeftShockJustDown() { return !!(NewState.LeftShock && !OldState.LeftShock); } + bool GetRightShockJustDown() { return !!(NewState.RightShock && !OldState.RightShock); } bool GetStartJustDown() { return !!(NewState.Start && !OldState.Start); } bool GetLeftStickXJustDown() { return !!(NewState.LeftStickX && !OldState.LeftStickX); } bool GetLeftStickYJustDown() { return !!(NewState.LeftStickY && !OldState.LeftStickY); } @@ -422,6 +428,10 @@ public: bool GetLeftShoulder2(void) { return !!NewState.LeftShoulder2; } bool GetRightShoulder1(void) { return !!NewState.RightShoulder1; } bool GetRightShoulder2(void) { return !!NewState.RightShoulder2; } + int16 GetLeftStickX(void) { return NewState.LeftStickX; } + int16 GetLeftStickY(void) { return NewState.LeftStickY; } + int16 GetRightStickX(void) { return NewState.RightStickX; } + int16 GetRightStickY(void) { return NewState.RightStickY; } bool ArePlayerControlsDisabled(void) { return DisablePlayerControls != PLAYERCONTROL_ENABLED; } void SetDisablePlayerControls(uint8 who) { DisablePlayerControls |= who; } diff --git a/src/core/Placeable.cpp b/src/core/Placeable.cpp index d2cec82b..c882fc27 100644 --- a/src/core/Placeable.cpp +++ b/src/core/Placeable.cpp @@ -63,6 +63,8 @@ CPlaceable::IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z1 <= GetPosition().z && GetPosition().z <= z2; } +#include <new> + class CPlaceable_ : public CPlaceable { public: diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index 3a830d37..6106f3df 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -198,7 +198,7 @@ CStreaming::Init(void) // PC only, figure out how much memory we got #ifdef GTA_PC #define MB (1024*1024) - extern DWORD &_dwMemAvailPhys; + extern unsigned long &_dwMemAvailPhys; ms_memoryAvailable = (_dwMemAvailPhys - 10*MB)/2; if(ms_memoryAvailable < 50*MB) ms_memoryAvailable = 50*MB; diff --git a/src/core/Timer.h b/src/core/Timer.h index 89c4a430..ef525be7 100644 --- a/src/core/Timer.h +++ b/src/core/Timer.h @@ -2,7 +2,7 @@ class CTimer { -public: + static uint32 &m_snTimeInMilliseconds; static uint32 &m_snTimeInMillisecondsPauseMode; static uint32 &m_snTimeInMillisecondsNonClipped; @@ -11,19 +11,20 @@ public: static float &ms_fTimeScale; static float &ms_fTimeStep; static float &ms_fTimeStepNonClipped; +public: static bool &m_UserPause; static bool &m_CodePause; - static float GetTimeStep(void) { return ms_fTimeStep; } + static const float &GetTimeStep(void) { return ms_fTimeStep; } static void SetTimeStep(float ts) { ms_fTimeStep = ts; } static float GetTimeStepInSeconds() { return ms_fTimeStep / 50.0f; } static float GetTimeStepInMilliseconds() { return ms_fTimeStep / 50.0f * 1000.0f; } - static float GetTimeStepNonClipped(void) { return ms_fTimeStepNonClipped; } + static const float &GetTimeStepNonClipped(void) { return ms_fTimeStepNonClipped; } static float GetTimeStepNonClippedInSeconds(void) { return ms_fTimeStepNonClipped / 50.0f; } static void SetTimeStepNonClipped(float ts) { ms_fTimeStepNonClipped = ts; } - static uint32 GetFrameCounter(void) { return m_FrameCounter; } + static const uint32 &GetFrameCounter(void) { return m_FrameCounter; } static void SetFrameCounter(uint32 fc) { m_FrameCounter = fc; } - static uint32 GetTimeInMilliseconds(void) { return m_snTimeInMilliseconds; } + static const uint32 &GetTimeInMilliseconds(void) { return m_snTimeInMilliseconds; } static void SetTimeInMilliseconds(uint32 t) { m_snTimeInMilliseconds = t; } static uint32 GetTimeInMillisecondsNonClipped(void) { return m_snTimeInMillisecondsNonClipped; } static void SetTimeInMillisecondsNonClipped(uint32 t) { m_snTimeInMillisecondsNonClipped = t; } @@ -31,7 +32,7 @@ public: static void SetTimeInMillisecondsPauseMode(uint32 t) { m_snTimeInMillisecondsPauseMode = t; } static uint32 GetPreviousTimeInMilliseconds(void) { return m_snPreviousTimeInMilliseconds; } static void SetPreviousTimeInMilliseconds(uint32 t) { m_snPreviousTimeInMilliseconds = t; } - static float GetTimeScale(void) { return ms_fTimeScale; } + static const float &GetTimeScale(void) { return ms_fTimeScale; } static void SetTimeScale(float ts) { ms_fTimeScale = ts; } static bool GetIsPaused() { return m_UserPause || m_CodePause; } diff --git a/src/core/World.cpp b/src/core/World.cpp index 1832ce72..769bd9ad 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -20,11 +20,12 @@ #include "Replay.h" #include "Population.h" +CColPoint *gaTempSphereColPoints = (CColPoint*)0x6E64C0; // [32] + 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; -CColPoint &CWorld::ms_testSpherePoint = *(CColPoint*)0x6E64C0; uint8 &CWorld::PlayerInFocus = *(uint8 *)0x95CD61; CPlayerInfo (&CWorld::Players)[NUMPLAYERS] = *(CPlayerInfo (*)[NUMPLAYERS])*(uintptr*)0x9412F0; @@ -610,9 +611,9 @@ CWorld::GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bo } void -CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector ¢re, float distance, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects) +CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector ¢re, float radius, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects) { - float distSqr = distance * distance; + float radiusSqr = radius * radius; float objDistSqr; for (CPtrNode *node = list.first; node; node = node->next) { @@ -626,7 +627,7 @@ CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector ¢re, float dist else objDistSqr = diff.MagnitudeSqr(); - if (objDistSqr < distSqr && *nextObject < lastObject) { + if (objDistSqr < radiusSqr && *nextObject < lastObject) { if (objects) { objects[*nextObject] = object; } @@ -637,22 +638,22 @@ CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector ¢re, float dist } void -CWorld::FindObjectsInRange(CVector ¢re, float distance, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies) +CWorld::FindObjectsInRange(CVector ¢re, float radius, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies) { - int minX = GetSectorIndexX(centre.x - distance); + int minX = GetSectorIndexX(centre.x - radius); if (minX <= 0) minX = 0; - int minY = GetSectorIndexY(centre.y - distance); + int minY = GetSectorIndexY(centre.y - radius); if (minY <= 0) minY = 0; - int maxX = GetSectorIndexX(centre.x + distance); + int maxX = GetSectorIndexX(centre.x + radius); #ifdef FIX_BUGS if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1; #else if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X; #endif - int maxY = GetSectorIndexY(centre.y + distance); + int maxY = GetSectorIndexY(centre.y + radius); #ifdef FIX_BUGS if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1; #else @@ -666,48 +667,48 @@ CWorld::FindObjectsInRange(CVector ¢re, float distance, bool ignoreZ, short for(int curX = minX; curX <= maxX; curX++) { CSector *sector = GetSector(curX, curY); if (checkBuildings) { - FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, ignoreZ, nextObject, lastObject, objects); - FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, radius, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects); } if (checkVehicles) { - FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, ignoreZ, nextObject, lastObject, objects); - FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, radius, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects); } if (checkPeds) { - FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, ignoreZ, nextObject, lastObject, objects); - FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, radius, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects); } if (checkObjects) { - FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, ignoreZ, nextObject, lastObject, objects); - FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, radius, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects); } if (checkDummies) { - FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, ignoreZ, nextObject, lastObject, objects); - FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, radius, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects); } } } } CEntity* -CWorld::TestSphereAgainstWorld(CVector centre, float distance, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects) +CWorld::TestSphereAgainstWorld(CVector centre, float radius, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects) { CEntity* foundE = nil; - int minX = GetSectorIndexX(centre.x - distance); + int minX = GetSectorIndexX(centre.x - radius); if (minX <= 0) minX = 0; - int minY = GetSectorIndexY(centre.y - distance); + int minY = GetSectorIndexY(centre.y - radius); if (minY <= 0) minY = 0; - int maxX = GetSectorIndexX(centre.x + distance); + int maxX = GetSectorIndexX(centre.x + radius); #ifdef FIX_BUGS if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1; #else if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X; #endif - int maxY = GetSectorIndexY(centre.y + distance); + int maxY = GetSectorIndexY(centre.y + radius); #ifdef FIX_BUGS if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1; #else @@ -720,47 +721,47 @@ CWorld::TestSphereAgainstWorld(CVector centre, float distance, CEntity *entityTo for (int curX = minX; curX <= maxX; curX++) { CSector* sector = GetSector(curX, curY); if (checkBuildings) { - foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, entityToIgnore, false); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, radius, entityToIgnore, false); if (foundE) return foundE; - foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, entityToIgnore, false); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, radius, entityToIgnore, false); if (foundE) return foundE; } if (checkVehicles) { - foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, entityToIgnore, false); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, radius, entityToIgnore, false); if (foundE) return foundE; - foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, entityToIgnore, false); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, radius, entityToIgnore, false); if (foundE) return foundE; } if (checkPeds) { - foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, entityToIgnore, false); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, radius, entityToIgnore, false); if (foundE) return foundE; - foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, entityToIgnore, false); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, radius, entityToIgnore, false); if (foundE) return foundE; } if (checkObjects) { - foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, entityToIgnore, ignoreSomeObjects); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, radius, entityToIgnore, ignoreSomeObjects); if (foundE) return foundE; - foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, entityToIgnore, ignoreSomeObjects); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, radius, entityToIgnore, ignoreSomeObjects); if (foundE) return foundE; } if (checkDummies) { - foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, entityToIgnore, false); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, radius, entityToIgnore, false); if (foundE) return foundE; - foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, entityToIgnore, false); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, radius, entityToIgnore, false); if (foundE) return foundE; } @@ -807,7 +808,7 @@ CWorld::TestSphereAgainstSectorList(CPtrList &list, CVector spherePos, float rad if (e->GetBoundRadius() + radius > distance) { CColModel *eCol = CModelInfo::GetModelInfo(e->m_modelIndex)->GetColModel(); int collidedSpheres = CCollision::ProcessColModels(sphereMat, sphereCol, e->GetMatrix(), - *eCol, &ms_testSpherePoint, nil, nil); + *eCol, gaTempSphereColPoints, nil, nil); if (collidedSpheres != 0 || (e->IsVehicle() && ((CVehicle*)e)->m_vehType == VEHICLE_TYPE_CAR && diff --git a/src/core/World.h b/src/core/World.h index 75d17a71..3fcbc301 100644 --- a/src/core/World.h +++ b/src/core/World.h @@ -60,8 +60,6 @@ class CWorld static uint16 &ms_nCurrentScanCode; public: - static CColPoint& ms_testSpherePoint; - static uint8 &PlayerInFocus; static CPlayerInfo (&Players)[NUMPLAYERS]; static CEntity *&pIgnoreEntity; @@ -101,7 +99,7 @@ public: static bool GetIsLineOfSightSectorClear(CSector §or, const CColLine &line, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false); static bool GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bool ignoreSeeThrough, bool ignoreSomeObjects = false); - static CEntity *TestSphereAgainstWorld(CVector centre, float distance, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects); + static CEntity *TestSphereAgainstWorld(CVector centre, float radius, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects); static CEntity *TestSphereAgainstSectorList(CPtrList&, CVector, float, CEntity*, bool); static void FindObjectsInRangeSectorList(CPtrList&, CVector&, float, bool, short*, short, CEntity**); static void FindObjectsInRange(CVector&, float, bool, short*, short, CEntity**, bool, bool, bool, bool, bool); @@ -142,6 +140,8 @@ public: static void Process(); }; +extern CColPoint *gaTempSphereColPoints; + class CPlayerPed; class CVehicle; CPlayerPed *FindPlayerPed(void); diff --git a/src/core/Zones.cpp b/src/core/Zones.cpp index 363fc3d9..4bce3e79 100644 --- a/src/core/Zones.cpp +++ b/src/core/Zones.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include <ctype.h> #include "Zones.h" diff --git a/src/core/common.h b/src/core/common.h index 3127cb12..7b4ff4a0 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -8,9 +8,12 @@ #pragma warning(disable: 4996) // POSIX names #include <stdint.h> +#include <string.h> #include <math.h> -//#include <assert.h> -#include <new> + +#ifdef WITHWINDOWS +#include <Windows.h> +#endif #ifdef WITHD3D #include <windows.h> @@ -30,6 +33,16 @@ #undef near #endif +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a))) +#endif + typedef uint8_t uint8; typedef int8_t int8; typedef uint16_t uint16; diff --git a/src/core/config.h b/src/core/config.h index 54a4c25f..d4e85f7c 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -101,6 +101,8 @@ enum Config { NUMPEDGROUPS = 31, NUMMODELSPERPEDGROUP = 8, + NUMROADBLOCKS = 600, + NUMVISIBLEENTITIES = 2000, NUMINVISIBLEENTITIES = 150, @@ -171,10 +173,12 @@ enum Config { #endif #define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more -#define TOGGLEABLE_BETA_FEATURES // toggleable from debug menu. doesn't have too many things +#define TOGGLEABLE_BETA_FEATURES // toggleable from debug menu. not too many things // Pad +#define XINPUT #define KANGAROO_CHEAT +#define REGISTER_START_BUTTON // currently only in menu sadly. resumes the game // Hud, frontend and radar #define ASPECT_RATIO_SCALE // Not just makes everything scale with aspect ratio, also adds support for all aspect ratios @@ -201,5 +205,7 @@ enum Config { // Peds #define ANIMATE_PED_COL_MODEL #define VC_PED_PORTS // various ports from VC's CPed, mostly subtle -#define NEW_WALK_AROUND_ALGORITHM // to make walking around vehicles/objects less awkward +// #define NEW_WALK_AROUND_ALGORITHM // to make walking around vehicles/objects less awkward #define CANCELLABLE_CAR_ENTER + +#define IMPROVED_CAMERA // Better Debug cam, and maybe more in the future diff --git a/src/core/main.cpp b/src/core/main.cpp index 2a15e20e..663b09da 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -325,6 +325,7 @@ DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 void DoRWStuffEndOfFrame(void) { + CDebug::DisplayScreenStrings(); // custom CDebug::DebugDisplayTextBuffer(); // FlushObrsPrintfs(); RwCameraEndUpdate(Scene.camera); diff --git a/src/core/patcher.h b/src/core/patcher.h index 87a6bea4..3dfbb05c 100644 --- a/src/core/patcher.h +++ b/src/core/patcher.h @@ -6,13 +6,7 @@ #define VARJMP(a) { _asm jmp a } #define WRAPARG(a) UNREFERENCED_PARAMETER(a) -#define NOVMT __declspec(novtable) -#define SETVMT(a) *((DWORD_PTR*)this) = (DWORD_PTR)a - -#include <algorithm> -#include <vector> - -#include "common.h" +#include <string.h> //memset enum { @@ -103,72 +97,36 @@ isVC(void) InjectHook(a, func); \ } +void InjectHook_internal(uint32 address, uint32 hook, int type); +void Protect_internal(uint32 address, uint32 size); +void Unprotect_internal(void); + 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]); + Protect_internal((uint32)address, sizeof(T)); *(T*)address = value; - VirtualProtect((void*)address, sizeof(T), dwProtect[0], &dwProtect[1]); + Unprotect_internal(); } template<typename AT> inline void Nop(AT address, unsigned int nCount) { - DWORD dwProtect[2]; - VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + Protect_internal((uint32)address, nCount); memset((void*)address, 0x90, nCount); - VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]); -} - -template<typename AT> inline void -ClearCC(AT address, unsigned int nCount) -{ - DWORD dwProtect[2]; - VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]); - memset((void*)address, 0xCC, nCount); - VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]); + Unprotect_internal(); } -extern std::vector<int32> usedAddresses; - template<typename AT, typename HT> inline void InjectHook(AT address, HT hook, unsigned int nType=PATCH_NOTHING) { - if(std::any_of(usedAddresses.begin(), usedAddresses.end(), - [address](AT value) { return (int32)value == address; })) { - debug("Used address %#06x twice when injecting hook\n", address); - } - - usedAddresses.push_back((int32)address); - - DWORD dwProtect[2]; - switch ( nType ) - { - case PATCH_JUMP: - VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); - *(BYTE*)address = 0xE9; - break; - case PATCH_CALL: - VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); - *(BYTE*)address = 0xE8; - break; - default: - VirtualProtect((void*)((DWORD)address + 1), 4, PAGE_EXECUTE_READWRITE, &dwProtect[0]); - break; - } - DWORD dwHook; + uint32 uiHook; _asm { mov eax, hook - mov dwHook, eax + mov uiHook, 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]); + InjectHook_internal((uint32)address, uiHook, nType); } inline void ExtractCall(void *dst, uint32_t a) diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 6f0a4682..137a890c 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -20,12 +20,64 @@ #include "debugmenu_public.h" #include "Particle.h" #include "Console.h" +#include "Debug.h" +#include <algorithm> #include <vector> #include <list> std::vector<int32> usedAddresses; +static DWORD protect[2]; +static uint32 protect_address; +static uint32 protect_size; + +void +Protect_internal(uint32 address, uint32 size) +{ + protect_address = address; + protect_size = size; + VirtualProtect((void*)address, size, PAGE_EXECUTE_READWRITE, &protect[0]); +} + +void +Unprotect_internal(void) +{ + VirtualProtect((void*)protect_address, protect_size, protect[0], &protect[1]); +} + +void +InjectHook_internal(uint32 address, uint32 hook, int type) +{ + if(std::any_of(usedAddresses.begin(), usedAddresses.end(), + [address](uint32 value) { return (int32)value == address; })) { + debug("Used address %#06x twice when injecting hook\n", address); + } + + usedAddresses.push_back((int32)address); + + + switch(type){ + case PATCH_JUMP: + VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &protect[0]); + *(uint8*)address = 0xE9; + break; + case PATCH_CALL: + VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &protect[0]); + *(uint8*)address = 0xE8; + break; + default: + VirtualProtect((void*)((uint32)address + 1), 4, PAGE_EXECUTE_READWRITE, &protect[0]); + break; + } + + *(ptrdiff_t*)(address + 1) = hook - address - 5; + if(type == PATCH_NOTHING) + VirtualProtect((void*)(address + 1), 4, protect[0], &protect[1]); + else + VirtualProtect((void*)address, 5, protect[0], &protect[1]); +} + void **rwengine = *(void***)0x5A10E1; DebugMenuAPI gDebugMenuAPI; @@ -114,13 +166,16 @@ SpawnCar(int id) CStreaming::LoadAllRequestedModels(false); if(CStreaming::HasModelLoaded(id)){ playerpos = FindPlayerCoors(); - int node = ThePaths.FindNodeClosestToCoors(playerpos, 0, 100.0f, false, false); - if(node < 0) - return; + int node; + if(!CModelInfo::IsBoatModel(id)){ + node = ThePaths.FindNodeClosestToCoors(playerpos, 0, 100.0f, false, false); + if(node < 0) + return; + } CVehicle *v; if(CModelInfo::IsBoatModel(id)) - return; + v = new CBoat(id, RANDOM_VEHICLE); else v = new CAutomobile(id, RANDOM_VEHICLE); @@ -130,7 +185,11 @@ SpawnCar(int id) if(carCol2) DebugMenuEntrySetAddress(carCol2, &v->m_currentColour2); - v->GetPosition() = ThePaths.m_pathNodes[node].pos; + if(CModelInfo::IsBoatModel(id)) + v->GetPosition() = TheCamera.GetPosition() + TheCamera.GetForward()*15.0f; + else + v->GetPosition() = ThePaths.m_pathNodes[node].pos; + v->GetPosition().z += 4.0f; v->SetOrientation(0.0f, 0.0f, 3.49f); v->m_status = STATUS_ABANDONED; @@ -197,6 +256,12 @@ PlaceOnRoad(void) ((CAutomobile*)veh)->PlaceOnRoadProperly(); } +static void +ResetCamStatics(void) +{ + TheCamera.Cams[TheCamera.ActiveCam].ResetStatics = true; +} + static const char *carnames[] = { "landstal", "idaho", "stinger", "linerun", "peren", "sentinel", "patriot", "firetruk", "trash", "stretch", "manana", "infernus", "blista", "pony", "mule", "cheetah", "ambulan", "fbicar", "moonbeam", "esperant", "taxi", "kuruma", "bobcat", "mrwhoop", "bfinject", "corpse", "police", "enforcer", @@ -358,7 +423,17 @@ DebugMenuPopulate(void) DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start); DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop); - + + extern bool PrintDebugCode; + extern int16 &DebugCamMode; + DebugMenuAddVarBool8("Cam", "Print Debug Code", (int8*)&PrintDebugCode, nil); + DebugMenuAddVar("Cam", "Cam Mode", &DebugCamMode, nil, 1, 0, CCam::MODE_EDITOR, nil); + DebugMenuAddCmd("Cam", "Normal", []() { DebugCamMode = 0; }); + DebugMenuAddCmd("Cam", "Follow Ped With Bind", []() { DebugCamMode = CCam::MODE_FOLLOW_PED_WITH_BIND; }); + DebugMenuAddCmd("Cam", "Reaction", []() { DebugCamMode = CCam::MODE_REACTION; }); + DebugMenuAddCmd("Cam", "Chris", []() { DebugCamMode = CCam::MODE_CHRIS; }); + DebugMenuAddCmd("Cam", "Reset Statics", ResetCamStatics); + CTweakVars::AddDBG("Debug"); } } @@ -433,7 +508,8 @@ void re3_debug(const char *format, ...) vsprintf_s(re3_buff, re3_buffsize, format, va); va_end(va); - printf("%s", re3_buff); +// printf("%s", re3_buff); + CDebug::DebugAddText(re3_buff); } void re3_trace(const char *filename, unsigned int lineno, const char *func, const char *format, ...) diff --git a/src/entities/Building.cpp b/src/entities/Building.cpp index 188cbfe7..7813c87f 100644 --- a/src/entities/Building.cpp +++ b/src/entities/Building.cpp @@ -21,6 +21,8 @@ CBuilding::ReplaceWithNewModel(int32 id) CStreaming::RequestModel(id, STREAMFLAGS_DONT_REMOVE); } +#include <new> + class CBuilding_ : public CBuilding { public: diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index 04a93420..8bec1ac8 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -865,6 +865,8 @@ CEntity::ModifyMatrixForBannerInWind(void) UpdateRwFrame(); } +#include <new> + class CEntity_ : public CEntity { public: diff --git a/src/objects/DummyObject.cpp b/src/objects/DummyObject.cpp index 9649cf7a..ba09ac3e 100644 --- a/src/objects/DummyObject.cpp +++ b/src/objects/DummyObject.cpp @@ -12,6 +12,8 @@ CDummyObject::CDummyObject(CObject *obj) m_level = obj->m_level; } +#include <new> + class CDummyObject_ : public CDummyObject { public: diff --git a/src/objects/Object.cpp b/src/objects/Object.cpp index 357d67d7..809ba971 100644 --- a/src/objects/Object.cpp +++ b/src/objects/Object.cpp @@ -141,6 +141,8 @@ CObject::CanBeDeleted(void) } } +#include <new> + class CObject_ : public CObject { public: diff --git a/src/objects/Projectile.cpp b/src/objects/Projectile.cpp index 0f6542e7..32bc6bdb 100644 --- a/src/objects/Projectile.cpp +++ b/src/objects/Projectile.cpp @@ -14,6 +14,8 @@ CProjectile::CProjectile(int32 model) : CObject() ObjectCreatedBy = MISSION_OBJECT; } +#include <new> + class CProjectile_ : public CProjectile { public: diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp index bb61e086..2e6166be 100644 --- a/src/peds/CivilianPed.cpp +++ b/src/peds/CivilianPed.cpp @@ -377,6 +377,8 @@ CCivilianPed::ProcessControl(void) Avoid(); } +#include <new> + class CCivilianPed_ : public CCivilianPed { public: diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp index 53ae1747..94acac05 100644 --- a/src/peds/CopPed.cpp +++ b/src/peds/CopPed.cpp @@ -7,8 +7,11 @@ #include "Vehicle.h" #include "RpAnimBlend.h" #include "General.h" +#include "ZoneCull.h" +#include "PathFind.h" +#include "RoadBlocks.h" -WRAPPER void CCopPed::ProcessControl() { EAXJMP(0x4C1400); } +WRAPPER void CCopPed::ProcessControl() { EAXJMP(0x4C1400); } CCopPed::CCopPed(eCopType copType) : CPed(PEDTYPE_COP) { @@ -58,11 +61,16 @@ CCopPed::CCopPed(eCopType copType) : CPed(PEDTYPE_COP) m_bIsDisabledCop = false; field_1356 = 0; m_attackTimer = 0; - field_1351 = 0; + m_bBeatingSuspect = false; m_bZoneDisabledButClose = false; m_bZoneDisabled = false; field_1364 = -1; m_pPointGunAt = nil; + + // VC also initializes in here, but it keeps object +#ifdef FIX_BUGS + m_wRoadblockNode = -1; +#endif } CCopPed::~CCopPed() @@ -181,15 +189,15 @@ CCopPed::ClearPursuit(void) } } -// TO-DO: m_MaxCops in for loop may be a bug, check it out after CopAI +// TODO: I don't know why they needed that parameter. void -CCopPed::SetPursuit(bool iMayAlreadyBeInPursuit) +CCopPed::SetPursuit(bool ignoreCopLimit) { CWanted *wanted = FindPlayerPed()->m_pWanted; if (m_bIsInPursuit || !IsPedInControl()) return; - if (wanted->m_CurrentCops < wanted->m_MaxCops || iMayAlreadyBeInPursuit) { + if (wanted->m_CurrentCops < wanted->m_MaxCops || ignoreCopLimit) { for (int i = 0; i < wanted->m_MaxCops; ++i) { if (!wanted->m_pCops[i]) { m_bIsInPursuit = true; @@ -275,6 +283,276 @@ CCopPed::ScanForCrimes(void) } } +void +CCopPed::CopAI(void) +{ + CWanted *wanted = FindPlayerPed()->m_pWanted; + int wantedLevel = wanted->m_nWantedLevel; + CPhysical *playerOrHisVeh = FindPlayerVehicle() ? (CPhysical*)FindPlayerVehicle() : (CPhysical*)FindPlayerPed(); + + if (wanted->m_bIgnoredByEveryone || wanted->m_bIgnoredByCops) { + if (m_nPedState != PED_ARREST_PLAYER) + ClearPursuit(); + + return; + } + if (CCullZones::NoPolice() && m_bIsInPursuit && !m_bIsDisabledCop) { + if (bHitSomethingLastFrame) { + m_bZoneDisabled = true; + m_bIsDisabledCop = true; +#ifdef FIX_BUGS + m_wRoadblockNode = -1; +#else + m_wRoadblockNode = 0; +#endif + bKindaStayInSamePlace = true; + bIsRunning = false; + bNotAllowedToDuck = false; + bCrouchWhenShooting = false; + SetIdle(); + ClearObjective(); + ClearPursuit(); + m_prevObjective = OBJECTIVE_NONE; + m_nLastPedState = PED_NONE; + SetAttackTimer(0); + if (m_fDistanceToTarget > 15.0f) + m_bZoneDisabledButClose = true; + } + } else if (m_bZoneDisabled && !CCullZones::NoPolice()) { + m_bZoneDisabled = false; + m_bIsDisabledCop = false; + m_bZoneDisabledButClose = false; + bKindaStayInSamePlace = false; + bCrouchWhenShooting = false; + bDuckAndCover = false; + ClearPursuit(); + } + if (wantedLevel > 0) { + if (!m_bIsDisabledCop) { + if (!m_bIsInPursuit || wanted->m_CurrentCops > wanted->m_MaxCops) { + CCopPed *copFarthestToTarget = nil; + float copFarthestToTargetDist = m_fDistanceToTarget; + + int oldCopNum = wanted->m_CurrentCops; + int maxCops = wanted->m_MaxCops; + + for (int i = 0; i < max(maxCops, oldCopNum); i++) { + CCopPed *cop = wanted->m_pCops[i]; + if (cop && cop->m_fDistanceToTarget > copFarthestToTargetDist) { + copFarthestToTargetDist = cop->m_fDistanceToTarget; + copFarthestToTarget = wanted->m_pCops[i]; + } + } + + if (m_bIsInPursuit) { + if (copFarthestToTarget && oldCopNum > maxCops) { + if (copFarthestToTarget == this && m_fDistanceToTarget > 10.0f) { + ClearPursuit(); + } else if(copFarthestToTargetDist > 10.0f) + copFarthestToTarget->ClearPursuit(); + } + } else { + if (oldCopNum < maxCops) { + SetPursuit(true); + } else { + if (m_fDistanceToTarget <= 10.0f || copFarthestToTarget && m_fDistanceToTarget < copFarthestToTargetDist) { + if (copFarthestToTarget && copFarthestToTargetDist > 10.0f) + copFarthestToTarget->ClearPursuit(); + + SetPursuit(true); + } + } + } + } else + SetPursuit(false); + + if (!m_bIsInPursuit) + return; + + if (wantedLevel > 1 && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) + SetCurrentWeapon(WEAPONTYPE_COLT45); + else if (wantedLevel == 1 && GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && !FindPlayerPed()->m_pCurrentPhysSurface) { + // i.e. if player is on top of car, cop will still use colt45. + SetCurrentWeapon(WEAPONTYPE_UNARMED); + } + + if (FindPlayerVehicle()) { + if (m_bBeatingSuspect) { + --wanted->m_CopsBeatingSuspect; + m_bBeatingSuspect = false; + } + if (m_fDistanceToTarget * FindPlayerSpeed().Magnitude() > 4.0f) + ClearPursuit(); + } + return; + } + float weaponRange = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_fRange; + SetLookFlag(playerOrHisVeh, true); + TurnBody(); + SetCurrentWeapon(WEAPONTYPE_COLT45); + if (!bIsDucking) { + if (m_attackTimer >= CTimer::GetTimeInMilliseconds()) { + if (m_nPedState != PED_ATTACK && m_nPedState != PED_FIGHT && !m_bZoneDisabled) { + CVector targetDist = playerOrHisVeh->GetPosition() - GetPosition(); + if (m_fDistanceToTarget > 30.0f) { + CAnimBlendAssociation* crouchShootAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RBLOCK_CSHOOT); + if (crouchShootAssoc) + crouchShootAssoc->blendDelta = -1000.0f; + + // Target is coming onto us + if (DotProduct(playerOrHisVeh->m_vecMoveSpeed, targetDist) > 0.0f) { + m_bIsDisabledCop = false; + bKindaStayInSamePlace = false; + bNotAllowedToDuck = false; + bDuckAndCover = false; + SetPursuit(false); + SetObjective(OBJECTIVE_KILL_CHAR_ANY_MEANS, FindPlayerPed()); + } + } else if (m_fDistanceToTarget < 5.0f + && (!FindPlayerVehicle() || FindPlayerVehicle()->m_vecMoveSpeed.MagnitudeSqr() < sq(1.f/200.f))) { + m_bIsDisabledCop = false; + bKindaStayInSamePlace = false; + bNotAllowedToDuck = false; + bDuckAndCover = false; + } else { + // VC checks for != nil compared to buggy behaviour of III. I check for != -1 here. +#ifdef VC_PED_PORTS + float dotProd; + if (m_wRoadblockNode != -1) { + CTreadable *roadBlockRoad = ThePaths.m_mapObjects[CRoadBlocks::RoadBlockObjects[m_wRoadblockNode]]; + dotProd = DotProduct2D(playerOrHisVeh->GetPosition() - roadBlockRoad->GetPosition(), GetPosition() - roadBlockRoad->GetPosition()); + } else + dotProd = -1.0f; + + if(dotProd >= 0.0f) { +#else + +#ifndef FIX_BUGS + float copRoadDotProd, targetRoadDotProd; +#else + float copRoadDotProd = 1.0f, targetRoadDotProd = 1.0f; + if (m_wRoadblockNode != -1) +#endif + { + CTreadable* roadBlockRoad = ThePaths.m_mapObjects[CRoadBlocks::RoadBlockObjects[m_wRoadblockNode]]; + CVector2D roadFwd = roadBlockRoad->GetForward(); + copRoadDotProd = DotProduct2D(GetPosition() - roadBlockRoad->GetPosition(), roadFwd); + targetRoadDotProd = DotProduct2D(playerOrHisVeh->GetPosition() - roadBlockRoad->GetPosition(), roadFwd); + } + // Roadblock may be towards road's fwd or opposite, so check both + if ((copRoadDotProd >= 0.0f || targetRoadDotProd >= 0.0f) + && (copRoadDotProd <= 0.0f || targetRoadDotProd <= 0.0f)) { +#endif + bIsPointingGunAt = true; + } else { + m_bIsDisabledCop = false; + bKindaStayInSamePlace = false; + bNotAllowedToDuck = false; + bCrouchWhenShooting = false; + bIsDucking = false; + bDuckAndCover = false; + SetPursuit(false); + } + } + } + } else { + if (m_fDistanceToTarget < weaponRange) { + CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + CVector gunPos = weaponInfo->m_vecFireOffset; + for (RwFrame *i = GetNodeFrame(PED_HANDR); i; i = RwFrameGetParent(i)) + RwV3dTransformPoints((RwV3d*)&gunPos, (RwV3d*)&gunPos, 1, RwFrameGetMatrix(i)); + + CColPoint foundCol; + CEntity *foundEnt; + if (!CWorld::ProcessLineOfSight(gunPos, playerOrHisVeh->GetPosition(), foundCol, foundEnt, + false, true, false, false, true, false, false) + || foundEnt && foundEnt == playerOrHisVeh) { + m_pPointGunAt = playerOrHisVeh; + if (playerOrHisVeh) + playerOrHisVeh->RegisterReference((CEntity**) &m_pPointGunAt); + + SetAttack(playerOrHisVeh); + SetShootTimer(CGeneral::GetRandomNumberInRange(500, 1000)); + } + SetAttackTimer(CGeneral::GetRandomNumberInRange(100, 300)); + } + SetMoveState(PEDMOVE_STILL); + } + } + } else { + if (!m_bIsDisabledCop || m_bZoneDisabled) { + if (m_nPedState != PED_AIM_GUN) { + if (m_bIsInPursuit) + ClearPursuit(); + + if (IsPedInControl()) { + // Entering the vehicle + if (m_pMyVehicle && !bInVehicle) { + if (m_pMyVehicle->IsLawEnforcementVehicle()) { + if (m_pMyVehicle->pDriver) { + if (m_pMyVehicle->pDriver->m_nPedType == PEDTYPE_COP) { + if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_pMyVehicle); + } else if (m_pMyVehicle->pDriver->IsPlayer()) { + FindPlayerPed()->SetWantedLevelNoDrop(1); + } + } else if (m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); + } + } else { + m_pMyVehicle = nil; + ClearObjective(); + SetWanderPath(CGeneral::GetRandomNumber() & 7); + } + } +#ifdef VC_PED_PORTS + else { + if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && CharCreatedBy == RANDOM_CHAR) { + for (int i = 0; i < m_numNearPeds; i++) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed->CharCreatedBy == RANDOM_CHAR) { + if ((nearPed->m_nPedType == PEDTYPE_CRIMINAL || nearPed->IsGangMember()) + && nearPed->IsPedInControl()) { + + bool anotherCopChasesHim = false; + if (nearPed->m_nPedState == PED_FLEE_ENTITY) { + if (nearPed->m_fleeFrom && nearPed->m_fleeFrom->IsPed() && + ((CPed*)nearPed->m_fleeFrom)->m_nPedType == PEDTYPE_COP) { + anotherCopChasesHim = true; + } + } + if (!anotherCopChasesHim) { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, nearPed); + nearPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, this); + nearPed->m_ped_flagE2 = true; + return; + } + } + } + } + } + } +#endif + } + } + } else { + if (m_bIsInPursuit && m_nPedState != PED_AIM_GUN) + ClearPursuit(); + + m_bIsDisabledCop = false; + bKindaStayInSamePlace = false; + bNotAllowedToDuck = false; + bCrouchWhenShooting = false; + bIsDucking = false; + bDuckAndCover = false; + if (m_pMyVehicle) + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); + } + } +} + +#include <new> + class CCopPed_ : public CCopPed { public: @@ -290,4 +568,5 @@ STARTPATCHES InjectHook(0x4C27D0, &CCopPed::SetPursuit, PATCH_JUMP); InjectHook(0x4C2C90, &CCopPed::ArrestPlayer, PATCH_JUMP); InjectHook(0x4C26A0, &CCopPed::ScanForCrimes, PATCH_JUMP); + InjectHook(0x4C1B50, &CCopPed::CopAI, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/CopPed.h b/src/peds/CopPed.h index 7705eb12..142be56a 100644 --- a/src/peds/CopPed.h +++ b/src/peds/CopPed.h @@ -17,9 +17,9 @@ public: int8 field_1343; float m_fDistanceToTarget; int8 m_bIsInPursuit; - int8 m_bIsDisabledCop; + int8 m_bIsDisabledCop; // What disabled cop actually is? int8 field_1350; - int8 field_1351; + bool m_bBeatingSuspect; int8 m_bZoneDisabledButClose; int8 m_bZoneDisabled; int8 field_1354; @@ -40,6 +40,7 @@ public: void SetPursuit(bool); void ArrestPlayer(void); void ScanForCrimes(void); + void CopAI(void); }; static_assert(sizeof(CCopPed) == 0x558, "CCopPed: error"); diff --git a/src/peds/EmergencyPed.cpp b/src/peds/EmergencyPed.cpp index ee559f57..0d27a532 100644 --- a/src/peds/EmergencyPed.cpp +++ b/src/peds/EmergencyPed.cpp @@ -413,6 +413,8 @@ CEmergencyPed::MedicAI(void) } } +#include <new> + class CEmergencyPed_ : public CEmergencyPed { public: diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index db6b7ee2..05cac3a7 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -2720,6 +2720,10 @@ CPed::SetObjective(eObjective newObj, void *entity) return; } +#ifdef VC_PED_PORTS + SetObjectiveTimer(0); + ClearPointGunAt(); +#endif bObjectiveCompleted = false; if (!IsTemporaryObjective(m_objective) || IsTemporaryObjective(newObj)) { if (m_objective != newObj) { @@ -3444,8 +3448,12 @@ CPed::ClearAll(void) m_fleeFrom = nil; m_fleeTimer = 0; bUsesCollision = true; +#ifdef VC_PED_PORTS + ClearPointGunAt(); +#else ClearAimFlag(); ClearLookFlag(); +#endif bIsPointingGunAt = false; bRenderPedInCar = true; bKnockedUpIntoAir = false; @@ -12169,11 +12177,11 @@ CPed::PlacePedOnDryLand(void) if (!CWorld::TestSphereAgainstWorld(potentialGround, 5.0f, nil, true, false, false, false, false, false)) return false; - CVector potentialGroundDist = CWorld::ms_testSpherePoint.point - GetPosition(); + CVector potentialGroundDist = gaTempSphereColPoints[0].point - GetPosition(); potentialGroundDist.z = 0.0f; potentialGroundDist.Normalise(); - CVector posToCheck = 0.5f * potentialGroundDist + CWorld::ms_testSpherePoint.point; + CVector posToCheck = 0.5f * potentialGroundDist + gaTempSphereColPoints[0].point; posToCheck.z = 3.0f + waterLevel; if (CWorld::ProcessVerticalLine(posToCheck, waterLevel - 1.0f, foundCol, foundEnt, true, true, false, true, false, false, false)) { @@ -17447,6 +17455,8 @@ CPed::SetExitBoat(CVehicle *boat) CWaterLevel::FreeBoatWakeArray(); } +#include <new> + class CPed_ : public CPed { public: diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp index c6580d32..49d0183e 100644 --- a/src/peds/PlayerPed.cpp +++ b/src/peds/PlayerPed.cpp @@ -1414,6 +1414,8 @@ CPlayerPed::ProcessControl(void) }
}
+#include <new>
+
class CPlayerPed_ : public CPlayerPed
{
public:
diff --git a/src/peds/Population.cpp b/src/peds/Population.cpp index d87764ff..6b674dd3 100644 --- a/src/peds/Population.cpp +++ b/src/peds/Population.cpp @@ -576,7 +576,7 @@ CPopulation::AddToPopulation(float minDist, float maxDist, float minDistOffScree } // Yeah, float float maxPossiblePedsForArea = (zoneInfo.pedDensity + zoneInfo.carDensity) * playerInfo->m_fRoadDensity * PedDensityMultiplier * CIniFile::PedNumberMultiplier; - // maxPossiblePedsForArea = min(maxPossiblePedsForArea, MaxNumberOfPedsInUse); + maxPossiblePedsForArea = min(maxPossiblePedsForArea, MaxNumberOfPedsInUse); if (ms_nTotalPeds < maxPossiblePedsForArea || addCop) { int decisionThreshold = CGeneral::GetRandomNumberInRange(0, 1000); diff --git a/src/render/Font.cpp b/src/render/Font.cpp index 7a16ad03..d7b4b5d8 100644 --- a/src/render/Font.cpp +++ b/src/render/Font.cpp @@ -94,7 +94,7 @@ CFont::Initialise(void) SetBackgroundColor(CRGBA(0x80, 0x80, 0x80, 0x80)); SetBackGroundOnlyTextOff(); SetPropOn(); - SetFontStyle(0); + SetFontStyle(FONT_BANK); SetRightJustifyWrap(0.0f); SetAlphaFade(255.0f); SetDropShadowPosition(0); diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index f0134062..52930067 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -115,47 +115,43 @@ void CHud::Draw() return; if (m_Wants_To_Draw_Hud && !TheCamera.m_WideScreenOn) { - bool Mode_RunAround = 0; - bool Mode_FirstPerson = 0; + bool DrawCrossHair = 0; + bool DrawCrossHairPC = 0; int32 WeaponType = FindPlayerPed()->m_weapons[FindPlayerPed()->m_currentWeapon].m_eWeaponType; int32 Mode = TheCamera.Cams[TheCamera.ActiveCam].Mode; - if (Mode == CCam::MODE_SNIPER || Mode == CCam::MODE_ROCKETLAUNCHER || Mode == CCam::MODE_M16_1STPERSON || Mode == CCam::MODE_EDITOR) - Mode_FirstPerson = 1; - if (Mode == CCam::MODE_M16_1STPERSON_RUNABOUT || Mode == CCam::MODE_SNIPER_RUNABOUT) - Mode_RunAround = 1; + if (Mode == CCam::MODE_SNIPER || Mode == CCam::MODE_ROCKETLAUNCHER || Mode == CCam::MODE_M16_1STPERSON || Mode == CCam::MODE_HELICANNON_1STPERSON) + DrawCrossHair = 1; + if (Mode == CCam::MODE_M16_1STPERSON_RUNABOUT || Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT || Mode == CCam::MODE_SNIPER_RUNABOUT) + DrawCrossHairPC = 1; /* Draw Crosshairs */ - if (TheCamera.Cams->Using3rdPersonMouseCam() && (!CPad::GetPad(0)->GetLookBehindForPed() || TheCamera.m_bPlayerIsInGarage) || Mode == CCam::MODE_1STPERSON_RUNABOUT) { + if (TheCamera.Cams[TheCamera.ActiveCam].Using3rdPersonMouseCam() && + (!CPad::GetPad(0)->GetLookBehindForPed() || TheCamera.m_bPlayerIsInGarage) || Mode == CCam::MODE_1STPERSON_RUNABOUT) { if (FindPlayerPed() && !FindPlayerPed()->EnteringCar()) { if ((WeaponType >= WEAPONTYPE_COLT45 && WeaponType <= WEAPONTYPE_M16) || WeaponType == WEAPONTYPE_FLAMETHROWER) - Mode_RunAround = 1; + DrawCrossHairPC = 1; } } - if (Mode_FirstPerson || Mode_RunAround) { + if (DrawCrossHair || DrawCrossHairPC) { RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void *)rwFILTERLINEAR); - int32 SpriteBrightLikeADiamond = SpriteBrightness + 1; - if (SpriteBrightLikeADiamond > 30) - SpriteBrightLikeADiamond = 30; - - SpriteBrightness = SpriteBrightLikeADiamond; + SpriteBrightness = min(SpriteBrightness+1, 30); RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); - float fStep = Sin((CTimer::GetTimeInMilliseconds() & 1023) * 0.0061328127); + float fStep = Sin((CTimer::GetTimeInMilliseconds() & 1023)/1024.0f * 6.28f); float fMultBright = SpriteBrightness * 0.03f * (0.25f * fStep + 0.75f); CRect rect; + if (DrawCrossHairPC && TheCamera.Cams[TheCamera.ActiveCam].Using3rdPersonMouseCam()) { #ifndef ASPECT_RATIO_SCALE - if (Mode_RunAround && TheCamera.Cams->Using3rdPersonMouseCam()) { float f3rdX = SCREEN_WIDTH * TheCamera.m_f3rdPersonCHairMultX; float f3rdY = SCREEN_HEIGHT * TheCamera.m_f3rdPersonCHairMultY; #else - if (Mode_RunAround && TheCamera.Cams->Using3rdPersonMouseCam()) { float f3rdX = (((TheCamera.m_f3rdPersonCHairMultX - 0.5f) / ((CDraw::GetAspectRatio()) / (DEFAULT_ASPECT_RATIO))) + 0.5f) * SCREEN_WIDTH; float f3rdY = SCREEN_HEIGHT * TheCamera.m_f3rdPersonCHairMultY + SCREEN_SCALE_Y(-2.0f); #endif @@ -179,14 +175,14 @@ void CHud::Draw() else { if (Mode == CCam::MODE_M16_1STPERSON || Mode == CCam::MODE_M16_1STPERSON_RUNABOUT || - Mode == CCam::MODE_EDITOR) { + Mode == CCam::MODE_HELICANNON_1STPERSON) { rect.left = (SCREEN_WIDTH / 2) - SCREEN_SCALE_X(32.0f); rect.top = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(32.0f); rect.right = (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(32.0f); rect.bottom = (SCREEN_HEIGHT / 2) + SCREEN_SCALE_Y(32.0f); Sprites[HUD_SITEM16].Draw(CRect(rect), CRGBA(255, 255, 255, 255)); } - else if (Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT) { + else if (Mode == CCam::MODE_1STPERSON_RUNABOUT) { rect.left = (SCREEN_WIDTH / 2) - SCREEN_SCALE_X(32.0f * 0.7f); rect.top = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(32.0f * 0.7f); rect.right = (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(32.0f * 0.7f); @@ -194,17 +190,18 @@ void CHud::Draw() Sprites[HUD_SITEM16].Draw(CRect(rect), CRGBA(255, 255, 255, 255)); } - else if (Mode == CCam::MODE_ROCKETLAUNCHER || Mode == CCam::MODE_SNIPER_RUNABOUT) { + else if (Mode == CCam::MODE_ROCKETLAUNCHER || Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT) { RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE); RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpRocketSightTex->raster); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRocketSightTex)); CSprite::RenderOneXLUSprite(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 1.0f, SCREEN_SCALE_X(40.0f), SCREEN_SCALE_Y(40.0f), (100.0f * fMultBright), (200.0f * fMultBright), (100.0f * fMultBright), 255, 1.0f, 255); } else { + // Sniper rect.left = (SCREEN_WIDTH / 2) - SCREEN_SCALE_X(210.0f); rect.top = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(210.0f); rect.right = SCREEN_WIDTH / 2; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index ff9f5755..d7834065 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -645,6 +645,9 @@ CRenderer::ScanWorld(void) m_loadingPriority = false; if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN || +#ifdef FIX_BUGS + TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_GTACLASSIC || +#endif TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){ CRect rect; int x1, x2, y1, y2; @@ -756,6 +759,9 @@ CRenderer::RequestObjectsInFrustum(void) RwV3dTransformPoints((RwV3d*)vectors, (RwV3d*)vectors, 9, cammatrix); if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN || +#ifdef FIX_BUGS + TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_GTACLASSIC || +#endif TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){ CRect rect; int x1, x2, y1, y2; diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp index 8c851686..2d5cfae2 100644 --- a/src/save/GenericGameStorage.cpp +++ b/src/save/GenericGameStorage.cpp @@ -1,3 +1,4 @@ +#define WITHWINDOWS #include "common.h" #include "main.h" #include "patcher.h" @@ -61,9 +62,9 @@ do {\ MakeSpaceForSizeInBufferPointer(presize, buf, postsize);\ save_func(buf, &size);\ CopySizeAndPreparePointer(presize, buf, postsize, reserved, size);\ - if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size + 4))\ + if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff))\ return false;\ - totalSize += size;\ + totalSize += buf - work_buff;\ } while (0) bool @@ -74,7 +75,6 @@ GenericSave(int file) uint32 reserved; uint32 totalSize; - uint32 i; wchar *lastMissionPassed; wchar suffix[6]; @@ -85,13 +85,11 @@ GenericSave(int file) CheckSum = 0; buf = work_buff; reserved = 0; - totalSize = 0; // Save simple vars -INITSAVEBUF lastMissionPassed = TheText.Get(CStats::LastMissionPassedName); if (*lastMissionPassed) { - AsciiToUnicode("'...", suffix); + AsciiToUnicode("...'", suffix); TextCopy(saveName, lastMissionPassed); int len = UnicodeStrlen(saveName); saveName[len] = '\0'; @@ -104,20 +102,20 @@ INITSAVEBUF WriteDataToBufferPointer(buf, saveTime); WriteDataToBufferPointer(buf, SIZE_OF_ONE_GAME_IN_BYTES); WriteDataToBufferPointer(buf, CGame::currLevel); - WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.x); - WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.y); - WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.z); + WriteDataToBufferPointer(buf, TheCamera.GetPosition().x); + WriteDataToBufferPointer(buf, TheCamera.GetPosition().y); + WriteDataToBufferPointer(buf, TheCamera.GetPosition().z); WriteDataToBufferPointer(buf, CClock::ms_nMillisecondsPerGameMinute); WriteDataToBufferPointer(buf, CClock::ms_nLastClockTick); WriteDataToBufferPointer(buf, CClock::ms_nGameClockHours); WriteDataToBufferPointer(buf, CClock::ms_nGameClockMinutes); currPad = CPad::GetPad(0); WriteDataToBufferPointer(buf, currPad->Mode); - WriteDataToBufferPointer(buf, CTimer::m_snTimeInMilliseconds); - WriteDataToBufferPointer(buf, CTimer::ms_fTimeScale); - WriteDataToBufferPointer(buf, CTimer::ms_fTimeStep); - WriteDataToBufferPointer(buf, CTimer::ms_fTimeStepNonClipped); - WriteDataToBufferPointer(buf, CTimer::m_FrameCounter); + WriteDataToBufferPointer(buf, CTimer::GetTimeInMilliseconds()); + WriteDataToBufferPointer(buf, CTimer::GetTimeScale()); + WriteDataToBufferPointer(buf, CTimer::GetTimeStep()); + WriteDataToBufferPointer(buf, CTimer::GetTimeStepNonClipped()); + WriteDataToBufferPointer(buf, CTimer::GetFrameCounter()); WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeStep); WriteDataToBufferPointer(buf, CTimeStep::ms_fFramesPerUpdate); WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeScale); @@ -134,10 +132,8 @@ INITSAVEBUF WriteDataToBufferPointer(buf, CWeather::WeatherTypeInList); WriteDataToBufferPointer(buf, TheCamera.CarZoomIndicator); WriteDataToBufferPointer(buf, TheCamera.PedZoomIndicator); -#ifdef VALIDATE_SAVE_SIZE - _saveBufCount = buf - work_buff; -#endif -VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS); + + assert(buf - work_buff == SIZE_OF_SIMPLEVARS); // Save scripts, block is nested within the same block as simple vars for some reason presize = buf; @@ -145,9 +141,10 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS); postsize = buf; CTheScripts::SaveAllScripts(buf, &size); CopySizeAndPreparePointer(presize, buf, postsize, reserved, size); - if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size + SIZE_OF_SIMPLEVARS + 4)) + if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff)) return false; - totalSize += size + SIZE_OF_SIMPLEVARS; + + totalSize = buf - work_buff; // Save the rest WRITE_BLOCK(CPools::SavePedPool); @@ -171,8 +168,7 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS); WRITE_BLOCK(CPedType::Save); // Write padding - i = 0; - do { + for (int i = 0; i < 4; i++) { size = align4bytes(SIZE_OF_ONE_GAME_IN_BYTES - totalSize - 4); if (size > sizeof(work_buff)) size = sizeof(work_buff); @@ -181,15 +177,15 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS); return false; totalSize += size; } - i++; - } while (i < 4); + } // Write checksum and close CFileMgr::Write(file, (const char *) &CheckSum, sizeof(CheckSum)); if (CFileMgr::GetErrorReadWrite(file)) { PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; - if (CloseFile(file)) + if (!CloseFile(file)) PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; + return false; } diff --git a/src/save/PCSave.cpp b/src/save/PCSave.cpp index 2702bd6e..744f5e0d 100644 --- a/src/save/PCSave.cpp +++ b/src/save/PCSave.cpp @@ -1,3 +1,4 @@ +#define WITHWINDOWS #include "common.h" #include "patcher.h" #include "FileMgr.h" @@ -38,7 +39,7 @@ C_PcSave::SaveSlot(int32 slot) if (file != 0) { DoGameSpecificStuffBeforeSave(); if (GenericSave(file)) { - if (CFileMgr::CloseFile(file) != 0) + if (!!CFileMgr::CloseFile(file)) nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; return true; } @@ -55,21 +56,21 @@ C_PcSave::PcClassSaveRoutine(int32 file, uint8 *data, uint32 size) CFileMgr::Write(file, (const char*)&size, sizeof(size)); if (CFileMgr::GetErrorReadWrite(file)) { nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; - strncpy(SaveFileNameJustSaved, ValidSaveName, 259); + strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1); return false; } CFileMgr::Write(file, (const char*)data, align4bytes(size)); - CheckSum += ((uint8*)&size)[0]; - CheckSum += ((uint8*)&size)[1]; - CheckSum += ((uint8*)&size)[2]; - CheckSum += ((uint8*)&size)[3]; + CheckSum += (uint8) size; + CheckSum += (uint8) (size >> 8); + CheckSum += (uint8) (size >> 16); + CheckSum += (uint8) (size >> 24); for (int i = 0; i < align4bytes(size); i++) { CheckSum += *data++; } if (CFileMgr::GetErrorReadWrite(file)) { nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; - strncpy(SaveFileNameJustSaved, ValidSaveName, 259); + strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1); return false; } diff --git a/src/text/Pager.h b/src/text/Pager.h index 727eeb24..1719e726 100644 --- a/src/text/Pager.h +++ b/src/text/Pager.h @@ -1,5 +1,5 @@ #pragma once
- +
struct PagerMessage {
wchar *m_pText;
uint16 m_nSpeedMs;
@@ -9,20 +9,20 @@ struct PagerMessage { uint32 m_nTimeToChangePosition;
int16 field_10;
int32 m_nNumber[6];
-}; - -#define NUMPAGERMESSAGES 8 - -class CPager -{ +};
+
+#define NUMPAGERMESSAGES 8
+
+class CPager
+{
int16 m_nNumDisplayLetters;
- PagerMessage m_messages[NUMPAGERMESSAGES]; + PagerMessage m_messages[NUMPAGERMESSAGES];
public:
- void Init(); - void Process(); - void Display(); + void Init();
+ void Process();
+ void Display();
void AddMessage(wchar*, uint16, uint16, uint16);
- void AddMessageWithNumber(wchar *str, int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6, uint16 speed, uint16 priority, uint16 a11); - void ClearMessages(); - void RestartCurrentMessage(); + void AddMessageWithNumber(wchar *str, int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6, uint16 speed, uint16 priority, uint16 a11);
+ void ClearMessages();
+ void RestartCurrentMessage();
};
\ No newline at end of file diff --git a/src/text/Text.cpp b/src/text/Text.cpp index 40717ed5..8bffa7e1 100644 --- a/src/text/Text.cpp +++ b/src/text/Text.cpp @@ -1,92 +1,92 @@ -#include "common.h" -#include "patcher.h" -#include "FileMgr.h" -#include "Frontend.h" -#include "Messages.h" -#include "Text.h" - -static wchar WideErrorString[25]; - -CText &TheText = *(CText*)0x941520; - -CText::CText(void) -{ - encoding = 'e'; - memset(WideErrorString, 0, sizeof(WideErrorString)); -} - -void -CText::Load(void) -{ - uint8 *filedata; - char filename[32], type[4]; - int length; - int offset, sectlen; - - Unload(); - filedata = new uint8[0x40000]; - - CFileMgr::SetDir("TEXT"); - switch(CMenuManager::m_PrefsLanguage){ - case LANGUAGE_AMERICAN: - sprintf(filename, "AMERICAN.GXT"); - break; - case LANGUAGE_FRENCH: - sprintf(filename, "FRENCH.GXT"); - break; - case LANGUAGE_GERMAN: - sprintf(filename, "GERMAN.GXT"); - break; - case LANGUAGE_ITALIAN: - sprintf(filename, "ITALIAN.GXT"); - break; - case LANGUAGE_SPANISH: - sprintf(filename, "SPANISH.GXT"); - break; - } - - length = CFileMgr::LoadFile(filename, filedata, 0x40000, "rb"); - CFileMgr::SetDir(""); - - offset = 0; - while(offset < length){ - type[0] = filedata[offset++]; - type[1] = filedata[offset++]; - type[2] = filedata[offset++]; - type[3] = filedata[offset++]; - sectlen = (int)filedata[offset+3]<<24 | (int)filedata[offset+2]<<16 | - (int)filedata[offset+1]<<8 | (int)filedata[offset+0]; - offset += 4; - if(sectlen != 0){ - if(strncmp(type, "TKEY", 4) == 0) - keyArray.Load(sectlen, filedata, &offset); - else if(strncmp(type, "TDAT", 4) == 0) - data.Load(sectlen, filedata, &offset); - else - offset += sectlen; - } - } - - keyArray.Update(data.chars); - - delete[] filedata; -} - -void -CText::Unload(void) -{ - CMessages::ClearAllMessagesDisplayedByGame(); - data.Unload(); - keyArray.Unload(); -} - -wchar* -CText::Get(const char *key) -{ - return keyArray.Search(key); -} - -wchar UpperCaseTable[128] = { +#include "common.h"
+#include "patcher.h"
+#include "FileMgr.h"
+#include "Frontend.h"
+#include "Messages.h"
+#include "Text.h"
+
+static wchar WideErrorString[25];
+
+CText &TheText = *(CText*)0x941520;
+
+CText::CText(void)
+{
+ encoding = 'e';
+ memset(WideErrorString, 0, sizeof(WideErrorString));
+}
+
+void
+CText::Load(void)
+{
+ uint8 *filedata;
+ char filename[32], type[4];
+ int length;
+ int offset, sectlen;
+
+ Unload();
+ filedata = new uint8[0x40000];
+
+ CFileMgr::SetDir("TEXT");
+ switch(CMenuManager::m_PrefsLanguage){
+ case LANGUAGE_AMERICAN:
+ sprintf(filename, "AMERICAN.GXT");
+ break;
+ case LANGUAGE_FRENCH:
+ sprintf(filename, "FRENCH.GXT");
+ break;
+ case LANGUAGE_GERMAN:
+ sprintf(filename, "GERMAN.GXT");
+ break;
+ case LANGUAGE_ITALIAN:
+ sprintf(filename, "ITALIAN.GXT");
+ break;
+ case LANGUAGE_SPANISH:
+ sprintf(filename, "SPANISH.GXT");
+ break;
+ }
+
+ length = CFileMgr::LoadFile(filename, filedata, 0x40000, "rb");
+ CFileMgr::SetDir("");
+
+ offset = 0;
+ while(offset < length){
+ type[0] = filedata[offset++];
+ type[1] = filedata[offset++];
+ type[2] = filedata[offset++];
+ type[3] = filedata[offset++];
+ sectlen = (int)filedata[offset+3]<<24 | (int)filedata[offset+2]<<16 |
+ (int)filedata[offset+1]<<8 | (int)filedata[offset+0];
+ offset += 4;
+ if(sectlen != 0){
+ if(strncmp(type, "TKEY", 4) == 0)
+ keyArray.Load(sectlen, filedata, &offset);
+ else if(strncmp(type, "TDAT", 4) == 0)
+ data.Load(sectlen, filedata, &offset);
+ else
+ offset += sectlen;
+ }
+ }
+
+ keyArray.Update(data.chars);
+
+ delete[] filedata;
+}
+
+void
+CText::Unload(void)
+{
+ CMessages::ClearAllMessagesDisplayedByGame();
+ data.Unload();
+ keyArray.Unload();
+}
+
+wchar*
+CText::Get(const char *key)
+{
+ return keyArray.Search(key);
+}
+
+wchar UpperCaseTable[128] = {
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
150, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137,
@@ -98,10 +98,10 @@ wchar UpperCaseTable[128] = { 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226,
227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237,
238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248,
- 249, 250, 251, 252, 253, 254, 255 -}; - -wchar FrenchUpperCaseTable[128] = { + 249, 250, 251, 252, 253, 254, 255
+};
+
+wchar FrenchUpperCaseTable[128] = {
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
150, 65, 65, 65, 65, 132, 133, 69, 69, 69, 69, 73, 73,
@@ -113,11 +113,11 @@ wchar FrenchUpperCaseTable[128] = { 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230,
231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252,
- 253, 254, 255 -}; - -wchar -CText::GetUpperCase(wchar c) + 253, 254, 255
+};
+
+wchar
+CText::GetUpperCase(wchar c)
{
switch (encoding)
{
@@ -144,176 +144,176 @@ CText::GetUpperCase(wchar c) default:
break;
}
- return c; -} - -void -CText::UpperCase(wchar *s) -{ - while(*s){ - *s = GetUpperCase(*s); - s++; - } -} - - -void -CKeyArray::Load(uint32 length, uint8 *data, int *offset) -{ - uint32 i; - uint8 *rawbytes; - - numEntries = length / sizeof(CKeyEntry); - entries = new CKeyEntry[numEntries]; - rawbytes = (uint8*)entries; - - for(i = 0; i < length; i++) - rawbytes[i] = data[(*offset)++]; -} - -void -CKeyArray::Unload(void) -{ - delete[] entries; - entries = nil; - numEntries = 0; -} - -void -CKeyArray::Update(wchar *chars) -{ - int i; - for(i = 0; i < numEntries; i++) - entries[i].value = (wchar*)((uint8*)chars + (uintptr)entries[i].value); -} - -CKeyEntry* -CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high) -{ - int mid; - int diff; - - if(low > high) - return nil; - - mid = (low + high)/2; - diff = strcmp(key, entries[mid].key); - if(diff == 0) - return &entries[mid]; - if(diff < 0) - return BinarySearch(key, entries, low, mid-1); - if(diff > 0) - return BinarySearch(key, entries, mid+1, high); - return nil; -} - -wchar* -CKeyArray::Search(const char *key) -{ - CKeyEntry *found; - char errstr[25]; - int i; - - found = BinarySearch(key, entries, 0, numEntries-1); - if(found) - return found->value; - sprintf(errstr, "%s missing", key); - for(i = 0; i < 25; i++) - WideErrorString[i] = errstr[i]; - return WideErrorString; -} - - -void -CData::Load(uint32 length, uint8 *data, int *offset) -{ - uint32 i; - uint8 *rawbytes; - - numChars = length / sizeof(wchar); - chars = new wchar[numChars]; - rawbytes = (uint8*)chars; - - for(i = 0; i < length; i++) - rawbytes[i] = data[(*offset)++]; -} - -void -CData::Unload(void) -{ - delete[] chars; - chars = nil; - numChars = 0; -} - -void -AsciiToUnicode(const char *src, wchar *dst) -{ - while((*dst++ = *src++) != '\0'); -} - -char* -UnicodeToAscii(wchar *src) -{ - static char aStr[256]; - int len; - for(len = 0; *src != '\0' && len < 256-1; len++, src++) - if(*src < 128) - aStr[len] = *src; - else - aStr[len] = '#'; - aStr[len] = '\0'; - return aStr; -} - -char* -UnicodeToAsciiForSaveLoad(wchar *src) -{ - static char aStr[256]; - int len; - for(len = 0; *src != '\0' && len < 256-1; len++, src++) - if(*src < 256) - aStr[len] = *src; - else - aStr[len] = '#'; - aStr[len] = '\0'; - return aStr; -} - -void -UnicodeStrcpy(wchar *dst, const wchar *src) -{ - while((*dst++ = *src++) != '\0'); -} - -int -UnicodeStrlen(const wchar *str) -{ - int len; - for(len = 0; *str != '\0'; len++, str++); - return len; -} - -void -TextCopy(wchar *dst, const wchar *src) -{ - while((*dst++ = *src++) != '\0'); -} - - -STARTPATCHES - InjectHook(0x52C3C0, &CText::Load, PATCH_JUMP); - InjectHook(0x52C580, &CText::Unload, PATCH_JUMP); - InjectHook(0x52C5A0, &CText::Get, PATCH_JUMP); - InjectHook(0x52C220, &CText::GetUpperCase, PATCH_JUMP); - InjectHook(0x52C2C0, &CText::UpperCase, PATCH_JUMP); - - InjectHook(0x52BE70, &CKeyArray::Load, PATCH_JUMP); - InjectHook(0x52BF60, &CKeyArray::Unload, PATCH_JUMP); - InjectHook(0x52BF80, &CKeyArray::Update, PATCH_JUMP); - InjectHook(0x52C060, &CKeyArray::BinarySearch, PATCH_JUMP); - InjectHook(0x52BFB0, &CKeyArray::Search, PATCH_JUMP); - - InjectHook(0x52C120, &CData::Load, PATCH_JUMP); - InjectHook(0x52C200, &CData::Unload, PATCH_JUMP); -ENDPATCHES + return c;
+}
+
+void
+CText::UpperCase(wchar *s)
+{
+ while(*s){
+ *s = GetUpperCase(*s);
+ s++;
+ }
+}
+
+
+void
+CKeyArray::Load(uint32 length, uint8 *data, int *offset)
+{
+ uint32 i;
+ uint8 *rawbytes;
+
+ numEntries = length / sizeof(CKeyEntry);
+ entries = new CKeyEntry[numEntries];
+ rawbytes = (uint8*)entries;
+
+ for(i = 0; i < length; i++)
+ rawbytes[i] = data[(*offset)++];
+}
+
+void
+CKeyArray::Unload(void)
+{
+ delete[] entries;
+ entries = nil;
+ numEntries = 0;
+}
+
+void
+CKeyArray::Update(wchar *chars)
+{
+ int i;
+ for(i = 0; i < numEntries; i++)
+ entries[i].value = (wchar*)((uint8*)chars + (uintptr)entries[i].value);
+}
+
+CKeyEntry*
+CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high)
+{
+ int mid;
+ int diff;
+
+ if(low > high)
+ return nil;
+
+ mid = (low + high)/2;
+ diff = strcmp(key, entries[mid].key);
+ if(diff == 0)
+ return &entries[mid];
+ if(diff < 0)
+ return BinarySearch(key, entries, low, mid-1);
+ if(diff > 0)
+ return BinarySearch(key, entries, mid+1, high);
+ return nil;
+}
+
+wchar*
+CKeyArray::Search(const char *key)
+{
+ CKeyEntry *found;
+ char errstr[25];
+ int i;
+
+ found = BinarySearch(key, entries, 0, numEntries-1);
+ if(found)
+ return found->value;
+ sprintf(errstr, "%s missing", key);
+ for(i = 0; i < 25; i++)
+ WideErrorString[i] = errstr[i];
+ return WideErrorString;
+}
+
+
+void
+CData::Load(uint32 length, uint8 *data, int *offset)
+{
+ uint32 i;
+ uint8 *rawbytes;
+
+ numChars = length / sizeof(wchar);
+ chars = new wchar[numChars];
+ rawbytes = (uint8*)chars;
+
+ for(i = 0; i < length; i++)
+ rawbytes[i] = data[(*offset)++];
+}
+
+void
+CData::Unload(void)
+{
+ delete[] chars;
+ chars = nil;
+ numChars = 0;
+}
+
+void
+AsciiToUnicode(const char *src, wchar *dst)
+{
+ while((*dst++ = *src++) != '\0');
+}
+
+char*
+UnicodeToAscii(wchar *src)
+{
+ static char aStr[256];
+ int len;
+ for(len = 0; *src != '\0' && len < 256-1; len++, src++)
+ if(*src < 128)
+ aStr[len] = *src;
+ else
+ aStr[len] = '#';
+ aStr[len] = '\0';
+ return aStr;
+}
+
+char*
+UnicodeToAsciiForSaveLoad(wchar *src)
+{
+ static char aStr[256];
+ int len;
+ for(len = 0; *src != '\0' && len < 256-1; len++, src++)
+ if(*src < 256)
+ aStr[len] = *src;
+ else
+ aStr[len] = '#';
+ aStr[len] = '\0';
+ return aStr;
+}
+
+void
+UnicodeStrcpy(wchar *dst, const wchar *src)
+{
+ while((*dst++ = *src++) != '\0');
+}
+
+int
+UnicodeStrlen(const wchar *str)
+{
+ int len;
+ for(len = 0; *str != '\0'; len++, str++);
+ return len;
+}
+
+void
+TextCopy(wchar *dst, const wchar *src)
+{
+ while((*dst++ = *src++) != '\0');
+}
+
+
+STARTPATCHES
+ InjectHook(0x52C3C0, &CText::Load, PATCH_JUMP);
+ InjectHook(0x52C580, &CText::Unload, PATCH_JUMP);
+ InjectHook(0x52C5A0, &CText::Get, PATCH_JUMP);
+ InjectHook(0x52C220, &CText::GetUpperCase, PATCH_JUMP);
+ InjectHook(0x52C2C0, &CText::UpperCase, PATCH_JUMP);
+
+ InjectHook(0x52BE70, &CKeyArray::Load, PATCH_JUMP);
+ InjectHook(0x52BF60, &CKeyArray::Unload, PATCH_JUMP);
+ InjectHook(0x52BF80, &CKeyArray::Update, PATCH_JUMP);
+ InjectHook(0x52C060, &CKeyArray::BinarySearch, PATCH_JUMP);
+ InjectHook(0x52BFB0, &CKeyArray::Search, PATCH_JUMP);
+
+ InjectHook(0x52C120, &CData::Load, PATCH_JUMP);
+ InjectHook(0x52C200, &CData::Unload, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index a05a1236..44ff6b6d 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -4483,6 +4483,8 @@ CAutomobile::SetAllTaxiLights(bool set) m_sAllTaxiLights = set; } +#include <new> + class CAutomobile_ : public CAutomobile { public: diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index 7dbd7080..6d584017 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -299,6 +299,8 @@ CBoat::FillBoatList() } } +#include <new> + class CBoat_ : public CBoat { public: diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp index aab9dd0d..9fc50651 100644 --- a/src/vehicles/Heli.cpp +++ b/src/vehicles/Heli.cpp @@ -1034,6 +1034,7 @@ bool CHeli::HasCatalinaBeenShotDown(void) { return CatalinaHasBeenShotDown; } void CHeli::ActivateHeli(bool activate) { ScriptHeliOn = activate; } +#include <new> class CHeli_ : public CHeli { diff --git a/src/vehicles/Plane.cpp b/src/vehicles/Plane.cpp index b4d80581..e44ff996 100644 --- a/src/vehicles/Plane.cpp +++ b/src/vehicles/Plane.cpp @@ -964,6 +964,7 @@ bool CPlane::HasCesnaLanded(void) { return CesnaMissionStatus == CESNA_STATUS_LA bool CPlane::HasCesnaBeenDestroyed(void) { return CesnaMissionStatus == CESNA_STATUS_DESTROYED; } bool CPlane::HasDropOffCesnaBeenShotDown(void) { return DropOffCesnaMissionStatus == CESNA_STATUS_DESTROYED; } +#include <new> class CPlane_ : public CPlane { diff --git a/src/vehicles/Train.cpp b/src/vehicles/Train.cpp index 1c73ed05..6446e6d1 100644 --- a/src/vehicles/Train.cpp +++ b/src/vehicles/Train.cpp @@ -691,6 +691,8 @@ CTrain::UpdateTrains(void) } } +#include <new> + class CTrain_ : public CTrain { public: diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index 63c9519f..16e61e5f 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -33,6 +33,7 @@ void CVehicle::operator delete(void *p, int handle) { CPools::GetVehiclePool()-> WRAPPER bool CVehicle::ShufflePassengersToMakeSpace(void) { EAXJMP(0x5528A0); } // or Weapon.cpp? WRAPPER void FireOneInstantHitRound(CVector *shotSource, CVector *shotTarget, int32 damage) { EAXJMP(0x563B00); } +WRAPPER void CVehicle::InflictDamage(CEntity *damagedBy, uint32 weaponType, float damage) { EAXJMP(0x551950); } CVehicle::CVehicle(uint8 CreatedBy) { diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index 8c0825cf..2ca97841 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -266,6 +266,7 @@ public: void ProcessCarAlarm(void); bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius); bool ShufflePassengersToMakeSpace(void); + void InflictDamage(CEntity *damagedBy, uint32 weaponType, float damage); bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1; } CVehicleModelInfo* GetModelInfo() { return (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); } |