diff options
Diffstat (limited to '')
53 files changed, 11004 insertions, 2196 deletions
diff --git a/src/core/AnimViewer.cpp b/src/core/AnimViewer.cpp index a2d7b94a..1086db20 100644 --- a/src/core/AnimViewer.cpp +++ b/src/core/AnimViewer.cpp @@ -33,6 +33,7 @@ #include "Clock.h" #include "Timecycle.h" #include "RpAnimBlend.h" +#include "AnimBlendAssociation.h" #include "Shadows.h" #include "Radar.h" #include "Hud.h" @@ -207,6 +208,7 @@ PlayAnimation(RpClump *clump, AssocGroupId animGroup, AnimationId anim) animAssoc->SetRun(); } +extern void (*DebugMenuProcess)(void); void CAnimViewer::Update(void) { @@ -246,6 +248,9 @@ CAnimViewer::Update(void) } CPad::UpdatePads(); CPad* pad = CPad::GetPad(0); + + DebugMenuProcess(); + CStreaming::UpdateForAnimViewer(); CStreaming::RequestModel(modelId, 0); if (CStreaming::HasModelLoaded(modelId)) { @@ -289,7 +294,7 @@ CAnimViewer::Update(void) } newEntity->GetPosition() = CVector(0.0f, 0.0f, 0.0f); CWorld::Add(newEntity); - TheCamera.TakeControl(pTarget, CCam::MODE_MODELVIEW, JUMP_CUT, CAM_CONTROLLER_1); + TheCamera.TakeControl(pTarget, CCam::MODE_MODELVIEW, JUMP_CUT, CAMCONTROL_SCRIPT); } if (pTarget->m_type == ENTITY_TYPE_VEHICLE || pTarget->m_type == ENTITY_TYPE_PED || pTarget->m_type == ENTITY_TYPE_OBJECT) { ((CPhysical*)pTarget)->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp new file mode 100644 index 00000000..5b7a53e9 --- /dev/null +++ b/src/core/Cam.cpp @@ -0,0 +1,5292 @@ +#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" +#include "DMAudio.h" + +const float DefaultFOV = 70.0f; // beta: 80.0f + +bool PrintDebugCode = false; +int16 &DebugCamMode = *(int16*)0x95CCF2; + +#ifdef FREE_CAM +bool CCamera::bFreeCam = false; +int nPreviousMode = -1; +#endif + +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 +#ifdef FREE_CAM + if(CCamera::bFreeCam) + Process_FollowPed_Rotation(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + else +#endif + 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: +#ifdef FREE_CAM + if(CCamera::bFreeCam) + Process_FollowCar_SA(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + else +#endif + 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: +#ifdef FREE_CAM + if (CCamera::bFreeCam) + Process_FollowCar_SA(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); + else +#endif + 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); + } + +#ifdef FREE_CAM + nPreviousMode = Mode; +#endif + 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) + 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 == CAM_ZOOM_1) + Offset = 0.45*DistScale + PedZDist; + if(TheCamera.PedZoomIndicator == CAM_ZOOM_2) + Offset = 0.35*DistScale + PedZDist; + if(TheCamera.PedZoomIndicator == CAM_ZOOM_3) + 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 == CAM_ZOOM_1) + m_fRoadOffSet += 0.2f; + if(TheCamera.PedZoomIndicator == CAM_ZOOM_2) + m_fRoadOffSet += 0.5f; + if(TheCamera.PedZoomIndicator == CAM_ZOOM_3) + 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, DEFAULT_NEAR); + 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 = DEFAULT_NEAR - (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 == CAM_ZOOM_1 || TheCamera.PedZoomIndicator == CAM_ZOOM_TOPDOWN){ + 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); + + 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 == CAM_ZOOM_1) m_fRealGroundDist = 2.090556f; + if(TheCamera.PedZoomIndicator == CAM_ZOOM_2) m_fRealGroundDist = 3.34973f; + if(TheCamera.PedZoomIndicator == CAM_ZOOM_3) m_fRealGroundDist = 4.704914f; + if(TheCamera.PedZoomIndicator == CAM_ZOOM_TOPDOWN) m_fRealGroundDist = 2.090556f; + } + // And what is this? It's only used for collision and rotation it seems + float RealGroundDist; + if(TheCamera.PedZoomIndicator == CAM_ZOOM_1) RealGroundDist = 2.090556f; + if(TheCamera.PedZoomIndicator == CAM_ZOOM_2) RealGroundDist = 3.34973f; + if(TheCamera.PedZoomIndicator == CAM_ZOOM_3) RealGroundDist = 4.704914f; + if(TheCamera.PedZoomIndicator == CAM_ZOOM_TOPDOWN) 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 RotDistance = (IdealSource - TargetCoors).Magnitude2D(); + m_fDistanceBeforeChanges = RotDistance; + + 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 + RotDistance * Cos(Beta); + Source.y = TargetCoors.y + RotDistance * 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 + RotDistance * Cos(Beta); + Source.y = TargetCoors.y + RotDistance * Sin(Beta); + } + if(TheCamera.m_bCamDirectlyInFront){ + Beta = TargetOrientation; + Source.x = TargetCoors.x + RotDistance * Cos(Beta); + Source.y = TargetCoors.y + RotDistance * Sin(Beta); + } + if(HackPlayerOnStoppingTrain){ + Beta = TargetOrientation + PI; + Source.x = TargetCoors.x + RotDistance * Cos(Beta); + Source.y = TargetCoors.y + RotDistance * 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); + + // SA code +#ifdef FREE_CAM + if((CCamera::bFreeCam && Alpha > 0.0f) || (!CCamera::bFreeCam && Alpha > fBaseDist)) +#else + if(Alpha > fBaseDist) // comparing an angle against a distance? +#endif + 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 < DEFAULT_NEAR + 0.3f) + RwCameraSetNearClipPlane(Scene.camera, max(PedColDist-0.3f, 0.05f)); + }else{ + RwCameraSetNearClipPlane(Scene.camera, min(ColCamDist-0.35f, DEFAULT_NEAR)); + } + }else{ + Source = colPoint.point; + if(PedColDist < DEFAULT_NEAR + 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 * DEFAULT_NEAR - 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 == CAM_ZOOM_1) + ModeAlpha = CGeneral::GetATanOfXY(23.0f, zoomvalue); // near + else if(TheCamera.CarZoomIndicator == CAM_ZOOM_2) + ModeAlpha = CGeneral::GetATanOfXY(10.8f, zoomvalue); // mid + else if(TheCamera.CarZoomIndicator == CAM_ZOOM_3) + 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, DEFAULT_NEAR); + + 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, DEFAULT_NEAR); + + 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, DEFAULT_NEAR); + + 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, DEFAULT_NEAR); + } + + 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; + + 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, DEFAULT_NEAR); + 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, DEFAULT_NEAR); + 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, DEFAULT_NEAR); + 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(); +} + +#ifdef FREE_CAM +void +CCam::Process_FollowPed_Rotation(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + FOV = DefaultFOV; + + const float MinDist = 2.0f; + const float MaxDist = 2.0f + TheCamera.m_fPedZoomValueSmooth; + const float BaseOffset = 0.75f; // base height of camera above target + + CVector TargetCoors = CameraTarget; + + TargetCoors.z += m_fSyphonModeTargetZOffSet; + TargetCoors = DoAverageOnVector(TargetCoors); + TargetCoors.z += BaseOffset; // add offset so alpha evens out to 0 +// TargetCoors.z += m_fRoadOffSet; + + CVector Dist = Source - TargetCoors; + CVector ToCam; + + bool Shooting = false; + if(((CPed*)CamTargetEntity)->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) + if(CPad::GetPad(0)->GetWeapon()) + Shooting = true; + if(((CPed*)CamTargetEntity)->GetWeapon()->m_eWeaponType == WEAPONTYPE_DETONATOR || + ((CPed*)CamTargetEntity)->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT) + Shooting = false; + + + if(ResetStatics){ + // Coming out of top down here probably + // so keep Beta, reset alpha and calculate vectors + Beta = CGeneral::GetATanOfXY(Dist.x, Dist.y); + Alpha = 0.0f; + + Dist = MaxDist*CVector(Cos(Alpha) * Cos(Beta), Cos(Alpha) * Sin(Beta), Sin(Alpha)); + Source = TargetCoors + Dist; + + ResetStatics = false; + } + + // Drag the camera along at the look-down offset + float CamDist = Dist.Magnitude(); + if(CamDist == 0.0f) + Dist = CVector(1.0f, 1.0f, 0.0f); + else if(CamDist < MinDist) + Dist *= MinDist/CamDist; + else if(CamDist > MaxDist) + Dist *= MaxDist/CamDist; + CamDist = Dist.Magnitude(); + + // Beta = 0 is looking east, HALFPI is north, &c. + // Alpha positive is looking up + float GroundDist = Dist.Magnitude2D(); + Beta = CGeneral::GetATanOfXY(-Dist.x, -Dist.y); + Alpha = CGeneral::GetATanOfXY(GroundDist, -Dist.z); + while(Beta >= PI) Beta -= 2.0f*PI; + while(Beta < -PI) Beta += 2.0f*PI; + while(Alpha >= PI) Alpha -= 2.0f*PI; + while(Alpha < -PI) Alpha += 2.0f*PI; + + // 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/10.0f) * FOV/80.0f * CTimer::GetTimeStep(); + AlphaOffset = LookUpDown * fStickSens * (0.3f/10.0f) * FOV/80.0f * CTimer::GetTimeStep(); + } + + // Stop centering once stick has been touched + if(BetaOffset) + Rotating = false; + + Beta += BetaOffset; + Alpha += AlphaOffset; + while(Beta >= PI) Beta -= 2.0f*PI; + while(Beta < -PI) Beta += 2.0f*PI; + if(Alpha > DEGTORAD(45.0f)) Alpha = DEGTORAD(45.0f); + if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f); + + + float BetaDiff = TargetOrientation+PI - Beta; + while(BetaDiff >= PI) BetaDiff -= 2.0f*PI; + while(BetaDiff < -PI) BetaDiff += 2.0f*PI; + float TargetAlpha = Alpha; + // 12deg to account for our little height offset. we're not working on the true alpha here + const float AlphaLimitUp = DEGTORAD(15.0f) + DEGTORAD(12.0f); + const float AlphaLimitDown = -DEGTORAD(15.0f) + DEGTORAD(12.0f); + if(Abs(BetaDiff) < DEGTORAD(25.0f) && ((CPed*)CamTargetEntity)->GetMoveSpeed().Magnitude2D() > 0.01f){ + // Limit alpha when player is walking towards camera + if(TargetAlpha > AlphaLimitUp) TargetAlpha = AlphaLimitUp; + if(TargetAlpha < AlphaLimitDown) TargetAlpha = AlphaLimitDown; + } + + WellBufferMe(TargetAlpha, &Alpha, &AlphaSpeed, 0.2f, 0.1f, true); + + if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){ + m_fTargetBeta = TargetOrientation; + Rotating = true; + } + + if(Rotating){ + WellBufferMe(m_fTargetBeta, &Beta, &BetaSpeed, 0.1f, 0.06f, true); + float DeltaBeta = m_fTargetBeta - Beta; + while(DeltaBeta >= PI) DeltaBeta -= 2*PI; + while(DeltaBeta < -PI) DeltaBeta += 2*PI; + if(Abs(DeltaBeta) < 0.06f) + Rotating = false; + } + + + Front = CVector(Cos(Alpha) * Cos(Beta), Cos(Alpha) * Sin(Beta), Sin(Alpha)); + Source = TargetCoors - Front*CamDist; + TargetCoors.z -= BaseOffset; // now get back to the real target coors again + + m_cvecTargetCoorsForFudgeInter = TargetCoors; + + + Front = TargetCoors - Source; + Front.Normalise(); + + + + /* + * Handle collisions - taken from FollowPedWithMouse + */ + + CEntity *entity; + CColPoint colPoint; + // 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 < DEFAULT_NEAR + 0.3f) + RwCameraSetNearClipPlane(Scene.camera, max(PedColDist-0.3f, 0.05f)); + }else{ + RwCameraSetNearClipPlane(Scene.camera, min(ColCamDist-0.35f, DEFAULT_NEAR)); + } + }else{ + Source = colPoint.point; + if(PedColDist < DEFAULT_NEAR + 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; + + // Keep testing + entity = CWorld::TestSphereAgainstWorld(Source + Front*Near, radius, nil, true, true, false, true, false, false); + + i++; + if(i > 5) + entity = nil; + } + + GetVectorsReadyForRW(); +} + +// LCS cam hehe +void +CCam::Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation, float, float) +{ + // Missing things on III CCam + static CVector m_aTargetHistoryPosOne; + static CVector m_aTargetHistoryPosTwo; + static CVector m_aTargetHistoryPosThree; + static int m_nCurrentHistoryPoints = 0; + static float lastBeta = -9999.0f; + static float lastAlpha = -9999.0f; + static float stepsLeftToChangeBetaByMouse; + static float dontCollideWithCars; + static bool alphaCorrected; + static float heightIncreaseMult; + + if (!CamTargetEntity->IsVehicle()) + return; + + CVehicle* car = (CVehicle*)CamTargetEntity; + CVector TargetCoors = CameraTarget; + uint8 camSetArrPos = 0; + + // We may need those later + bool isPlane = car->m_modelIndex == MI_DODO; + bool isHeli = false; + bool isBike = false; + bool isCar = car->IsCar() && !isPlane && !isHeli && !isBike; + + CPad* pad = CPad::GetPad(0); + + // Next direction is non-existent in III + uint8 nextDirectionIsForward = !(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight()) && + DirectionWasLooking == LOOKING_FORWARD; + + if (car->m_modelIndex == MI_FIRETRUCK) { + camSetArrPos = 7; + } else if (car->m_modelIndex == MI_RCBANDIT) { + camSetArrPos = 5; + } else if (car->IsBoat()) { + camSetArrPos = 4; + } else if (isBike) { + camSetArrPos = 1; + } else if (isPlane) { + camSetArrPos = 3; + } else if (isHeli) { + camSetArrPos = 2; + } + + // LCS one but index 1(firetruck) moved to last + float CARCAM_SET[][15] = { + {1.3f, 1.0f, 0.4f, 10.0f, 15.0f, 0.5f, 1.0f, 1.0f, 0.85f, 0.2f, 0.075f, 0.05f, 0.8f, DEGTORAD(45.0f), DEGTORAD(89.0f)}, // cars + {1.1f, 1.0f, 0.1f, 10.0f, 11.0f, 0.5f, 1.0f, 1.0f, 0.85f, 0.2f, 0.075f, 0.05f, 0.75f, DEGTORAD(45.0f), DEGTORAD(89.0f)}, // bike + {1.1f, 1.0f, 0.2f, 10.0f, 15.0f, 0.05f, 0.05f, 0.0f, 0.9f, 0.05f, 0.01f, 0.05f, 1.0f, DEGTORAD(10.0f), DEGTORAD(70.0f)}, // heli (SA values) + {1.1f, 3.5f, 0.2f, 10.0f, 25.0f, 0.5f, 1.0f, 1.0f, 0.75f, 0.1f, 0.005f, 0.2f, 1.0f, DEGTORAD(89.0f), DEGTORAD(89.0f)}, // plane (SA values) + {0.9f, 1.0f, 0.1f, 10.0f, 15.0f, 0.5f, 1.0f, 0.0f, 0.9f, 0.05f, 0.005f, 0.05f, 1.0f, -0.2f, DEGTORAD(70.0f)}, // boat + {1.1f, 1.0f, 0.2f, 10.0f, 5.0f, 0.5f, 1.0f, 1.0f, 0.75f, 0.1f, 0.005f, 0.2f, 1.0f, DEGTORAD(45.0f), DEGTORAD(89.0f)}, // rc cars + {1.1f, 1.0f, 0.2f, 10.0f, 5.0f, 0.5f, 1.0f, 1.0f, 0.75f, 0.1f, 0.005f, 0.2f, 1.0f, DEGTORAD(20.0f), DEGTORAD(70.0f)}, // rc heli/planes + {1.3f, 1.0f, 0.4f, 10.0f, 15.0f, 0.5f, 1.0f, 1.0f, 0.85f, 0.2f, 0.075f, 0.05f, 0.8f, -0.18f, DEGTORAD(40.0f)}, // firetruck... + }; + + // RC Heli/planes use same alpha values with heli/planes (LCS firetruck will fallback to 0) + uint8 alphaArrPos = (camSetArrPos > 4 ? (isPlane ? 3 : (isHeli ? 2 : 0)) : camSetArrPos); + float zoomModeAlphaOffset = 0.0f; + static float ZmOneAlphaOffsetLCS[] = { 0.12f, 0.08f, 0.15f, 0.08f, 0.08f }; + static float ZmTwoAlphaOffsetLCS[] = { 0.1f, 0.08f, 0.3f, 0.08f, 0.08f }; + static float ZmThreeAlphaOffsetLCS[] = { 0.065f, 0.05f, 0.15f, 0.06f, 0.08f }; + + if (isHeli && car->m_status == STATUS_PLAYER_REMOTE) + zoomModeAlphaOffset = ZmTwoAlphaOffsetLCS[alphaArrPos]; + else { + switch ((int)TheCamera.CarZoomIndicator) { + // near + case 1: + zoomModeAlphaOffset = ZmOneAlphaOffsetLCS[alphaArrPos]; + break; + // mid + case 2: + zoomModeAlphaOffset = ZmTwoAlphaOffsetLCS[alphaArrPos]; + break; + // far + case 3: + zoomModeAlphaOffset = ZmThreeAlphaOffsetLCS[alphaArrPos]; + break; + default: + break; + } + } + + CColModel* carCol = (CColModel*)car->GetColModel(); + float colMaxZ = carCol->boundingBox.max.z; // As opposed to LCS and SA, VC does this: carCol->boundingBox.max.z - carCol->boundingBox.min.z; + float approxCarLength = 2.0f * Abs(carCol->boundingBox.min.y); // SA taxi min.y = -2.95, max.z = 0.883502f + + float newDistance = TheCamera.CarZoomValueSmooth + CARCAM_SET[camSetArrPos][1] + approxCarLength; + + float minDistForThisCar = approxCarLength * CARCAM_SET[camSetArrPos][3]; + + if (!isHeli || car->m_status == STATUS_PLAYER_REMOTE) { + float radiusToStayOutside = colMaxZ * CARCAM_SET[camSetArrPos][0] - CARCAM_SET[camSetArrPos][2]; + if (radiusToStayOutside > 0.0f) { + TargetCoors.z += radiusToStayOutside; + newDistance += radiusToStayOutside; + zoomModeAlphaOffset += 0.3f / newDistance * radiusToStayOutside; + } + } else { + // 0.6f = fTestShiftHeliCamTarget + TargetCoors.x += 0.6f * car->GetUp().x * colMaxZ; + TargetCoors.y += 0.6f * car->GetUp().y * colMaxZ; + TargetCoors.z += 0.6f * car->GetUp().z * colMaxZ; + } + + float minDistForVehType = CARCAM_SET[camSetArrPos][4]; + + if ((int)TheCamera.CarZoomIndicator == 1 && (camSetArrPos < 2 || camSetArrPos == 7)) { + minDistForVehType = minDistForVehType * 0.65f; + } + + float nextDistance = max(newDistance, minDistForVehType); + + CA_MAX_DISTANCE = newDistance; + CA_MIN_DISTANCE = 3.5f; + + if (ResetStatics) { + FOV = DefaultFOV; + + // GTA 3 has this in veh. camera + if (TheCamera.m_bIdleOn) + TheCamera.m_uiTimeWeEnteredIdle = CTimer::GetTimeInMilliseconds(); + } else { + if (isCar || isBike) { + // 0.4f: CAR_FOV_START_SPEED + if (DotProduct(car->GetForward(), car->m_vecMoveSpeed) > 0.4f) + FOV += (DotProduct(car->GetForward(), car->m_vecMoveSpeed) - 0.4f) * CTimer::GetTimeStep(); + } + + if (FOV > DefaultFOV) + // 0.98f: CAR_FOV_FADE_MULT + FOV = pow(0.98f, CTimer::GetTimeStep()) * (FOV - DefaultFOV) + DefaultFOV; + + if (FOV <= DefaultFOV + 30.0f) { + if (FOV < DefaultFOV) + FOV = DefaultFOV; + } else + FOV = DefaultFOV + 30.0f; + } + + // WORKAROUND: I still don't know how looking behind works (m_bCamDirectlyInFront is unused in III, they seem to use m_bUseTransitionBeta) + if (pad->GetLookBehindForCar()) + if (DirectionWasLooking == LOOKING_FORWARD || !LookingBehind) + TheCamera.m_bCamDirectlyInFront = true; + + // Taken from RotCamIfInFrontCar, because we don't call it anymore + if (!(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight())) + if (DirectionWasLooking != LOOKING_FORWARD) + TheCamera.m_bCamDirectlyBehind = true; + + // Called when we just entered the car, just started to look behind or returned back from looking left, right or behind + if (ResetStatics || TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront) { + ResetStatics = false; + Rotating = false; + m_bCollisionChecksOn = true; + // TheCamera.m_bResetOldMatrix = 1; + + // Garage exit cam is not working well in III... + // if (!TheCamera.m_bJustCameOutOfGarage) // && !sthForScript) + // { + Alpha = 0.0f; + Beta = car->GetForward().Heading() - HALFPI; + if (TheCamera.m_bCamDirectlyInFront) { + Beta += PI; + } + // } + + BetaSpeed = 0.0; + AlphaSpeed = 0.0; + Distance = 1000.0; + + Front.x = -(cos(Beta) * cos(Alpha)); + Front.y = -(sin(Beta) * cos(Alpha)); + Front.z = sin(Alpha); + + m_aTargetHistoryPosOne = TargetCoors - nextDistance * Front; + + m_aTargetHistoryPosTwo = TargetCoors - newDistance * Front; + + m_nCurrentHistoryPoints = 0; + if (!TheCamera.m_bJustCameOutOfGarage) // && !sthForScript) + Alpha = -zoomModeAlphaOffset; + } + + Front = TargetCoors - m_aTargetHistoryPosOne; + Front.Normalise(); + + // Code that makes cam rotate around the car + float camRightHeading = Front.Heading() - HALFPI; + if (camRightHeading < -PI) + camRightHeading = camRightHeading + TWOPI; + + float velocityRightHeading; + if (car->m_vecMoveSpeed.Magnitude2D() <= 0.02f) + velocityRightHeading = camRightHeading; + else + velocityRightHeading = car->m_vecMoveSpeed.Heading() - HALFPI; + + if (velocityRightHeading < camRightHeading - PI) + velocityRightHeading = velocityRightHeading + TWOPI; + else if (velocityRightHeading > camRightHeading + PI) + velocityRightHeading = velocityRightHeading - TWOPI; + + float betaChangeMult1 = CTimer::GetTimeStep() * CARCAM_SET[camSetArrPos][10]; + float betaChangeLimit = CTimer::GetTimeStep() * CARCAM_SET[camSetArrPos][11]; + + float betaChangeMult2 = (car->m_vecMoveSpeed - DotProduct(car->m_vecMoveSpeed, Front) * Front).Magnitude(); + + float betaChange = min(1.0f, betaChangeMult1 * betaChangeMult2) * (velocityRightHeading - camRightHeading); + if (betaChange <= betaChangeLimit) { + if (betaChange < -betaChangeLimit) + betaChange = -betaChangeLimit; + } else { + betaChange = betaChangeLimit; + } + float targetBeta = camRightHeading + betaChange; + + if (targetBeta < Beta - HALFPI) + targetBeta += TWOPI; + else if (targetBeta > Beta + PI) + targetBeta -= TWOPI; + + float carPosChange = (TargetCoors - m_aTargetHistoryPosTwo).Magnitude(); + if (carPosChange < newDistance && newDistance > minDistForThisCar) { + newDistance = max(minDistForThisCar, carPosChange); + } + float maxAlphaAllowed = CARCAM_SET[camSetArrPos][13]; + + // Originally this is to prevent camera enter into car while we're stopping, but what about moving??? + // This is also original LCS and SA bug, or some attempt to fix lag. We'll never know + + // if (car->m_vecMoveSpeed.MagnitudeSqr() < sq(0.2f)) + if (car->m_modelIndex != MI_FIRETRUCK) { + // if (!isBike || GetMysteriousWheelRelatedThingBike(car) > 3) + // if (!isHeli && (!isPlane || car->GetWheelsOnGround())) { + + CVector left = CrossProduct(car->GetForward(), CVector(0.0f, 0.0f, 1.0f)); + left.Normalise(); + CVector up = CrossProduct(left, car->GetForward()); + up.Normalise(); + float lookingUp = DotProduct(up, Front); + if (lookingUp > 0.0f) { + float v88 = Asin(Abs(Sin(Beta - (car->GetForward().Heading() - HALFPI)))); + float v200; + if (v88 <= Atan2(carCol->boundingBox.max.x, -carCol->boundingBox.min.y)) { + v200 = (1.5f - carCol->boundingBox.min.y) / Cos(v88); + } else { + float a6g = 1.2f + carCol->boundingBox.max.x; + v200 = a6g / Cos(max(0.0f, HALFPI - v88)); + } + maxAlphaAllowed = Cos(Beta - (car->GetForward().Heading() - HALFPI)) * Atan2(car->GetForward().z, car->GetForward().Magnitude2D()) + + Atan2(TargetCoors.z - car->GetPosition().z + car->GetHeightAboveRoad(), v200 * 1.2f); + + if (isCar && ((CAutomobile*)car)->m_nWheelsOnGround > 1 && Abs(DotProduct(car->m_vecTurnSpeed, car->GetForward())) < 0.05f) { + maxAlphaAllowed += Cos(Beta - (car->GetForward().Heading() - HALFPI) + HALFPI) * Atan2(car->GetRight().z, car->GetRight().Magnitude2D()); + } + } + } + + float targetAlpha = Asin(clamp(Front.z, -1.0f, 1.0f)) - zoomModeAlphaOffset; + if (targetAlpha <= maxAlphaAllowed) { + if (targetAlpha < -CARCAM_SET[camSetArrPos][14]) + targetAlpha = -CARCAM_SET[camSetArrPos][14]; + } else { + targetAlpha = maxAlphaAllowed; + } + float maxAlphaBlendAmount = CTimer::GetTimeStep() * CARCAM_SET[camSetArrPos][6]; + float targetAlphaBlendAmount = (1.0f - pow(CARCAM_SET[camSetArrPos][5], CTimer::GetTimeStep())) * (targetAlpha - Alpha); + if (targetAlphaBlendAmount <= maxAlphaBlendAmount) { + if (targetAlphaBlendAmount < -maxAlphaBlendAmount) + targetAlphaBlendAmount = -maxAlphaBlendAmount; + } else { + targetAlphaBlendAmount = maxAlphaBlendAmount; + } + + // Using GetCarGun(LR/UD) will give us same unprocessed RightStick value as SA + float stickX = -(pad->GetCarGunLeftRight()); + float stickY = pad->GetCarGunUpDown(); + + // In SA this checks for m_bUseMouse3rdPerson so num2/num8 do not move camera when Keyboard & Mouse controls are used. + if (CCamera::m_bUseMouse3rdPerson) + stickY = 0.0f; + + float xMovement = Abs(stickX) * (FOV / 80.0f * 5.f / 70.f) * stickX * 0.007f * 0.007f; + float yMovement = Abs(stickY) * (FOV / 80.0f * 3.f / 70.f) * stickY * 0.007f * 0.007f; + + bool correctAlpha = true; + // if (SA checks if we aren't in work car, why?) { + if (!isCar || car->m_modelIndex != MI_YARDIE) { + correctAlpha = false; + } + else { + xMovement = 0.0f; + yMovement = 0.0f; + } + // } else + // yMovement = 0.0; + + if (!nextDirectionIsForward) { + yMovement = 0.0; + xMovement = 0.0; + } + + if (camSetArrPos == 0 || camSetArrPos == 7) { + // This is not working on cars as SA + // Because III/VC doesn't have any buttons tied to LeftStick if you're not in Classic Configuration, using Dodo or using GInput/Pad, so :shrug: + if (Abs(pad->GetSteeringUpDown()) > 120.0f) { + if (car->pDriver && car->pDriver->m_objective != OBJECTIVE_LEAVE_VEHICLE) { + yMovement += Abs(pad->GetSteeringUpDown()) * (FOV / 80.0f * 3.f / 70.f) * pad->GetSteeringUpDown() * 0.007f * 0.007f * 0.5; + } + } + } + + if (yMovement > 0.0) + yMovement = yMovement * 0.5; + + bool mouseChangesBeta = false; + + // FIX: Disable mouse movement in drive-by, it's buggy. Original SA bug. + if (/*bFreeMouseCam &&*/ CCamera::m_bUseMouse3rdPerson && !pad->ArePlayerControlsDisabled() && nextDirectionIsForward) { + float mouseY = pad->GetMouseY() * 2.0f; + float mouseX = pad->GetMouseX() * -2.0f; + + // If you want an ability to toggle free cam while steering with mouse, you can add an OR after DisableMouseSteering. + // There was a pad->NewState.m_bVehicleMouseLook in SA, which doesn't exists in III. + + if ((mouseX != 0.0 || mouseY != 0.0) && (CVehicle::m_bDisableMouseSteering)) { + yMovement = mouseY * FOV / 80.0f * TheCamera.m_fMouseAccelHorzntl; // Same as SA, horizontal sensitivity. + BetaSpeed = 0.0; + AlphaSpeed = 0.0; + xMovement = mouseX * FOV / 80.0f * TheCamera.m_fMouseAccelHorzntl; + targetAlpha = Alpha; + stepsLeftToChangeBetaByMouse = 1.0f * 50.0f; + mouseChangesBeta = true; + } else if (stepsLeftToChangeBetaByMouse > 0.0f) { + // Finish rotation by decreasing speed when we stopped moving mouse + BetaSpeed = 0.0; + AlphaSpeed = 0.0; + yMovement = 0.0; + xMovement = 0.0; + targetAlpha = Alpha; + stepsLeftToChangeBetaByMouse = max(0.0f, stepsLeftToChangeBetaByMouse - CTimer::GetTimeStep()); + mouseChangesBeta = true; + } + } + + if (correctAlpha) { + if (nPreviousMode != MODE_CAM_ON_A_STRING) + alphaCorrected = false; + + if (!alphaCorrected && Abs(zoomModeAlphaOffset + Alpha) > 0.05f) { + yMovement = (-zoomModeAlphaOffset - Alpha) * 0.05f; + } else + alphaCorrected = true; + } + float alphaSpeedFromStickY = yMovement * CARCAM_SET[camSetArrPos][12]; + float betaSpeedFromStickX = xMovement * CARCAM_SET[camSetArrPos][12]; + + float newAngleSpeedMaxBlendAmount = CARCAM_SET[camSetArrPos][9]; + float angleChangeStep = pow(CARCAM_SET[camSetArrPos][8], CTimer::GetTimeStep()); + float targetBetaWithStickBlendAmount = betaSpeedFromStickX + (targetBeta - Beta) / max(CTimer::GetTimeStep(), 1.0f); + + if (targetBetaWithStickBlendAmount < -newAngleSpeedMaxBlendAmount) + targetBetaWithStickBlendAmount = -newAngleSpeedMaxBlendAmount; + else if (targetBetaWithStickBlendAmount > newAngleSpeedMaxBlendAmount) + targetBetaWithStickBlendAmount = newAngleSpeedMaxBlendAmount; + + float angleChangeStepLeft = 1.0f - angleChangeStep; + BetaSpeed = targetBetaWithStickBlendAmount * angleChangeStepLeft + angleChangeStep * BetaSpeed; + if (Abs(BetaSpeed) < 0.0001f) + BetaSpeed = 0.0f; + + float betaChangePerFrame; + if (mouseChangesBeta) + betaChangePerFrame = betaSpeedFromStickX; + else + betaChangePerFrame = CTimer::GetTimeStep() * BetaSpeed; + Beta = betaChangePerFrame + Beta; + + if (TheCamera.m_bJustCameOutOfGarage) { + float invHeading = Atan2(Front.y, Front.x); + if (invHeading < 0.0f) + invHeading += TWOPI; + + Beta = invHeading + PI; + } + + Beta = CGeneral::LimitRadianAngle(Beta); + if (Beta < 0.0f) + Beta += TWOPI; + + if ((camSetArrPos <= 1 || camSetArrPos == 7) && targetAlpha < Alpha && carPosChange >= newDistance) { + if (isCar && ((CAutomobile*)car)->m_nWheelsOnGround > 1) + // || isBike && GetMysteriousWheelRelatedThingBike(car) > 1) + alphaSpeedFromStickY += (targetAlpha - Alpha) * 0.075f; + } + + AlphaSpeed = angleChangeStepLeft * alphaSpeedFromStickY + angleChangeStep * AlphaSpeed; + float maxAlphaSpeed = newAngleSpeedMaxBlendAmount; + if (alphaSpeedFromStickY > 0.0f) + maxAlphaSpeed = maxAlphaSpeed * 0.5; + + if (AlphaSpeed <= maxAlphaSpeed) { + float minAlphaSpeed = -maxAlphaSpeed; + if (AlphaSpeed < minAlphaSpeed) + AlphaSpeed = minAlphaSpeed; + } else { + AlphaSpeed = maxAlphaSpeed; + } + + if (Abs(AlphaSpeed) < 0.0001f) + AlphaSpeed = 0.0f; + + float alphaWithSpeedAccounted; + if (mouseChangesBeta) { + alphaWithSpeedAccounted = alphaSpeedFromStickY + targetAlpha; + Alpha += alphaSpeedFromStickY; + } else { + alphaWithSpeedAccounted = CTimer::GetTimeStep() * AlphaSpeed + targetAlpha; + Alpha += targetAlphaBlendAmount; + } + + if (Alpha <= maxAlphaAllowed) { + float minAlphaAllowed = -CARCAM_SET[camSetArrPos][14]; + if (minAlphaAllowed > Alpha) { + Alpha = minAlphaAllowed; + AlphaSpeed = 0.0f; + } + } else { + Alpha = maxAlphaAllowed; + AlphaSpeed = 0.0f; + } + + // Prevent unsignificant angle changes + if (Abs(lastAlpha - Alpha) < 0.0001f) + Alpha = lastAlpha; + + lastAlpha = Alpha; + + if (Abs(lastBeta - Beta) < 0.0001f) + Beta = lastBeta; + + lastBeta = Beta; + + Front.x = -(cos(Beta) * cos(Alpha)); + Front.y = -(sin(Beta) * cos(Alpha)); + Front.z = sin(Alpha); + GetVectorsReadyForRW(); + TheCamera.m_bCamDirectlyBehind = false; + TheCamera.m_bCamDirectlyInFront = false; + + Source = TargetCoors - newDistance * Front; + + m_cvecTargetCoorsForFudgeInter = TargetCoors; + m_aTargetHistoryPosThree = m_aTargetHistoryPosOne; + float nextAlpha = alphaWithSpeedAccounted + zoomModeAlphaOffset; + float nextFrontX = -(cos(Beta) * cos(nextAlpha)); + float nextFrontY = -(sin(Beta) * cos(nextAlpha)); + float nextFrontZ = sin(nextAlpha); + + m_aTargetHistoryPosOne.x = TargetCoors.x - nextFrontX * nextDistance; + m_aTargetHistoryPosOne.y = TargetCoors.y - nextFrontY * nextDistance; + m_aTargetHistoryPosOne.z = TargetCoors.z - nextFrontZ * nextDistance; + + m_aTargetHistoryPosTwo.x = TargetCoors.x - nextFrontX * newDistance; + m_aTargetHistoryPosTwo.y = TargetCoors.y - nextFrontY * newDistance; + m_aTargetHistoryPosTwo.z = TargetCoors.z - nextFrontZ * newDistance; + + // SA calls SetColVarsVehicle in here + if (nextDirectionIsForward) { + + // This is new in LCS! + float timestepFactor = Pow(0.99f, CTimer::GetTimeStep()); + dontCollideWithCars = (timestepFactor * dontCollideWithCars) + ((1.0f - timestepFactor) * car->m_vecMoveSpeed.Magnitude()); + + // Move cam if on collision + CColPoint foundCol; + CEntity* foundEnt; + CWorld::pIgnoreEntity = CamTargetEntity; + if (CWorld::ProcessLineOfSight(TargetCoors, Source, foundCol, foundEnt, true, dontCollideWithCars < 0.1f, false, true, false, true, false)) { + float obstacleTargetDist = (TargetCoors - foundCol.point).Magnitude(); + float obstacleCamDist = newDistance - obstacleTargetDist; + if (!foundEnt->IsPed() || obstacleCamDist <= 1.0f) { + Source = foundCol.point; + if (obstacleTargetDist < 1.2f) { + RwCameraSetNearClipPlane(Scene.camera, max(0.05f, obstacleTargetDist - 0.3f)); + } + } else { + if (!CWorld::ProcessLineOfSight(foundCol.point, Source, foundCol, foundEnt, true, dontCollideWithCars < 0.1f, false, true, false, true, false)) { + float lessClip = obstacleCamDist - 0.35f; + if (lessClip <= DEFAULT_NEAR) + RwCameraSetNearClipPlane(Scene.camera, lessClip); + else + RwCameraSetNearClipPlane(Scene.camera, DEFAULT_NEAR); + } else { + obstacleTargetDist = (TargetCoors - foundCol.point).Magnitude(); + Source = foundCol.point; + if (obstacleTargetDist < 1.2f) { + float lessClip = obstacleTargetDist - 0.3f; + if (lessClip >= 0.05f) + RwCameraSetNearClipPlane(Scene.camera, lessClip); + else + RwCameraSetNearClipPlane(Scene.camera, 0.05f); + } + } + } + } + CWorld::pIgnoreEntity = nil; + float nearClip = RwCameraGetNearClipPlane(Scene.camera); + float radius = Tan(DEGTORAD(FOV * 0.5f)) * CDraw::GetAspectRatio() * 1.1f; + + // If we're seeing blue hell due to camera intersects some surface, fix it. + // SA and LCS have this unrolled. + for (int i = 0; + i <= 5 && CWorld::TestSphereAgainstWorld((nearClip * Front) + Source, radius * nearClip, nil, true, true, false, true, false, false); + i++) { + + CVector surfaceCamDist = gaTempSphereColPoints->point - Source; + CVector frontButInvertedIfTouchesSurface = DotProduct(surfaceCamDist, Front) * Front; + float newNearClip = (surfaceCamDist - frontButInvertedIfTouchesSurface).Magnitude() / radius; + + if (newNearClip > nearClip) + newNearClip = nearClip; + if (newNearClip < 0.1f) + newNearClip = 0.1f; + if (nearClip > newNearClip) + RwCameraSetNearClipPlane(Scene.camera, newNearClip); + + if (newNearClip == 0.1f) + Source += (TargetCoors - Source) * 0.3f; + + nearClip = RwCameraGetNearClipPlane(Scene.camera); + radius = Tan(DEGTORAD(FOV * 0.5f)) * CDraw::GetAspectRatio() * 1.1f; + } + } + TheCamera.m_bCamDirectlyBehind = false; + TheCamera.m_bCamDirectlyInFront = false; + + // ------- LCS specific part starts + + if (camSetArrPos == 5 && Source.z < 1.0f) // RC Bandit and Baron + Source.z = 1.0f; + + // Obviously some specific place in LC + if (Source.x > 11.0f && Source.x < 91.0f) { + if (Source.y > -680.0f && Source.y < -600.0f && Source.z < 24.4f) + Source.z = 24.4f; + } + + // CCam::FixSourceAboveWaterLevel + if (CameraTarget.z >= -2.0f) { + float level = -6000.0; + // +0.5f is needed for III + if (CWaterLevel::GetWaterLevelNoWaves(Source.x, Source.y, Source.z, &level)) { + if (Source.z < level + 0.5f) + Source.z = level + 0.5f; + } + } + Front = TargetCoors - Source; + + // -------- LCS specific part ends + + GetVectorsReadyForRW(); + // SA + // gTargetCoordsForLookingBehind = TargetCoors; + + // SA code from CAutomobile::TankControl/FireTruckControl. + if (car->m_modelIndex == MI_RHINO || car->m_modelIndex == MI_FIRETRUCK) { + + float &carGunLR = ((CAutomobile*)car)->m_fCarGunLR; + CVector hi = Multiply3x3(Front, car->GetMatrix()); + + // III/VC's firetruck turret angle is reversed + float angleToFace = (car->m_modelIndex == MI_FIRETRUCK ? -hi.Heading() : hi.Heading()); + + if (angleToFace <= carGunLR + PI) { + if (angleToFace < carGunLR - PI) + angleToFace = angleToFace + TWOPI; + } else { + angleToFace = angleToFace - TWOPI; + } + + float neededTurn = angleToFace - carGunLR; + float turnPerFrame = CTimer::GetTimeStep() * (car->m_modelIndex == MI_FIRETRUCK ? 0.05f : 0.015f); + if (neededTurn <= turnPerFrame) { + if (neededTurn < -turnPerFrame) + angleToFace = carGunLR - turnPerFrame; + } else { + angleToFace = turnPerFrame + carGunLR; + } + + if (car->m_modelIndex == MI_RHINO && carGunLR != angleToFace) { + DMAudio.PlayOneShot(car->m_audioEntityId, SOUND_CAR_TANK_TURRET_ROTATE, Abs(angleToFace - carGunLR)); + } + carGunLR = angleToFace; + + if (carGunLR < -PI) { + carGunLR += TWOPI; + } else if (carGunLR > PI) { + carGunLR -= TWOPI; + } + + // Because firetruk turret also has Y movement + if (car->m_modelIndex == MI_FIRETRUCK) { + float &carGunUD = ((CAutomobile*)car)->m_fCarGunUD; + + float alphaToFace = Atan2(hi.z, hi.Magnitude2D()) + DEGTORAD(15.0f); + float neededAlphaTurn = alphaToFace - carGunUD; + float alphaTurnPerFrame = CTimer::GetTimeStep() * 0.02f; + + if (neededAlphaTurn > alphaTurnPerFrame) { + neededTurn = alphaTurnPerFrame; + carGunUD = neededTurn + carGunUD; + } else { + if (neededAlphaTurn >= -alphaTurnPerFrame) { + carGunUD = alphaToFace; + } else { + carGunUD = carGunUD - alphaTurnPerFrame; + } + } + + float turretMinY = -DEGTORAD(20.0f); + float turretMaxY = DEGTORAD(20.0f); + if (turretMinY <= carGunUD) { + if (carGunUD > turretMaxY) + carGunUD = turretMaxY; + } else { + carGunUD = turretMinY; + } + } + } +} +#endif + +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); +ENDPATCHES diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 75e52c5f..e5bc09c8 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -4,1382 +4,3185 @@ #include "Draw.h" #include "World.h" #include "Vehicle.h" +#include "Train.h" +#include "Automobile.h" #include "Ped.h" #include "PlayerPed.h" +#include "Wanted.h" #include "Pad.h" +#include "ControllerConfig.h" #include "General.h" #include "ZoneCull.h" #include "SurfaceTable.h" +#include "WaterLevel.h" +#include "World.h" +#include "Garages.h" +#include "Replay.h" +#include "CutsceneMgr.h" +#include "Renderer.h" #include "MBlur.h" +#include "Text.h" +#include "Hud.h" +#include "DMAudio.h" +#include "FileMgr.h" +#include "Frontend.h" +#include "SceneEdit.h" +#include "Pools.h" +#include "Debug.h" #include "Camera.h" -const float DefaultFOV = 70.0f; // beta: 80.0f +enum +{ + // car + OBBE_WHEEL, + OBBE_1, + OBBE_2, + OBBE_3, + OBBE_1STPERSON, // unused + OBBE_5, + OBBE_ONSTRING, + OBBE_COPCAR, + OBBE_COPCAR_WHEEL, + // ped + OBBE_9, + OBBE_10, + OBBE_11, + OBBE_12, + OBBE_13, + + OBBE_INVALID +}; + +// abbreviate a few things +#define PLAYER (CWorld::Players[CWorld::PlayerInFocus].m_pPed) +// NB: removed explicit TheCamera from all functions CCamera &TheCamera = *(CCamera*)0x6FACF8; bool &CCamera::m_bUseMouse3rdPerson = *(bool *)0x5F03D8; +bool &bDidWeProcessAnyCinemaCam = *(bool*)0x95CD46; -WRAPPER void CCamera::CamShake(float strength, float x, float y, float z) { EAXJMP(0x46B200); } -WRAPPER void CCamera::DrawBordersForWideScreen(void) { EAXJMP(0x46B430); } -WRAPPER void CCamera::CalculateDerivedValues(void) { EAXJMP(0x46EEA0); } -WRAPPER void CCamera::Restore(void) { EAXJMP(0x46F990); } -WRAPPER void CamShakeNoPos(CCamera*, float) { EAXJMP(0x46B100); } -WRAPPER void CCamera::TakeControl(CEntity*, int16, int16, int32) { EAXJMP(0x471500); } -WRAPPER void CCamera::TakeControlNoEntity(const CVector&, int16, int32) { EAXJMP(0x4715B0); } -WRAPPER void CCamera::Init(void) { EAXJMP(0x46BAD0); } -WRAPPER void CCamera::Process(void) { EAXJMP(0x46D3F0); } -WRAPPER void CCamera::LoadPathSplines(int file) { EAXJMP(0x46D1D0); } -WRAPPER void CCamera::RestoreWithJumpCut(void) { EAXJMP(0x46FAE0); }; -WRAPPER void CCamera::SetPercentAlongCutScene(float) { EAXJMP(0x46FE20); }; -WRAPPER void CCamera::SetParametersForScriptInterpolation(float, float, int32) { EAXJMP(0x46FDE0); } +#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)) +#endif -bool -CCamera::GetFading() +void +CCamera::Init(void) { - return m_bFading; + memset(this, 0, sizeof(CCamera)); // getting rid of vtable, eh? + + m_pRwCamera = nil; + m_1rstPersonRunCloseToAWall = false; + m_fPositionAlongSpline = 0.0f; + m_bCameraJustRestored = false; + Cams[0].Init(); + Cams[1].Init(); + Cams[2].Init(); + Cams[0].Mode = CCam::MODE_FOLLOWPED; + Cams[1].Mode = CCam::MODE_FOLLOWPED; + unknown = 0; + m_bJustJumpedOutOf1stPersonBecauseOfTarget = 0; + ClearPlayerWeaponMode(); + m_bInATunnelAndABigVehicle = false; + m_iModeObbeCamIsInForCar = OBBE_INVALID; + Cams[0].CamTargetEntity = nil; + Cams[1].CamTargetEntity = nil; + Cams[2].CamTargetEntity = nil; + Cams[0].m_fCamBufferedHeight = 0.0f; + Cams[0].m_fCamBufferedHeightSpeed = 0.0f; + Cams[1].m_fCamBufferedHeight = 0.0f; + Cams[1].m_fCamBufferedHeightSpeed = 0.0f; + Cams[0].m_bCamLookingAtVector = false; + Cams[1].m_bCamLookingAtVector = false; + Cams[2].m_bCamLookingAtVector = false; + Cams[0].m_fPlayerVelocity = 0.0f; + Cams[1].m_fPlayerVelocity = 0.0f; + Cams[2].m_fPlayerVelocity = 0.0f; + m_bHeadBob = false; + m_fFractionInterToStopMovingTarget = 0.25f; + m_fFractionInterToStopCatchUpTarget = 0.75f; + m_fGaitSwayBuffer = 0.85f; + m_bScriptParametersSetForInterPol = false; + m_uiCamShakeStart = 0; + m_fCamShakeForce = 0.0f; + m_iModeObbeCamIsInForCar = OBBE_INVALID; + m_bIgnoreFadingStuffForMusic = false; + m_bWaitForInterpolToFinish = false; + pToGarageWeAreIn = nil; + pToGarageWeAreInForHackAvoidFirstPerson = nil; + m_bPlayerIsInGarage = false; + m_bJustCameOutOfGarage = false; + m_fNearClipScript = DEFAULT_NEAR; + m_bUseNearClipScript = false; + m_vecDoingSpecialInterPolation = false; + m_bAboveGroundTrainNodesLoaded = false; + m_bBelowGroundTrainNodesLoaded = false; + m_WideScreenOn = false; + m_fFOV_Wide_Screen = 0.0f; + m_bRestoreByJumpCut = false; + CarZoomIndicator = 2.0f; + PedZoomIndicator = 2.0f; + CarZoomValueSmooth = 0.0f; + m_fPedZoomValueSmooth = 0.0f; + pTargetEntity = nil; + if(FindPlayerVehicle()) + pTargetEntity = FindPlayerVehicle(); + else + pTargetEntity = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + m_bInitialNodeFound = false; + m_ScreenReductionPercentage = 0.0f; + m_ScreenReductionSpeed = 0.0f; + m_WideScreenOn = false; + m_bWantsToSwitchWidescreenOff = false; + WorldViewerBeingUsed = false; + PlayerExhaustion = 1.0f; + DebugCamMode = CCam::MODE_NONE; + m_PedOrientForBehindOrInFront = 0.0f; + if(!FrontEndMenuManager.m_bStartGameLoading){ + m_bFading = false; + CDraw::FadeValue = 0; + m_fFLOATingFade = 0.0f; + m_bMusicFading = false; + m_fTimeToFadeMusic = 0.0f; + m_fFLOATingFadeMusic = 0.0f; + } + m_bMoveCamToAvoidGeom = false; + if(FrontEndMenuManager.m_bStartGameLoading) + m_bMoveCamToAvoidGeom = true; + m_bStartingSpline = false; + m_iTypeOfSwitch = INTERPOLATION; + m_bUseScriptZoomValuePed = false; + m_bUseScriptZoomValueCar = false; + m_fPedZoomValueScript = 0.0f; + m_fCarZoomValueScript = 0.0f; + m_bUseSpecialFovTrain = false; + m_fFovForTrain = 70.0f; // or DefaultFOV from Cam.cpp + m_iModeToGoTo = CCam::MODE_FOLLOWPED; + m_bJust_Switched = false; + m_bUseTransitionBeta = false; + m_matrix.SetScale(1.0f); + m_bTargetJustBeenOnTrain = false; + m_bInitialNoNodeStaticsSet = false; + m_uiLongestTimeInMill = 5000; + m_uiTimeLastChange = 0; + m_uiTimeWeEnteredIdle = 0; + m_bIdleOn = false; + LODDistMultiplier = 1.0f; + m_bCamDirectlyBehind = false; + m_bCamDirectlyInFront = false; + m_motionBlur = 0; + m_bGarageFixedCamPositionSet = false; + SetMotionBlur(255, 255, 255, 0, 0); + m_bCullZoneChecksOn = false; + m_bFailedCullZoneTestPreviously = false; + m_iCheckCullZoneThisNumFrames = 6; + m_iZoneCullFrameNumWereAt = 0; + m_CameraAverageSpeed = 0.0f; + m_CameraSpeedSoFar = 0.0f; + m_PreviousCameraPosition = CVector(0.0f, 0.0f, 0.0f); + m_iWorkOutSpeedThisNumFrames = 4; + m_iNumFramesSoFar = 0; + m_bJustInitalised = true; + m_uiTransitionState = 0; + m_uiTimeTransitionStart = 0; + m_bLookingAtPlayer = true; + m_fMouseAccelHorzntl = 0.0025f; + m_fMouseAccelVertical = 0.003f; + m_f3rdPersonCHairMultX = 0.53f; + m_f3rdPersonCHairMultY = 0.4f; } -bool -CCamera::IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat) +void +CCamera::Process(void) { - RwV3d c; - c = *(RwV3d*)¢er; - RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix); - if(c.y + radius < CDraw::GetNearClipZ()) return false; - if(c.y - radius > CDraw::GetFarClipZ()) return false; - if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > radius) return false; - if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > radius) return false; - if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > radius) return false; - if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > radius) return false; - return true; -} + // static bool InterpolatorNotInitialised = true; // unused + static float PlayerMinDist = 1.6f; // not on PS2 + static bool WasPreviouslyInterSyhonFollowPed = false; // only written + float FOV = 0.0f; + float oldBeta, newBeta; + float deltaBeta = 0.0f; + bool lookLRBVehicle = false; + CVector CamFront, CamUp, CamSource, Target; + + m_bJust_Switched = false; + m_RealPreviousCameraPosition = GetPosition(); + + // Update target entity + if(m_bLookingAtPlayer || m_bTargetJustBeenOnTrain || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) + UpdateTargetEntity(); + if(pTargetEntity == nil) + pTargetEntity = FindPlayerPed(); + if(Cams[ActiveCam].CamTargetEntity == nil) + Cams[ActiveCam].CamTargetEntity = pTargetEntity; + if(Cams[(ActiveCam+1)%2].CamTargetEntity == nil) + Cams[(ActiveCam+1)%2].CamTargetEntity = pTargetEntity; + + CamControl(); + if(m_bFading) + ProcessFade(); + if(m_bMusicFading) + ProcessMusicFade(); + if(m_WideScreenOn) + ProcessWideScreenOn(); + +#ifdef IMPROVED_CAMERA + if(CPad::GetPad(1)->GetCircleJustDown() || CTRLJUSTDOWN('B')){ +#else + if(CPad::GetPad(1)->GetCircleJustDown()){ +#endif + WorldViewerBeingUsed = !WorldViewerBeingUsed; + if(WorldViewerBeingUsed) + InitialiseCameraForDebugMode(); + else + CPad::m_bMapPadOneToPadTwo = false; + } -bool -CCamera::IsSphereVisible(const CVector ¢er, float radius) -{ - CMatrix mat = m_cameraMatrix; - return IsSphereVisible(center, radius, &mat); -} + RwCameraSetNearClipPlane(Scene.camera, DEFAULT_NEAR); -bool -CCamera::IsPointVisible(const CVector ¢er, const CMatrix *mat) -{ - RwV3d c; - c = *(RwV3d*)¢er; - RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix); - if(c.y < CDraw::GetNearClipZ()) return false; - if(c.y > CDraw::GetFarClipZ()) return false; - if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > 0.0f) return false; - if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > 0.0f) return false; - if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > 0.0f) return false; - if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > 0.0f) return false; - return true; -} + if(Cams[ActiveCam].Front.x == 0.0f && Cams[ActiveCam].Front.y == 0.0f) + oldBeta = 0.0f; + else + oldBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y); -bool -CCamera::IsBoxVisible(RwV3d *box, const CMatrix *mat) -{ - int i; - int frustumTests[6] = { 0 }; - RwV3dTransformPoints(box, box, 8, &mat->m_matrix); + Cams[ActiveCam].Process(); + Cams[ActiveCam].ProcessSpecialHeightRoutines(); - for(i = 0; i < 8; i++){ - if(box[i].y < CDraw::GetNearClipZ()) frustumTests[0]++; - if(box[i].y > CDraw::GetFarClipZ()) frustumTests[1]++; - if(box[i].x*m_vecFrustumNormals[0].x + box[i].y*m_vecFrustumNormals[0].y > 0.0f) frustumTests[2]++; - if(box[i].x*m_vecFrustumNormals[1].x + box[i].y*m_vecFrustumNormals[1].y > 0.0f) frustumTests[3]++; -// Why not test z? -// if(box[i].y*m_vecFrustumNormals[2].y + box[i].z*m_vecFrustumNormals[2].z > 0.0f) frustumTests[4]++; -// if(box[i].y*m_vecFrustumNormals[3].y + box[i].z*m_vecFrustumNormals[3].z > 0.0f) frustumTests[5]++; - } - for(i = 0; i < 6; i++) - if(frustumTests[i] == 8) - return false; // Box is completely outside of one plane - return true; -} + if(Cams[ActiveCam].Front.x == 0.0f && Cams[ActiveCam].Front.y == 0.0f) + newBeta = 0.0f; + else + newBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y); -int -CCamera::GetLookDirection(void) -{ - if(Cams[ActiveCam].Mode == CCam::MODE_CAM_ON_A_STRING || - Cams[ActiveCam].Mode == CCam::MODE_1STPERSON || - Cams[ActiveCam].Mode == CCam::MODE_BEHINDBOAT || - Cams[ActiveCam].Mode == CCam::MODE_FOLLOWPED) - return Cams[ActiveCam].DirectionWasLooking; - return LOOKING_FORWARD;; -} -bool -CCamera::GetLookingForwardFirstPerson() -{ - return Cams[ActiveCam].Mode == CCam::MODE_1STPERSON && - Cams[ActiveCam].DirectionWasLooking == LOOKING_FORWARD; -} + // Stop transition when it's done + if(m_uiTransitionState != 0){ +/* + // PS2: + if(!m_bWaitForInterpolToFinish){ + Cams[(ActiveCam+1)%2].Process(); + Cams[(ActiveCam+1)%2].ProcessSpecialHeightRoutines(); + } +*/ + // not PS2 (done in CamControl there it seems) + if(CTimer::GetTimeInMilliseconds() > m_uiTransitionDuration+m_uiTimeTransitionStart){ + m_uiTransitionState = 0; + m_vecDoingSpecialInterPolation = false; + m_bWaitForInterpolToFinish = false; + } + } + if(m_bUseNearClipScript) + RwCameraSetNearClipPlane(Scene.camera, m_fNearClipScript); + + deltaBeta = newBeta - oldBeta; + while(deltaBeta >= PI) deltaBeta -= 2*PI; + while(deltaBeta < -PI) deltaBeta += 2*PI; + if(Abs(deltaBeta) > 0.3f) + m_bJust_Switched = true; + + // Debug stuff + if(!gbModelViewer) + Cams[ActiveCam].PrintMode(); + if(WorldViewerBeingUsed) + Cams[2].Process(); + + if(Cams[ActiveCam].DirectionWasLooking != LOOKING_FORWARD && pTargetEntity->IsVehicle()) + lookLRBVehicle = true; + + if(m_uiTransitionState != 0 && !lookLRBVehicle){ + // Process transition + // different on PS2 + + uint32 currentTime = CTimer::GetTimeInMilliseconds() - m_uiTimeTransitionStart; + if(currentTime >= m_uiTransitionDuration) + currentTime = m_uiTransitionDuration; + float fractionInter = (float) currentTime / m_uiTransitionDuration; + + if(fractionInter <= m_fFractionInterToStopMovingTarget){ + float inter; + if(m_fFractionInterToStopMovingTarget == 0.0f) + inter = 0.0f; + else + inter = (m_fFractionInterToStopMovingTarget - fractionInter)/m_fFractionInterToStopMovingTarget; + inter = 0.5f - 0.5*Cos(inter*PI); // smooth it + + m_vecSourceWhenInterPol = m_cvecStartingSourceForInterPol + inter*m_cvecSourceSpeedAtStartInter; + m_vecTargetWhenInterPol = m_cvecStartingTargetForInterPol + inter*m_cvecTargetSpeedAtStartInter; + m_vecUpWhenInterPol = m_cvecStartingUpForInterPol + inter*m_cvecUpSpeedAtStartInter; + m_fFOVWhenInterPol = m_fStartingFOVForInterPol + inter*m_fFOVSpeedAtStartInter; + + CamSource = m_vecSourceWhenInterPol; + + if(m_bItsOkToLookJustAtThePlayer){ + m_vecTargetWhenInterPol.x = FindPlayerPed()->GetPosition().x; + m_vecTargetWhenInterPol.y = FindPlayerPed()->GetPosition().y; + m_fBetaWhenInterPol = m_fStartingBetaForInterPol + inter*m_fBetaSpeedAtStartInter; + + float dist = (CamSource - m_vecTargetWhenInterPol).Magnitude2D(); + if(dist < PlayerMinDist){ + if(dist > 0.0f){ + CamSource.x = m_vecTargetWhenInterPol.x + PlayerMinDist*Cos(m_fBetaWhenInterPol); + CamSource.y = m_vecTargetWhenInterPol.y + PlayerMinDist*Sin(m_fBetaWhenInterPol); + }else{ + // can only be 0.0 now... + float beta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y); + CamSource.x = m_vecTargetWhenInterPol.x + PlayerMinDist*Cos(beta); + CamSource.y = m_vecTargetWhenInterPol.y + PlayerMinDist*Sin(beta); + } + }else{ + CamSource.x = m_vecTargetWhenInterPol.x + dist*Cos(m_fBetaWhenInterPol); + CamSource.y = m_vecTargetWhenInterPol.y + dist*Sin(m_fBetaWhenInterPol); + } + } -WRAPPER void CCamera::Fade(float timeout, int16 direction) { EAXJMP(0x46B3A0); } -WRAPPER void CCamera::ProcessFade(void) { EAXJMP(0x46F080); } -WRAPPER void CCamera::ProcessMusicFade(void) { EAXJMP(0x46F1E0); } + CamFront = m_vecTargetWhenInterPol - CamSource; + StoreValuesDuringInterPol(CamSource, m_vecTargetWhenInterPol, m_vecUpWhenInterPol, m_fFOVWhenInterPol); + Target = m_vecTargetWhenInterPol; + CamFront.Normalise(); + if(m_bLookingAtPlayer) + CamUp = CVector(0.0f, 0.0f, 1.0f); + else + CamUp = m_vecUpWhenInterPol; + CamUp.Normalise(); -int -CCamera::GetScreenFadeStatus(void) -{ - if(m_fFLOATingFade == 0.0f) - return FADE_0; - if(m_fFLOATingFade == 255.0f) - return FADE_2; - return FADE_1; -} + if(Cams[ActiveCam].Mode == CCam::MODE_TOPDOWN || Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){ + CamFront.Normalise(); + CamUp = CrossProduct(CamFront, CVector(-1.0f, 0.0f, 0.0f)); + }else{ + CamFront.Normalise(); + CamUp.Normalise(); + CVector right = CrossProduct(CamFront, CamUp); + right.Normalise(); + CamUp = CrossProduct(right, CamFront); + } + CamUp.Normalise(); + FOV = m_fFOVWhenInterPol; + }else if(fractionInter > m_fFractionInterToStopMovingTarget && fractionInter <= 1.0f){ + float inter; + if(m_fFractionInterToStopCatchUpTarget == 0.0f) + inter = 0.0f; + else + inter = (fractionInter - m_fFractionInterToStopMovingTarget)/m_fFractionInterToStopCatchUpTarget; + inter = 0.5f - 0.5*Cos(inter*PI); // smooth it + + CamSource = m_vecSourceWhenInterPol + inter*(Cams[ActiveCam].Source - m_vecSourceWhenInterPol); + FOV = m_fFOVWhenInterPol + inter*(Cams[ActiveCam].FOV - m_fFOVWhenInterPol); + Target = m_vecTargetWhenInterPol + inter*(Cams[ActiveCam].m_cvecTargetCoorsForFudgeInter - m_vecTargetWhenInterPol); + CamUp = m_vecUpWhenInterPol + inter*(Cams[ActiveCam].Up - m_vecUpWhenInterPol); + deltaBeta = Cams[ActiveCam].m_fTrueBeta - m_fBetaWhenInterPol; + MakeAngleLessThan180(deltaBeta); + float interpBeta = m_fBetaWhenInterPol + inter*deltaBeta; + + if(m_bItsOkToLookJustAtThePlayer){ + Target.x = FindPlayerPed()->GetPosition().x; + Target.y = FindPlayerPed()->GetPosition().y; + + float dist = (CamSource - Target).Magnitude2D(); + if(dist < PlayerMinDist){ + if(dist > 0.0f){ + CamSource.x = Target.x + PlayerMinDist*Cos(interpBeta); + CamSource.y = Target.y + PlayerMinDist*Sin(interpBeta); + }else{ + // can only be 0.0 now... + float beta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y); + CamSource.x = Target.x + PlayerMinDist*Cos(beta); + CamSource.y = Target.y + PlayerMinDist*Sin(beta); + } + }else{ + CamSource.x = Target.x + dist*Cos(interpBeta); + CamSource.y = Target.y + dist*Sin(interpBeta); + } + } -void -CCamera::SetFadeColour(uint8 r, uint8 g, uint8 b) -{ - m_FadeTargetIsSplashScreen = r == 0 && g == 0 && b == 0; - CDraw::FadeRed = r; - CDraw::FadeGreen = g; - CDraw::FadeBlue = b; -} + CamFront = Target - CamSource; + StoreValuesDuringInterPol(CamSource, Target, CamUp, FOV); + CamFront.Normalise(); + if(m_bLookingAtPlayer) + CamUp = CVector(0.0f, 0.0f, 1.0f); -void -CCamera::SetMotionBlur(int r, int g, int b, int a, int type) -{ - m_BlurRed = r; - m_BlurGreen = g; - m_BlurBlue = b; - m_motionBlur = a; - m_BlurType = type; -} + if(Cams[ActiveCam].Mode == CCam::MODE_TOPDOWN || Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){ + CamFront.Normalise(); + CamUp = CrossProduct(CamFront, CVector(-1.0f, 0.0f, 0.0f)); + }else{ + CamFront.Normalise(); + CamUp.Normalise(); + CVector right = CrossProduct(CamFront, CamUp); + right.Normalise(); + CamUp = CrossProduct(right, CamFront); + } + CamUp.Normalise(); +#ifndef FIX_BUGS + // BUG: FOV was already interpolated but m_fFOVWhenInterPol was not + FOV = m_fFOVWhenInterPol; +#endif + } -void -CCamera::SetMotionBlurAlpha(int a) -{ - m_imotionBlurAddAlpha = a; -} + CVector Dist = CamSource - Target; + float DistOnGround = Dist.Magnitude2D(); + float Alpha = CGeneral::GetATanOfXY(DistOnGround, Dist.z); + float Beta = CGeneral::GetATanOfXY(Dist.x, Dist.y); + Cams[ActiveCam].KeepTrackOfTheSpeed(CamSource, Target, CamUp, Alpha, Beta, FOV); + }else{ + // No transition, take Cam values directly + if(WorldViewerBeingUsed){ + CamSource = Cams[2].Source; + CamFront = Cams[2].Front; + CamUp = Cams[2].Up; + FOV = Cams[2].FOV; + }else{ + CamSource = Cams[ActiveCam].Source; + CamFront = Cams[ActiveCam].Front; + CamUp = Cams[ActiveCam].Up; + FOV = Cams[ActiveCam].FOV; + } + WasPreviouslyInterSyhonFollowPed = false; // unused + } -void -CCamera::SetNearClipScript(float clip) -{ - m_fNearClipScript = clip; - m_bUseNearClipScript = true; -} + if(m_uiTransitionState != 0) + if(!m_bLookingAtVector && m_bLookingAtPlayer && !CCullZones::CamStairsForPlayer() && !m_bPlayerIsInGarage){ + CEntity *entity = nil; + CColPoint colPoint; + if(CWorld::ProcessLineOfSight(pTargetEntity->GetPosition(), CamSource, colPoint, entity, true, false, false, true, false, true, true)){ + CamSource = colPoint.point; + RwCameraSetNearClipPlane(Scene.camera, 0.05f); + } + } -void -CCamera::RenderMotionBlur(void) -{ - if(m_BlurType == 0) - return; + GetRight() = CrossProduct(CamUp, CamFront); // actually Left + GetForward() = CamFront; + GetUp() = CamUp; + GetPosition() = CamSource; + + // Process Shake + float shakeStrength = m_fCamShakeForce - 0.28f*(CTimer::GetTimeInMilliseconds()-m_uiCamShakeStart)/1000.0f; + shakeStrength = clamp(shakeStrength, 0.0f, 2.0f); + int shakeRand = CGeneral::GetRandomNumber(); + float shakeOffset = shakeStrength*0.1f; + GetPosition().x += shakeOffset*((shakeRand&0xF)-7); + GetPosition().y += shakeOffset*(((shakeRand&0xF0)>>4)-7); + GetPosition().z += shakeOffset*(((shakeRand&0xF00)>>8)-7); + + if(shakeOffset > 0.0f && m_BlurType != MBLUR_SNIPER) + SetMotionBlurAlpha(min((int)(shakeStrength*255.0f) + 25, 150)); + if(Cams[ActiveCam].Mode == CCam::MODE_1STPERSON && FindPlayerVehicle() && FindPlayerVehicle()->GetUp().z < 0.2f) + SetMotionBlur(230, 230, 230, 215, MBLUR_NORMAL); + + CalculateDerivedValues(); + CDraw::SetFOV(FOV); + + // Set RW camera + if(WorldViewerBeingUsed){ + RwFrame *frame = RwCameraGetFrame(m_pRwCamera); + CVector Source = Cams[2].Source; + CVector Front = Cams[2].Front; + CVector Up = Cams[2].Up; + + GetRight() = CrossProduct(Up, Front); + GetForward() = Front; + GetUp() = Up; + GetPosition() = Source; + + CDraw::SetFOV(Cams[2].FOV); + m_vecGameCamPos = Cams[ActiveCam].Source; + + *RwMatrixGetPos(RwFrameGetMatrix(frame)) = (RwV3d)GetPosition(); + *RwMatrixGetAt(RwFrameGetMatrix(frame)) = (RwV3d)GetForward(); + *RwMatrixGetUp(RwFrameGetMatrix(frame)) = (RwV3d)GetUp(); + *RwMatrixGetRight(RwFrameGetMatrix(frame)) = (RwV3d)GetRight(); + RwMatrixUpdate(RwFrameGetMatrix(frame)); + RwFrameUpdateObjects(frame); + }else{ + RwFrame *frame = RwCameraGetFrame(m_pRwCamera); + m_vecGameCamPos = GetPosition(); + *RwMatrixGetPos(RwFrameGetMatrix(frame)) = (RwV3d)GetPosition(); + *RwMatrixGetAt(RwFrameGetMatrix(frame)) = (RwV3d)GetForward(); + *RwMatrixGetUp(RwFrameGetMatrix(frame)) = (RwV3d)GetUp(); + *RwMatrixGetRight(RwFrameGetMatrix(frame)) = (RwV3d)GetRight(); + RwMatrixUpdate(RwFrameGetMatrix(frame)); + RwFrameUpdateObjects(frame); + } - CMBlur::MotionBlurRender(m_pRwCamera, - m_BlurRed, m_BlurGreen, m_BlurBlue, - m_motionBlur, m_BlurType, m_imotionBlurAddAlpha); -} + CDraw::SetNearClipZ(RwCameraGetNearClipPlane(m_pRwCamera)); + CDraw::SetFarClipZ(RwCameraGetFarClipPlane(m_pRwCamera)); -void -CCamera::ClearPlayerWeaponMode() -{ - PlayerWeaponMode.Mode = 0; - PlayerWeaponMode.MaxZoom = 1; - PlayerWeaponMode.MinZoom = -1; - PlayerWeaponMode.Duration = 0.0f; -} + UpdateSoundDistances(); + if((CTimer::GetFrameCounter()&0xF) == 3) + DistanceToWater = CWaterLevel::CalcDistanceToWater(GetPosition().x, GetPosition().y); -/* - * - * CCam - * - */ + // LOD dist + if(!CCutsceneMgr::IsRunning() || CCutsceneMgr::UseLodMultiplier()) + LODDistMultiplier = 70.0f/CDraw::GetFOV() * CDraw::GetAspectRatio()/(4.0f/3.0f); + else + LODDistMultiplier = 1.0f; + GenerationDistMultiplier = LODDistMultiplier; + LODDistMultiplier *= CRenderer::ms_lodDistScale; + + // Keep track of speed + if(m_bJustInitalised || m_bJust_Switched){ + m_PreviousCameraPosition = GetPosition(); + m_bJustInitalised = false; + } + m_CameraSpeedSoFar += (GetPosition() - m_PreviousCameraPosition).Magnitude(); + m_iNumFramesSoFar++; + if(m_iNumFramesSoFar == m_iWorkOutSpeedThisNumFrames){ + m_CameraAverageSpeed = m_CameraSpeedSoFar / m_iWorkOutSpeedThisNumFrames; + m_CameraSpeedSoFar = 0.0f; + m_iNumFramesSoFar = 0; + } + m_PreviousCameraPosition = GetPosition(); + // PS2: something doing on with forward vector here -// 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(Cams[ActiveCam].DirectionWasLooking != LOOKING_FORWARD && Cams[ActiveCam].Mode != CCam::MODE_TOP_DOWN_PED){ + Cams[ActiveCam].Source = Cams[ActiveCam].SourceBeforeLookBehind; + Orientation += PI; + } - if(IsAngle){ - while(Delta >= PI) Delta -= 2*PI; - while(Delta < -PI) Delta += 2*PI; + if(m_uiTransitionState != 0){ + int OtherCam = (ActiveCam+1)%2; + if(Cams[OtherCam].CamTargetEntity && + pTargetEntity && pTargetEntity->IsPed() && + !Cams[OtherCam].CamTargetEntity->IsVehicle() && + Cams[ActiveCam].Mode != CCam::MODE_TOP_DOWN_PED && Cams[ActiveCam].DirectionWasLooking != LOOKING_FORWARD){ + Cams[OtherCam].Source = Cams[ActiveCam%2].SourceBeforeLookBehind; + Orientation += 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()); + m_bCameraJustRestored = false; } 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) +CCamera::CamControl(void) { - int i; - CVector Average = { 0.0f, 0.0f, 0.0f }; - - if(ResetStatics){ - m_iRunningVectorArrayPos = 0; - m_iRunningVectorCounter = 1; + static bool PlaceForFixedWhenSniperFound = false; + static int16 ReqMode; + bool disableGarageCam = false; + bool switchByJumpCut = false; + bool stairs = false; + bool boatTarget = false; + CVector targetPos; + CVector garageCenter, garageDoorPos1, garageDoorPos2; + CVector garageCenterToDoor, garageCamPos; + int whichDoor; + + m_bObbeCinematicPedCamOn = false; + m_bObbeCinematicCarCamOn = false; + m_bUseTransitionBeta = false; + m_bUseSpecialFovTrain = false; + m_bJustCameOutOfGarage = false; + m_bTargetJustCameOffTrain = false; + m_bInATunnelAndABigVehicle = false; + + if(Cams[ActiveCam].CamTargetEntity == nil && pTargetEntity == nil) + pTargetEntity = PLAYER; + + m_iZoneCullFrameNumWereAt++; + if(m_iZoneCullFrameNumWereAt > m_iCheckCullZoneThisNumFrames) + m_iZoneCullFrameNumWereAt = 1; + m_bCullZoneChecksOn = m_iZoneCullFrameNumWereAt == m_iCheckCullZoneThisNumFrames; + if(m_bCullZoneChecksOn) + m_bFailedCullZoneTestPreviously = CCullZones::CamCloseInForPlayer(); + + if(m_bLookingAtPlayer){ + CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_1; + FindPlayerPed()->bIsVisible = true; } - // 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; + if(!CTimer::GetIsPaused()){ + float CloseInCarHeightTarget = 0.0f; + float CloseInPedHeightTarget = 0.0f; + + if(m_bTargetJustBeenOnTrain){ + // Getting off train + if(!pTargetEntity->IsVehicle() || !((CVehicle*)pTargetEntity)->IsTrain()){ + Restore(); + m_bTargetJustCameOffTrain = true; + m_bTargetJustBeenOnTrain = false; + SetWideScreenOff(); + } + } - for(i = 0; i <= m_iRunningVectorArrayPos; i++) - Average += m_arrPreviousVectors[i]; - Average /= i; + // Vehicle target + if(pTargetEntity->IsVehicle()){ + if(((CVehicle*)pTargetEntity)->IsTrain()){ + if(!m_bTargetJustBeenOnTrain){ + m_bInitialNodeFound = false; + m_bInitialNoNodeStaticsSet = false; + } + Process_Train_Camera_Control(); + }else{ + if(((CVehicle*)pTargetEntity)->IsBoat()) + boatTarget = true; + + // Change user selected mode + if(CPad::GetPad(0)->CycleCameraModeUpJustDown() && !CReplay::IsPlayingBack() && + (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) && + !m_WideScreenOn) + CarZoomIndicator -= 1.0f; + if(CPad::GetPad(0)->CycleCameraModeDownJustDown() && !CReplay::IsPlayingBack() && + (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) && + !m_WideScreenOn) + CarZoomIndicator += 1.0f; + if(!m_bFailedCullZoneTestPreviously){ + if(CarZoomIndicator < CAM_ZOOM_1STPRS) CarZoomIndicator = CAM_ZOOM_CINEMATIC; + else if(CarZoomIndicator > CAM_ZOOM_CINEMATIC) CarZoomIndicator = CAM_ZOOM_1STPRS; + } - 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; + if(m_bFailedCullZoneTestPreviously) + if(CarZoomIndicator != CAM_ZOOM_1STPRS && CarZoomIndicator != CAM_ZOOM_TOPDOWN) + ReqMode = CCam::MODE_CAM_ON_A_STRING; + + switch(((CVehicle*)pTargetEntity)->m_vehType){ + case VEHICLE_TYPE_CAR: + case VEHICLE_TYPE_BIKE: + if(CGarages::IsPointInAGarageCameraZone(pTargetEntity->GetPosition())){ + if(!m_bGarageFixedCamPositionSet && m_bLookingAtPlayer || + WhoIsInControlOfTheCamera == CAMCONTROL_OBBE){ + if(pToGarageWeAreIn){ + float ground; + bool foundGround; + + // This is all very strange.... + // targetPos = pTargetEntity->GetPosition(); // unused + if(pToGarageWeAreIn->m_pDoor1){ + whichDoor = 1; + garageDoorPos1.x = pToGarageWeAreIn->m_fDoor1X; + garageDoorPos1.y = pToGarageWeAreIn->m_fDoor1Y; + garageDoorPos1.z = 0.0f; + // targetPos.z = 0.0f; // unused + // (targetPos - doorPos1).Magnitude(); // unused + }else if(pToGarageWeAreIn->m_pDoor2){ + whichDoor = 2; +#ifdef FIX_BUGS + garageDoorPos2.x = pToGarageWeAreIn->m_fDoor2X; + garageDoorPos2.y = pToGarageWeAreIn->m_fDoor2Y; + garageDoorPos2.z = 0.0f; +#endif + }else{ + whichDoor = 1; + garageDoorPos1.x = pTargetEntity->GetPosition().x; + garageDoorPos1.y = pTargetEntity->GetPosition().y; +#ifdef FIX_BUGS + garageDoorPos1.z = 0.0f; +#else + garageDoorPos2.z = 0.0f; +#endif + } + garageCenter.x = (pToGarageWeAreIn->m_fX1 + pToGarageWeAreIn->m_fX2)/2.0f; + garageCenter.y = (pToGarageWeAreIn->m_fY1 + pToGarageWeAreIn->m_fY2)/2.0f; + garageCenter.z = 0.0f; + if(whichDoor == 1) + garageCenterToDoor = garageDoorPos1 - garageCenter; + else + garageCenterToDoor = garageDoorPos2 - garageCenter; + targetPos = pTargetEntity->GetPosition(); + ground = CWorld::FindGroundZFor3DCoord(targetPos.x, targetPos.y, targetPos.z, &foundGround); + if(!foundGround) + ground = targetPos.z - 0.2f; + garageCenterToDoor.z = 0.0f; + garageCenterToDoor.Normalise(); + if(whichDoor == 1) + garageCamPos = garageDoorPos1 + 13.0f*garageCenterToDoor; + else + garageCamPos = garageDoorPos2 + 13.0f*garageCenterToDoor; + garageCamPos.z = ground + 3.1f; + SetCamPositionForFixedMode(garageCamPos, CVector(0.0f, 0.0f, 0.0f)); + m_bGarageFixedCamPositionSet = true; + } + } + + if(CGarages::CameraShouldBeOutside() && m_bGarageFixedCamPositionSet && + (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE)){ + if(pToGarageWeAreIn){ + ReqMode = CCam::MODE_FIXED; + m_bPlayerIsInGarage = true; + } + }else{ + if(m_bPlayerIsInGarage){ + m_bJustCameOutOfGarage = true; + m_bPlayerIsInGarage = false; + } + ReqMode = CCam::MODE_CAM_ON_A_STRING; + } + }else{ + if(m_bPlayerIsInGarage){ + m_bJustCameOutOfGarage = true; + m_bPlayerIsInGarage = false; + } + m_bGarageFixedCamPositionSet = false; + ReqMode = CCam::MODE_CAM_ON_A_STRING; + } + break; + case VEHICLE_TYPE_BOAT: + ReqMode = CCam::MODE_BEHINDBOAT; + break; + } - return Average; -} + // Car zoom value + if(CarZoomIndicator == CAM_ZOOM_1STPRS && !m_bPlayerIsInGarage){ + CarZoomValue = 0.0f; + ReqMode = CCam::MODE_1STPERSON; + }else if(CarZoomIndicator == CAM_ZOOM_1) + CarZoomValue = 0.05f; + else if(CarZoomIndicator == CAM_ZOOM_2) + CarZoomValue = 1.9f; + else if(CarZoomIndicator == CAM_ZOOM_3) + CarZoomValue = 3.9f; + if(CarZoomIndicator == CAM_ZOOM_TOPDOWN && !m_bPlayerIsInGarage){ + CarZoomValue = 1.0f; + ReqMode = CCam::MODE_TOPDOWN; + } -// 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; -} + // Check if we have to go into first person + if(((CVehicle*)pTargetEntity)->IsCar() && !m_bPlayerIsInGarage){ + if(CCullZones::Cam1stPersonForPlayer() && + pTargetEntity->GetColModel()->boundingBox.GetSize().z >= 3.026f && + pToGarageWeAreInForHackAvoidFirstPerson == nil){ + ReqMode = CCam::MODE_1STPERSON; + m_bInATunnelAndABigVehicle = true; + } + } + if(ReqMode == CCam::MODE_TOPDOWN && + (CCullZones::Cam1stPersonForPlayer() || CCullZones::CamNoRain() || CCullZones::PlayerNoRain())) + ReqMode = CCam::MODE_1STPERSON; + + // Smooth zoom value - ugly code + if(m_bUseScriptZoomValueCar){ + if(CarZoomValueSmooth < m_fCarZoomValueScript){ + CarZoomValueSmooth += 0.12f * CTimer::GetTimeStep(); + CarZoomValueSmooth = min(CarZoomValueSmooth, m_fCarZoomValueScript); + }else{ + CarZoomValueSmooth -= 0.12f * CTimer::GetTimeStep(); + CarZoomValueSmooth = max(CarZoomValueSmooth, m_fCarZoomValueScript); + } + }else if(m_bFailedCullZoneTestPreviously){ + CloseInCarHeightTarget = 0.65f; + if(CarZoomValueSmooth < -0.65f){ + CarZoomValueSmooth += 0.12f * CTimer::GetTimeStep(); + CarZoomValueSmooth = min(CarZoomValueSmooth, -0.65f); + }else{ + CarZoomValueSmooth -= 0.12f * CTimer::GetTimeStep(); + CarZoomValueSmooth = max(CarZoomValueSmooth, -0.65f); + } + }else{ + if(CarZoomValueSmooth < CarZoomValue){ + CarZoomValueSmooth += 0.12f * CTimer::GetTimeStep(); + CarZoomValueSmooth = min(CarZoomValueSmooth, CarZoomValue); + }else{ + CarZoomValueSmooth -= 0.12f * CTimer::GetTimeStep(); + CarZoomValueSmooth = max(CarZoomValueSmooth, CarZoomValue); + } + } -static float DefaultAcceleration = 0.045f; -static float DefaultMaxStep = 0.15f; + WellBufferMe(CloseInCarHeightTarget, &Cams[ActiveCam].m_fCloseInCarHeightOffset, &Cams[ActiveCam].m_fCloseInCarHeightOffsetSpeed, 0.1f, 0.25f, false); -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; + // Fallen into water + if(Cams[ActiveCam].IsTargetInWater(Cams[ActiveCam].Source) && !boatTarget && + !Cams[ActiveCam].CamTargetEntity->IsPed()) + ReqMode = CCam::MODE_PLAYER_FALLEN_WATER; + } } - 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 - } + // Ped target + else if(pTargetEntity->IsPed()){ + // Change user selected mode + if(CPad::GetPad(0)->CycleCameraModeUpJustDown() && !CReplay::IsPlayingBack() && + (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) && + !m_WideScreenOn && !m_bFailedCullZoneTestPreviously){ + if(FrontEndMenuManager.m_ControlMethod == CONTROL_STANDARD){ + if(PedZoomIndicator == CAM_ZOOM_TOPDOWN) + PedZoomIndicator = CAM_ZOOM_1; + else + PedZoomIndicator = CAM_ZOOM_TOPDOWN; + }else + PedZoomIndicator -= 1.0f; + } + if(CPad::GetPad(0)->CycleCameraModeDownJustDown() && !CReplay::IsPlayingBack() && + (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) && + !m_WideScreenOn && !m_bFailedCullZoneTestPreviously){ + if(FrontEndMenuManager.m_ControlMethod == CONTROL_STANDARD){ + if(PedZoomIndicator == CAM_ZOOM_TOPDOWN) + PedZoomIndicator = CAM_ZOOM_1; + else + PedZoomIndicator = CAM_ZOOM_TOPDOWN; + }else + PedZoomIndicator += 1.0f; + } + // disabled obbe's cam here + if(PedZoomIndicator < CAM_ZOOM_1) PedZoomIndicator = CAM_ZOOM_TOPDOWN; + else if(PedZoomIndicator > CAM_ZOOM_TOPDOWN) PedZoomIndicator = CAM_ZOOM_1; + + ReqMode = CCam::MODE_FOLLOWPED; + + // Check 1st person mode + if(m_bLookingAtPlayer && pTargetEntity->IsPed() && !m_WideScreenOn && !Cams[0].Using3rdPersonMouseCam() +#ifdef FREE_CAM + && !CCamera::bFreeCam +#endif + ){ + // See if we want to enter first person mode + if(CPad::GetPad(0)->LookAroundLeftRight() || CPad::GetPad(0)->LookAroundUpDown()){ + m_uiFirstPersonCamLastInputTime = CTimer::GetTimeInMilliseconds(); + m_bFirstPersonBeingUsed = true; + }else if(m_bFirstPersonBeingUsed){ + // Or if we want to go back to 3rd person + if(CPad::GetPad(0)->GetPedWalkLeftRight() || CPad::GetPad(0)->GetPedWalkUpDown() || + CPad::GetPad(0)->GetSquare() || CPad::GetPad(0)->GetTriangle() || + CPad::GetPad(0)->GetCross() || CPad::GetPad(0)->GetCircle() || + CTimer::GetTimeInMilliseconds() - m_uiFirstPersonCamLastInputTime > 2850.0f) + m_bFirstPersonBeingUsed = false; + } + }else + m_bFirstPersonBeingUsed = false; + + if(!FindPlayerPed()->IsPedInControl() || FindPlayerPed()->m_fMoveSpeed > 0.0f) + m_bFirstPersonBeingUsed = false; + if(m_bFirstPersonBeingUsed){ + ReqMode = CCam::MODE_1STPERSON; + CPad::GetPad(0)->DisablePlayerControls |= PLAYERCONTROL_DISABLED_1; + } + // Zoom value + if(PedZoomIndicator == CAM_ZOOM_1) + m_fPedZoomValue = 0.25f; + else if(PedZoomIndicator == CAM_ZOOM_2) + m_fPedZoomValue = 1.5f; + else if(PedZoomIndicator == CAM_ZOOM_3) + m_fPedZoomValue = 2.9f; + + // Smooth zoom value - ugly code + if(m_bUseScriptZoomValuePed){ + if(m_fPedZoomValueSmooth < m_fPedZoomValueScript){ + m_fPedZoomValueSmooth += 0.12f * CTimer::GetTimeStep(); + m_fPedZoomValueSmooth = min(m_fPedZoomValueSmooth, m_fPedZoomValueScript); + }else{ + m_fPedZoomValueSmooth -= 0.12f * CTimer::GetTimeStep(); + m_fPedZoomValueSmooth = max(m_fPedZoomValueSmooth, m_fPedZoomValueScript); + } + }else if(m_bFailedCullZoneTestPreviously){ + static float PedZoomedInVal = 0.5f; + CloseInPedHeightTarget = 0.7f; + if(m_fPedZoomValueSmooth < PedZoomedInVal){ + m_fPedZoomValueSmooth += 0.12f * CTimer::GetTimeStep(); + m_fPedZoomValueSmooth = min(m_fPedZoomValueSmooth, PedZoomedInVal); + }else{ + m_fPedZoomValueSmooth -= 0.12f * CTimer::GetTimeStep(); + m_fPedZoomValueSmooth = max(m_fPedZoomValueSmooth, PedZoomedInVal); + } + }else{ + if(m_fPedZoomValueSmooth < m_fPedZoomValue){ + m_fPedZoomValueSmooth += 0.12f * CTimer::GetTimeStep(); + m_fPedZoomValueSmooth = min(m_fPedZoomValueSmooth, m_fPedZoomValue); + }else{ + m_fPedZoomValueSmooth -= 0.12f * CTimer::GetTimeStep(); + m_fPedZoomValueSmooth = max(m_fPedZoomValueSmooth, m_fPedZoomValue); + } + } - TargetCoors = CameraTarget; - IdealSource = Source; - TargetCoors.z += m_fSyphonModeTargetZOffSet; + WellBufferMe(CloseInPedHeightTarget, &Cams[ActiveCam].m_fCloseInPedHeightOffset, &Cams[ActiveCam].m_fCloseInPedHeightOffsetSpeed, 0.1f, 0.025f, false); - CVector TempTargetCoors; - TempTargetCoors = DoAverageOnVector(TargetCoors); - TargetCoors = TempTargetCoors; - // Add this unknown offset, but later it's removed again - TargetCoors.z += m_fUnknownZOffSet; + // Check if entering fight cam + if(!m_bFirstPersonBeingUsed){ + if(FindPlayerPed()->GetPedState() == PED_FIGHT && !m_bUseMouse3rdPerson) + ReqMode = CCam::MODE_FIGHT_CAM; + if(((CPed*)pTargetEntity)->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT && + FindPlayerPed()->GetPedState() == PED_ATTACK && !m_bUseMouse3rdPerson) + ReqMode = CCam::MODE_FIGHT_CAM; + } - Dist.x = IdealSource.x - TargetCoors.x; - Dist.y = IdealSource.y - TargetCoors.y; - Length = Dist.Magnitude2D(); + // Garage cam + if(CCullZones::CamStairsForPlayer() && CCullZones::FindZoneWithStairsAttributeForPlayer()) + stairs = true; + // Some hack for Mr Whoopee in a bomb shop + if(Cams[ActiveCam].Using3rdPersonMouseCam() && CCollision::ms_collisionInMemory == LEVEL_COMMERCIAL){ + if(pTargetEntity->GetPosition().x < 83.0f && pTargetEntity->GetPosition().x > 18.0f && + pTargetEntity->GetPosition().y < -305.0f && pTargetEntity->GetPosition().y > -390.0f) + disableGarageCam = true; + } + if(!disableGarageCam && (CGarages::IsPointInAGarageCameraZone(pTargetEntity->GetPosition()) || stairs)){ + if(!m_bGarageFixedCamPositionSet && m_bLookingAtPlayer){ + if(pToGarageWeAreIn || stairs){ + float ground; + bool foundGround; + + if(pToGarageWeAreIn){ + // targetPos = pTargetEntity->GetPosition(); // unused + if(pToGarageWeAreIn->m_pDoor1){ + whichDoor = 1; + garageDoorPos1.x = pToGarageWeAreIn->m_fDoor1X; + garageDoorPos1.y = pToGarageWeAreIn->m_fDoor1Y; + garageDoorPos1.z = 0.0f; + // targetPos.z = 0.0f; // unused + // (targetPos - doorPos1).Magnitude(); // unused + }else if(pToGarageWeAreIn->m_pDoor2){ + whichDoor = 2; +#ifdef FIX_BUGS + garageDoorPos2.x = pToGarageWeAreIn->m_fDoor2X; + garageDoorPos2.y = pToGarageWeAreIn->m_fDoor2Y; + garageDoorPos2.z = 0.0f; +#endif + }else{ + whichDoor = 1; + garageDoorPos1.x = pTargetEntity->GetPosition().x; + garageDoorPos1.y = pTargetEntity->GetPosition().y; +#ifdef FIX_BUGS + garageDoorPos1.z = 0.0f; +#else + garageDoorPos2.z = 0.0f; +#endif + } + }else{ + whichDoor = 1; + garageDoorPos1 = Cams[ActiveCam].Source; + } + + if(pToGarageWeAreIn){ + garageCenter.x = (pToGarageWeAreIn->m_fX1 + pToGarageWeAreIn->m_fX2)/2.0f; + garageCenter.y = (pToGarageWeAreIn->m_fY1 + pToGarageWeAreIn->m_fY2)/2.0f; + garageCenter.z = 0.0f; + }else{ + garageDoorPos1.z = 0.0f; + if(stairs){ + CAttributeZone *az = CCullZones::FindZoneWithStairsAttributeForPlayer(); + garageCenter.x = (az->minx + az->maxx)/2.0f; + garageCenter.y = (az->miny + az->maxy)/2.0f; + garageCenter.z = 0.0f; + }else + garageCenter = pTargetEntity->GetPosition(); + } + if(whichDoor == 1) + garageCenterToDoor = garageDoorPos1 - garageCenter; + else + garageCenterToDoor = garageDoorPos2 - garageCenter; + targetPos = pTargetEntity->GetPosition(); + ground = CWorld::FindGroundZFor3DCoord(targetPos.x, targetPos.y, targetPos.z, &foundGround); + if(!foundGround) + ground = targetPos.z - 0.2f; + garageCenterToDoor.z = 0.0f; + garageCenterToDoor.Normalise(); + if(whichDoor == 1){ + if(pToGarageWeAreIn == nil && stairs) + garageCamPos = garageDoorPos1 + 3.75f*garageCenterToDoor; + else + garageCamPos = garageDoorPos1 + 13.0f*garageCenterToDoor; + }else{ + garageCamPos = garageDoorPos2 + 13.0f*garageCenterToDoor; + } + if(PedZoomIndicator == CAM_ZOOM_TOPDOWN && !stairs){ + garageCamPos = garageCenter; + garageCamPos.z += FindPlayerPed()->GetPosition().z + 2.1f; + if(pToGarageWeAreIn && garageCamPos.z > pToGarageWeAreIn->m_fX2) // What? + garageCamPos.z = pToGarageWeAreIn->m_fX2; + }else + garageCamPos.z = ground + 3.1f; + SetCamPositionForFixedMode(garageCamPos, CVector(0.0f, 0.0f, 0.0f)); + m_bGarageFixedCamPositionSet = true; + } + } - // 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((CGarages::CameraShouldBeOutside() || stairs) && m_bLookingAtPlayer && m_bGarageFixedCamPositionSet){ + if(pToGarageWeAreIn || stairs){ + ReqMode = CCam::MODE_FIXED; + m_bPlayerIsInGarage = true; + } + }else{ + if(m_bPlayerIsInGarage){ + m_bJustCameOutOfGarage = true; + m_bPlayerIsInGarage = false; + } + ReqMode = CCam::MODE_FOLLOWPED; + } + }else{ + if(m_bPlayerIsInGarage){ + m_bJustCameOutOfGarage = true; + m_bPlayerIsInGarage = false; + } + m_bGarageFixedCamPositionSet = false; + } - if(TheCamera.m_bCamDirectlyBehind){ - m_bCollisionChecksOn = true; - Beta = TargetOrientation + PI; + // Fallen into water + if(Cams[ActiveCam].IsTargetInWater(Cams[ActiveCam].Source) && + Cams[ActiveCam].CamTargetEntity->IsPed()) + ReqMode = CCam::MODE_PLAYER_FALLEN_WATER; + + // Set top down + if(PedZoomIndicator == CAM_ZOOM_TOPDOWN && + !CCullZones::Cam1stPersonForPlayer() && + !CCullZones::CamNoRain() && + !CCullZones::PlayerNoRain() && + !m_bFirstPersonBeingUsed && + !m_bPlayerIsInGarage) + ReqMode = CCam::MODE_TOP_DOWN_PED; + + // Weapon mode + if(!CPad::GetPad(0)->GetTarget() && PlayerWeaponMode.Mode != CCam::MODE_HELICANNON_1STPERSON) + ClearPlayerWeaponMode(); + if(m_PlayerMode.Mode != CCam::MODE_NONE) + ReqMode = m_PlayerMode.Mode; + if(PlayerWeaponMode.Mode != CCam::MODE_NONE && !stairs){ + if(PlayerWeaponMode.Mode == CCam::MODE_SNIPER || + PlayerWeaponMode.Mode == CCam::MODE_ROCKETLAUNCHER || + PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON || + PlayerWeaponMode.Mode == CCam::MODE_HELICANNON_1STPERSON || + Cams[ActiveCam].GetWeaponFirstPersonOn()){ + // First person weapon mode + if(PLAYER->GetPedState() == PED_SEEK_CAR){ + if(ReqMode == CCam::MODE_TOP_DOWN_PED || Cams[ActiveCam].GetWeaponFirstPersonOn()) + ReqMode = PlayerWeaponMode.Mode; + else + ReqMode = CCam::MODE_FOLLOWPED; + }else + ReqMode = PlayerWeaponMode.Mode; + }else if(ReqMode != CCam::MODE_TOP_DOWN_PED){ + // Syphon mode + float playerTargetDist; + float deadPedDist = 4.0f; + static float alivePedDist = 2.0f; // original name lost + float pedDist; // actually only used on dead target + bool targetDead = false; + float camAngle, targetAngle; + CVector playerToTarget = m_cvecAimingTargetCoors - pTargetEntity->GetPosition(); + CVector playerToCam = Cams[ActiveCam].Source - pTargetEntity->GetPosition(); + + if(PedZoomIndicator == CAM_ZOOM_1) + deadPedDist = 2.25f; + if(FindPlayerPed()->m_pPointGunAt){ + // BUG: this need not be a ped! + if(((CPed*)FindPlayerPed()->m_pPointGunAt)->DyingOrDead()){ + targetDead = true; + pedDist = deadPedDist; + }else + pedDist = alivePedDist; + playerTargetDist = playerToTarget.Magnitude2D(); + camAngle = CGeneral::GetATanOfXY(playerToCam.x, playerToCam.y); + targetAngle = CGeneral::GetATanOfXY(playerToTarget.x, playerToTarget.y); + ReqMode = PlayerWeaponMode.Mode; + + // Check whether to start aiming in crim-in-front mode + if(Cams[ActiveCam].Mode != CCam::MODE_SYPHON){ + float angleDiff = camAngle - targetAngle; + while(angleDiff >= PI) angleDiff -= 2*PI; + while(angleDiff < -PI) angleDiff += 2*PI; + if(Abs(angleDiff) < HALFPI && playerTargetDist < 3.5f && playerToTarget.z > -1.0f) + ReqMode = CCam::MODE_SYPHON_CRIM_IN_FRONT; + } + + // Check whether to go to special fixed mode + float fixedModeDist = 0.0f; + if((ReqMode == CCam::MODE_SYPHON_CRIM_IN_FRONT || ReqMode == CCam::MODE_SYPHON) && + (m_uiTransitionState == 0 || Cams[ActiveCam].Mode == CCam::MODE_SPECIAL_FIXED_FOR_SYPHON) && + playerTargetDist < pedDist && targetDead){ + if(ReqMode == CCam::MODE_SYPHON_CRIM_IN_FRONT) + fixedModeDist = 5.0f; + else + fixedModeDist = 3.0f; + ReqMode = CCam::MODE_SPECIAL_FIXED_FOR_SYPHON; + } + if(ReqMode == CCam::MODE_SPECIAL_FIXED_FOR_SYPHON){ + if(!PlaceForFixedWhenSniperFound){ + // Find position + CEntity *entity; + CColPoint colPoint; + CVector fixedPos = pTargetEntity->GetPosition(); + fixedPos.x += fixedModeDist*Cos(camAngle); + fixedPos.y += fixedModeDist*Sin(camAngle); + fixedPos.z += 1.15f; + if(CWorld::ProcessLineOfSight(pTargetEntity->GetPosition(), fixedPos, colPoint, entity, true, false, false, true, false, true, true)) + SetCamPositionForFixedMode(colPoint.point, CVector(0.0f, 0.0f, 0.0f)); + else + SetCamPositionForFixedMode(fixedPos, CVector(0.0f, 0.0f, 0.0f)); + PlaceForFixedWhenSniperFound = true; + } + }else + PlaceForFixedWhenSniperFound = false; + } + } + } + } } - if(FindPlayerVehicle()) - if(FindPlayerVehicle()->m_vehType == VEHICLE_TYPE_TRAIN) - HackPlayerOnStoppingTrain = true; + m_bIdleOn = false; - if(TheCamera.m_bCamDirectlyInFront){ - m_bCollisionChecksOn = true; - Beta = TargetOrientation; - } + if(DebugCamMode) + ReqMode = DebugCamMode; - 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; + // Process arrested player + static int ThePickedArrestMode; + static int LastPedState; + bool startArrestCam = false; + + if(LastPedState != PED_ARRESTED && PLAYER->GetPedState() == PED_ARRESTED){ + if(CarZoomIndicator != CAM_ZOOM_1STPRS && pTargetEntity->IsVehicle()) + startArrestCam = true; + }else + startArrestCam = false; + LastPedState = PLAYER->GetPedState(); + if(startArrestCam){ + if(m_uiTransitionState) + ReqMode = Cams[ActiveCam].Mode; + else{ + bool valid; + if(pTargetEntity->IsPed()){ + // How can this happen if arrest cam is only done in cars? + Cams[(ActiveCam+1)%2].ResetStatics = true; + valid = Cams[(ActiveCam+1)%2].ProcessArrestCamOne(); + ReqMode = CCam::MODE_ARRESTCAM_ONE; + }else{ + Cams[(ActiveCam+1)%2].ResetStatics = true; + valid = Cams[(ActiveCam+1)%2].ProcessArrestCamTwo(); + ReqMode = CCam::MODE_ARRESTCAM_TWO; + } + if(!valid) + ReqMode = Cams[ActiveCam].Mode; + } } - // 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; + ThePickedArrestMode = ReqMode; + if(PLAYER->GetPedState() == PED_ARRESTED) + ReqMode = ThePickedArrestMode; // this is rather useless... + + // Process dead player + if(PLAYER->GetPedState() == PED_DEAD){ + if(Cams[ActiveCam].Mode == CCam::MODE_PED_DEAD_BABY) + ReqMode = CCam::MODE_PED_DEAD_BABY; + else{ + bool foundRoof; + CVector pos = FindPlayerPed()->GetPosition(); + CWorld::FindRoofZFor3DCoord(pos.x, pos.y, pos.z, &foundRoof); + if(!foundRoof) + ReqMode = CCam::MODE_PED_DEAD_BABY; } + } + + // Restore with a jump cut + if(m_bRestoreByJumpCut){ + if(ReqMode != CCam::MODE_FOLLOWPED && + ReqMode != CCam::MODE_M16_1STPERSON && + ReqMode != CCam::MODE_SNIPER && + ReqMode != CCam::MODE_ROCKETLAUNCHER || + !m_bUseMouse3rdPerson) + SetCameraDirectlyBehindForFollowPed_CamOnAString(); + + ReqMode = m_iModeToGoTo; + Cams[ActiveCam].Mode = ReqMode; + m_bJust_Switched = true; + Cams[ActiveCam].ResetStatics = true; + Cams[ActiveCam].m_cvecCamFixedModeVector = m_vecFixedModeVector; + Cams[ActiveCam].CamTargetEntity = pTargetEntity; + Cams[ActiveCam].m_cvecCamFixedModeSource = m_vecFixedModeSource; + Cams[ActiveCam].m_cvecCamFixedModeUpOffSet = m_vecFixedModeUpOffSet; + Cams[ActiveCam].m_bCamLookingAtVector = false; + Cams[ActiveCam].m_vecLastAboveWaterCamPosition = Cams[(ActiveCam+1)%2].m_vecLastAboveWaterCamPosition; + m_bRestoreByJumpCut = false; + Cams[ActiveCam].ResetStatics = true; + pTargetEntity->RegisterReference(&pTargetEntity); + Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity); + CarZoomValueSmooth = CarZoomValue; + m_fPedZoomValueSmooth = m_fPedZoomValue; + m_uiTransitionState = 0; + m_vecDoingSpecialInterPolation = false; + } - TargetCoors.z += 0.1f; - Beta = OriginalBeta; + if(gbModelViewer) + ReqMode = CCam::MODE_MODELVIEW; - if(PickedASide){ - if(AngleToGoTo == 0.0f) - FixedTargetOrientation = TargetOrientation + PI; - Rotating = true; + // Turn on Obbe's cam + bool canUseObbeCam = true; + if(pTargetEntity){ + if(pTargetEntity->IsVehicle()){ + if(CarZoomIndicator == CAM_ZOOM_CINEMATIC) + m_bObbeCinematicCarCamOn = true; }else{ - FixedTargetOrientation = TargetOrientation + PI + AngleToGoTo; - Rotating = true; - PickedASide = true; + if(PedZoomIndicator == CAM_ZOOM_CINEMATIC) + m_bObbeCinematicPedCamOn = true; } - }else{ + } + if(m_bTargetJustBeenOnTrain || + ReqMode == CCam::MODE_SYPHON || ReqMode == CCam::MODE_SYPHON_CRIM_IN_FRONT || ReqMode == CCam::MODE_SPECIAL_FIXED_FOR_SYPHON || + ReqMode == CCam::MODE_PED_DEAD_BABY || ReqMode == CCam::MODE_ARRESTCAM_ONE || ReqMode == CCam::MODE_ARRESTCAM_TWO || + ReqMode == CCam::MODE_FIGHT_CAM || ReqMode == CCam::MODE_PLAYER_FALLEN_WATER || + ReqMode == CCam::MODE_SNIPER || ReqMode == CCam::MODE_ROCKETLAUNCHER || ReqMode == CCam::MODE_M16_1STPERSON || + ReqMode == CCam::MODE_SNIPER_RUNABOUT || ReqMode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT || + ReqMode == CCam::MODE_1STPERSON_RUNABOUT || ReqMode == CCam::MODE_M16_1STPERSON_RUNABOUT || + ReqMode == CCam::MODE_FIGHT_CAM_RUNABOUT || ReqMode == CCam::MODE_HELICANNON_1STPERSON || + WhoIsInControlOfTheCamera == CAMCONTROL_SCRIPT || + m_bJustCameOutOfGarage || m_bPlayerIsInGarage) + canUseObbeCam = false; + + if(m_bObbeCinematicPedCamOn && canUseObbeCam) + ProcessObbeCinemaCameraPed(); + else if(m_bObbeCinematicCarCamOn && canUseObbeCam) + ProcessObbeCinemaCameraCar(); + else{ + if(m_bPlayerIsInGarage && m_bObbeCinematicCarCamOn) + switchByJumpCut = true; + canUseObbeCam = false; + DontProcessObbeCinemaCamera(); + } - // Rotate cam to avoid clipping into buildings + // Start the transition or do a jump cut + if(m_bLookingAtPlayer){ + // Going into top down modes normally needs a jump cut (but see below) + if(ReqMode == CCam::MODE_TOPDOWN || ReqMode == CCam::MODE_1STPERSON || ReqMode == CCam::MODE_TOP_DOWN_PED){ + switchByJumpCut = true; + } + // Going from top down to vehicle + else if(ReqMode == CCam::MODE_CAM_ON_A_STRING || ReqMode == CCam::MODE_BEHINDBOAT){ + if(Cams[ActiveCam].Mode == CCam::MODE_TOPDOWN || + Cams[ActiveCam].Mode == CCam::MODE_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED) + switchByJumpCut = true; + }else if(ReqMode == CCam::MODE_FIXED){ + if(Cams[ActiveCam].Mode == CCam::MODE_TOPDOWN) + switchByJumpCut = true; + } - TargetCoors.z -= 0.1f; + // Top down modes can interpolate between each other + if(ReqMode == CCam::MODE_TOPDOWN){ + if(Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED || Cams[ActiveCam].Mode == CCam::MODE_PED_DEAD_BABY) + switchByJumpCut = false; + }else if(ReqMode == CCam::MODE_TOP_DOWN_PED){ + if(Cams[ActiveCam].Mode == CCam::MODE_TOPDOWN || Cams[ActiveCam].Mode == CCam::MODE_PED_DEAD_BABY) + switchByJumpCut = false; + } - 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(ReqMode == CCam::MODE_1STPERSON || ReqMode == CCam::MODE_M16_1STPERSON || + ReqMode == CCam::MODE_SNIPER || ReqMode == CCam::MODE_ROCKETLAUNCHER || + ReqMode == CCam::MODE_SNIPER_RUNABOUT || ReqMode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT || + ReqMode == CCam::MODE_1STPERSON_RUNABOUT || ReqMode == CCam::MODE_M16_1STPERSON_RUNABOUT || + ReqMode == CCam::MODE_FIGHT_CAM_RUNABOUT || + ReqMode == CCam::MODE_HELICANNON_1STPERSON || + ReqMode == CCam::MODE_ARRESTCAM_ONE || ReqMode == CCam::MODE_ARRESTCAM_TWO){ + // Going into any 1st person mode is a jump cut + if(pTargetEntity->IsPed()) + switchByJumpCut = true; + }else if(ReqMode == CCam::MODE_FIXED && m_bPlayerIsInGarage){ + // Going from 1st peron mode into garage + if(Cams[ActiveCam].Mode == CCam::MODE_SNIPER || + Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER || + Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED || + stairs || + Cams[ActiveCam].Mode == CCam::MODE_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT){ + if(pTargetEntity && pTargetEntity->IsVehicle()) + switchByJumpCut = true; + } + }else if(ReqMode == CCam::MODE_FOLLOWPED){ + if(Cams[ActiveCam].Mode == CCam::MODE_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_SNIPER || + Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER || + Cams[ActiveCam].Mode == CCam::MODE_ARRESTCAM_ONE || + Cams[ActiveCam].Mode == CCam::MODE_ARRESTCAM_TWO || + Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_PED_DEAD_BABY || + Cams[ActiveCam].Mode == CCam::MODE_PILLOWS_PAPS || + Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_TOPDOWN || + Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){ + if(!m_bJustCameOutOfGarage){ + if(Cams[ActiveCam].Mode == CCam::MODE_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_SNIPER || + Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER || + Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON){ + float angle = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) - HALFPI; + ((CPed*)pTargetEntity)->m_fRotationCur = angle; + ((CPed*)pTargetEntity)->m_fRotationDest = angle; + } + m_bUseTransitionBeta = true; + switchByJumpCut = true; + if(Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){ + CVector front = Cams[ActiveCam].Source - FindPlayerPed()->GetPosition(); + front.z = 0.0f; + front.Normalise(); +#ifdef FIX_BUGS + // this is almost as bad as the bugged code + if(front.x == 0.001f && front.y == 0.001f) + front.y = 1.0f; +#else + // someone used = instead of == in the above check by accident + front.x = 0.001f; + front.y = 1.0f; +#endif + Cams[ActiveCam].m_fTransitionBeta = CGeneral::GetATanOfXY(front.x, front.y); + }else + Cams[ActiveCam].m_fTransitionBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) + PI; } } - if(LateralLeft != 0.0f || LateralRight != 0.0f || Center != 0.0f) - BuildingCheckObscured = true; + }else if(ReqMode == CCam::MODE_FIGHT_CAM){ + if(Cams[ActiveCam].Mode == CCam::MODE_1STPERSON) + switchByJumpCut = true; } - TargetCoors.z += 0.1f; - } - - if(m_fCloseInPedHeightOffset > 0.00001f) - TargetCoors.z += m_fUnknownZOffSet; + if(ReqMode != Cams[ActiveCam].Mode && Cams[ActiveCam].CamTargetEntity == nil) + switchByJumpCut = true; + if(m_bPlayerIsInGarage && pToGarageWeAreIn){ + if(pToGarageWeAreIn->m_eGarageType == GARAGE_BOMBSHOP1 || + pToGarageWeAreIn->m_eGarageType == GARAGE_BOMBSHOP2 || + pToGarageWeAreIn->m_eGarageType == GARAGE_BOMBSHOP3){ + if(pTargetEntity->IsVehicle() && pTargetEntity->GetModelIndex() == MI_MRWHOOP && + ReqMode != Cams[ActiveCam].Mode) + switchByJumpCut = true; + } + } + if(CSceneEdit::m_bEditOn) + ReqMode = CCam::MODE_EDITOR; + + if((m_uiTransitionState == 0 || switchByJumpCut) && ReqMode != Cams[ActiveCam].Mode){ + if(switchByJumpCut){ + if(!m_bPlayerIsInGarage || m_bJustCameOutOfGarage){ + if(ReqMode != CCam::MODE_FOLLOWPED && + ReqMode != CCam::MODE_M16_1STPERSON && + ReqMode != CCam::MODE_SNIPER && + ReqMode != CCam::MODE_ROCKETLAUNCHER || + !m_bUseMouse3rdPerson) + SetCameraDirectlyBehindForFollowPed_CamOnAString(); + } + Cams[ActiveCam].Mode = ReqMode; + m_bJust_Switched = true; + Cams[ActiveCam].m_cvecCamFixedModeVector = m_vecFixedModeVector; + Cams[ActiveCam].CamTargetEntity = pTargetEntity; + Cams[ActiveCam].m_cvecCamFixedModeSource = m_vecFixedModeSource; + Cams[ActiveCam].m_cvecCamFixedModeUpOffSet = m_vecFixedModeUpOffSet; + Cams[ActiveCam].m_bCamLookingAtVector = m_bLookingAtVector; + Cams[ActiveCam].m_vecLastAboveWaterCamPosition = Cams[(ActiveCam+1)%2].m_vecLastAboveWaterCamPosition; + CarZoomValueSmooth = CarZoomValue; + m_fPedZoomValueSmooth = m_fPedZoomValue; + m_uiTransitionState = 0; + m_vecDoingSpecialInterPolation = false; + m_bStartInterScript = false; + Cams[ActiveCam].ResetStatics = true; + + pTargetEntity->RegisterReference(&pTargetEntity); + Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity); + }else if(!m_bWaitForInterpolToFinish){ + StartTransition(ReqMode); + pTargetEntity->RegisterReference(&pTargetEntity); + Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity); + } + }else if(m_uiTransitionState != 0 && ReqMode != Cams[ActiveCam].Mode){ + bool startTransition = true; + + if(ReqMode == CCam::MODE_FIGHT_CAM || Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM) + startTransition = false; + if(ReqMode == CCam::MODE_FOLLOWPED && Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM) + startTransition = false; + + if(!m_bWaitForInterpolToFinish && m_bLookingAtPlayer && m_uiTransitionState != 0){ + CVector playerDist; + playerDist.x = FindPlayerPed()->GetPosition().x - GetPosition().x; + playerDist.y = FindPlayerPed()->GetPosition().y - GetPosition().y; + playerDist.z = FindPlayerPed()->GetPosition().z - GetPosition().z; + // if player is too far away, keep interpolating and don't transition + if(pTargetEntity && pTargetEntity->IsPed()){ + if(playerDist.Magnitude() > 17.5f && + (ReqMode == CCam::MODE_SYPHON || ReqMode == CCam::MODE_SYPHON_CRIM_IN_FRONT)) + m_bWaitForInterpolToFinish = true; + } + } + if(m_bWaitForInterpolToFinish) + startTransition = false; + if(startTransition){ + StartTransitionWhenNotFinishedInter(ReqMode); + pTargetEntity->RegisterReference(&pTargetEntity); + Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity); + } + }else if(ReqMode == CCam::MODE_FIXED && pTargetEntity != Cams[ActiveCam].CamTargetEntity && m_bPlayerIsInGarage){ + if(m_uiTransitionState != 0) + StartTransitionWhenNotFinishedInter(ReqMode); + else + StartTransition(ReqMode); + pTargetEntity->RegisterReference(&pTargetEntity); + Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity); + } + }else{ + // not following player + if(m_uiTransitionState == 0 && m_bStartInterScript && m_iTypeOfSwitch == INTERPOLATION){ + ReqMode = m_iModeToGoTo; + StartTransition(ReqMode); + pTargetEntity->RegisterReference(&pTargetEntity); + Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity); + }else if(m_uiTransitionState != 0 && m_bStartInterScript && m_iTypeOfSwitch == INTERPOLATION){ + ReqMode = m_iModeToGoTo; + StartTransitionWhenNotFinishedInter(ReqMode); + pTargetEntity->RegisterReference(&pTargetEntity); + Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity); + }else if(m_bStartInterScript && m_iTypeOfSwitch == JUMP_CUT){ + m_uiTransitionState = 0; + m_vecDoingSpecialInterPolation = false; + Cams[ActiveCam].Mode = m_iModeToGoTo; + m_bJust_Switched = true; + Cams[ActiveCam].ResetStatics = true; + Cams[ActiveCam].m_cvecCamFixedModeVector = m_vecFixedModeVector; + Cams[ActiveCam].CamTargetEntity = pTargetEntity; + Cams[ActiveCam].m_cvecCamFixedModeSource = m_vecFixedModeSource; + Cams[ActiveCam].m_cvecCamFixedModeUpOffSet = m_vecFixedModeUpOffSet; + Cams[ActiveCam].m_bCamLookingAtVector = m_bLookingAtVector; + Cams[ActiveCam].m_vecLastAboveWaterCamPosition = Cams[(ActiveCam+1)%2].m_vecLastAboveWaterCamPosition; + m_bJust_Switched = true; + pTargetEntity->RegisterReference(&pTargetEntity); + Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity); + CarZoomValueSmooth = CarZoomValue; + m_fPedZoomValueSmooth = m_fPedZoomValue; + } + } - // Have to fix to avoid collision + m_bStartInterScript = false; - 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; + if(Cams[ActiveCam].CamTargetEntity == nil) + Cams[ActiveCam].CamTargetEntity = pTargetEntity; - // This calculation is only really used to figure out how fast to rotate out of collision + // Ped visibility + if((Cams[ActiveCam].Mode == CCam::MODE_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_SNIPER || + Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER) && pTargetEntity->IsPed() || + Cams[ActiveCam].Mode == CCam::MODE_FLYBY) + FindPlayerPed()->bIsVisible = false; + else + FindPlayerPed()->bIsVisible = true; - 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; + if(!canUseObbeCam && WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) + Restore(); +} - 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; +// What a mess! +void +CCamera::UpdateTargetEntity(void) +{ + bool enteringCar = false; // not on PS2 but only used as && !enteringCar so we can keep it + bool obbeCam = false; + + if(WhoIsInControlOfTheCamera == CAMCONTROL_OBBE){ + obbeCam = true; + if(m_iModeObbeCamIsInForCar == OBBE_COPCAR_WHEEL || m_iModeObbeCamIsInForCar == OBBE_COPCAR){ + if(FindPlayerPed()->GetPedState() != PED_ARRESTED) + obbeCam = false; + if(FindPlayerVehicle() == nil) + pTargetEntity = FindPlayerPed(); } } - if(m_fAmountFractionObscured < 0.0f) m_fAmountFractionObscured = 0.0f; - if(m_fAmountFractionObscured > 1.0f) m_fAmountFractionObscured = 1.0f; - + if((m_bLookingAtPlayer || obbeCam) && m_uiTransitionState == 0 || + pTargetEntity == nil || + m_bTargetJustBeenOnTrain){ + if(FindPlayerVehicle()) + pTargetEntity = FindPlayerVehicle(); + else{ + pTargetEntity = FindPlayerPed(); +#ifndef GTA_PS2_STUFF + // this keeps the camera on the player while entering cars + if(PLAYER->GetPedState() == PED_ENTER_CAR || + PLAYER->GetPedState() == PED_CARJACK || + PLAYER->GetPedState() == PED_OPEN_DOOR) + enteringCar = true; + + if(!enteringCar) + if(Cams[ActiveCam].CamTargetEntity != pTargetEntity) + Cams[ActiveCam].CamTargetEntity = pTargetEntity; +#endif + } - // Figure out speed values for Beta rotation + bool cantOpen = true; + if(PLAYER && + PLAYER->m_pMyVehicle && + PLAYER->m_pMyVehicle->CanPedOpenLocks(PLAYER)) + cantOpen = false; + + if(PLAYER->GetPedState() == PED_ENTER_CAR && !cantOpen){ + if(!enteringCar && CarZoomIndicator != 0.0f){ + pTargetEntity = PLAYER->m_pMyVehicle; + if(PLAYER->m_pMyVehicle == nil) + pTargetEntity = PLAYER; + } + } - 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((PLAYER->GetPedState() == PED_CARJACK || PLAYER->GetPedState() == PED_OPEN_DOOR) && !cantOpen){ + if(!enteringCar && CarZoomIndicator != 0.0f) +#ifdef GTA_PS2_STUFF +// dunno if this has any amazing effects + { +#endif + pTargetEntity = PLAYER->m_pMyVehicle; + if(PLAYER->m_pMyVehicle == nil) + pTargetEntity = PLAYER; +#ifdef GTA_PS2_STUFF + } +#endif } + + if(PLAYER->GetPedState() == PED_EXIT_CAR) + pTargetEntity = FindPlayerPed(); + if(PLAYER->GetPedState() == PED_DRAG_FROM_CAR) + pTargetEntity = FindPlayerPed(); + if(pTargetEntity->IsVehicle() && CarZoomIndicator != 0.0f && FindPlayerPed()->GetPedState() == PED_ARRESTED) + pTargetEntity = FindPlayerPed(); } - 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; +} +const float SOUND_DIST = 20.0f; - int MoveState = ((CPed*)CamTargetEntity)->m_nMoveState; - if(MoveState != PEDMOVE_NONE && MoveState != PEDMOVE_STILL && - !CPad::GetPad(0)->ForceCameraBehindPlayer() && !Obscured && !Shooting){ - Rotating = false; - BetaSpeed = 0.0f; +void +CCamera::UpdateSoundDistances(void) +{ + CVector center, end; + CEntity *entity; + CColPoint colPoint; + float f; + int n; + + if((Cams[ActiveCam].Mode == CCam::MODE_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_SNIPER || + Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER) && + pTargetEntity->IsPed()) + center = GetPosition() + 0.5f*GetForward(); + else + center = GetPosition() + 5.0f*GetForward(); + + // check up + n = CTimer::GetFrameCounter() % 12; + if(n == 0){ + SoundDistUpAsReadOld = SoundDistUpAsRead; + if(CWorld::ProcessVerticalLine(center, center.z+SOUND_DIST, colPoint, entity, true, false, false, false, true, false, nil)) + SoundDistUpAsRead = colPoint.point.z - center.z; + else + SoundDistUpAsRead = SOUND_DIST; } + f = (n + 1) / 6.0f; + SoundDistUp = (1.0f-f)*SoundDistUpAsReadOld + f*SoundDistUpAsRead; + + // check left + n = (CTimer::GetFrameCounter()+2) % 12; + if(n == 0){ + SoundDistLeftAsReadOld = SoundDistLeftAsRead; + end = center + SOUND_DIST*GetRight(); + if(CWorld::ProcessLineOfSight(center, end, colPoint, entity, true, false, false, false, true, true, true)) + SoundDistLeftAsRead = (colPoint.point - center).Magnitude(); + else + SoundDistLeftAsRead = SOUND_DIST; + } + f = (n + 1) / 6.0f; + SoundDistLeft = (1.0f-f)*SoundDistLeftAsReadOld + f*SoundDistLeftAsRead; + + // check right + // end = center - SOUND_DIST*GetRight(); // useless + n = (CTimer::GetFrameCounter()+4) % 12; + if(n == 0){ + SoundDistRightAsReadOld = SoundDistRightAsRead; + end = center - SOUND_DIST*GetRight(); + if(CWorld::ProcessLineOfSight(center, end, colPoint, entity, true, false, false, false, true, true, true)) + SoundDistRightAsRead = (colPoint.point - center).Magnitude(); + else + SoundDistRightAsRead = SOUND_DIST; + } + f = (n + 1) / 6.0f; + SoundDistRight = (1.0f-f)*SoundDistRightAsReadOld + f*SoundDistRightAsRead; +} - // Now do the Beta rotation - - float Distance = (IdealSource - TargetCoors).Magnitude2D(); - m_fDistanceBeforeChanges = Distance; +void +CCamera::InitialiseCameraForDebugMode(void) +{ + if(FindPlayerVehicle()) + Cams[2].Source = FindPlayerVehicle()->GetPosition(); + else if(FindPlayerPed()) + Cams[2].Source = FindPlayerPed()->GetPosition(); + Cams[2].Alpha = 0.0f; + Cams[2].Beta = 0.0f; + Cams[2].Mode = CCam::MODE_DEBUG; +} - if(Rotating){ - m_bFixingBeta = true; +void +CCamera::CamShake(float strength, float x, float y, float z) +{ + CVector Dist = Cams[ActiveCam].Source - CVector(x, y, z); + // a bit complicated... + float dist2d = Sqrt(SQR(Dist.x) + SQR(Dist.y)); + float dist3d = Sqrt(SQR(dist2d) + SQR(Dist.z)); + if(dist3d > 100.0f) dist3d = 100.0f; + if(dist3d < 0.0f) dist3d = 0.0f; + float mult = 1.0f - dist3d/100.0f; + + float curForce = mult*(m_fCamShakeForce - (CTimer::GetTimeInMilliseconds() - m_uiCamShakeStart)/1000.0f); + strength = mult*strength; + if(clamp(curForce, 0.0f, 2.0f) < strength){ + m_fCamShakeForce = strength; + m_uiCamShakeStart = CTimer::GetTimeInMilliseconds(); + } +} - while(FixedTargetOrientation >= PI) FixedTargetOrientation -= 2*PI; - while(FixedTargetOrientation < -PI) FixedTargetOrientation += 2*PI; +// This seems to be CCamera::CamShake(float) on PS2 +void +CamShakeNoPos(CCamera *cam, float strength) +{ + float curForce = cam->m_fCamShakeForce - (CTimer::GetTimeInMilliseconds() - cam->m_uiCamShakeStart)/1000.0f; + if(clamp(curForce, 0.0f, 2.0f) < strength){ + cam->m_fCamShakeForce = strength; + cam->m_uiCamShakeStart = CTimer::GetTimeInMilliseconds(); + } +} - 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(); +void +CCamera::TakeControl(CEntity *target, int16 mode, int16 typeOfSwitch, int32 controller) +{ + bool doSwitch = true; + if(controller == CAMCONTROL_OBBE && WhoIsInControlOfTheCamera == CAMCONTROL_SCRIPT) + doSwitch = false; + if(doSwitch){ + WhoIsInControlOfTheCamera = controller; + if(target){ + if(mode == CCam::MODE_NONE){ + // Why are we checking the old entity? + if(pTargetEntity->IsPed()) + mode = CCam::MODE_FOLLOWPED; + else if(pTargetEntity->IsVehicle()) + mode = CCam::MODE_CAM_ON_A_STRING; + } + }else if(FindPlayerVehicle()) + target = FindPlayerVehicle(); 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; + target = PLAYER; + + m_bLookingAtVector = false; + pTargetEntity = target; + m_iModeToGoTo = mode; + m_iTypeOfSwitch = typeOfSwitch; + m_bLookingAtPlayer = false; + m_bStartInterScript = true; + // FindPlayerPed(); // unused + } +} - Beta += BetaSpeed * min(10.0f, CTimer::GetTimeStep()); -*/ - WellBufferMe(FixedTargetOrientation, &Beta, &BetaSpeed, MaxSpeed, Acceleration, true); +void +CCamera::TakeControlNoEntity(const CVector &position, int16 typeOfSwitch, int32 controller) +{ + bool doSwitch = true; + if(controller == CAMCONTROL_OBBE && WhoIsInControlOfTheCamera == CAMCONTROL_SCRIPT) + doSwitch = false; + if(doSwitch){ + WhoIsInControlOfTheCamera = controller; + m_bLookingAtVector = true; + m_bLookingAtPlayer = false; + m_iModeToGoTo = CCam::MODE_FIXED; + m_vecFixedModeVector = position; + m_iTypeOfSwitch = typeOfSwitch; + m_bStartInterScript = true; + } +} - if(ResetStatics){ - Beta = FixedTargetOrientation; - BetaSpeed = 0.0f; - } +void +CCamera::TakeControlWithSpline(int16 typeOfSwitch) +{ + m_iModeToGoTo = CCam::MODE_FLYBY; + m_bLookingAtPlayer = false; + m_bLookingAtVector = false; + m_bcutsceneFinished = false; + m_iTypeOfSwitch = typeOfSwitch; + m_bStartInterScript = true; - 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; - } - } + //FindPlayerPed(); // unused +}; +void +CCamera::Restore(void) +{ + m_bLookingAtPlayer = true; + m_bLookingAtVector = false; + m_iTypeOfSwitch = INTERPOLATION; + m_bUseNearClipScript = false; + m_iModeObbeCamIsInForCar = OBBE_INVALID; + m_fPositionAlongSpline = 0.0; + m_bStartingSpline = false; + m_bScriptParametersSetForInterPol = false; + WhoIsInControlOfTheCamera = CAMCONTROL_GAME; - 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 + if(FindPlayerVehicle()){ + m_iModeToGoTo = CCam::MODE_CAM_ON_A_STRING; + pTargetEntity = FindPlayerVehicle(); }else{ - Source = IdealSource; - BetaSpeed = 0.0f; + m_iModeToGoTo = CCam::MODE_FOLLOWPED; + pTargetEntity = PLAYER; } - // 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(); - } + if(PLAYER->GetPedState() == PED_ENTER_CAR || + PLAYER->GetPedState() == PED_CARJACK || + PLAYER->GetPedState() == PED_OPEN_DOOR){ + m_iModeToGoTo = CCam::MODE_CAM_ON_A_STRING; + pTargetEntity = PLAYER->m_pSeekTarget; } - - 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); - } + if(PLAYER->GetPedState() == PED_EXIT_CAR){ + m_iModeToGoTo = CCam::MODE_FOLLOWPED; + pTargetEntity = PLAYER; } - 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; + m_bUseScriptZoomValuePed = false; + m_bUseScriptZoomValueCar = false; + m_bStartInterScript = true; + m_bCameraJustRestored = true; } void -CCam::Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float) +CCamera::RestoreWithJumpCut(void) { - FOV = DefaultFOV; + m_bRestoreByJumpCut = true; + m_bLookingAtPlayer = true; + m_bLookingAtVector = false; + m_iTypeOfSwitch = JUMP_CUT; + m_bUseNearClipScript = false; + m_iModeObbeCamIsInForCar = OBBE_INVALID; + m_fPositionAlongSpline = 0.0; + m_bStartingSpline = false; + m_bScriptParametersSetForInterPol = false; + WhoIsInControlOfTheCamera = CAMCONTROL_GAME; + m_bCameraJustRestored = true; - if(!CamTargetEntity->IsVehicle()) - return; + if(FindPlayerVehicle()){ + m_iModeToGoTo = CCam::MODE_CAM_ON_A_STRING; + pTargetEntity = FindPlayerVehicle(); + }else{ + m_iModeToGoTo = CCam::MODE_FOLLOWPED; + pTargetEntity = PLAYER; + } - 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; + if(PLAYER->GetPedState() == PED_ENTER_CAR || + PLAYER->GetPedState() == PED_CARJACK || + PLAYER->GetPedState() == PED_OPEN_DOOR){ + m_iModeToGoTo = CCam::MODE_CAM_ON_A_STRING; + pTargetEntity = PLAYER->m_pSeekTarget; + } + if(PLAYER->GetPedState() == PED_EXIT_CAR){ + m_iModeToGoTo = CCam::MODE_FOLLOWPED; + pTargetEntity = PLAYER; } - TargetCoors.z += 0.8f; - WorkOutCamHeightWeeCar(TargetCoors, TargetOrientation); - RotCamIfInFrontCar(TargetCoors, TargetOrientation); - FixCamIfObscured(TargetCoors, 1.2f, TargetOrientation); + m_bUseScriptZoomValuePed = false; + m_bUseScriptZoomValueCar = false; +} - Front = TargetCoors - Source; - m_cvecTargetCoorsForFudgeInter = TargetCoors; - ResetStatics = false; - GetVectorsReadyForRW(); +void +CCamera::SetCamPositionForFixedMode(const CVector &Source, const CVector &UpOffSet) +{ + m_vecFixedModeSource = Source; + m_vecFixedModeUpOffSet = UpOffSet; } + + +/* + * On PS2 the transition happens between Cams[1] and Cams[2]. + * On PC the whole system has been changed. + */ 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; +CCamera::StartTransition(int16 newMode) +{ + bool foo = false; + bool switchSyphonMode = false; + bool switchPedToCar = false; + bool switchPedMode = false; + bool switchFromFixed = false; + bool switch1stPersonToVehicle = false; + float betaOffset, targetBeta, camBeta, deltaBeta; + int door; + bool vehicleVertical; + +// missing on PS2 + m_bItsOkToLookJustAtThePlayer = false; + m_fFractionInterToStopMovingTarget = 0.25f; + m_fFractionInterToStopCatchUpTarget = 0.75f; + + if(Cams[ActiveCam].Mode == CCam::MODE_SYPHON_CRIM_IN_FRONT || + Cams[ActiveCam].Mode == CCam::MODE_FOLLOWPED || + Cams[ActiveCam].Mode == CCam::MODE_SYPHON || + Cams[ActiveCam].Mode == CCam::MODE_SPECIAL_FIXED_FOR_SYPHON){ + if(newMode == CCam::MODE_SYPHON_CRIM_IN_FRONT || + newMode == CCam::MODE_FOLLOWPED || + newMode == CCam::MODE_SYPHON || + newMode == CCam::MODE_SPECIAL_FIXED_FOR_SYPHON) + m_bItsOkToLookJustAtThePlayer = true; + if(newMode == CCam::MODE_CAM_ON_A_STRING) + switchPedToCar = true; + } +// + + if(Cams[ActiveCam].Mode == CCam::MODE_SYPHON_CRIM_IN_FRONT && newMode == CCam::MODE_SYPHON) + switchSyphonMode = true; + if(Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM && newMode == CCam::MODE_FOLLOWPED) + switchPedMode = true; + if(Cams[ActiveCam].Mode == CCam::MODE_FIXED) + switchFromFixed = true; + + m_bUseTransitionBeta = false; + + if((Cams[ActiveCam].Mode == CCam::MODE_SNIPER || + Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER || + Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT || + Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT) && + pTargetEntity->IsPed()){ + float angle = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) - HALFPI; + ((CPed*)pTargetEntity)->m_fRotationCur = angle; + ((CPed*)pTargetEntity)->m_fRotationDest = angle; } - 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; - } +/* // PS2 + ActiveCam = (ActiveCam+1)%2; + Cams[ActiveCam].Init(); + Cams[ActiveCam].Mode = newMode; + */ - 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; + Cams[ActiveCam].m_cvecCamFixedModeVector = m_vecFixedModeVector; + Cams[ActiveCam].CamTargetEntity = pTargetEntity; + Cams[ActiveCam].m_cvecCamFixedModeSource = m_vecFixedModeSource; + Cams[ActiveCam].m_cvecCamFixedModeUpOffSet = m_vecFixedModeUpOffSet; + Cams[ActiveCam].m_bCamLookingAtVector = m_bLookingAtVector; + + if(newMode == CCam::MODE_SNIPER || + newMode == CCam::MODE_ROCKETLAUNCHER || + newMode == CCam::MODE_M16_1STPERSON || + newMode == CCam::MODE_SNIPER_RUNABOUT || + newMode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT || + newMode == CCam::MODE_1STPERSON_RUNABOUT || + newMode == CCam::MODE_M16_1STPERSON_RUNABOUT || + newMode == CCam::MODE_FIGHT_CAM_RUNABOUT || + newMode == CCam::MODE_HELICANNON_1STPERSON) + Cams[ActiveCam].Alpha = 0.0f; + + // PS2 also copies values to ActiveCam here + switch(Cams[ActiveCam].Mode) + case CCam::MODE_SNIPER_RUNABOUT: + case CCam::MODE_ROCKETLAUNCHER_RUNABOUT: + case CCam::MODE_1STPERSON_RUNABOUT: + case CCam::MODE_M16_1STPERSON_RUNABOUT: + case CCam::MODE_FIGHT_CAM_RUNABOUT: + if(newMode == CCam::MODE_CAM_ON_A_STRING || newMode == CCam::MODE_BEHINDBOAT) + switch1stPersonToVehicle = true; + + switch(newMode){ + case CCam::MODE_BEHINDCAR: + Cams[ActiveCam].BetaSpeed = 0.0f; + break; + + case CCam::MODE_FOLLOWPED: + // Getting out of vehicle normally + betaOffset = DEGTORAD(55.0f); + if(m_bJustCameOutOfGarage){ + m_bUseTransitionBeta = true; +/* + // weird logic... + if(CMenuManager::m_ControlMethod == CONTROL_CLASSIC) + Cams[ActiveCam].m_fTransitionBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) + PI; + else if(Cams[ActiveCam].Front.x != 0.0f && Cams[ActiveCam].Front.y != 0.0f) // && is wrong here + Cams[ActiveCam].m_fTransitionBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) + PI; + else + Cams[ActiveCam].m_fTransitionBeta = 0.0f; +*/ + // this is better: + if(Cams[ActiveCam].Front.x != 0.0f || Cams[ActiveCam].Front.y != 0.0f) + Cams[ActiveCam].m_fTransitionBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) + PI; + else + Cams[ActiveCam].m_fTransitionBeta = 0.0f; + } + if(m_bTargetJustCameOffTrain) + m_bCamDirectlyInFront = true; + if(Cams[ActiveCam].Mode != CCam::MODE_CAM_ON_A_STRING) + break; + m_bUseTransitionBeta = true; + vehicleVertical = false; + if(((CPed*)pTargetEntity)->m_carInObjective && + ((CPed*)pTargetEntity)->m_carInObjective->GetForward().x == 0.0f && + ((CPed*)pTargetEntity)->m_carInObjective->GetForward().y == 0.0f) + vehicleVertical = true; + if(vehicleVertical){ + Cams[ActiveCam].m_fTransitionBeta = 0.0f; + break; + } + camBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y); + if(((CPed*)pTargetEntity)->m_carInObjective) + targetBeta = CGeneral::GetATanOfXY(((CPed*)pTargetEntity)->m_carInObjective->GetForward().x, ((CPed*)pTargetEntity)->m_carInObjective->GetForward().y); + else + targetBeta = camBeta; + deltaBeta = targetBeta - camBeta; + while(deltaBeta >= PI) deltaBeta -= 2*PI; + while(deltaBeta < -PI) deltaBeta += 2*PI; + deltaBeta = Abs(deltaBeta); + + door = FindPlayerPed()->m_vehEnterType; + if(deltaBeta > HALFPI){ + if(((CPed*)pTargetEntity)->m_carInObjective){ + if(((CPed*)pTargetEntity)->m_carInObjective->IsUpsideDown()){ + if(door == CAR_DOOR_LF || door == CAR_DOOR_LR) + betaOffset = -DEGTORAD(95.0f); + }else{ + if(door == CAR_DOOR_RF || door == CAR_DOOR_RR) + betaOffset = -DEGTORAD(95.0f); + } } + Cams[ActiveCam].m_fTransitionBeta = targetBeta + betaOffset; }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; + if(((CPed*)pTargetEntity)->m_carInObjective){ + if(((CPed*)pTargetEntity)->m_carInObjective->IsUpsideDown()){ + if(door == CAR_DOOR_RF || door == CAR_DOOR_RR) + betaOffset = -DEGTORAD(55.0f); + else if(door == CAR_DOOR_LF || door == CAR_DOOR_LR) + betaOffset = DEGTORAD(95.0f); }else{ - if(m_bCollisionChecksOn) - PreviouslyFailedRoadHeightCheck = false; - else - TargetZOffSet = 0.0f; + if(door == CAR_DOOR_LF || door == CAR_DOOR_LR) + betaOffset = -DEGTORAD(55.0f); + else if(door == CAR_DOOR_RF || door == CAR_DOOR_RR) + betaOffset = DEGTORAD(95.0f); } } + Cams[ActiveCam].m_fTransitionBeta = targetBeta + betaOffset + PI; + } + break; + + case CCam::MODE_SNIPER: + case CCam::MODE_ROCKETLAUNCHER: + case CCam::MODE_M16_1STPERSON: + case CCam::MODE_SNIPER_RUNABOUT: + case CCam::MODE_ROCKETLAUNCHER_RUNABOUT: + case CCam::MODE_1STPERSON_RUNABOUT: + case CCam::MODE_M16_1STPERSON_RUNABOUT: + case CCam::MODE_FIGHT_CAM_RUNABOUT: + case CCam::MODE_HELICANNON_1STPERSON: + if(FindPlayerVehicle()) + Cams[ActiveCam].Beta = Atan2(FindPlayerVehicle()->GetForward().x, FindPlayerVehicle()->GetForward().y); + else + Cams[ActiveCam].Beta = Atan2(PLAYER->GetForward().x, PLAYER->GetForward().y); + break; + + case CCam::MODE_SYPHON: + Cams[ActiveCam].Alpha = 0.0f; + Cams[ActiveCam].AlphaSpeed = 0.0f; + break; + + case CCam::MODE_CAM_ON_A_STRING: + // Get into vehicle + betaOffset = DEGTORAD(57.0f); + if(!m_bLookingAtPlayer || m_bJustCameOutOfGarage) + break; + m_bUseTransitionBeta = true; + targetBeta = CGeneral::GetATanOfXY(pTargetEntity->GetForward().x, pTargetEntity->GetForward().y); + camBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y); + deltaBeta = targetBeta - camBeta; + while(deltaBeta >= PI) deltaBeta -= 2*PI; + while(deltaBeta < -PI) deltaBeta += 2*PI; + deltaBeta = Abs(deltaBeta); + // switchFromFixed logic again here, skipped + if(switchFromFixed){ + Cams[ActiveCam].m_fTransitionBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y); + break; } - } - if(TargetZOffSet > RoadHeightFix) - RoadHeightFix = TargetZOffSet; - else - WellBufferMe(TargetZOffSet, &RoadHeightFix, &RoadHeightFixSpeed, 0.27f, 0.1f, false); + door = FindPlayerPed()->m_vehEnterType; + if(deltaBeta > HALFPI){ + if(((CVehicle*)pTargetEntity)->IsUpsideDown()){ + if(door == CAR_DOOR_LF || door == CAR_DOOR_LR) // BUG: game checks LF twice + betaOffset = -DEGTORAD(57.0f); + }else{ + if(door == CAR_DOOR_RF || door == CAR_DOOR_RR) + betaOffset = -DEGTORAD(57.0f); + } + Cams[ActiveCam].m_fTransitionBeta = targetBeta + betaOffset + PI; + }else{ + if(((CVehicle*)pTargetEntity)->IsUpsideDown()){ + if(door == CAR_DOOR_RF || door == CAR_DOOR_RR) + betaOffset = -DEGTORAD(57.0f); + else if(door == CAR_DOOR_LF || door == CAR_DOOR_LR) + betaOffset = DEGTORAD(57.0f); + }else{ + if(door == CAR_DOOR_LF || door == CAR_DOOR_LR) + betaOffset = -DEGTORAD(57.0f); + else if(door == CAR_DOOR_RF || door == CAR_DOOR_RR) + betaOffset = DEGTORAD(57.0f); + } + Cams[ActiveCam].m_fTransitionBeta = targetBeta + betaOffset; + } + break; + + case CCam::MODE_BEHINDBOAT: + Cams[ActiveCam].BetaSpeed = 0.0f; + break; + + case CCam::MODE_PED_DEAD_BABY: + Cams[ActiveCam].Alpha = DEGTORAD(15.0f); + break; + + case CCam::MODE_FIGHT_CAM: + Cams[ActiveCam].Beta = 0.0f; + Cams[ActiveCam].BetaSpeed = 0.0f; + Cams[ActiveCam].Alpha = 0.0f; + Cams[ActiveCam].AlphaSpeed = 0.0f; + break; + } - if((colpoint.surfaceB == SURFACE_DEFAULT || colpoint.surfaceB >= SURFACE_METAL6) && - colpoint.surfaceB != SURFACE_STEEL && colpoint.surfaceB != SURFACE_STONE && - RoadHeightFix > 1.4f) - RoadHeightFix = 1.4f; + Cams[ActiveCam].Init(); + Cams[ActiveCam].Mode = newMode; + + m_uiTransitionDuration = 1350; + if(switchSyphonMode) + m_uiTransitionDuration = 1800; + else if(switchPedMode) + m_uiTransitionDuration = 750; +// not on PS2 + else if(switchPedToCar){ + m_fFractionInterToStopMovingTarget = 0.2f; + m_fFractionInterToStopCatchUpTarget = 0.8f; + m_uiTransitionDuration = 950; + }else if(switchFromFixed){ + m_fFractionInterToStopMovingTarget = 0.05f; + m_fFractionInterToStopCatchUpTarget = 0.95f; + }else if(switch1stPersonToVehicle){ + m_fFractionInterToStopMovingTarget = 0.0f; + m_fFractionInterToStopCatchUpTarget = 1.0f; + m_uiTransitionDuration = 1; + }else + m_uiTransitionDuration = 1350; // already set above +// + m_uiTransitionState = 1; + m_uiTimeTransitionStart = CTimer::GetTimeInMilliseconds(); + m_uiTransitionJUSTStarted = 1; +// PS2 returns here + if(m_vecDoingSpecialInterPolation){ + m_cvecStartingSourceForInterPol = SourceDuringInter; + m_cvecStartingTargetForInterPol = TargetDuringInter; + m_cvecStartingUpForInterPol = UpDuringInter; + m_fStartingAlphaForInterPol = m_fAlphaDuringInterPol; + m_fStartingBetaForInterPol = m_fBetaDuringInterPol; + }else{ + m_cvecStartingSourceForInterPol = Cams[ActiveCam].Source; + m_cvecStartingTargetForInterPol = Cams[ActiveCam].m_cvecTargetCoorsForFudgeInter; + m_cvecStartingUpForInterPol = Cams[ActiveCam].Up; + m_fStartingAlphaForInterPol = Cams[ActiveCam].m_fTrueAlpha; + m_fStartingBetaForInterPol = Cams[ActiveCam].m_fTrueBeta; + } + Cams[ActiveCam].m_bCamLookingAtVector = m_bLookingAtVector; + Cams[ActiveCam].m_cvecCamFixedModeVector = m_vecFixedModeVector; + Cams[ActiveCam].m_cvecCamFixedModeSource = m_vecFixedModeSource; + Cams[ActiveCam].m_cvecCamFixedModeUpOffSet = m_vecFixedModeUpOffSet; + Cams[ActiveCam].Mode = newMode; // already done above + Cams[ActiveCam].CamTargetEntity = pTargetEntity; + m_uiTransitionState = 1; // these three already done above + m_uiTimeTransitionStart = CTimer::GetTimeInMilliseconds(); + m_uiTransitionJUSTStarted = 1; + m_fStartingFOVForInterPol = Cams[ActiveCam].FOV; + m_cvecSourceSpeedAtStartInter = Cams[ActiveCam].m_cvecSourceSpeedOverOneFrame; + m_cvecTargetSpeedAtStartInter = Cams[ActiveCam].m_cvecTargetSpeedOverOneFrame; + m_cvecUpSpeedAtStartInter = Cams[ActiveCam].m_cvecUpOverOneFrame; + m_fAlphaSpeedAtStartInter = Cams[ActiveCam].m_fAlphaSpeedOverOneFrame; + m_fBetaSpeedAtStartInter = Cams[ActiveCam].m_fBetaSpeedOverOneFrame; + m_fFOVSpeedAtStartInter = Cams[ActiveCam].m_fFovSpeedOverOneFrame; + Cams[ActiveCam].ResetStatics = true; + if(!m_bLookingAtPlayer && m_bScriptParametersSetForInterPol){ + m_fFractionInterToStopMovingTarget = m_fScriptPercentageInterToStopMoving; + m_fFractionInterToStopCatchUpTarget = m_fScriptPercentageInterToCatchUp; + m_uiTransitionDuration = m_fScriptTimeForInterPolation; + } +} - Source.z += RoadHeightFix; +void +CCamera::StartTransitionWhenNotFinishedInter(int16 mode) +{ + m_vecDoingSpecialInterPolation = true; + StartTransition(mode); } void -CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight) +CCamera::StoreValuesDuringInterPol(CVector &source, CVector &target, CVector &up, float &FOV) { - static float LastTargetAlphaWithCollisionOn = 0.0f; - static float LastTopAlphaSpeed = 0.0f; - static float LastAlphaSpeedStep = 0.0f; - static bool PreviousNearCheckNearClipSmall = false; + SourceDuringInter = source; + TargetDuringInter = target; + UpDuringInter = up; + FOVDuringInter = FOV; + CVector Dist = source - TargetDuringInter; + float DistOnGround = Dist.Magnitude2D(); + m_fBetaDuringInterPol = CGeneral::GetATanOfXY(Dist.x, Dist.y); + m_fAlphaDuringInterPol = CGeneral::GetATanOfXY(DistOnGround, Dist.z); +} - 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; +void +CCamera::SetWideScreenOn(void) +{ + m_WideScreenOn = true; +} - 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 +void +CCamera::SetWideScreenOff(void) +{ + m_bWantsToSwitchWidescreenOff = m_WideScreenOn; +} +void +CCamera::ProcessWideScreenOn(void) +{ + if(m_bWantsToSwitchWidescreenOff){ + m_bWantsToSwitchWidescreenOff = false; + m_WideScreenOn = false; + m_ScreenReductionPercentage = 0.0f; + m_fFOV_Wide_Screen = 0.0f; + m_fWideScreenReductionAmount = 0.0f; + }else{ + m_fFOV_Wide_Screen = 0.3f*Cams[ActiveCam].FOV; + m_fWideScreenReductionAmount = 1.0f; + m_ScreenReductionPercentage = 30.0f; + } +} - 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; +void +CCamera::DrawBordersForWideScreen(void) +{ + if(m_BlurType == MBLUR_NONE || m_BlurType == MBLUR_NORMAL) + SetMotionBlurAlpha(80); + + CSprite2d::DrawRect( + CRect(0.0f, (SCREEN_HEIGHT/2) * m_ScreenReductionPercentage/100.0f - 8.0f, + SCREEN_WIDTH, 0.0f), + CRGBA(0, 0, 0, 255)); + + CSprite2d::DrawRect( + CRect(0.0f, SCREEN_HEIGHT, + SCREEN_WIDTH, SCREEN_HEIGHT - (SCREEN_HEIGHT/2) * m_ScreenReductionPercentage/100.0f - 8.0f), + CRGBA(0, 0, 0, 255)); +} - 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; +bool +CCamera::IsItTimeForNewcam(int32 obbeMode, int32 time) +{ + CVehicle *veh; + uint32 t = time; // no annoying compiler warnings + CVector fwd; + + if(obbeMode < 0) + return true; + switch(obbeMode){ + case OBBE_WHEEL: + veh = FindPlayerVehicle(); + if(veh == nil){ + if(CTimer::GetTimeInMilliseconds() > t+5000) + return true; + SetNearClipScript(0.6f); + return false; } - - 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(veh->IsBoat() || veh->GetModelIndex() == MI_RHINO) + return true; + if(CWorld::GetIsLineOfSightClear(pTargetEntity->GetPosition(), Cams[ActiveCam].Source, true, false, false, false, false, false, false)){ + if(CTimer::GetTimeInMilliseconds() > t+5000) + return true; + SetNearClipScript(0.6f); + return 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; + return true; + case OBBE_1: + if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat()) + return true; + if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){ + fwd = FindPlayerCoors() - m_vecFixedModeSource; + fwd.z = 0.0f; + + // too far and driving away from cam + if(fwd.Magnitude() > 20.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f) + return true; + // too close + if(fwd.Magnitude() < 1.6f) + return true; + return 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; + return true; + case OBBE_2: + if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat()) + return true; + if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){ + fwd = FindPlayerCoors() - m_vecFixedModeSource; + fwd.z = 0.0f; + + if(fwd.Magnitude() < 2.0f) + // very close, fix near clip + SetNearClipScript(max(fwd.Magnitude()*0.5f, 0.05f)); + // too far and driving away from cam + if(fwd.Magnitude() > 19.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f) + return true; + // too close + if(fwd.Magnitude() < 1.6f) + return true; + return false; } + return true; + case OBBE_3: + if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){ + fwd = FindPlayerCoors() - m_vecFixedModeSource; + fwd.z = 0.0f; + + // too far and driving away from cam + if(fwd.Magnitude() > 28.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f) + return true; + return false; + } + return true; + case OBBE_1STPERSON: + return CTimer::GetTimeInMilliseconds() > t+3000; + case OBBE_5: + if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat()) + return true; + if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){ + fwd = FindPlayerCoors() - m_vecFixedModeSource; + fwd.z = 0.0f; + + // too far and driving away from cam + if(fwd.Magnitude() > 28.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f) + return true; + return false; + } + return true; + case OBBE_ONSTRING: + return CTimer::GetTimeInMilliseconds() > t+3000; + case OBBE_COPCAR: + return CTimer::GetTimeInMilliseconds() > t+2000 && !FindPlayerVehicle()->GetIsOnScreen(); + case OBBE_COPCAR_WHEEL: + if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat()) + return true; + if(CWorld::GetIsLineOfSightClear(pTargetEntity->GetPosition(), Cams[ActiveCam].Source, true, false, false, false, false, false, false)){ + if(CTimer::GetTimeInMilliseconds() > t+1000) + return true; + SetNearClipScript(0.6f); + return false; + } + return true; + + // Ped modes + case OBBE_9: + if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){ + fwd = FindPlayerCoors() - m_vecFixedModeSource; + fwd.z = 0.0f; + + // too far and driving away from cam + if(fwd.Magnitude() > 20.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f) + return true; + return false; + } + return true; + case OBBE_10: + if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){ + fwd = FindPlayerCoors() - m_vecFixedModeSource; + fwd.z = 0.0f; + + // too far and driving away from cam + if(fwd.Magnitude() > 8.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f) + return true; + return false; + } + return true; + case OBBE_11: + if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){ + fwd = FindPlayerCoors() - m_vecFixedModeSource; + fwd.z = 0.0f; + + // too far and driving away from cam + if(fwd.Magnitude() > 25.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f) + return true; + return false; + } + return true; + case OBBE_12: + if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){ + fwd = FindPlayerCoors() - m_vecFixedModeSource; + fwd.z = 0.0f; + + // too far and driving away from cam + if(fwd.Magnitude() > 8.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f) + return true; + return false; + } + return true; + case OBBE_13: + return CTimer::GetTimeInMilliseconds() > t+5000; + default: + return false; + } +} - // 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; +bool +CCamera::TryToStartNewCamMode(int obbeMode) +{ + CVehicle *veh; + CVector target, camPos, playerSpeed, fwd; + float ground; + bool foundGround; + int i; + + if(obbeMode < 0) + return true; + switch(obbeMode){ + case OBBE_WHEEL: + veh = FindPlayerVehicle(); + if(veh == nil || veh->IsBoat() || veh->GetModelIndex() == MI_RHINO) + return false; + target = Multiply3x3(FindPlayerVehicle()->GetMatrix(), CVector(-1.4f, -2.3f, 0.3f)); + target += FindPlayerVehicle()->GetPosition(); + if(!CWorld::GetIsLineOfSightClear(veh->GetPosition(), target, true, false, false, false, false, false, false)) + return false; + TakeControl(veh, CCam::MODE_WHEELCAM, JUMP_CUT, CAMCONTROL_OBBE); + return true; + case OBBE_1: + camPos = FindPlayerCoors(); + playerSpeed = FindPlayerSpeed(); + playerSpeed.z = 0.0f; + playerSpeed.Normalise(); + camPos += 20.0f*playerSpeed; + camPos += 3.0f*CVector(playerSpeed.y, -playerSpeed.x, 0.0f); + if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat()) + return false; + + ground = CWorld::FindGroundZFor3DCoord(camPos.x, camPos.y, camPos.z+5.0f, &foundGround); + if(foundGround) + camPos.z = ground + 1.5f; + else{ + ground = CWorld::FindRoofZFor3DCoord(camPos.x, camPos.y, camPos.z-5.0f, &foundGround); + if(foundGround) + camPos.z = ground + 1.5f; + } + if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false)) + return false; + + fwd = FindPlayerCoors() - camPos; + fwd.z = 0.0f; + // too far and driving away from cam + if(fwd.Magnitude() > 20.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f) + return false; + // too close + if(fwd.Magnitude() < 1.6f) + return true; + + SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f)); + TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE); + return true; + case OBBE_2: + if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat()) + return false; + camPos = FindPlayerCoors(); + playerSpeed = FindPlayerSpeed(); + playerSpeed.z = 0.0f; + playerSpeed.Normalise(); + camPos += 16.0f*playerSpeed; + camPos += 2.5f*CVector(playerSpeed.y, -playerSpeed.x, 0.0f); + + ground = CWorld::FindGroundZFor3DCoord(camPos.x, camPos.y, camPos.z+5.0f, &foundGround); + if(foundGround) + camPos.z = ground + 0.5f; + else{ + ground = CWorld::FindRoofZFor3DCoord(camPos.x, camPos.y, camPos.z-5.0f, &foundGround); + if(foundGround) + camPos.z = ground + 0.5f; + } + if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false)) + return false; + + fwd = FindPlayerCoors() - camPos; + fwd.z = 0.0f; + // too far and driving away from cam + if(fwd.Magnitude() > 19.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f) + return false; + // too close + if(fwd.Magnitude() < 1.6f) + return true; + + SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f)); + TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE); + return true; + case OBBE_3: + camPos = FindPlayerCoors(); + playerSpeed = FindPlayerSpeed(); + playerSpeed.z = 0.0f; + playerSpeed.Normalise(); + camPos += 30.0f*playerSpeed; + camPos += 8.0f*CVector(playerSpeed.y, -playerSpeed.x, 0.0f); + + if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false)) + return false; + + SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f)); + TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE); + return true; + case OBBE_1STPERSON: + TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE); + return true; + case OBBE_5: + camPos = FindPlayerCoors(); + playerSpeed = FindPlayerSpeed(); + playerSpeed.z = 0.0f; + playerSpeed.Normalise(); + camPos += 30.0f*playerSpeed; + camPos += 6.0f*CVector(playerSpeed.y, -playerSpeed.x, 0.0f); + + ground = CWorld::FindGroundZFor3DCoord(camPos.x, camPos.y, camPos.z+5.0f, &foundGround); + if(foundGround) + camPos.z = ground + 3.5f; + else{ + ground = CWorld::FindRoofZFor3DCoord(camPos.x, camPos.y, camPos.z-5.0f, &foundGround); + if(foundGround) + camPos.z = ground + 3.5f; + } + if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false)) + return false; + + SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f)); + TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE); + return true; + case OBBE_ONSTRING: + TakeControl(FindPlayerEntity(), CCam::MODE_CAM_ON_A_STRING, JUMP_CUT, CAMCONTROL_OBBE); + return true; + case OBBE_COPCAR: + if(FindPlayerPed()->m_pWanted->m_nWantedLevel < 1) + return false; + if(FindPlayerVehicle() == nil) + return false; + if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat()) + return false; + i = CPools::GetVehiclePool()->GetSize(); + while(--i >= 0){ + veh = CPools::GetVehiclePool()->GetSlot(i); + if(veh && veh->IsCar() && veh != FindPlayerVehicle() && veh->bIsLawEnforcer){ + float dx = veh->GetPosition().x - FindPlayerCoors().x; + float dy = veh->GetPosition().y - FindPlayerCoors().y; + float dist = (veh->GetPosition() - FindPlayerCoors()).Magnitude(); + if(dist < 30.0f){ + if(dx*FindPlayerVehicle()->GetForward().x + dy*FindPlayerVehicle()->GetForward().y < 0.0f && + veh->GetForward().x*FindPlayerVehicle()->GetForward().x + veh->GetForward().y*FindPlayerVehicle()->GetForward().y > 0.8f){ + TakeControl(veh, CCam::MODE_CAM_ON_A_STRING, JUMP_CUT, CAMCONTROL_OBBE); + return true; + } } - }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; + } + } + return false; + case OBBE_COPCAR_WHEEL: + if(FindPlayerPed()->m_pWanted->m_nWantedLevel < 1) + return false; + if(FindPlayerVehicle() == nil) + return false; + if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat()) + return false; + i = CPools::GetVehiclePool()->GetSize(); + while(--i >= 0){ + veh = CPools::GetVehiclePool()->GetSlot(i); + if(veh && veh->IsCar() && veh != FindPlayerVehicle() && veh->bIsLawEnforcer){ + float dx = veh->GetPosition().x - FindPlayerCoors().x; + float dy = veh->GetPosition().y - FindPlayerCoors().y; + float dist = (veh->GetPosition() - FindPlayerCoors()).Magnitude(); + if(dist < 30.0f){ + if(dx*FindPlayerVehicle()->GetForward().x + dy*FindPlayerVehicle()->GetForward().y < 0.0f && + veh->GetForward().x*FindPlayerVehicle()->GetForward().x + veh->GetForward().y*FindPlayerVehicle()->GetForward().y > 0.8f){ + target = Multiply3x3(veh->GetMatrix(), CVector(-1.4f, -2.3f, 0.3f)); + target += veh->GetPosition(); + if(!CWorld::GetIsLineOfSightClear(veh->GetPosition(), target, true, false, false, false, false, false, false)) + return false; + TakeControl(veh, CCam::MODE_WHEELCAM, JUMP_CUT, CAMCONTROL_OBBE); + return true; + } } } } + return false; - LastTargetAlphaWithCollisionOn = DeltaAlpha + Alpha; - LastTopAlphaSpeed = TopAlphaSpeed; - LastAlphaSpeedStep = AlphaSpeedStep; - }else{ - if(PreviousNearCheckNearClipSmall) - RwCameraSetNearClipPlane(Scene.camera, 0.9f); + case OBBE_9: + camPos = FindPlayerCoors(); + playerSpeed = FindPlayerSpeed(); + playerSpeed.z = 0.0f; + playerSpeed.Normalise(); + camPos += 15.0f*playerSpeed; + camPos += CVector(2.0f, 1.0f, 0.0f); + + ground = CWorld::FindGroundZFor3DCoord(camPos.x, camPos.y, camPos.z+5.0f, &foundGround); + if(foundGround) + camPos.z = ground + 0.5f; + else{ + ground = CWorld::FindRoofZFor3DCoord(camPos.x, camPos.y, camPos.z-5.0f, &foundGround); + if(foundGround) + camPos.z = ground + 0.5f; + } + if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false)) + return false; + + SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f)); + TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE); + return true; + case OBBE_10: + camPos = FindPlayerCoors(); + playerSpeed = FindPlayerSpeed(); + playerSpeed.z = 0.0f; + playerSpeed.Normalise(); + camPos += 5.0f*playerSpeed; + camPos += CVector(2.0f, 1.0f, 0.5f); + + if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false)) + return false; + + SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f)); + TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE); + return true; + case OBBE_11: + camPos = FindPlayerCoors(); + playerSpeed = FindPlayerSpeed(); + playerSpeed.z = 0.0f; + playerSpeed.Normalise(); + camPos += 20.0f*playerSpeed; + camPos += CVector(2.0f, 1.0f, 20.0f); + + if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false)) + return false; + + SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f)); + TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE); + return true; + case OBBE_12: + camPos = FindPlayerCoors(); + playerSpeed = FindPlayerSpeed(); + playerSpeed.z = 0.0f; + playerSpeed.Normalise(); + camPos += 5.0f*playerSpeed; + camPos += CVector(2.0f, 1.0f, 10.5f); + + if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false)) + return false; + + SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f)); + TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE); + return true; + case OBBE_13: +#ifdef FIX_BUGS + TakeControl(FindPlayerEntity(), CCam::MODE_TOP_DOWN_PED, JUMP_CUT, CAMCONTROL_OBBE); +#else + TakeControl(FindPlayerEntity(), CCam::MODE_TOPDOWN, JUMP_CUT, CAMCONTROL_OBBE); +#endif + return true; + default: + return false; } - - 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; +static int32 SequenceOfCams[16] = { + OBBE_WHEEL, OBBE_COPCAR, OBBE_3, OBBE_1, OBBE_3, OBBE_COPCAR_WHEEL, + OBBE_2, OBBE_3, OBBE_COPCAR_WHEEL, OBBE_COPCAR, OBBE_2, OBBE_3, + OBBE_5, OBBE_3, + OBBE_ONSTRING // actually unused... +}; - float Dist = (Source - TargetCoors).Magnitude2D(); +void +CCamera::ProcessObbeCinemaCameraCar(void) +{ + static int OldMode = -1; + static int32 TimeForNext = 0; + int i = 0; - float DeltaBeta = TargetOrientation - Beta; - while(DeltaBeta >= PI) DeltaBeta -= 2*PI; - while(DeltaBeta < -PI) DeltaBeta += 2*PI; + if(!bDidWeProcessAnyCinemaCam){ + OldMode = -1; + CHud::SetHelpMessage(TheText.Get("CINCAM"), true); + } - if(Abs(DeltaBeta) > DEGTORAD(20.0f) && MovingForward && TheCamera.m_uiTransitionState == 0) - m_bFixingBeta = true; + if(!bDidWeProcessAnyCinemaCam || IsItTimeForNewcam(SequenceOfCams[OldMode], TimeForNext)){ + // This is very strange code... + for(OldMode = (OldMode+1) % 14; + !TryToStartNewCamMode(SequenceOfCams[OldMode]) && i <= 14; + OldMode = (OldMode+1) % 14) + i++; + TimeForNext = CTimer::GetTimeInMilliseconds(); + if(i >= 14){ + OldMode = 14; + TryToStartNewCamMode(SequenceOfCams[14]); + } + } - CPad *pad = CPad::GetPad(0); - if(!(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight())) - if(DirectionWasLooking != LOOKING_FORWARD) - TheCamera.m_bCamDirectlyBehind = true; + m_iModeObbeCamIsInForCar = OldMode; + bDidWeProcessAnyCinemaCam = true; +} - if(!m_bFixingBeta && !TheCamera.m_bUseTransitionBeta && !TheCamera.m_bCamDirectlyBehind && !TheCamera.m_bCamDirectlyInFront) - return false; +static int32 SequenceOfPedCams[5] = { OBBE_9, OBBE_10, OBBE_11, OBBE_12, OBBE_13 }; - 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; +void +CCamera::ProcessObbeCinemaCameraPed(void) +{ + // static bool bObbePedProcessed = false; // unused + static int PedOldMode = -1; + static int32 PedTimeForNext = 0; + + if(!bDidWeProcessAnyCinemaCam) + PedOldMode = -1; + + if(!bDidWeProcessAnyCinemaCam || IsItTimeForNewcam(SequenceOfPedCams[PedOldMode], PedTimeForNext)){ + for(PedOldMode = (PedOldMode+1) % 5; + !TryToStartNewCamMode(SequenceOfPedCams[PedOldMode]); + PedOldMode = (PedOldMode+1) % 5); + PedTimeForNext = CTimer::GetTimeInMilliseconds(); } - TheCamera.m_bCamDirectlyBehind = false; - TheCamera.m_bCamDirectlyInFront = false; - return true; + bDidWeProcessAnyCinemaCam = 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(); +void +CCamera::DontProcessObbeCinemaCamera(void) +{ + bDidWeProcessAnyCinemaCam = false; +} + + +void +CCamera::LoadTrainCamNodes(char const *name) +{ + CFileMgr::SetDir("data"); + + char token[16] = { 0 }; + char filename[16] = { 0 }; + uint8 *buf; + int bufpos = 0; + int field = 0; + int tokpos = 0; + char c; + int i; + int len; + + strcpy(filename, name); + len = strlen(filename); + filename[len] = '.'; + filename[len+1] = 'd'; + filename[len+2] = 'a'; + filename[len+3] = 't'; + + m_uiNumberOfTrainCamNodes = 0; + + buf = new uint8[20000]; + len = CFileMgr::LoadFile(filename, buf, 20000, "r"); + + for(i = 0; i < MAX_NUM_OF_NODES; i++){ + m_arrTrainCamNode[i].m_cvecPointToLookAt = CVector(0.0f, 0.0f, 0.0f); + m_arrTrainCamNode[i].m_cvecMinPointInRange = CVector(0.0f, 0.0f, 0.0f); + m_arrTrainCamNode[i].m_cvecMaxPointInRange = CVector(0.0f, 0.0f, 0.0f); + m_arrTrainCamNode[i].m_fDesiredFOV = 0.0f; + m_arrTrainCamNode[i].m_fNearClip = 0.0f; } - 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); + while(bufpos <= len){ + c = buf[bufpos]; + switch(c){ + case '-': + case '.': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': +// case '10': case '11': case '12': case '13': // ahem... + token[tokpos++] = c; + bufpos++; + break; + + case ',': + case ';': // game has the code for this duplicated but we handle both under the same case + switch((field+14)%14){ + case 0: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecCamPosition.x = atof(token); + break; + case 1: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecCamPosition.y = atof(token); + break; + case 2: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecCamPosition.z = atof(token); + break; + case 3: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecPointToLookAt.x = atof(token); + break; + case 4: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecPointToLookAt.y = atof(token); + break; + case 5: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecPointToLookAt.z = atof(token); + break; + case 6: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecMinPointInRange.x = atof(token); + break; + case 7: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecMinPointInRange.y = atof(token); + break; + case 8: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecMinPointInRange.z = atof(token); + break; + case 9: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecMaxPointInRange.x = atof(token); + break; + case 10: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecMaxPointInRange.y = atof(token); + break; + case 11: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecMaxPointInRange.z = atof(token); + break; + case 12: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_fDesiredFOV = atof(token); + break; + case 13: + m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_fNearClip = atof(token); + m_uiNumberOfTrainCamNodes++; + break; } + field++; + bufpos++; + memset(token, 0, sizeof(token)); + tokpos = 0; + break; + + default: + bufpos++; + break; } - LastObscured = Obscured1 || Obscured2; } - // nothing to do - if(!LastObscured) - return false; + delete[] buf; + CFileMgr::SetDir(""); +} + +void +CCamera::Process_Train_Camera_Control(void) +{ + bool found = false; + CTrain *target = (CTrain*)pTargetEntity; + m_bUseSpecialFovTrain = true; + static bool OKtoGoBackToNodeCam = true; // only ever set to true + uint32 i; + + if(target->m_nTrackId == TRACK_ELTRAIN && !m_bAboveGroundTrainNodesLoaded){ + m_bAboveGroundTrainNodesLoaded = true; + m_bBelowGroundTrainNodesLoaded = false; + LoadTrainCamNodes("Train"); + m_uiTimeLastChange = CTimer::GetTimeInMilliseconds(); + OKtoGoBackToNodeCam = true; + m_iCurrentTrainCamNode = 0; + } + if(target->m_nTrackId == TRACK_SUBWAY && !m_bBelowGroundTrainNodesLoaded){ + m_bBelowGroundTrainNodesLoaded = true; + m_bAboveGroundTrainNodesLoaded = false; + LoadTrainCamNodes("Train2"); + m_uiTimeLastChange = CTimer::GetTimeInMilliseconds(); + OKtoGoBackToNodeCam = true; + m_iCurrentTrainCamNode = 0; + } - if(Fix1){ - Source.x = Target.x - Cos(Beta)*Dist1; - Source.y = Target.y - Sin(Beta)*Dist1; - if(Mode == MODE_BEHINDCAR) - Source = colPoint.point; + m_bTargetJustBeenOnTrain = true; + uint32 node = m_iCurrentTrainCamNode; + for(i = 0; i < m_uiNumberOfTrainCamNodes && !found; i++){ + if(target->IsWithinArea(m_arrTrainCamNode[node].m_cvecMinPointInRange.x, + m_arrTrainCamNode[node].m_cvecMinPointInRange.y, + m_arrTrainCamNode[node].m_cvecMinPointInRange.z, + m_arrTrainCamNode[node].m_cvecMaxPointInRange.x, + m_arrTrainCamNode[node].m_cvecMaxPointInRange.y, + m_arrTrainCamNode[node].m_cvecMaxPointInRange.z)){ + m_iCurrentTrainCamNode = node; + found = true; + } + node++; + if(node >= m_uiNumberOfTrainCamNodes) + node = 0; + } + + if(found){ + SetWideScreenOn(); + if(DotProduct(((CTrain*)pTargetEntity)->GetMoveSpeed(), pTargetEntity->GetForward()) < 0.001f){ + TakeControl(FindPlayerPed(), CCam::MODE_FOLLOWPED, JUMP_CUT, CAMCONTROL_SCRIPT); + if(target->Doors[0].IsFullyOpen()) + SetWideScreenOff(); + }else{ + SetCamPositionForFixedMode(m_arrTrainCamNode[m_iCurrentTrainCamNode].m_cvecCamPosition, CVector(0.0f, 0.0f, 0.0f)); + if(m_arrTrainCamNode[m_iCurrentTrainCamNode].m_cvecPointToLookAt.x == 999.0f && + m_arrTrainCamNode[m_iCurrentTrainCamNode].m_cvecPointToLookAt.y == 999.0f && + m_arrTrainCamNode[m_iCurrentTrainCamNode].m_cvecPointToLookAt.z == 999.0f) + TakeControl(target, CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_SCRIPT); + else + TakeControlNoEntity(m_arrTrainCamNode[m_iCurrentTrainCamNode].m_cvecPointToLookAt, JUMP_CUT, CAMCONTROL_SCRIPT); + RwCameraSetNearClipPlane(Scene.camera, m_arrTrainCamNode[m_iCurrentTrainCamNode].m_fNearClip); + } }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(DotProduct(((CTrain*)pTargetEntity)->GetMoveSpeed(), pTargetEntity->GetForward()) < 0.001f){ + TakeControl(FindPlayerPed(), CCam::MODE_FOLLOWPED, JUMP_CUT, CAMCONTROL_SCRIPT); + if(target->Doors[0].IsFullyOpen()) + SetWideScreenOff(); + } } +} + - if(ResetStatics){ - m_fDistanceBeforeChanges = (Source - Target).Magnitude2D(); - DistanceSpeed = 0.0f; - Source.x = colPoint.point.x; - Source.y = colPoint.point.y; + +void +CCamera::LoadPathSplines(int file) +{ + bool reading = true; + char c, token[32] = { 0 }; + int i, j, n; + + n = 0; + + for(i = 0; i < MAX_NUM_OF_SPLINETYPES; i++) + for(j = 0; j < CCamPathSplines::MAXPATHLENGTH; j++) + m_arrPathArray[i].m_arr_PathData[j] = 0.0f; + + m_bStartingSpline = false; + + i = 0; + j = 0; + while(reading){ + CFileMgr::Read(file, &c, 1); + switch(c){ + case '\0': + reading = false; + break; + + case '+': case '-': case '.': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'e': case 'E': + token[n++] = c; + break; + + case ',': +#ifdef FIX_BUGS + if(i < MAX_NUM_OF_SPLINETYPES && j < CCamPathSplines::MAXPATHLENGTH) +#endif + m_arrPathArray[i].m_arr_PathData[j] = atof(token); + j++; + memset(token, 0, 32); + n = 0; + break; + + case ';': +#ifdef FIX_BUGS + if(i < MAX_NUM_OF_SPLINETYPES && j < CCamPathSplines::MAXPATHLENGTH) +#endif + m_arrPathArray[i].m_arr_PathData[j] = atof(token); + i++; + j = 0; + memset(token, 0, 32); + n = 0; + } } - return true; } void -CCam::Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float) +CCamera::FinishCutscene(void) { - if(!CamTargetEntity->IsVehicle()) - return; + SetPercentAlongCutScene(100.0f); + m_fPositionAlongSpline = 1.0f; + m_bcutsceneFinished = true; +} - FOV = DefaultFOV; +uint32 +CCamera::GetCutSceneFinishTime(void) +{ + int cam = ActiveCam; + if (Cams[cam].Mode == CCam::MODE_FLYBY) + return Cams[cam].m_uiFinishTime; + cam = (cam + 1) % 2; + if (Cams[cam].Mode == CCam::MODE_FLYBY) + return Cams[cam].m_uiFinishTime; - if(ResetStatics){ - AlphaSpeed = 0.0f; - if(TheCamera.m_bIdleOn) - TheCamera.m_uiTimeWeEnteredIdle = CTimer::GetTimeInMilliseconds(); - } + return 0; +} + +void +CCamera::SetCamCutSceneOffSet(const CVector &pos) +{ + m_vecCutSceneOffset = pos; +}; - 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; +void +CCamera::SetPercentAlongCutScene(float percent) +{ + if(Cams[ActiveCam].Mode == CCam::MODE_FLYBY) + Cams[ActiveCam].m_fTimeElapsedFloat = percent/100.0f * Cams[ActiveCam].m_uiFinishTime; + else if(Cams[(ActiveCam+1)%2].Mode == CCam::MODE_FLYBY) + Cams[(ActiveCam+1)%2].m_fTimeElapsedFloat = percent/100.0f * Cams[(ActiveCam+1)%2].m_uiFinishTime; } -// Basic Cam on a string algorithm void -CCam::Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist) +CCamera::SetParametersForScriptInterpolation(float stopMoving, float catchUp, int32 time) { - CA_MAX_DISTANCE = BaseDist + 0.1f + TheCamera.CarZoomValueSmooth; - CA_MIN_DISTANCE = min(BaseDist*0.6f, 3.5f); + m_fScriptPercentageInterToStopMoving = stopMoving * 0.01f; + m_fScriptPercentageInterToCatchUp = catchUp * 0.01f; + m_fScriptTimeForInterPolation = time; + m_bScriptParametersSetForInterPol = true; +} - CVector Dist = Source - TargetCoors; +void +CCamera::SetZoomValueFollowPedScript(int16 dist) +{ + switch (dist) { + case 0: m_fPedZoomValueScript = 0.25f; break; + case 1: m_fPedZoomValueScript = 1.5f; break; + case 2: m_fPedZoomValueScript = 2.9f; break; + default: m_fPedZoomValueScript = m_fPedZoomValueScript; break; + } - if(ResetStatics) - Source = TargetCoors + Dist*(CA_MAX_DISTANCE + 1.0f); + m_bUseScriptZoomValuePed = true; +} - 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(); +void +CCamera::SetZoomValueCamStringScript(int16 dist) +{ + switch (dist) { + case 0: m_fCarZoomValueScript = 0.05f; break; + case 1: m_fCarZoomValueScript = 1.9f; break; + case 2: m_fCarZoomValueScript = 3.9f; break; + default: m_fCarZoomValueScript = m_fCarZoomValueScript; break; } - 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; + m_bUseScriptZoomValueCar = true; +} + +void +CCamera::SetNearClipScript(float clip) +{ + m_fNearClipScript = clip; + m_bUseNearClipScript = true; +} + + + +void +CCamera::ProcessFade(void) +{ + float fade = (CTimer::GetTimeInMilliseconds() - m_uiFadeTimeStarted)/1000.0f; + // Why even set CDraw::FadeValue if m_fFLOATingFade sets it anyway? + if(m_bFading){ + if(m_iFadingDirection == FADE_IN){ + if(m_fTimeToFadeOut != 0.0f){ + m_fFLOATingFade = 255.0f - 255.0f*fade/m_fTimeToFadeOut; + if(m_fFLOATingFade <= 0.0f){ + m_bFading = false; + CDraw::FadeValue = 0; + m_fFLOATingFade = 0.0f; + } + }else{ + m_bFading = false; + CDraw::FadeValue = 0; + m_fFLOATingFade = 0.0f; + } + }else if(m_iFadingDirection == FADE_OUT){ + if(m_fTimeToFadeOut != 0.0f){ + m_fFLOATingFade = 255.0f*fade/m_fTimeToFadeOut; + if(m_fFLOATingFade >= 255.0f){ + m_bFading = false; + CDraw::FadeValue = 255; + m_fFLOATingFade = 255.0f; + } + }else{ + m_bFading = false; + CDraw::FadeValue = 255; + m_fFLOATingFade = 255.0f; + } + } + CDraw::FadeValue = m_fFLOATingFade; } } void -CCam::FixCamWhenObscuredByVehicle(const CVector &TargetCoors) +CCamera::ProcessMusicFade(void) { - // BUG? is this never reset - static float HeightFixerCarsObscuring = 0.0f; - static float HeightFixerCarsObscuringSpeed = 0.0f; - CColPoint colPoint; - CEntity *entity; + float fade = (CTimer::GetTimeInMilliseconds() - m_uiFadeTimeStartedMusic)/1000.0f; + if(m_bMusicFading){ + if(m_iMusicFadingDirection == FADE_IN){ + if(m_fTimeToFadeMusic == 0.0f) + m_fTimeToFadeMusic = 1.0f; + + m_fFLOATingFadeMusic = 255.0f*fade/m_fTimeToFadeMusic; + if(m_fFLOATingFadeMusic > 255.0f){ + m_bMusicFading = false; + m_fFLOATingFadeMusic = 0.0f; + DMAudio.SetEffectsFadeVol(127); + DMAudio.SetMusicFadeVol(127); + }else{ + DMAudio.SetEffectsFadeVol(m_fFLOATingFadeMusic/255.0f * 127); + DMAudio.SetMusicFadeVol(m_fFLOATingFadeMusic/255.0f * 127); + } + }else if(m_iMusicFadingDirection == FADE_OUT){ + if(m_fTimeToFadeMusic == 0.0f) + m_fTimeToFadeMusic = 1.0f; + + if(m_bMoveCamToAvoidGeom || StillToFadeOut){ + m_fFLOATingFadeMusic = 256.0f; + m_bMoveCamToAvoidGeom = false; + }else + m_fFLOATingFadeMusic = 255.0f*fade/m_fTimeToFadeMusic; + + if(m_fFLOATingFadeMusic > 255.0f){ + m_bMusicFading = false; + m_fFLOATingFadeMusic = 255.0f; + DMAudio.SetEffectsFadeVol(0); + DMAudio.SetMusicFadeVol(0); + }else{ + DMAudio.SetEffectsFadeVol(127 - m_fFLOATingFadeMusic/255.0f * 127); + DMAudio.SetMusicFadeVol(127 - m_fFLOATingFadeMusic/255.0f * 127); + } + } + } +} - 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; +void +CCamera::Fade(float timeout, int16 direction) +{ + m_bFading = true; + m_iFadingDirection = direction; + m_fTimeToFadeOut = timeout; + m_uiFadeTimeStarted = CTimer::GetTimeInMilliseconds(); + if(!m_bIgnoreFadingStuffForMusic){ + m_bMusicFading = true; + m_iMusicFadingDirection = direction; + m_fTimeToFadeMusic = timeout; + m_uiFadeTimeStartedMusic = CTimer::GetTimeInMilliseconds(); +// Not on PS2 + if(!m_bJustJumpedOutOf1stPersonBecauseOfTarget && m_iMusicFadingDirection == FADE_OUT){ + unknown++; + if(unknown >= 2){ + m_bJustJumpedOutOf1stPersonBecauseOfTarget = true; + unknown = 0; + }else + m_bMoveCamToAvoidGeom = true; + } } - WellBufferMe(HeightTarget, &HeightFixerCarsObscuring, &HeightFixerCarsObscuringSpeed, 0.2f, 0.025f, false); - Source.z += HeightFixerCarsObscuring; } -bool -CCam::Using3rdPersonMouseCam() +void +CCamera::SetFadeColour(uint8 r, uint8 g, uint8 b) { - return CCamera::m_bUseMouse3rdPerson && - (Mode == MODE_FOLLOWPED || - TheCamera.m_bPlayerIsInGarage && - FindPlayerPed() && FindPlayerPed()->m_nPedState != PED_DRIVING && - Mode != MODE_TOPDOWN && this->CamTargetEntity == FindPlayerPed()); + m_FadeTargetIsSplashScreen = r == 0 && g == 0 && b == 0; + CDraw::FadeRed = r; + CDraw::FadeGreen = g; + CDraw::FadeBlue = b; } bool -CCam::GetWeaponFirstPersonOn() +CCamera::GetFading(void) { - CEntity *target = this->CamTargetEntity; - if (target && target->IsPed()) - return ((CPed*)target)->GetWeapon()->m_bAddRotOffset; - - return false; + return m_bFading; } -float -CCamera::Find3rdPersonQuickAimPitch(void) +int +CCamera::GetFadingDirection(void) { - float clampedFrontZ = clamp(Cams[ActiveCam].Front.z, -1.0f, 1.0f); + if(m_bFading) + return m_iFadingDirection == FADE_IN ? FADE_IN : FADE_OUT; + else + return FADE_NONE; +} - // float rot = atan2(clampedFrontZ, sqrt(1.0f - sq(clampedFrontZ))); - float rot = Asin(clampedFrontZ); +int +CCamera::GetScreenFadeStatus(void) +{ + if(m_fFLOATingFade == 0.0f) + return FADE_0; + if(m_fFLOATingFade == 255.0f) + return FADE_2; + return FADE_1; +} - return -(DEGTORAD(((0.5f - m_f3rdPersonCHairMultY) * 1.8f * 0.5f * Cams[ActiveCam].FOV)) + rot); + + +void +CCamera::RenderMotionBlur(void) +{ + if(m_BlurType == 0) + return; + + CMBlur::MotionBlurRender(m_pRwCamera, + m_BlurRed, m_BlurGreen, m_BlurBlue, + m_motionBlur, m_BlurType, m_imotionBlurAddAlpha); } void -CCamera::SetCamCutSceneOffSet(const CVector &pos) +CCamera::SetMotionBlur(int r, int g, int b, int a, int type) { - m_vecCutSceneOffset = pos; -}; + m_BlurRed = r; + m_BlurGreen = g; + m_BlurBlue = b; + m_motionBlur = a; + m_BlurType = type; +} void -CCamera::TakeControlWithSpline(short nSwitch) +CCamera::SetMotionBlurAlpha(int a) { - m_iModeToGoTo = CCam::MODE_FLYBY; - m_bLookingAtPlayer = false; - m_bLookingAtVector = false; - m_bcutsceneFinished = false; - m_iTypeOfSwitch = nSwitch; - m_bStartInterScript = true; + m_imotionBlurAddAlpha = a; +} - //FindPlayerPed(); // unused -}; -void CCamera::SetCameraDirectlyInFrontForFollowPed_CamOnAString() + +int +CCamera::GetLookDirection(void) { - m_bCamDirectlyInFront = true; - CPlayerPed *player = FindPlayerPed(); - if (player) - m_PedOrientForBehindOrInFront = CGeneral::GetATanOfXY(player->GetForward().x, player->GetForward().y); + if(Cams[ActiveCam].Mode == CCam::MODE_CAM_ON_A_STRING || + Cams[ActiveCam].Mode == CCam::MODE_1STPERSON || + Cams[ActiveCam].Mode == CCam::MODE_BEHINDBOAT || + Cams[ActiveCam].Mode == CCam::MODE_FOLLOWPED) + return Cams[ActiveCam].DirectionWasLooking; + return LOOKING_FORWARD;; } -void CCamera::SetCameraDirectlyBehindForFollowPed_CamOnAString() +bool +CCamera::GetLookingForwardFirstPerson(void) { - m_bCamDirectlyBehind = true; - CPlayerPed *player = FindPlayerPed(); - if (player) - m_PedOrientForBehindOrInFront = CGeneral::GetATanOfXY(player->GetForward().x, player->GetForward().y); + return Cams[ActiveCam].Mode == CCam::MODE_1STPERSON && + Cams[ActiveCam].DirectionWasLooking == LOOKING_FORWARD; +} + +bool +CCamera::GetLookingLRBFirstPerson(void) +{ + return Cams[ActiveCam].Mode == CCam::MODE_1STPERSON && Cams[ActiveCam].DirectionWasLooking != LOOKING_FORWARD; } void -CCamera::SetWideScreenOn(void) +CCamera::SetCameraDirectlyBehindForFollowPed_CamOnAString(void) { - m_WideScreenOn = true; + m_bCamDirectlyBehind = true; + CPlayerPed *player = FindPlayerPed(); + if (player) + m_PedOrientForBehindOrInFront = CGeneral::GetATanOfXY(player->GetForward().x, player->GetForward().y); } void -CCamera::SetWideScreenOff(void) +CCamera::SetCameraDirectlyInFrontForFollowPed_CamOnAString(void) { - m_bWantsToSwitchWidescreenOff = m_WideScreenOn; + m_bCamDirectlyInFront = true; + CPlayerPed *player = FindPlayerPed(); + if (player) + m_PedOrientForBehindOrInFront = CGeneral::GetATanOfXY(player->GetForward().x, player->GetForward().y); } void @@ -1392,18 +3195,52 @@ CCamera::SetNewPlayerWeaponMode(int16 mode, int16 minZoom, int16 maxZoom) } void +CCamera::ClearPlayerWeaponMode(void) +{ + PlayerWeaponMode.Mode = 0; + PlayerWeaponMode.MaxZoom = 1; + PlayerWeaponMode.MinZoom = -1; + PlayerWeaponMode.Duration = 0.0f; +} + +void CCamera::UpdateAimingCoors(CVector const &coors) { m_cvecAimingTargetCoors = coors; } void -CCamera::SetCamPositionForFixedMode(const CVector &Source, const CVector &UpOffSet) +CCamera::Find3rdPersonCamTargetVector(float dist, CVector pos, CVector &source, CVector &target) { - m_vecFixedModeSource = Source; - m_vecFixedModeUpOffSet = UpOffSet; + if(CPad::GetPad(0)->GetLookBehindForPed()){ + source = pos; + target = dist*Cams[ActiveCam].CamTargetEntity->GetForward() + source; + }else{ + float angleX = DEGTORAD((m_f3rdPersonCHairMultX-0.5f) * 1.8f * 0.5f * Cams[ActiveCam].FOV * CDraw::GetAspectRatio()); + float angleY = DEGTORAD((0.5f-m_f3rdPersonCHairMultY) * 1.8f * 0.5f * Cams[ActiveCam].FOV); + source = Cams[ActiveCam].Source; + target = Cams[ActiveCam].Front; + target += Cams[ActiveCam].Up * Tan(angleY); + target += CrossProduct(Cams[ActiveCam].Front, Cams[ActiveCam].Up) * Tan(angleX); + target.Normalise(); + float dot = DotProduct(pos - source, target); + source += dot*target; + target = dist*target + source; + } +} + +float +CCamera::Find3rdPersonQuickAimPitch(void) +{ + float clampedFrontZ = clamp(Cams[ActiveCam].Front.z, -1.0f, 1.0f); + + float rot = Asin(clampedFrontZ); + + return -(DEGTORAD(((0.5f - m_f3rdPersonCHairMultY) * 1.8f * 0.5f * Cams[ActiveCam].FOV)) + rot); } + + void CCamera::SetRwCamera(RwCamera *cam) { @@ -1412,53 +3249,112 @@ CCamera::SetRwCamera(RwCamera *cam) CMBlur::MotionBlurOpen(m_pRwCamera); } -uint32 -CCamera::GetCutSceneFinishTime(void) +void +CCamera::CalculateDerivedValues(void) { - int cam = ActiveCam; - if (Cams[cam].Mode == CCam::MODE_FLYBY) - return Cams[cam].m_uiFinishTime; - cam = (cam + 1) % 2; - if (Cams[cam].Mode == CCam::MODE_FLYBY) - return Cams[cam].m_uiFinishTime; - - return 0; + m_cameraMatrix = Invert(m_matrix); + + float hfov = DEGTORAD(CDraw::GetFOV()/2.0f); + float c = cos(hfov); + float s = sin(hfov); + + // right plane + m_vecFrustumNormals[0] = CVector(c, -s, 0.0f); + // left plane + m_vecFrustumNormals[1] = CVector(-c, -s, 0.0f); + + c /= CDraw::FindAspectRatio(); + s /= CDraw::FindAspectRatio(); + // bottom plane + m_vecFrustumNormals[2] = CVector(0.0f, -s, -c); + // top plane + m_vecFrustumNormals[3] = CVector(0.0f, -s, c); + + if(GetForward().x == 0.0f && GetForward().y == 0.0f) + GetForward().x = 0.0001f; + else + Orientation = Atan2(GetForward().x, GetForward().y); + + CamFrontXNorm = GetForward().x; + CamFrontYNorm = GetForward().y; + float l = Sqrt(SQR(CamFrontXNorm) + SQR(CamFrontYNorm)); + if(l == 0.0f) + CamFrontXNorm = 1.0f; + else{ + CamFrontXNorm /= l; + CamFrontYNorm /= l; + } } -void -CCamera::FinishCutscene(void) +bool +CCamera::IsPointVisible(const CVector ¢er, const CMatrix *mat) { - SetPercentAlongCutScene(100.0f); - m_fPositionAlongSpline = 1.0f; - m_bcutsceneFinished = true; + RwV3d c; + c = *(RwV3d*)¢er; + RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix); + if(c.y < CDraw::GetNearClipZ()) return false; + if(c.y > CDraw::GetFarClipZ()) return false; + if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > 0.0f) return false; + if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > 0.0f) return false; + if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > 0.0f) return false; + if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > 0.0f) return false; + return true; } -void -CCamera::SetZoomValueFollowPedScript(int16 mode) +bool +CCamera::IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat) { - switch (mode) { - case 0: m_fPedZoomValueScript = 0.25f; break; - case 1: m_fPedZoomValueScript = 1.5f; break; - case 2: m_fPedZoomValueScript = 2.9f; break; - default: m_fPedZoomValueScript = m_fPedZoomValueScript; break; - } + RwV3d c; + c = *(RwV3d*)¢er; + RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix); + if(c.y + radius < CDraw::GetNearClipZ()) return false; + if(c.y - radius > CDraw::GetFarClipZ()) return false; + if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > radius) return false; + if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > radius) return false; + if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > radius) return false; + if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > radius) return false; + return true; +} - m_bUseScriptZoomValuePed = true; +bool +CCamera::IsSphereVisible(const CVector ¢er, float radius) +{ + CMatrix mat = m_cameraMatrix; + return IsSphereVisible(center, radius, &mat); } -void -CCamera::SetZoomValueCamStringScript(int16 mode) +bool +CCamera::IsBoxVisible(RwV3d *box, const CMatrix *mat) { - switch (mode) { - case 0: m_fCarZoomValueScript = 0.05f; break; - case 1: m_fCarZoomValueScript = 1.9f; break; - case 2: m_fCarZoomValueScript = 3.9f; break; - default: m_fCarZoomValueScript = m_fCarZoomValueScript; break; + int i; + int frustumTests[6] = { 0 }; + RwV3dTransformPoints(box, box, 8, &mat->m_matrix); + + for(i = 0; i < 8; i++){ + if(box[i].y < CDraw::GetNearClipZ()) frustumTests[0]++; + if(box[i].y > CDraw::GetFarClipZ()) frustumTests[1]++; + if(box[i].x*m_vecFrustumNormals[0].x + box[i].y*m_vecFrustumNormals[0].y > 0.0f) frustumTests[2]++; + if(box[i].x*m_vecFrustumNormals[1].x + box[i].y*m_vecFrustumNormals[1].y > 0.0f) frustumTests[3]++; +// Why not test z? +// if(box[i].y*m_vecFrustumNormals[2].y + box[i].z*m_vecFrustumNormals[2].z > 0.0f) frustumTests[4]++; +// if(box[i].y*m_vecFrustumNormals[3].y + box[i].z*m_vecFrustumNormals[3].z > 0.0f) frustumTests[5]++; } + for(i = 0; i < 6; i++) + if(frustumTests[i] == 8) + return false; // Box is completely outside of one plane + return true; +} - m_bUseScriptZoomValueCar = true; + + +CCamPathSplines::CCamPathSplines(void) +{ + int i; + for(i = 0; i < MAXPATHLENGTH; i++) + m_arr_PathData[i] = 0.0f; } + STARTPATCHES InjectHook(0x42C760, (bool (CCamera::*)(const CVector ¢er, float radius, const CMatrix *mat))&CCamera::IsSphereVisible, PATCH_JUMP); InjectHook(0x46FD00, &CCamera::SetFadeColour, PATCH_JUMP); @@ -1480,20 +3376,35 @@ STARTPATCHES 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); + InjectHook(0x46F8E0, &CCamera::ProcessWideScreenOn, PATCH_JUMP); + InjectHook(0x46FDE0, &CCamera::SetParametersForScriptInterpolation, PATCH_JUMP); + InjectHook(0x46BA20, &CCamera::GetLookingLRBFirstPerson, PATCH_JUMP); + InjectHook(0x470D80, &CCamera::StartTransitionWhenNotFinishedInter, PATCH_JUMP); + InjectHook(0x46FFF0, &CCamera::StartTransition, PATCH_JUMP); + InjectHook(0x46BEB0, &CCamera::InitialiseCameraForDebugMode, PATCH_JUMP); + InjectHook(0x471500, &CCamera::TakeControl, PATCH_JUMP); + InjectHook(0x4715B0, &CCamera::TakeControlNoEntity, PATCH_JUMP); + InjectHook(0x46B3A0, &CCamera::Fade, PATCH_JUMP); + InjectHook(0x46FE20, &CCamera::SetPercentAlongCutScene, PATCH_JUMP); + InjectHook(0x46B100, &CamShakeNoPos, PATCH_JUMP); + InjectHook(0x46B200, &CCamera::CamShake, PATCH_JUMP); + InjectHook(0x46F520, &CCamera::ProcessObbeCinemaCameraPed, PATCH_JUMP); + InjectHook(0x46F3E0, &CCamera::ProcessObbeCinemaCameraCar, PATCH_JUMP); + InjectHook(0x470DA0, &CCamera::StoreValuesDuringInterPol, PATCH_JUMP); + InjectHook(0x46B430, &CCamera::DrawBordersForWideScreen, PATCH_JUMP); + InjectHook(0x46F990, &CCamera::Restore, PATCH_JUMP); + InjectHook(0x46FAE0, &CCamera::RestoreWithJumpCut, PATCH_JUMP); + InjectHook(0x46F080, &CCamera::ProcessFade, PATCH_JUMP); + InjectHook(0x46EEA0, &CCamera::CalculateDerivedValues, PATCH_JUMP); + InjectHook(0x46F1E0, &CCamera::ProcessMusicFade, PATCH_JUMP); + InjectHook(0x46D1D0, &CCamera::LoadPathSplines, PATCH_JUMP); + InjectHook(0x4712A0, &CCamera::UpdateTargetEntity, PATCH_JUMP); + InjectHook(0x46B580, &CCamera::Find3rdPersonCamTargetVector, PATCH_JUMP); + InjectHook(0x46BAD0, &CCamera::Init, PATCH_JUMP); + InjectHook(0x46C9E0, &CCamera::LoadTrainCamNodes, PATCH_JUMP); + InjectHook(0x46F600, &CCamera::Process_Train_Camera_Control, PATCH_JUMP); + InjectHook(0x470EA0, &CCamera::UpdateSoundDistances, PATCH_JUMP); + InjectHook(0x46BF10, &CCamera::IsItTimeForNewcam, PATCH_JUMP); + InjectHook(0x471650, &CCamera::TryToStartNewCamMode, PATCH_JUMP); +// InjectHook(0x46D3F0, &CCamera::Process, PATCH_JUMP); ENDPATCHES diff --git a/src/core/Camera.h b/src/core/Camera.h index 980af5c1..f21fe913 100644 --- a/src/core/Camera.h +++ b/src/core/Camera.h @@ -4,11 +4,28 @@ class CEntity; class CPed; class CAutomobile; +class CGarage; -#define NUMBER_OF_VECTORS_FOR_AVERAGE 2 +extern int16 &DebugCamMode; -struct CCam +enum +{ + NUMBER_OF_VECTORS_FOR_AVERAGE = 2, + MAX_NUM_OF_SPLINETYPES = 4, + MAX_NUM_OF_NODES = 800 // for trains +}; + +#define DEFAULT_NEAR (0.9f) +#define CAM_ZOOM_1STPRS (0.0f) +#define CAM_ZOOM_1 (1.0f) +#define CAM_ZOOM_2 (2.0f) +#define CAM_ZOOM_3 (3.0f) +#define CAM_ZOOM_TOPDOWN (4.0f) +#define CAM_ZOOM_CINEMATIC (5.0f) + +class CCam { +public: enum { MODE_NONE = 0, @@ -66,17 +83,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 +102,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 +112,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 +120,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 +128,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 +137,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 +170,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,21 +183,74 @@ 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 + + // custom stuff + void Process_FollowPed_Rotation(const CVector &CameraTarget, float TargetOrientation, float, float); + void Process_FollowCar_SA(const CVector &CameraTarget, float TargetOrientation, float, float); }; static_assert(sizeof(CCam) == 0x1A4, "CCam: wrong size"); static_assert(offsetof(CCam, Alpha) == 0xA8, "CCam: error"); static_assert(offsetof(CCam, Front) == 0x140, "CCam: error"); -struct CCamPathSplines +class CCamPathSplines { - float m_arr_PathData[800]; +public: + enum {MAXPATHLENGTH=800}; + float m_arr_PathData[MAXPATHLENGTH]; + CCamPathSplines(void); }; struct CTrainCamNode @@ -223,6 +288,7 @@ enum FADE_OUT = 0, FADE_IN, + FADE_NONE }; enum @@ -248,13 +314,14 @@ enum enum { - CAM_CONTROLLER_0, - CAM_CONTROLLER_1, - CAM_CONTROLLER_2 + CAMCONTROL_GAME, + CAMCONTROL_SCRIPT, + CAMCONTROL_OBBE }; -struct CCamera : public CPlaceable +class CCamera : public CPlaceable { +public: bool m_bAboveGroundTrainNodesLoaded; bool m_bBelowGroundTrainNodesLoaded; bool m_bCamDirectlyBehind; @@ -296,16 +363,12 @@ struct CCamera : public CPlaceable bool m_bHeadBob; bool m_bFailedCullZoneTestPreviously; -bool m_FadeTargetIsSplashScreen; + bool m_FadeTargetIsSplashScreen; bool WorldViewerBeingUsed; uint8 ActiveCam; uint32 m_uiCamShakeStart; uint32 m_uiFirstPersonCamLastInputTime; -// where are those? -//bool m_bVehicleSuspenHigh; -//bool m_bEnable1rstPersonCamCntrlsScript; -//bool m_bAllow1rstPersonWeaponsCamera; uint32 m_uiLongestTimeInMill; uint32 m_uiNumberOfTrainCamNodes; @@ -321,7 +384,7 @@ bool m_FadeTargetIsSplashScreen; int m_BlurRed; int m_BlurType; -uint32 unknown; +uint32 unknown; // some counter having to do with music int m_iWorkOutSpeedThisNumFrames; int m_iNumFramesSoFar; @@ -364,20 +427,20 @@ uint32 unknown; float m_fOldBetaDiff; float m_fPedZoomValue; - float m_fPedZoomValueScript; - float m_fPedZoomValueSmooth; - float m_fPositionAlongSpline; - float m_ScreenReductionPercentage; - float m_ScreenReductionSpeed; - float m_AlphaForPlayerAnim1rstPerson; - float Orientation; - float PedZoomIndicator; - float PlayerExhaustion; - float SoundDistUp, SoundDistLeft, SoundDistRight; - float SoundDistUpAsRead, SoundDistLeftAsRead, SoundDistRightAsRead; - float SoundDistUpAsReadOld, SoundDistLeftAsReadOld, SoundDistRightAsReadOld; - float m_fWideScreenReductionAmount; - float m_fStartingFOVForInterPol; + float m_fPedZoomValueScript; + float m_fPedZoomValueSmooth; + float m_fPositionAlongSpline; + float m_ScreenReductionPercentage; + float m_ScreenReductionSpeed; + float m_AlphaForPlayerAnim1rstPerson; + float Orientation; + float PedZoomIndicator; + float PlayerExhaustion; + float SoundDistUp, SoundDistLeft, SoundDistRight; + float SoundDistUpAsRead, SoundDistLeftAsRead, SoundDistRightAsRead; + float SoundDistUpAsReadOld, SoundDistLeftAsReadOld, SoundDistRightAsReadOld; + float m_fWideScreenReductionAmount; + float m_fStartingFOVForInterPol; // not static yet float m_fMouseAccelHorzntl;// acceleration multiplier for 1st person controls @@ -387,8 +450,8 @@ uint32 unknown; CCam Cams[3]; - void *pToGarageWeAreIn; - void *pToGarageWeAreInForHackAvoidFirstPerson; + CGarage *pToGarageWeAreIn; + CGarage *pToGarageWeAreInForHackAvoidFirstPerson; CQueuedMode m_PlayerMode; CQueuedMode PlayerWeaponMode; CVector m_PreviousCameraPosition; @@ -399,17 +462,15 @@ uint32 unknown; CVector m_vecFixedModeUpOffSet; CVector m_vecCutSceneOffset; - // one of those has to go - CVector m_cvecStartingSourceForInterPol; - CVector m_cvecStartingTargetForInterPol; - CVector m_cvecStartingUpForInterPol; - CVector m_cvecSourceSpeedAtStartInter; - CVector m_cvecTargetSpeedAtStartInter; - CVector m_cvecUpSpeedAtStartInter; - CVector m_vecSourceWhenInterPol; - CVector m_vecTargetWhenInterPol; - CVector m_vecUpWhenInterPol; - //CVector m_vecClearGeometryVec; + CVector m_cvecStartingSourceForInterPol; + CVector m_cvecStartingTargetForInterPol; + CVector m_cvecStartingUpForInterPol; + CVector m_cvecSourceSpeedAtStartInter; + CVector m_cvecTargetSpeedAtStartInter; + CVector m_cvecUpSpeedAtStartInter; + CVector m_vecSourceWhenInterPol; + CVector m_vecTargetWhenInterPol; + CVector m_vecUpWhenInterPol; CVector m_vecGameCamPos; CVector SourceDuringInter; @@ -417,8 +478,8 @@ uint32 unknown; CVector UpDuringInter; RwCamera *m_pRwCamera; CEntity *pTargetEntity; - CCamPathSplines m_arrPathArray[4]; - CTrainCamNode m_arrTrainCamNode[800]; + CCamPathSplines m_arrPathArray[MAX_NUM_OF_SPLINETYPES]; + CTrainCamNode m_arrTrainCamNode[MAX_NUM_OF_NODES]; CMatrix m_cameraMatrix; bool m_bGarageFixedCamPositionSet; bool m_vecDoingSpecialInterPolation; @@ -442,11 +503,11 @@ uint32 unknown; float m_fScriptPercentageInterToStopMoving; float m_fScriptPercentageInterToCatchUp; -uint32 m_fScriptTimeForInterPolation; + uint32 m_fScriptTimeForInterPolation; -int16 m_iFadingDirection; -int m_iModeObbeCamIsInForCar; + int16 m_iFadingDirection; + int m_iModeObbeCamIsInForCar; int16 m_iModeToGoTo; int16 m_iMusicFadingDirection; int16 m_iTypeOfSwitch; @@ -455,67 +516,97 @@ int m_iModeObbeCamIsInForCar; uint32 m_uiFadeTimeStartedMusic; static bool &m_bUseMouse3rdPerson; - +#ifdef FREE_CAM + static bool bFreeCam; +#endif + + // High level and misc + void Init(void); + void Process(void); + void CamControl(void); + void UpdateTargetEntity(void); + void UpdateSoundDistances(void); + void InitialiseCameraForDebugMode(void); + void CamShake(float strength, float x, float y, float z); bool Get_Just_Switched_Status() { return m_bJust_Switched; } - inline const CMatrix& GetCameraMatrix(void) { return m_cameraMatrix; } - CVector &GetGameCamPosition(void) { return m_vecGameCamPos; } - float GetPositionAlongSpline(void) { return m_fPositionAlongSpline; } - bool IsPointVisible(const CVector ¢er, const CMatrix *mat); - bool IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat); - bool IsSphereVisible(const CVector ¢er, float radius); - bool IsBoxVisible(RwV3d *box, const CMatrix *mat); - int GetLookDirection(void); - bool GetLookingForwardFirstPerson(void); - - void Fade(float timeout, int16 direction); - int GetScreenFadeStatus(void); - void ProcessFade(void); - void ProcessMusicFade(void); - void SetFadeColour(uint8 r, uint8 g, uint8 b); - void CamShake(float strength, float x, float y, float z); + // Who's in control + void TakeControl(CEntity *target, int16 mode, int16 typeOfSwitch, int32 controller); + void TakeControlNoEntity(const CVector &position, int16 typeOfSwitch, int32 controller); + void TakeControlWithSpline(int16 typeOfSwitch); + void Restore(void); + void RestoreWithJumpCut(void); + void SetCamPositionForFixedMode(const CVector &Source, const CVector &UppOffSet); - void SetMotionBlur(int r, int g, int b, int a, int type); - void SetMotionBlurAlpha(int a); - void RenderMotionBlur(void); - void ClearPlayerWeaponMode(); - void CalculateDerivedValues(void); + // Transition + void StartTransition(int16 mode); + void StartTransitionWhenNotFinishedInter(int16 mode); + void StoreValuesDuringInterPol(CVector &source, CVector &target, CVector &up, float &FOV); - void DrawBordersForWideScreen(void); - void Restore(void); + // Widescreen borders void SetWideScreenOn(void); void SetWideScreenOff(void); - void SetNearClipScript(float); - - float Find3rdPersonQuickAimPitch(void); + void ProcessWideScreenOn(void); + void DrawBordersForWideScreen(void); - void TakeControl(CEntity*, int16, int16, int32); - void TakeControlNoEntity(const CVector&, int16, int32); - void SetCamPositionForFixedMode(const CVector&, const CVector&); - bool GetFading(); + // Obbe's cam + bool IsItTimeForNewcam(int32 obbeMode, int32 time); + bool TryToStartNewCamMode(int32 obbeMode); + void DontProcessObbeCinemaCamera(void); + void ProcessObbeCinemaCameraCar(void); + void ProcessObbeCinemaCameraPed(void); - void Init(); - void SetRwCamera(RwCamera*); - void Process(); + // Train + void LoadTrainCamNodes(char const *name); + void Process_Train_Camera_Control(void); + // Script void LoadPathSplines(int file); - uint32 GetCutSceneFinishTime(void); void FinishCutscene(void); + float GetPositionAlongSpline(void) { return m_fPositionAlongSpline; } + uint32 GetCutSceneFinishTime(void); + void SetCamCutSceneOffSet(const CVector &pos); + void SetPercentAlongCutScene(float percent); + void SetParametersForScriptInterpolation(float stopMoving, float catchUp, int32 time); + void SetZoomValueFollowPedScript(int16 dist); + void SetZoomValueCamStringScript(int16 dist); + void SetNearClipScript(float); - void SetCamCutSceneOffSet(const CVector&); - void TakeControlWithSpline(short); - void RestoreWithJumpCut(void); + // Fading + void ProcessFade(void); + void ProcessMusicFade(void); + void Fade(float timeout, int16 direction); + void SetFadeColour(uint8 r, uint8 g, uint8 b); + bool GetFading(void); + int GetFadingDirection(void); + int GetScreenFadeStatus(void); + + // Motion blur + void RenderMotionBlur(void); + void SetMotionBlur(int r, int g, int b, int a, int type); + void SetMotionBlurAlpha(int a); + + // Player looking and aiming + int GetLookDirection(void); + bool GetLookingForwardFirstPerson(void); + bool GetLookingLRBFirstPerson(void); void SetCameraDirectlyInFrontForFollowPed_CamOnAString(void); void SetCameraDirectlyBehindForFollowPed_CamOnAString(void); - void SetZoomValueFollowPedScript(int16); - void SetZoomValueCamStringScript(int16); - void SetNewPlayerWeaponMode(int16, int16, int16); - void UpdateAimingCoors(CVector const &); - - void SetPercentAlongCutScene(float); - void SetParametersForScriptInterpolation(float, float, int32); + void SetNewPlayerWeaponMode(int16 mode, int16 minZoom, int16 maxZoom); + void ClearPlayerWeaponMode(void); + void UpdateAimingCoors(CVector const &coors); + void Find3rdPersonCamTargetVector(float dist, CVector pos, CVector &source, CVector &target); + float Find3rdPersonQuickAimPitch(void); - void dtor(void) { this->CCamera::~CCamera(); } + // Physical camera + void SetRwCamera(RwCamera *cam); + const CMatrix& GetCameraMatrix(void) { return m_cameraMatrix; } + CVector &GetGameCamPosition(void) { return m_vecGameCamPos; } + void CalculateDerivedValues(void); + bool IsPointVisible(const CVector ¢er, const CMatrix *mat); + bool IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat); + bool IsSphereVisible(const CVector ¢er, float radius); + bool IsBoxVisible(RwV3d *box, const CMatrix *mat); }; static_assert(offsetof(CCamera, DistanceToWater) == 0xe4, "CCamera: error"); static_assert(offsetof(CCamera, m_WideScreenOn) == 0x70, "CCamera: error"); @@ -525,8 +616,14 @@ 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); +void MakeAngleLessThan180(float &Angle); +void WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSpeed, float Acceleration, bool IsAngle); 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..283f34b8 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" @@ -8,12 +9,14 @@ #include "FileMgr.h" #include "main.h" #include "AnimManager.h" +#include "AnimBlendAssociation.h" #include "AnimBlendAssocGroup.h" #include "AnimBlendClumpData.h" #include "Pad.h" #include "DMAudio.h" #include "World.h" #include "PlayerPed.h" +#include "Wanted.h" #include "CutsceneHead.h" #include "RpAnimBlend.h" #include "ModelIndices.h" @@ -27,79 +30,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 +131,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(true); + + 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 +276,9 @@ CCutsceneMgr::SetupCutsceneToStart(void) } } - CTimer::Update();
- CTimer::Update();
- ms_running = true;
+ CTimer::Update(); + CTimer::Update(); + ms_running = true; ms_cutsceneTimer = 0.0f; } @@ -297,14 +300,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 +336,88 @@ 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(); + CGame::DrasticTidyUpMemory(TheCamera.GetScreenFadeStatus() == 2); + 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/CutsceneMgr.h b/src/core/CutsceneMgr.h index 381c71c9..7b809964 100644 --- a/src/core/CutsceneMgr.h +++ b/src/core/CutsceneMgr.h @@ -29,6 +29,7 @@ public: static void SetRunning(bool running) { ms_running = running; } static bool IsRunning(void) { return ms_running; } static bool IsCutsceneProcessing(void) { return ms_cutsceneProcessing; } + static bool UseLodMultiplier(void) { return ms_useLodMultiplier; } static CCutsceneObject* GetCutsceneObject(int id) { return ms_pCutsceneObjects[id]; } static int GetCutsceneTimeInMilleseconds(void) { return 1000.0f * ms_cutsceneTimer; } static char *GetCutsceneName(void) { return ms_cutsceneName; } diff --git a/src/core/Debug.cpp b/src/core/Debug.cpp index b80e9959..2b713198 100644 --- a/src/core/Debug.cpp +++ b/src/core/Debug.cpp @@ -1,12 +1,137 @@ +#include "common.h" #include "Debug.h" +#include "Font.h" +#include "main.h" +#include "Text.h" -int CDebug::ms_nCurrentTextLine; +bool gbDebugStuffInRelease = false; -void CDebug::DebugInitTextBuffer() +#define DEBUG_X_POS (300) +#define DEBUG_Y_POS (41) +#define DEBUG_LINE_HEIGHT (22) + +int16 CDebug::ms_nCurrentTextLine; +char CDebug::ms_aTextBuffer[MAX_LINES][MAX_STR_LEN]; + +void +CDebug::DebugInitTextBuffer() { ms_nCurrentTextLine = 0; } -void CDebug::DebugDisplayTextBuffer() +void +CDebug::DebugAddText(const char *str) +{ + int32 i = 0; + if (*str != '\0') { + while (i < MAX_STR_LEN) { + ms_aTextBuffer[ms_nCurrentTextLine][i++] = *(str++); + if (*str == '\0') + break; + } + } + + ms_aTextBuffer[ms_nCurrentTextLine++][i] = '\0'; + if (ms_nCurrentTextLine >= MAX_LINES) + ms_nCurrentTextLine = 0; +} + +void +CDebug::DebugDisplayTextBuffer() +{ +#ifndef MASTER + if (gbDebugStuffInRelease) + { + int32 i = 0; + int32 y = DEBUG_Y_POS; +#ifdef FIX_BUGS + CFont::SetPropOn(); + CFont::SetBackgroundOff(); + CFont::SetScale(1.0f, 1.0f); + CFont::SetCentreOff(); + CFont::SetRightJustifyOff(); + CFont::SetJustifyOn(); + CFont::SetRightJustifyWrap(0.0f); + CFont::SetBackGroundOnlyTextOff(); + CFont::SetFontStyle(FONT_BANK); +#else + // this is not even readable + CFont::SetPropOff(); + CFont::SetBackgroundOff(); + CFont::SetScale(1.0f, 1.0f); + CFont::SetCentreOff(); + CFont::SetRightJustifyOn(); + CFont::SetRightJustifyWrap(0.0f); + CFont::SetBackGroundOnlyTextOff(); + CFont::SetFontStyle(FONT_BANK); + CFont::SetPropOff(); +#endif + do { + char *line; + while (true) { + line = ms_aTextBuffer[(ms_nCurrentTextLine + i++) % MAX_LINES]; + if (*line != '\0') + break; + y += DEBUG_LINE_HEIGHT; + if (i == MAX_LINES) { + CFont::DrawFonts(); + return; + } + } + AsciiToUnicode(line, gUString); + CFont::SetColor(CRGBA(0, 0, 0, 255)); + CFont::PrintString(DEBUG_X_POS, y-1, gUString); + CFont::SetColor(CRGBA(255, 128, 128, 255)); + CFont::PrintString(DEBUG_X_POS+1, y, gUString); + y += DEBUG_LINE_HEIGHT; + } while (i != MAX_LINES); + CFont::DrawFonts(); + } +#endif +} + + +// custom + +CDebug::ScreenStr CDebug::ms_aScreenStrs[MAX_SCREEN_STRS]; +int CDebug::ms_nScreenStrs; + +void +CDebug::DisplayScreenStrings() +{ + int i; + + + CFont::SetPropOn(); + CFont::SetBackgroundOff(); + CFont::SetScale(1.0f, 1.0f); + CFont::SetCentreOff(); + CFont::SetRightJustifyOff(); + CFont::SetJustifyOff(); + CFont::SetRightJustifyWrap(0.0f); + CFont::SetWrapx(9999.0f); + CFont::SetBackGroundOnlyTextOff(); + CFont::SetFontStyle(FONT_BANK); + + for(i = 0; i < ms_nScreenStrs; i++){ + AsciiToUnicode(ms_aScreenStrs[i].str, gUString); + CFont::SetColor(CRGBA(0, 0, 0, 255)); + CFont::PrintString(ms_aScreenStrs[i].x, ms_aScreenStrs[i].y, gUString); + CFont::SetColor(CRGBA(255, 255, 255, 255)); + CFont::PrintString(ms_aScreenStrs[i].x+1, ms_aScreenStrs[i].y+1, gUString); + } + 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 395f66af..d169a0b4 100644 --- a/src/core/Debug.h +++ b/src/core/Debug.h @@ -2,10 +2,33 @@ class CDebug { - static int ms_nCurrentTextLine; + enum + { + 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..d1c76f33 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 { @@ -206,7 +209,7 @@ CEventList::ReportCrimeForEvent(eEventType type, int32 crimeId, bool copsDontCar case EVENT_CAR_SET_ON_FIRE: crime = CRIME_VEHICLE_BURNED; break; default: crime = CRIME_NONE; break; } - + if(crime == CRIME_NONE) return; 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..cfa849e9 100644 --- a/src/core/Fire.cpp +++ b/src/core/Fire.cpp @@ -1,19 +1,291 @@ #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); + + CGeneral::GetRandomNumber(); CGeneral::GetRandomNumber(); CGeneral::GetRandomNumber(); /* unsure why these three rands are called */ + + CParticle::AddParticle(PARTICLE_CARFLAME_SMOKE, firePos, + CVector(0.0f, 0.0f, 0.0f), 0, 0.0f, 0, 0, 0, 0); + } + if (CTimer::GetTimeInMilliseconds() < m_nExtinguishTime || m_bIsScriptFire) { + if (CTimer::GetTimeInMilliseconds() > m_nStartTime) + m_nStartTime = CTimer::GetTimeInMilliseconds() + 400; + + nRandNumber = CGeneral::GetRandomNumber() & 127; + lightpos.x = m_vecPos.x; + lightpos.y = m_vecPos.y; + lightpos.z = m_vecPos.z + 5.0f; + + if (!m_pEntity) { + CShadows::StoreStaticShadow((uint32)this, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &lightpos, + 7.0f, 0.0f, 0.0f, -7.0f, + 255, // this is 0 on PC which results in no shadow + 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 +310,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 +359,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..61fe96ea 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -64,7 +64,6 @@ bool &CMenuManager::m_bShutDownFrontEndRequested = *(bool*)0x95CD6A; int8 &CMenuManager::m_PrefsUseWideScreen = *(int8*)0x95CD23; int8 &CMenuManager::m_PrefsRadioStation = *(int8*)0x95CDA4; -int8 &CMenuManager::m_bDisableMouseSteering = *(int8*)0x60252C; // 1 int32 &CMenuManager::m_PrefsBrightness = *(int32*)0x5F2E50; // 256 float &CMenuManager::m_PrefsLOD = *(float*)0x8F42C4; int8 &CMenuManager::m_bFrontEnd_ReloadObrTxtGxt = *(int8*)0x628CFC; @@ -94,10 +93,14 @@ int32 *&pControlEdit = *(int32**)0x628D08; bool &DisplayComboButtonErrMsg = *(bool*)0x628D14; int32 &MouseButtonJustClicked = *(int32*)0x628D0C; int32 &JoyButtonJustClicked = *(int32*)0x628D10; -uint32 &nTimeForSomething = *(uint32*)0x628D54; bool &holdingScrollBar = *(bool*)0x628D59; //int32 *pControlTemp = 0; +#ifndef MASTER +bool CMenuManager::m_PrefsMarketing = false; +bool CMenuManager::m_PrefsDisableTutorials = false; +#endif // !MASTER + // 0x5F311C const char* FrontendFilenames[][2] = { {"fe2_mainpanel_ul", "" }, @@ -181,6 +184,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 +239,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) @@ -492,7 +529,7 @@ WRAPPER void CMenuManager::DoSettingsBeforeStartingAGame() { EAXJMP(0x48AB40); } #else void CMenuManager::DoSettingsBeforeStartingAGame() { - CCamera::m_bUseMouse3rdPerson = m_ControlMethod == CONTROL_STANDART; + CCamera::m_bUseMouse3rdPerson = m_ControlMethod == CONTROL_STANDARD; if (m_PrefsVsyncDisp != m_PrefsVsync) m_PrefsVsync = m_PrefsVsyncDisp; @@ -935,7 +972,7 @@ void CMenuManager::Draw() rightText = TheText.Get(m_PrefsDMA ? "FEM_ON" : "FEM_OFF"); break; case MENUACTION_MOUSESTEER: - rightText = TheText.Get(m_bDisableMouseSteering ? "FEM_OFF" : "FEM_ON"); + rightText = TheText.Get(CVehicle::m_bDisableMouseSteering ? "FEM_OFF" : "FEM_ON"); break; } @@ -1173,7 +1210,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 +1222,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 +1321,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 +1350,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; @@ -1323,23 +1358,39 @@ 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)); + static float fadeAlpha = 0.0f; + static int lastState = 0; + + // reverseAlpha = PS2 fading (wait for 255->0, then change screen) if (m_nMenuFadeAlpha < 255) { - static int LastFade = 0; + if (lastState == 1 && !reverseAlpha) + fadeAlpha = 0.f; if (m_nMenuFadeAlpha <= 0 && reverseAlpha) { reverseAlpha = false; ChangeScreen(pendingScreen, pendingOption, true, false); - } else if(CTimer::GetTimeInMillisecondsPauseMode() - LastFade > 10){ + } else { + float timestep = CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond(); + + // +20 per every 33 ms (1000.f/30.f - original frame limiter fps) if (!reverseAlpha) - m_nMenuFadeAlpha += 20; + fadeAlpha += (timestep * 100.f) * 20.f / 33.f; else - m_nMenuFadeAlpha = max(m_nMenuFadeAlpha - 30, 0); + fadeAlpha = max(0.0f, fadeAlpha - (timestep * 100.f) * 30.f / 33.f); - LastFade = CTimer::GetTimeInMillisecondsPauseMode(); + m_nMenuFadeAlpha = fadeAlpha; } + lastState = 0; } else { - if (reverseAlpha) - m_nMenuFadeAlpha -= 20; + if (lastState == 0) fadeAlpha = 255.f; + + if (reverseAlpha) { + float timestep = CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond(); + fadeAlpha -= (timestep * 100.f) * 30.f / 33.f; + + m_nMenuFadeAlpha = fadeAlpha; + } + lastState = 1; // TODO: what is this? waiting mouse? if(field_518 == 4){ @@ -1537,12 +1588,25 @@ void CMenuManager::DrawFrontEndNormal() } if (m_nMenuFadeAlpha < 255) { - static int LastFade = 0; + + // Famous transparent menu bug +#ifdef FIX_BUGS + static float fadeAlpha = 0.0f; + if (m_nMenuFadeAlpha == 0 && fadeAlpha > 1.0f) fadeAlpha = 0.0f; + + float timestep = CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond(); + + // +20 per every 33 ms (1000.f/30.f - original frame limiter fps) + fadeAlpha += (timestep * 100.f) * 20.f / 33.f; + m_nMenuFadeAlpha = fadeAlpha; +#else + static uint32 LastFade = 0; 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)); @@ -1657,9 +1721,6 @@ int CMenuManager::GetStartOptionsCntrlConfigScreens() } #endif -#if DONT_USE_SUSPICIOUS_FUNCS -WRAPPER void CMenuManager::InitialiseChangedLanguageSettings() { EAXJMP(0x47A4D0); } -#else void CMenuManager::InitialiseChangedLanguageSettings() { if (m_bFrontEnd_ReloadObrTxtGxt) { @@ -1670,6 +1731,17 @@ void CMenuManager::InitialiseChangedLanguageSettings() CTimer::Update(); CGame::frenchGame = false; CGame::germanGame = false; +#ifdef MORE_LANGUAGES + switch (CMenuManager::m_PrefsLanguage) { + case LANGUAGE_RUSSIAN: + CFont::ReloadFonts(FONT_LANGSET_RUSSIAN); + break; + default: + CFont::ReloadFonts(FONT_LANGSET_EFIGS); + break; + } +#endif + switch (CMenuManager::m_PrefsLanguage) { case LANGUAGE_FRENCH: CGame::frenchGame = true; @@ -1677,12 +1749,16 @@ void CMenuManager::InitialiseChangedLanguageSettings() case LANGUAGE_GERMAN: CGame::germanGame = true; break; +#ifdef MORE_LANGUAGES + case LANGUAGE_RUSSIAN: + CGame::russianGame = true; + break; +#endif default: break; } } } -#endif void CMenuManager::LoadAllTextures() { @@ -1950,7 +2026,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; @@ -1993,7 +2069,7 @@ void CMenuManager::Process(void) } if (m_nCurrScreen == MENUPAGE_LOADING_IN_PROGRESS) { if (CheckSlotDataValid(m_nCurrSaveSlot)) { - TheCamera.m_bUseMouse3rdPerson = m_ControlMethod == CONTROL_STANDART; + TheCamera.m_bUseMouse3rdPerson = m_ControlMethod == CONTROL_STANDARD; if (m_PrefsVsyncDisp != m_PrefsVsync) m_PrefsVsync = m_PrefsVsyncDisp; DMAudio.Service(); @@ -2164,15 +2240,15 @@ CMenuManager::ProcessButtonPresses(void) field_535 = false; } - static int nTimeForSomething = 0; + static uint32 lastTimeClickedScrollButton = 0; - if (CTimer::GetTimeInMillisecondsPauseMode() - nTimeForSomething >= 200) { + if (CTimer::GetTimeInMillisecondsPauseMode() - lastTimeClickedScrollButton >= 200) { m_bPressedPgUpOnList = false; m_bPressedPgDnOnList = false; m_bPressedUpOnList = false; m_bPressedDownOnList = false; m_bPressedScrollButton = false; - nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode(); + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); } if (CPad::GetPad(0)->GetTabJustDown()) { @@ -2211,7 +2287,7 @@ CMenuManager::ProcessButtonPresses(void) m_nCurrExLayer = 19; if (!m_bPressedUpOnList) { m_bPressedUpOnList = true; - nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode(); + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); ScrollUpListByOne(); } @@ -2233,7 +2309,7 @@ CMenuManager::ProcessButtonPresses(void) m_nCurrExLayer = 19; if (!m_bPressedDownOnList) { m_bPressedDownOnList = true; - nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode(); + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); ScrollDownListByOne(); } @@ -2248,7 +2324,7 @@ CMenuManager::ProcessButtonPresses(void) m_nCurrExLayer = 19; if (!m_bPressedPgUpOnList) { m_bPressedPgUpOnList = true; - nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode(); + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); m_bShowMouse = false; DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); PageUpList(false); @@ -2260,7 +2336,7 @@ CMenuManager::ProcessButtonPresses(void) m_nCurrExLayer = 19; if (!m_bPressedPgDnOnList) { m_bPressedPgDnOnList = true; - nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode(); + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); m_bShowMouse = false; DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); PageDownList(false); @@ -2346,7 +2422,7 @@ CMenuManager::ProcessButtonPresses(void) case HOVEROPTION_CLICKED_SCROLL_UP: if (!m_bPressedScrollButton) { m_bPressedScrollButton = true; - nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode(); + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); ScrollUpListByOne(); } break; @@ -2354,7 +2430,7 @@ CMenuManager::ProcessButtonPresses(void) case HOVEROPTION_CLICKED_SCROLL_DOWN: if (!m_bPressedScrollButton) { m_bPressedScrollButton = true; - nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode(); + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); ScrollDownListByOne(); } break; @@ -2701,6 +2777,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; @@ -2877,6 +2955,14 @@ CMenuManager::ProcessButtonPresses(void) CMenuManager::InitialiseChangedLanguageSettings(); SaveSettings(); break; +#ifdef MORE_LANGUAGES + case MENUACTION_LANG_RUS: + m_PrefsLanguage = LANGUAGE_RUSSIAN; + m_bFrontEnd_ReloadObrTxtGxt = true; + CMenuManager::InitialiseChangedLanguageSettings(); + SaveSettings(); + break; +#endif case MENUACTION_POPULATESLOTS_CHANGEMENU: PcSaveHelper.PopulateSlotInfo(); @@ -3080,10 +3166,10 @@ CMenuManager::ProcessButtonPresses(void) PSGLOBAL(joy1)->GetCapabilities(&devCaps); ControlsManager.InitDefaultControlConfigJoyPad(devCaps.dwButtons); } - CMenuManager::m_ControlMethod = CONTROL_STANDART; + CMenuManager::m_ControlMethod = CONTROL_STANDARD; MousePointerStateHelper.bInvertVertically = false; TheCamera.m_fMouseAccelHorzntl = 0.0025f; - m_bDisableMouseSteering = true; + CVehicle::m_bDisableMouseSteering = true; TheCamera.m_bHeadBob = false; SaveSettings(); } @@ -3093,7 +3179,7 @@ CMenuManager::ProcessButtonPresses(void) #ifndef TIDY_UP_PBP if (CMenuManager::m_ControlMethod == CONTROL_CLASSIC) { CCamera::m_bUseMouse3rdPerson = true; - CMenuManager::m_ControlMethod = CONTROL_STANDART; + CMenuManager::m_ControlMethod = CONTROL_STANDARD; } else { CCamera::m_bUseMouse3rdPerson = false; CMenuManager::m_ControlMethod = CONTROL_CLASSIC; @@ -3116,51 +3202,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 +3246,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?! @@ -3412,7 +3488,7 @@ void CMenuManager::ProcessOnOffMenuOptions() SaveSettings(); break; case MENUACTION_MOUSESTEER: - m_bDisableMouseSteering = !m_bDisableMouseSteering; + CVehicle::m_bDisableMouseSteering = !CVehicle::m_bDisableMouseSteering; DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0); SaveSettings(); break; @@ -3512,11 +3588,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 +3606,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 +3639,7 @@ void CMenuManager::SwitchMenuOnAndOff() PcSaveHelper.PopulateSlotInfo(); m_nCurrOption = 0; } -/* // Unused? +/* // PS2 leftover if (m_nCurrScreen != MENUPAGE_SOUND_SETTINGS && gMusicPlaying) { DMAudio.StopFrontEndTrack(); @@ -3561,8 +3647,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..39e46ddd 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -51,6 +51,9 @@ enum eLanguages LANGUAGE_GERMAN, LANGUAGE_ITALIAN, LANGUAGE_SPANISH, +#ifdef MORE_LANGUAGES + LANGUAGE_RUSSIAN, +#endif }; enum eFrontendSprites @@ -301,6 +304,9 @@ enum eMenuAction MENUACTION_UNK108, MENUACTION_UNK109, MENUACTION_UNK110, +#ifdef MORE_LANGUAGES + MENUACTION_LANG_RUS, +#endif }; enum eCheckHover @@ -357,7 +363,7 @@ enum enum eControlMethod { - CONTROL_STANDART = 0, + CONTROL_STANDARD = 0, CONTROL_CLASSIC, }; @@ -403,7 +409,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; @@ -473,7 +479,6 @@ public: static int32 &m_ControlMethod; static int8 &m_PrefsDMA; static int32 &m_PrefsLanguage; - static int8 &m_bDisableMouseSteering; static int32 &m_PrefsBrightness; static float &m_PrefsLOD; static int8 &m_bFrontEnd_ReloadObrTxtGxt; @@ -492,6 +497,12 @@ public: static int32 &sthWithButtons; static int32 &sthWithButtons2; +#ifndef MASTER
+ static bool m_PrefsMarketing;
+ static bool m_PrefsDisableTutorials;
+#endif // !MASTER
+ + public: static void BuildStatLine(char *text, void *stat, uint8 aFloat, void *stat2); static void CentreMousePointer(); @@ -540,8 +551,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/Game.cpp b/src/core/Game.cpp index e89d62a0..8571e93e 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -1,7 +1,14 @@ +#pragma warning( push ) +#pragma warning( disable : 4005) +#define DIRECTINPUT_VERSION 0x0800 +#include <dinput.h> +#pragma warning( pop ) #include "common.h" +#include "win.h" #include "patcher.h" #include "Game.h" #include "main.h" +#include "RwHelper.h" #include "Accident.h" #include "Antennas.h" #include "Bridge.h" @@ -17,6 +24,7 @@ #include "Cranes.h" #include "Credits.h" #include "CutsceneMgr.h" +#include "DMAudio.h" #include "Darkel.h" #include "Debug.h" #include "EventList.h" @@ -28,24 +36,32 @@ #include "Frontend.h" #include "GameLogic.h" #include "Garages.h" +#include "GenericGameStorage.h" #include "Glass.h" +#include "HandlingMgr.h" #include "Heli.h" +#include "Hud.h" #include "IniFile.h" +#include "Lights.h" +#include "MBlur.h" #include "Messages.h" #include "Pad.h" #include "Particle.h" +#include "ParticleObject.h" +#include "PedRoutes.h" #include "Phones.h" #include "Pickups.h" #include "Plane.h" +#include "PlayerSkin.h" #include "Population.h" +#include "Radar.h" #include "Record.h" +#include "References.h" #include "Renderer.h" #include "Replay.h" #include "Restart.h" #include "RoadBlocks.h" -#include "PedRoutes.h" #include "Rubbish.h" -#include "RwHelper.h" #include "SceneEdit.h" #include "Script.h" #include "Shadows.h" @@ -54,11 +70,14 @@ #include "Sprite2d.h" #include "Stats.h" #include "Streaming.h" +#include "SurfaceTable.h" +#include "TempColModels.h" #include "TimeCycle.h" #include "TrafficLights.h" #include "Train.h" #include "TxdStore.h" #include "User.h" +#include "VisibilityPlugins.h" #include "WaterCannon.h" #include "WaterLevel.h" #include "Weapon.h" @@ -68,6 +87,10 @@ #include "ZoneCull.h" #include "Zones.h" + + +#define DEFAULT_VIEWWINDOW (0.7f) + eLevelName &CGame::currLevel = *(eLevelName*)0x941514; bool &CGame::bDemoMode = *(bool*)0x5F4DD0; bool &CGame::nastyGame = *(bool*)0x5F4DD4; @@ -76,7 +99,11 @@ bool &CGame::germanGame = *(bool*)0x95CD1E; bool &CGame::noProstitutes = *(bool*)0x95CDCF; bool &CGame::playingIntro = *(bool*)0x95CDC2; char *CGame::aDatFile = (char*)0x773A48; +#ifdef MORE_LANGUAGES +bool CGame::russianGame = false; +#endif +int &gameTxdSlot = *(int*)0x628D88; bool CGame::InitialiseOnceBeforeRW(void) @@ -87,7 +114,139 @@ CGame::InitialiseOnceBeforeRW(void) return true; } -int &gameTxdSlot = *(int*)0x628D88; +bool +CGame::InitialiseRenderWare(void) +{ + _TexturePoolsInitialise(); + + CTxdStore::Initialise(); + CVisibilityPlugins::Initialise(); + + /* Create camera */ + Scene.camera = CameraCreate(RsGlobal.width, RsGlobal.height, TRUE); + ASSERT(Scene.camera != nil); + if (!Scene.camera) + { + return (false); + } + + RwCameraSetFarClipPlane(Scene.camera, 2000.0f); + RwCameraSetNearClipPlane(Scene.camera, 0.9f); + + CameraSize(Scene.camera, nil, DEFAULT_VIEWWINDOW, DEFAULT_ASPECT_RATIO); + + /* Create a world */ + RwBBox bbox; + + bbox.sup.x = bbox.sup.y = bbox.sup.z = 10000.0f; + bbox.inf.x = bbox.inf.y = bbox.inf.z = -10000.0f; + + Scene.world = RpWorldCreate(&bbox); + ASSERT(Scene.world != nil); + if (!Scene.world) + { + CameraDestroy(Scene.camera); + Scene.camera = nil; + return (false); + } + + /* Add the camera to the world */ + RpWorldAddCamera(Scene.world, Scene.camera); + LightsCreate(Scene.world); + + CreateDebugFont(); + + CFont::Initialise(); + CHud::Initialise(); + CPlayerSkin::Initialise(); + + return (true); +} + +void CGame::ShutdownRenderWare(void) +{ + CMBlur::MotionBlurClose(); + DestroySplashScreen(); + CHud::Shutdown(); + CFont::Shutdown(); + + for ( int32 i = 0; i < NUMPLAYERS; i++ ) + CWorld::Players[i].DeletePlayerSkin(); + + CPlayerSkin::Shutdown(); + + DestroyDebugFont(); + + /* Destroy world */ + LightsDestroy(Scene.world); + RpWorldRemoveCamera(Scene.world, Scene.camera); + RpWorldDestroy(Scene.world); + + /* destroy camera */ + CameraDestroy(Scene.camera); + + Scene.world = nil; + Scene.camera = nil; + + CVisibilityPlugins::Shutdown(); + + _TexturePoolsShutdown(); +} + +bool CGame::InitialiseOnceAfterRW(void) +{ + TheText.Load(); + DMAudio.Initialise(); + CTimer::Initialise(); + CTempColModels::Initialise(); + mod_HandlingManager.Initialise(); + CSurfaceTable::Initialise("DATA\\SURFACE.DAT"); + CPedStats::Initialise(); + CTimeCycle::Initialise(); + + if ( DMAudio.GetNum3DProvidersAvailable() == 0 ) + FrontEndMenuManager.m_nPrefsAudio3DProviderIndex = -1; + + if ( FrontEndMenuManager.m_nPrefsAudio3DProviderIndex == -99 || FrontEndMenuManager.m_nPrefsAudio3DProviderIndex == -2 ) + { + CMenuManager::m_PrefsSpeakers = 0; + + for ( int32 i = 0; i < DMAudio.GetNum3DProvidersAvailable(); i++ ) + { + wchar buff[64]; + + char *name = DMAudio.Get3DProviderName(i); + AsciiToUnicode(name, buff); + char *providername = UnicodeToAscii(buff); + strupr(providername); + + if ( !strcmp(providername, "MILES FAST 2D POSITIONAL AUDIO") ) + { + FrontEndMenuManager.m_nPrefsAudio3DProviderIndex = i; + break; + } + } + } + + DMAudio.SetCurrent3DProvider(FrontEndMenuManager.m_nPrefsAudio3DProviderIndex); + DMAudio.SetSpeakerConfig(CMenuManager::m_PrefsSpeakers); + DMAudio.SetDynamicAcousticModelingStatus(CMenuManager::m_PrefsDMA); + DMAudio.SetMusicMasterVolume(CMenuManager::m_PrefsMusicVolume); + DMAudio.SetEffectsMasterVolume(CMenuManager::m_PrefsSfxVolume); + DMAudio.SetEffectsFadeVol(127); + DMAudio.SetMusicFadeVol(127); + CWorld::Players[0].SetPlayerSkin(CMenuManager::m_PrefsSkinFile); + + return true; +} + +void +CGame::FinalShutdown(void) +{ + CTxdStore::Shutdown(); + CPedStats::Shutdown(); + CdStreamShutdown(); +} bool CGame::Initialise(const char* datFile) { @@ -158,7 +317,7 @@ bool CGame::Initialise(const char* datFile) CStreaming::Init(); } else { CStreaming::Init(); - if (ConvertTextures()) { + if (CreateTxdImageForVideoCard()) { CStreaming::Shutdown(); CdStreamAddImage("MODELS\\TXD.IMG"); CStreaming::Init(); @@ -196,7 +355,7 @@ bool CGame::Initialise(const char* datFile) CSceneEdit::Init(); LoadingScreen("Loading the Game", "Load scripts", nil); CTheScripts::Init(); - CGangs::Initialize(); + CGangs::Initialise(); LoadingScreen("Loading the Game", "Setup game variables", nil); CClock::Initialise(1000); CHeli::InitHelis(); @@ -225,16 +384,227 @@ bool CGame::Initialise(const char* datFile) CTheScripts::Process(); TheCamera.Process(); LoadingScreen("Loading the Game", "Load scene", nil); - CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); - CCollision::ms_collisionInMemory = CGame::currLevel; + CModelInfo::RemoveColModelsFromOtherLevels(currLevel); + CCollision::ms_collisionInMemory = currLevel; for (int i = 0; i < MAX_PADS; i++) CPad::GetPad(i)->Clear(true); return true; } -#if 0 -WRAPPER void CGame::Process(void) { EAXJMP(0x48C850); } -#else +bool CGame::ShutDown(void) +{ + CReplay::FinishPlayback(); + CPlane::Shutdown(); + CTrain::Shutdown(); + CSpecialFX::Shutdown(); +#ifndef PS2 + CGarages::Shutdown(); +#endif + CMovingThings::Shutdown(); + gPhoneInfo.Shutdown(); + CWeapon::ShutdownWeapons(); + CPedType::Shutdown(); + CMBlur::MotionBlurClose(); + + for (int32 i = 0; i < NUMPLAYERS; i++) + { + if ( CWorld::Players[i].m_pPed ) + { + CWorld::Remove(CWorld::Players[i].m_pPed); + delete CWorld::Players[i].m_pPed; + CWorld::Players[i].m_pPed = nil; + } + + CWorld::Players[i].Clear(); + } + + CRenderer::Shutdown(); + CWorld::ShutDown(); + DMAudio.DestroyAllGameCreatedEntities(); + CModelInfo::ShutDown(); + CAnimManager::Shutdown(); + CCutsceneMgr::Shutdown(); + CVehicleModelInfo::DeleteVehicleColourTextures(); + CVehicleModelInfo::ShutdownEnvironmentMaps(); + CRadar::Shutdown(); + CStreaming::Shutdown(); + CTxdStore::GameShutdown(); + CCollision::Shutdown(); + CWaterLevel::Shutdown(); + CRubbish::Shutdown(); + CClouds::Shutdown(); + CShadows::Shutdown(); + CCoronas::Shutdown(); + CSkidmarks::Shutdown(); + CWeaponEffects::Shutdown(); + CParticle::Shutdown(); + CPools::ShutDown(); + CTxdStore::RemoveTxdSlot(gameTxdSlot); + CdStreamRemoveImages(); + return true; +} + +void CGame::ReInitGameObjectVariables(void) +{ + CGameLogic::InitAtStartOfGame(); + TheCamera.CCamera::Init(); + TheCamera.SetRwCamera(Scene.camera); + CDebug::DebugInitTextBuffer(); + CWeather::Init(); + CUserDisplay::Init(); + CMessages::Init(); + CRestart::Initialise(); + CWorld::bDoingCarCollisions = false; + CHud::ReInitialise(); + CRadar::Initialise(); + CCarCtrl::ReInit(); + CTimeCycle::Initialise(); + CDraw::SetFOV(120.0f); + CDraw::ms_fLODDistance = 500.0f; + CStreaming::RequestBigBuildings(LEVEL_NONE); + CStreaming::LoadAllRequestedModels(false); + CPed::Initialise(); + CEventList::Initialise(); + CWeapon::InitialiseWeapons(); + CPopulation::Initialise(); + + for (int i = 0; i < NUMPLAYERS; i++) + CWorld::Players[i].Clear(); + + CWorld::PlayerInFocus = 0; + CAntennas::Init(); + CGlass::Init(); + gPhoneInfo.Initialise(); + CTheScripts::Init(); + CGangs::Initialise(); + CTimer::Initialise(); + CClock::Initialise(1000); + CTheCarGenerators::Init(); + CHeli::InitHelis(); + CMovingThings::Init(); + CDarkel::Init(); + CStats::Init(); + CPickups::Init(); + CPacManPickups::Init(); + CGarages::Init(); + CSpecialFX::Init(); + CWaterCannons::Init(); + CParticle::ReloadConfig(); + CCullZones::ResolveVisibilities(); + + if ( !FrontEndMenuManager.m_bLoadingSavedGame ) + { + CCranes::InitCranes(); + CTheScripts::StartTestScript(); + CTheScripts::Process(); + TheCamera.Process(); + CTrain::InitTrains(); + CPlane::InitPlanes(); + } + + for (int32 i = 0; i < MAX_PADS; i++) + CPad::GetPad(i)->Clear(true); +} + +void CGame::ReloadIPLs(void) +{ + CTimer::Stop(); + CWorld::RemoveStaticObjects(); + ThePaths.Init(); + CCullZones::Init(); + CFileLoader::ReloadPaths("GTA3.IDE"); + CFileLoader::LoadScene("INDUST.IPL"); + CFileLoader::LoadScene("COMMER.IPL"); + CFileLoader::LoadScene("SUBURBAN.IPL"); + CFileLoader::LoadScene("CULL.IPL"); + ThePaths.PreparePathData(); + CTrafficLights::ScanForLightsOnMap(); + CRoadBlocks::Init(); + CCranes::InitCranes(); + CGarages::Init(); + CWorld::RepositionCertainDynamicObjects(); + CCullZones::ResolveVisibilities(); + CRenderer::SortBIGBuildings(); + CTimer::Update(); +} + +void CGame::ShutDownForRestart(void) +{ + CReplay::FinishPlayback(); + CReplay::EmptyReplayBuffer(); + DMAudio.DestroyAllGameCreatedEntities(); + + for (int i = 0; i < NUMPLAYERS; i++) + CWorld::Players[i].Clear(); + + CGarages::SetAllDoorsBackToOriginalHeight(); + CTheScripts::UndoBuildingSwaps(); + CTheScripts::UndoEntityInvisibilitySettings(); + CWorld::ClearForRestart(); + CTimer::Shutdown(); + CStreaming::FlushRequestList(); + CStreaming::DeleteAllRwObjects(); + CStreaming::RemoveAllUnusedModels(); + CStreaming::ms_disableStreaming = false; + CRadar::RemoveRadarSections(); + FrontEndMenuManager.UnloadTextures(); + CParticleObject::RemoveAllParticleObjects(); + CPedType::Shutdown(); + CSpecialFX::Shutdown(); + TidyUpMemory(true, false); +} + +void CGame::InitialiseWhenRestarting(void) +{ + CRect rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + CRGBA color(255, 255, 255, 255); + + CTimer::Initialise(); + CSprite2d::SetRecipNearClip(); + + b_FoundRecentSavedGameWantToLoad = false; + + TheCamera.Init(); + + if ( FrontEndMenuManager.m_bLoadingSavedGame == true ) + { + RestoreForStartLoad(); + CStreaming::LoadScene(TheCamera.GetPosition()); + } + + ReInitGameObjectVariables(); + + if ( FrontEndMenuManager.m_bLoadingSavedGame == true ) + { + if ( GenericLoad() == true ) + { + DMAudio.ResetTimers(CTimer::GetTimeInMilliseconds()); + CTrain::InitTrains(); + CPlane::InitPlanes(); + } + else + { + for ( int32 i = 0; i < 50; i++ ) + { + HandleExit(); + FrontEndMenuManager.MessageScreen("FED_LFL"); // Loading save game has failed. The game will restart now. + } + + ShutDownForRestart(); + CTimer::Stop(); + CTimer::Initialise(); + FrontEndMenuManager.m_bLoadingSavedGame = false; + ReInitGameObjectVariables(); + currLevel = LEVEL_INDUSTRIAL; + CCollision::SortOutCollisionAfterLoad(); + } + } + + CTimer::Update(); + + DMAudio.ChangeMusicMode(MUSICMODE_GAME); +} + extern void (*DebugMenuProcess)(void); void CGame::Process(void) { @@ -310,50 +680,34 @@ void CGame::Process(void) } } } -#endif -void CGame::ReloadIPLs(void) +void CGame::DrasticTidyUpMemory(bool) { - CTimer::Stop(); - CWorld::RemoveStaticObjects(); - ThePaths.Init(); - CCullZones::Init(); - CFileLoader::ReloadPaths("GTA3.IDE"); - CFileLoader::LoadScene("INDUST.IPL"); - CFileLoader::LoadScene("COMMER.IPL"); - CFileLoader::LoadScene("SUBURBAN.IPL"); - CFileLoader::LoadScene("CULL.IPL"); - ThePaths.PreparePathData(); - CTrafficLights::ScanForLightsOnMap(); - CRoadBlocks::Init(); - CCranes::InitCranes(); - CGarages::Init(); - CWorld::RepositionCertainDynamicObjects(); - CCullZones::ResolveVisibilities(); - CRenderer::SortBIGBuildings(); - CTimer::Update(); +#ifdef PS2 + // meow +#endif } -#if 0 -WRAPPER void CGame::FinalShutdown(void) { EAXJMP(0x48BEC0); } -#else -void -CGame::FinalShutdown(void) +void CGame::TidyUpMemory(bool, bool) { - CTxdStore::Shutdown(); - CPedStats::Shutdown(); - CdStreamShutdown(); -} +#ifdef PS2 + // meow #endif - -WRAPPER bool CGame::InitialiseRenderWare(void) { EAXJMP(0x48BBA0); } -WRAPPER void CGame::ShutdownRenderWare(void) { EAXJMP(0x48BCB0); } -WRAPPER void CGame::ShutDown(void) { EAXJMP(0x48C3A0); } -WRAPPER void CGame::ShutDownForRestart(void) { EAXJMP(0x48C6B0); } -WRAPPER void CGame::InitialiseWhenRestarting(void) { EAXJMP(0x48C740); } -WRAPPER bool CGame::InitialiseOnceAfterRW(void) { EAXJMP(0x48BD50); } +} STARTPATCHES - InjectHook(0x48C850, CGame::Process, PATCH_JUMP); + InjectHook(0x48BB80, CGame::InitialiseOnceBeforeRW, PATCH_JUMP); + InjectHook(0x48BBA0, CGame::InitialiseRenderWare, PATCH_JUMP); + InjectHook(0x48BCB0, CGame::ShutdownRenderWare, PATCH_JUMP); + InjectHook(0x48BD50, CGame::InitialiseOnceAfterRW, PATCH_JUMP); InjectHook(0x48BEC0, CGame::FinalShutdown, PATCH_JUMP); + InjectHook(0x48BED0, CGame::Initialise, PATCH_JUMP); + InjectHook(0x48C3A0, CGame::ShutDown, PATCH_JUMP); + InjectHook(0x48C4B0, CGame::ReInitGameObjectVariables, PATCH_JUMP); + InjectHook(0x48C620, CGame::ReloadIPLs, PATCH_JUMP); + InjectHook(0x48C6B0, CGame::ShutDownForRestart, PATCH_JUMP); + InjectHook(0x48C740, CGame::InitialiseWhenRestarting, PATCH_JUMP); + InjectHook(0x48C850, CGame::Process, PATCH_JUMP); + InjectHook(0x48CA10, CGame::DrasticTidyUpMemory, PATCH_JUMP); + InjectHook(0x48CA20, CGame::TidyUpMemory, PATCH_JUMP); ENDPATCHES diff --git a/src/core/Game.h b/src/core/Game.h index 7b20099c..318ff54b 100644 --- a/src/core/Game.h +++ b/src/core/Game.h @@ -16,23 +16,27 @@ public: static bool &nastyGame; static bool &frenchGame; static bool &germanGame; +#ifdef MORE_LANGUAGES + static bool russianGame; +#endif static bool &noProstitutes; static bool &playingIntro; static char *aDatFile; //[32]; - static bool Initialise(const char *datFile); static bool InitialiseOnceBeforeRW(void); static bool InitialiseRenderWare(void); - static bool InitialiseOnceAfterRW(void); - static void InitialiseWhenRestarting(void); - static void ShutDown(void); static void ShutdownRenderWare(void); + static bool InitialiseOnceAfterRW(void); static void FinalShutdown(void); + static bool Initialise(const char *datFile); + static bool ShutDown(void); + static void ReInitGameObjectVariables(void); + static void ReloadIPLs(void); static void ShutDownForRestart(void); + static void InitialiseWhenRestarting(void); static void Process(void); - static void ReloadIPLs(void); - + // NB: these do something on PS2 - static void TidyUpMemory(bool, bool) {} - static void DrasticTidyUpMemory(void) {} + static void TidyUpMemory(bool, bool); + static void DrasticTidyUpMemory(bool); }; 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/MenuScreens.h b/src/core/MenuScreens.h index 427d01bf..ace6a719 100644 --- a/src/core/MenuScreens.h +++ b/src/core/MenuScreens.h @@ -65,6 +65,9 @@ const CMenuScreen aScreens[] = { MENUACTION_LANG_GER, "FEL_GER", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_LANG_ITA, "FEL_ITA", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_LANG_SPA, "FEL_SPA", SAVESLOT_NONE, MENUPAGE_NONE, +#ifdef MORE_LANGUAGES + MENUACTION_LANG_RUS, "FEL_RUS", SAVESLOT_NONE, MENUPAGE_NONE, +#endif MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, }, diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index 51102c7b..6bbe00f2 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,79 @@ 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; +#ifdef REGISTER_START_BUTTON + PCTempJoyState.Start = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_START) ? 255 : 0; +#endif + 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 +636,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 09691128..ca44a9f7 100644 --- a/src/core/Pad.h +++ b/src/core/Pad.h @@ -2,9 +2,9 @@ enum { PLAYERCONTROL_ENABLED = 0, - PLAYERCONTROL_DISABLED_1 = 1, + PLAYERCONTROL_DISABLED_1 = 1, // used by first person camera PLAYERCONTROL_DISABLED_2 = 2, - PLAYERCONTROL_DISABLED_4 = 4, + PLAYERCONTROL_GARAGE = 4, PLAYERCONTROL_DISABLED_8 = 8, PLAYERCONTROL_DISABLED_10 = 16, PLAYERCONTROL_DISABLED_20 = 32, // used on CPlayerInfo::MakePlayerSafe @@ -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,8 +428,15 @@ 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; } + bool ArePlayerControlsDisabled(void) { return DisablePlayerControls != PLAYERCONTROL_ENABLED; } + void SetDisablePlayerControls(uint8 who) { DisablePlayerControls |= who; } + void SetEnablePlayerControls(uint8 who) { DisablePlayerControls &= ~who; } + bool IsPlayerControlsDisabledBy(uint8 who) { return DisablePlayerControls & who; } }; VALIDATE_SIZE(CPad, 0xFC); 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/PlayerInfo.cpp b/src/core/PlayerInfo.cpp index e0c0259e..ead32ee7 100644 --- a/src/core/PlayerInfo.cpp +++ b/src/core/PlayerInfo.cpp @@ -2,7 +2,9 @@ #include "patcher.h" #include "main.h" #include "PlayerPed.h" +#include "Wanted.h" #include "PlayerInfo.h" +#include "Fire.h" #include "Frontend.h" #include "PlayerSkin.h" #include "Darkel.h" @@ -12,6 +14,7 @@ #include "Remote.h" #include "World.h" #include "Replay.h" +#include "Camera.h" #include "Pad.h" #include "ProjectileInfo.h" #include "Explosion.h" diff --git a/src/core/PlayerSkin.cpp b/src/core/PlayerSkin.cpp index 4d2c31df..4f730b90 100644 --- a/src/core/PlayerSkin.cpp +++ b/src/core/PlayerSkin.cpp @@ -1,22 +1,22 @@ -#include "common.h" -#include "patcher.h" -#include "main.h" -#include "PlayerSkin.h" -#include "TxdStore.h" -#include "rtbmp.h" -#include "ClumpModelInfo.h" -#include "VisibilityPlugins.h" -#include "World.h" -#include "PlayerInfo.h" -#include "CdStream.h" -#include "FileMgr.h" -#include "Directory.h" -#include "RwHelper.h" -#include "Timer.h" -#include "Lights.h" - -int CPlayerSkin::m_txdSlot; - +#include "common.h"
+#include "patcher.h"
+#include "main.h"
+#include "PlayerSkin.h"
+#include "TxdStore.h"
+#include "rtbmp.h"
+#include "ClumpModelInfo.h"
+#include "VisibilityPlugins.h"
+#include "World.h"
+#include "PlayerInfo.h"
+#include "CdStream.h"
+#include "FileMgr.h"
+#include "Directory.h"
+#include "RwHelper.h"
+#include "Timer.h"
+#include "Lights.h"
+
+int CPlayerSkin::m_txdSlot;
+
void
FindPlayerDff(uint32 &offset, uint32 &size)
{
@@ -32,8 +32,8 @@ FindPlayerDff(uint32 &offset, uint32 &size) offset = info.offset;
size = info.size;
-} - +}
+
void
LoadPlayerDff(void)
{
@@ -65,22 +65,22 @@ LoadPlayerDff(void) if (streamWasAdded)
CdStreamRemoveImages();
-} - +}
+
void
CPlayerSkin::Initialise(void)
{
m_txdSlot = CTxdStore::AddTxdSlot("skin");
CTxdStore::Create(m_txdSlot);
CTxdStore::AddRef(m_txdSlot);
-} - +}
+
void
CPlayerSkin::Shutdown(void)
{
CTxdStore::RemoveTxdSlot(m_txdSlot);
-} - +}
+
RwTexture *
CPlayerSkin::GetSkinTexture(const char *texName)
{
@@ -112,8 +112,8 @@ CPlayerSkin::GetSkinTexture(const char *texName) RwImageDestroy(image);
}
return tex;
-} - +}
+
void
CPlayerSkin::BeginFrontendSkinEdit(void)
{
@@ -163,11 +163,11 @@ CPlayerSkin::RenderFrontendSkinEdit(void) RpClumpRender(gpPlayerClump);
}
-STARTPATCHES -InjectHook(0x59B9B0, &CPlayerSkin::Initialise, PATCH_JUMP); -InjectHook(0x59B9E0, &CPlayerSkin::Shutdown, PATCH_JUMP); -InjectHook(0x59B9F0, &CPlayerSkin::GetSkinTexture, PATCH_JUMP); -InjectHook(0x59BC70, &CPlayerSkin::BeginFrontendSkinEdit, PATCH_JUMP); -InjectHook(0x59BCB0, &CPlayerSkin::EndFrontendSkinEdit, PATCH_JUMP); -InjectHook(0x59BCE0, &CPlayerSkin::RenderFrontendSkinEdit, PATCH_JUMP); +STARTPATCHES
+InjectHook(0x59B9B0, &CPlayerSkin::Initialise, PATCH_JUMP);
+InjectHook(0x59B9E0, &CPlayerSkin::Shutdown, PATCH_JUMP);
+InjectHook(0x59B9F0, &CPlayerSkin::GetSkinTexture, PATCH_JUMP);
+InjectHook(0x59BC70, &CPlayerSkin::BeginFrontendSkinEdit, PATCH_JUMP);
+InjectHook(0x59BCB0, &CPlayerSkin::EndFrontendSkinEdit, PATCH_JUMP);
+InjectHook(0x59BCE0, &CPlayerSkin::RenderFrontendSkinEdit, PATCH_JUMP);
ENDPATCHES
\ No newline at end of file diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp index 6421520b..f1d8ec96 100644 --- a/src/core/Radar.cpp +++ b/src/core/Radar.cpp @@ -75,9 +75,6 @@ static_assert(RADAR_TILE_SIZE == (WORLD_SIZE_Y / RADAR_NUM_TILES), "CRadar: not #define RADAR_MIN_SPEED (0.3f)
#define RADAR_MAX_SPEED (0.9f)
-#if 0
-WRAPPER void CRadar::CalculateBlipAlpha(float) { EAXJMP(0x4A4F90); }
-#else
uint8 CRadar::CalculateBlipAlpha(float dist)
{
if (dist <= 1.0f)
@@ -88,55 +85,35 @@ uint8 CRadar::CalculateBlipAlpha(float dist) return 128;
}
-#endif
-#if 0
-WRAPPER void CRadar::ChangeBlipBrightness(int32, int32) { EAXJMP(0x4A57A0); }
-#else
void CRadar::ChangeBlipBrightness(int32 i, int32 bright)
{
int index = GetActualBlipArrayIndex(i);
if (index != -1)
ms_RadarTrace[index].m_bDim = bright != 1;
}
-#endif
-#if 0
-WRAPPER void CRadar::ChangeBlipColour(int32, int32) { EAXJMP(0x4A5770); }
-#else
void CRadar::ChangeBlipColour(int32 i, int32 color)
{
int index = GetActualBlipArrayIndex(i);
if (index != -1)
ms_RadarTrace[index].m_nColor = color;
}
-#endif
-#if 0
-WRAPPER void CRadar::ChangeBlipDisplay(int32, eBlipDisplay) { EAXJMP(0x4A5810); }
-#else
void CRadar::ChangeBlipDisplay(int32 i, eBlipDisplay display)
{
int index = GetActualBlipArrayIndex(i);
if (index != -1)
ms_RadarTrace[index].m_eBlipDisplay = display;
}
-#endif
-#if 0
-WRAPPER void CRadar::ChangeBlipScale(int32, int32) { EAXJMP(0x4A57E0); }
-#else
void CRadar::ChangeBlipScale(int32 i, int32 scale)
{
int index = GetActualBlipArrayIndex(i);
if (index != -1)
ms_RadarTrace[index].m_wScale = scale;
}
-#endif
-#if 0
-WRAPPER void CRadar::ClearBlip(int32) { EAXJMP(0x4A5720); }
-#else
void CRadar::ClearBlip(int32 i)
{
int index = GetActualBlipArrayIndex(i);
@@ -148,11 +125,7 @@ void CRadar::ClearBlip(int32 i) ms_RadarTrace[index].m_IconID = RADAR_SPRITE_NONE;
}
}
-#endif
-#if 0
-WRAPPER void CRadar::ClearBlipForEntity(eBlipType, int32) { EAXJMP(0x4A56C0); }
-#else
void CRadar::ClearBlipForEntity(eBlipType type, int32 id)
{
for (int i = 0; i < NUMRADARBLIPS; i++) {
@@ -165,11 +138,7 @@ void CRadar::ClearBlipForEntity(eBlipType type, int32 id) }
};
}
-#endif
-#if 0
-WRAPPER int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *in) { EAXJMP(0x4A64A0); }
-#else
// Why not a proper clipping algorithm?
int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *rect)
{
@@ -249,7 +218,6 @@ int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *rect) return n;
}
-#endif
bool CRadar::DisplayThisBlip(int32 counter)
{
@@ -263,9 +231,6 @@ bool CRadar::DisplayThisBlip(int32 counter) }
}
-#if 0
-WRAPPER void CRadar::Draw3dMarkers() { EAXJMP(0x4A4C70); }
-#else
void CRadar::Draw3dMarkers()
{
for (int i = 0; i < NUMRADARBLIPS; i++) {
@@ -317,12 +282,7 @@ void CRadar::Draw3dMarkers() }
}
}
-#endif
-
-#if 0
-WRAPPER void CRadar::DrawBlips() { EAXJMP(0x4A42F0); }
-#else
void CRadar::DrawBlips()
{
if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
@@ -580,12 +540,7 @@ void CRadar::DrawBlips() }
}
}
-#endif
-
-#if 0
-WRAPPER void CRadar::DrawMap () { EAXJMP(0x4A4200); }
-#else
void CRadar::DrawMap()
{
if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
@@ -605,11 +560,7 @@ void CRadar::DrawMap() DrawRadarMap();
}
}
-#endif
-#if 0
-WRAPPER void CRadar::DrawRadarMap() { EAXJMP(0x4A6C20); }
-#else
void CRadar::DrawRadarMap()
{
// Game calculates an unused CRect here
@@ -642,11 +593,7 @@ void CRadar::DrawRadarMap() DrawRadarSection(x, y + 1);
DrawRadarSection(x + 1, y + 1);
}
-#endif
-#if 0
-WRAPPER void CRadar::DrawRadarMask() { EAXJMP(0x4A69C0); }
-#else
void CRadar::DrawRadarMask()
{
CVector2D corners[4] = {
@@ -690,11 +637,7 @@ void CRadar::DrawRadarMask() RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONGREATER);
}
-#endif
-#if 0
-WRAPPER void CRadar::DrawRadarSection(int32, int32) { EAXJMP(0x4A67E0); }
-#else
void CRadar::DrawRadarSection(int32 x, int32 y)
{
int i;
@@ -738,20 +681,12 @@ void CRadar::DrawRadarSection(int32 x, int32 y) // if(numVertices > 2)
RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), numVertices);
}
-#endif
-#if 0
-WRAPPER void CRadar::DrawRadarSprite(uint16 sprite, float x, float y, uint8 alpha) { EAXJMP(0x4A5EF0); }
-#else
void CRadar::DrawRadarSprite(uint16 sprite, float x, float y, uint8 alpha)
{
RadarSprites[sprite]->Draw(CRect(x - SCREEN_SCALE_X(8.0f), y - SCREEN_SCALE_Y(8.0f), x + SCREEN_SCALE_X(8.0f), y + SCREEN_SCALE_Y(8.0f)), CRGBA(255, 255, 255, alpha));
}
-#endif
-#if 0
-WRAPPER void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha) { EAXJMP(0x4A5D10); }
-#else
void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha)
{
CVector curPosn[4];
@@ -778,11 +713,7 @@ void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float sprite->Draw(curPosn[2].x, curPosn[2].y, curPosn[3].x, curPosn[3].y, curPosn[0].x, curPosn[0].y, curPosn[1].x, curPosn[1].y, CRGBA(255, 255, 255, alpha));
}
-#endif
-#if 0
-WRAPPER int32 CRadar::GetActualBlipArrayIndex(int32) { EAXJMP(0x4A41C0); }
-#else
int32 CRadar::GetActualBlipArrayIndex(int32 i)
{
if (i == -1)
@@ -792,11 +723,7 @@ int32 CRadar::GetActualBlipArrayIndex(int32 i) else
return (uint16)i;
}
-#endif
-#if 0
-WRAPPER int32 CRadar::GetNewUniqueBlipIndex(int32) { EAXJMP(0x4A4180); }
-#else
int32 CRadar::GetNewUniqueBlipIndex(int32 i)
{
if (ms_RadarTrace[i].m_BlipIndex >= UINT16_MAX - 1)
@@ -805,11 +732,7 @@ int32 CRadar::GetNewUniqueBlipIndex(int32 i) ms_RadarTrace[i].m_BlipIndex++;
return i | (ms_RadarTrace[i].m_BlipIndex << 16);
}
-#endif
-#if 0
-WRAPPER uint32 CRadar::GetRadarTraceColour(uint32 color, bool bright) { EAXJMP(0x4A5BB0); }
-#else
uint32 CRadar::GetRadarTraceColour(uint32 color, bool bright)
{
int32 c;
@@ -862,7 +785,6 @@ uint32 CRadar::GetRadarTraceColour(uint32 color, bool bright) };
return c;
}
-#endif
const char* gRadarTexNames[] = {
"radar00", "radar01", "radar02", "radar03", "radar04", "radar05", "radar06", "radar07",
@@ -875,9 +797,6 @@ const char* gRadarTexNames[] = { "radar56", "radar57", "radar58", "radar59", "radar60", "radar61", "radar62", "radar63",
};
-#if 0
-WRAPPER void CRadar::Initialise() { EAXJMP(0x4A3EF0); }
-#else
void
CRadar::Initialise()
{
@@ -894,11 +813,7 @@ CRadar::Initialise() for (int i = 0; i < 64; i++)
gRadarTxdIds[i] = CTxdStore::FindTxdSlot(gRadarTexNames[i]);
}
-#endif
-#if 0
-WRAPPER float CRadar::LimitRadarPoint(CVector2D &point) { EAXJMP(0x4A4F30); }
-#else
float CRadar::LimitRadarPoint(CVector2D &point)
{
float dist, invdist;
@@ -911,11 +826,7 @@ float CRadar::LimitRadarPoint(CVector2D &point) }
return dist;
}
-#endif
-#if 0
-WRAPPER void CRadar::LoadAllRadarBlips(int32) { EAXJMP(0x4A6F30); }
-#else
void CRadar::LoadAllRadarBlips(uint8 *buf, uint32 size)
{
Initialise();
@@ -927,11 +838,7 @@ INITSAVEBUF VALIDATESAVEBUF(size);
}
-#endif
-#if 0
-WRAPPER void CRadar::LoadTextures() { EAXJMP(0x4A4030); }
-#else
void
CRadar::LoadTextures()
{
@@ -959,42 +866,26 @@ CRadar::LoadTextures() WeaponSprite.SetTexture("radar_weapon");
CTxdStore::PopCurrentTxd();
}
-#endif
-#if 0
-WRAPPER void RemoveMapSection(int32, int32) { EAXJMP(0x00); }
-#else
void RemoveMapSection(int32 x, int32 y)
{
if (x >= 0 && x <= 7 && y >= 0 && y <= 7)
CStreaming::RemoveTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y]);
}
-#endif
-#if 0
-WRAPPER void CRadar::RemoveRadarSections() { EAXJMP(0x4A60E0); }
-#else
void CRadar::RemoveRadarSections()
{
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
RemoveMapSection(i, j);
}
-#endif
-#if 0
-WRAPPER void CRadar::RequestMapSection(int32, int32) { EAXJMP(0x00); }
-#else
void CRadar::RequestMapSection(int32 x, int32 y)
{
ClipRadarTileCoords(x, y);
CStreaming::RequestTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y], STREAMFLAGS_DONT_REMOVE | STREAMFLAGS_DEPENDENCY);
}
-#endif
-#if 0
-WRAPPER void CRadar::SaveAllRadarBlips(uint8 *buf, uint32 *size) { EAXJMP(0x4A6E30); }
-#else
void CRadar::SaveAllRadarBlips(uint8 *buf, uint32 *size)
{
*size = SAVE_HEADER_SIZE + sizeof(ms_RadarTrace);
@@ -1006,11 +897,7 @@ INITSAVEBUF VALIDATESAVEBUF(*size);
}
-#endif
-#if 0
-WRAPPER void CRadar::SetBlipSprite(int32, int32) { EAXJMP(0x4A5840); }
-#else
void CRadar::SetBlipSprite(int32 i, int32 icon)
{
int index = CRadar::GetActualBlipArrayIndex(i);
@@ -1018,11 +905,7 @@ void CRadar::SetBlipSprite(int32 i, int32 icon) ms_RadarTrace[index].m_IconID = icon;
}
}
-#endif
-#if 0
-WRAPPER int32 CRadar::SetCoordBlip(eBlipType, CVector, int32, eBlipDisplay display) { EAXJMP(0x4A5590); }
-#else
int CRadar::SetCoordBlip(eBlipType type, CVector pos, int32 color, eBlipDisplay display)
{
int nextBlip;
@@ -1043,11 +926,7 @@ int CRadar::SetCoordBlip(eBlipType type, CVector pos, int32 color, eBlipDisplay ms_RadarTrace[nextBlip].m_IconID = RADAR_SPRITE_NONE;
return CRadar::GetNewUniqueBlipIndex(nextBlip);
}
-#endif
-#if 0
-WRAPPER int CRadar::SetEntityBlip(eBlipType type, int32, int32, eBlipDisplay) { EAXJMP(0x4A5640); }
-#else
int CRadar::SetEntityBlip(eBlipType type, int32 handle, int32 color, eBlipDisplay display)
{
int nextBlip;
@@ -1066,11 +945,7 @@ int CRadar::SetEntityBlip(eBlipType type, int32 handle, int32 color, eBlipDispla ms_RadarTrace[nextBlip].m_IconID = RADAR_SPRITE_NONE;
return GetNewUniqueBlipIndex(nextBlip);
}
-#endif
-#if 0
-WRAPPER void CRadar::SetRadarMarkerState(int32, bool) { EAXJMP(0x4A5C60); }
-#else
void CRadar::SetRadarMarkerState(int32 counter, bool flag)
{
CEntity *e;
@@ -1091,11 +966,7 @@ void CRadar::SetRadarMarkerState(int32 counter, bool flag) if (e)
e->bHasBlip = flag;
}
-#endif
-#if 0
-WRAPPER void CRadar::ShowRadarMarker(CVector pos, uint32 color, float radius) { EAXJMP(0x4A59C0); }
-#else
void CRadar::ShowRadarMarker(CVector pos, uint32 color, float radius) {
float f1 = radius * 1.4f;
float f2 = radius * 0.5f;
@@ -1117,11 +988,7 @@ void CRadar::ShowRadarMarker(CVector pos, uint32 color, float radius) { p2 = pos - TheCamera.GetRight()*f2;
CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
}
-#endif
-#if 0
-WRAPPER void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha) { EAXJMP(0x4A5870); }
-#else
void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha)
{
if (!CHud::m_Wants_To_Draw_Hud || TheCamera.m_WideScreenOn)
@@ -1130,7 +997,6 @@ void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint8 red, uint8 gree CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha));
CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha));
}
-#endif
void CRadar::ShowRadarTraceWithHeight(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha, uint8 mode)
{
@@ -1156,9 +1022,6 @@ void CRadar::ShowRadarTraceWithHeight(float x, float y, uint32 size, uint8 red, }
}
-#if 0
-WRAPPER void CRadar::Shutdown() { EAXJMP(0x4A3F60); }
-#else
void CRadar::Shutdown()
{
AsukaSprite.Delete();
@@ -1183,20 +1046,12 @@ void CRadar::Shutdown() WeaponSprite.Delete();
RemoveRadarSections();
}
-#endif
-#if 0
-WRAPPER void CRadar::StreamRadarSections(const CVector &posn) { EAXJMP(0x4A6B60); }
-#else
void CRadar::StreamRadarSections(const CVector &posn)
{
StreamRadarSections(floorf((2000.0f + posn.x) / 500.0f), ceilf(7.0f - (2000.0f + posn.y) / 500.0f));
}
-#endif
-#if 0
-WRAPPER void CRadar::StreamRadarSections(int32 x, int32 y) { EAXJMP(0x4A6100); }
-#else
void CRadar::StreamRadarSections(int32 x, int32 y)
{
for (int i = 0; i < RADAR_NUM_TILES; ++i) {
@@ -1208,11 +1063,7 @@ void CRadar::StreamRadarSections(int32 x, int32 y) };
};
}
-#endif
-#if 0
-WRAPPER void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y) { EAXJMP(0x4A5530); }
-#else
void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y)
{
out.x = in.x - (x * RADAR_TILE_SIZE + WORLD_MIN_X);
@@ -1220,11 +1071,7 @@ void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D & out.x /= RADAR_TILE_SIZE;
out.y /= RADAR_TILE_SIZE;
}
-#endif
-#if 0
-WRAPPER void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A5300); }
-#else
void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in)
{
float s, c;
@@ -1255,19 +1102,18 @@ void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D out = out * m_radarRange + vec2DRadarOrigin;
}
-#endif
// Radar space goes from -1.0 to 1.0 in x and y, top right is (1.0, 1.0)
void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in)
{
- // FIX? scale RADAR_LEFT here somehow
+#ifdef FIX_BUGS
+ out.x = (in.x + 1.0f)*0.5f*SCREEN_SCALE_X(RADAR_WIDTH) + SCREEN_SCALE_X(RADAR_LEFT);
+#else
out.x = (in.x + 1.0f)*0.5f*SCREEN_SCALE_X(RADAR_WIDTH) + RADAR_LEFT;
+#endif
out.y = (1.0f - in.y)*0.5f*SCREEN_SCALE_Y(RADAR_HEIGHT) + SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT);
}
-#if 0
-WRAPPER void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A50D0); }
-#else
void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in)
{
float s, c;
@@ -1299,11 +1145,7 @@ void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D out.x = s * y + c * x;
out.y = c * y - s * x;
}
-#endif
-#if 0
-WRAPPER void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out) { EAXJMP(0x4A61C0); };
-#else
// Transform from section indices to world coordinates
void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out)
{
@@ -1326,11 +1168,7 @@ void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out) out[3].x = RADAR_TILE_SIZE * (x);
out[3].y = RADAR_TILE_SIZE * (y);
}
-#endif
-#if 0
-WRAPPER void CRadar::ClipRadarTileCoords(int32 &, int32 &) { EAXJMP(0x00); };
-#else
void CRadar::ClipRadarTileCoords(int32 &x, int32 &y)
{
if (x < 0)
@@ -1342,24 +1180,16 @@ void CRadar::ClipRadarTileCoords(int32 &x, int32 &y) if (y > RADAR_NUM_TILES-1)
y = RADAR_NUM_TILES-1;
}
-#endif
-#if 0
-WRAPPER bool CRadar::IsPointInsideRadar(const CVector2D &) { EAXJMP(0x4A6160); }
-#else
bool CRadar::IsPointInsideRadar(const CVector2D &point)
{
if (point.x < -1.0f || point.x > 1.0f) return false;
if (point.y < -1.0f || point.y > 1.0f) return false;
return true;
}
-#endif
// clip line p1,p2 against (-1.0, 1.0) in x and y, set out to clipped point closest to p1
-#if 0
-WRAPPER int CRadar::LineRadarBoxCollision(CVector2D &, const CVector2D &, const CVector2D &) { EAXJMP(0x4A6250); }
-#else
int CRadar::LineRadarBoxCollision(CVector2D &out, const CVector2D &p1, const CVector2D &p2)
{
float d1, d2;
@@ -1430,7 +1260,6 @@ int CRadar::LineRadarBoxCollision(CVector2D &out, const CVector2D &p1, const CVe return edge;
}
-#endif
STARTPATCHES
InjectHook(0x4A3EF0, CRadar::Initialise, PATCH_JUMP);
diff --git a/src/core/RwHelper.cpp b/src/core/RwHelper.cpp index 1030d69e..6325bf15 100644 --- a/src/core/RwHelper.cpp +++ b/src/core/RwHelper.cpp @@ -352,7 +352,25 @@ WRAPPER bool CheckVideoCardCaps(void) { EAXJMP(0x592740); } WRAPPER void WriteVideoCardCapsFile(void) { EAXJMP(0x5927D0); } WRAPPER void ConvertingTexturesScreen(uint32, uint32, const char*) { EAXJMP(0x592880); } WRAPPER void DealWithTxdWriteError(uint32, uint32, const char*) { EAXJMP(0x592BF0); } -WRAPPER bool ConvertTextures() { EAXJMP(0x592C70); } +WRAPPER bool CreateTxdImageForVideoCard() { EAXJMP(0x592C70); } + +void CreateDebugFont() +{ + ; +} + +void DestroyDebugFont() +{ + ; +} + +void FlushObrsPrintfs() +{ + ; +} + +WRAPPER void _TexturePoolsInitialise() { EAXJMP(0x598B10); } +WRAPPER void _TexturePoolsShutdown() { EAXJMP(0x598B30); } STARTPATCHES //InjectHook(0x526450, GetFirstObjectCallback, PATCH_JUMP); diff --git a/src/core/RwHelper.h b/src/core/RwHelper.h index 1f0290cc..a9f0bdf4 100644 --- a/src/core/RwHelper.h +++ b/src/core/RwHelper.h @@ -3,6 +3,9 @@ void *RwMallocAlign(RwUInt32 size, RwUInt32 align); void RwFreeAlign(void *mem); +void CreateDebugFont(); +void DestroyDebugFont(); +void FlushObrsPrintfs(); void DefinedState(void); RwFrame *GetFirstChild(RwFrame *frame); RwObject *GetFirstObject(RwFrame *frame); @@ -17,7 +20,7 @@ bool CheckVideoCardCaps(void); void WriteVideoCardCapsFile(void); void ConvertingTexturesScreen(uint32, uint32, const char*); void DealWithTxdWriteError(uint32, uint32, const char*); -bool ConvertTextures(); // not a real name +bool CreateTxdImageForVideoCard(); bool RpClumpGtaStreamRead1(RwStream *stream); RpClump *RpClumpGtaStreamRead2(RwStream *stream); @@ -31,3 +34,7 @@ void CameraDestroy(RwCamera *camera); RwCamera *CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer); + + +void _TexturePoolsInitialise(); +void _TexturePoolsShutdown();
\ No newline at end of file diff --git a/src/core/Stats.h b/src/core/Stats.h index 826dcd73..41d926e6 100644 --- a/src/core/Stats.h +++ b/src/core/Stats.h @@ -62,6 +62,8 @@ public: static int32 &CarsCrushed; static int32(&FastestTimes)[TOTAL_FASTEST_TIMES]; static int32(&HighestScores)[TOTAL_HIGHEST_SCORES]; + static int32 &KgOfExplosivesUsed; + static int32 &CarsCrushed; public: static void RegisterFastestTime(int32, int32); diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index 3a830d37..3dcb767a 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -10,6 +10,7 @@ #include "TxdStore.h" #include "ModelIndices.h" #include "Pools.h" +#include "Wanted.h" #include "Directory.h" #include "RwHelper.h" #include "World.h" @@ -198,7 +199,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.cpp b/src/core/Timer.cpp index bcf84560..18d6b6a3 100644 --- a/src/core/Timer.cpp +++ b/src/core/Timer.cpp @@ -75,9 +75,6 @@ void CTimer::Shutdown(void) ; } -#if 0 -WRAPPER void CTimer::Update(void) { EAXJMP(0x4ACF70); } -#else void CTimer::Update(void) { m_snPreviousTimeInMilliseconds = m_snTimeInMilliseconds; @@ -149,7 +146,6 @@ void CTimer::Update(void) m_FrameCounter++; } -#endif void CTimer::Suspend(void) { @@ -218,6 +214,11 @@ void CTimer::EndUserPause(void) m_UserPause = false; } +uint32 CTimer::GetCyclesPerFrame() +{ + return 20; +} + #if 1 STARTPATCHES InjectHook(0x4ACE60, CTimer::Initialise, PATCH_JUMP); diff --git a/src/core/Timer.h b/src/core/Timer.h index 89c4a430..2498ec8a 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,8 +32,9 @@ 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 uint32 GetCyclesPerFrame(); static bool GetIsPaused() { return m_UserPause || m_CodePause; } static bool GetIsUserPaused() { return m_UserPause; } diff --git a/src/core/TxdStore.cpp b/src/core/TxdStore.cpp index ab970b99..c751147d 100644 --- a/src/core/TxdStore.cpp +++ b/src/core/TxdStore.cpp @@ -10,7 +10,7 @@ CPool<TxdDef,TxdDef> *&CTxdStore::ms_pTxdPool = *(CPool<TxdDef,TxdDef>**)0x8F5FB RwTexDictionary *&CTxdStore::ms_pStoredTxd = *(RwTexDictionary**)0x9405BC; void -CTxdStore::Initialize(void) +CTxdStore::Initialise(void) { if(ms_pTxdPool == nil) ms_pTxdPool = new CPool<TxdDef,TxdDef>(TXDSTORESIZE); @@ -187,7 +187,7 @@ CTxdStore::RemoveTxd(int slot) } STARTPATCHES - InjectHook(0x527440, CTxdStore::Initialize, PATCH_JUMP); + InjectHook(0x527440, CTxdStore::Initialise, PATCH_JUMP); InjectHook(0x527470, CTxdStore::Shutdown, PATCH_JUMP); InjectHook(0x527490, CTxdStore::GameShutdown, PATCH_JUMP); InjectHook(0x5274E0, CTxdStore::AddTxdSlot, PATCH_JUMP); diff --git a/src/core/TxdStore.h b/src/core/TxdStore.h index a9e57d31..12ac708f 100644 --- a/src/core/TxdStore.h +++ b/src/core/TxdStore.h @@ -13,7 +13,7 @@ class CTxdStore static CPool<TxdDef,TxdDef> *&ms_pTxdPool; static RwTexDictionary *&ms_pStoredTxd; public: - static void Initialize(void); + static void Initialise(void); static void Shutdown(void); static void GameShutdown(void); static int AddTxdSlot(const char *name); diff --git a/src/core/Wanted.cpp b/src/core/Wanted.cpp index 7af753e8..29294a2b 100644 --- a/src/core/Wanted.cpp +++ b/src/core/Wanted.cpp @@ -7,19 +7,16 @@ #include "ZoneCull.h" #include "Darkel.h" #include "DMAudio.h" +#include "CopPed.h" #include "Wanted.h" +#include "General.h" int32 &CWanted::MaximumWantedLevel = *(int32*)0x5F7714; // 6 int32 &CWanted::nMaximumWantedLevel = *(int32*)0x5F7718; // 6400 -WRAPPER void CWanted::Reset() { EAXJMP(0x4AD790) }; -WRAPPER void CWanted::Update() { EAXJMP(0x4AD7B0) }; - void CWanted::Initialise() { - int i; - m_nChaos = 0; m_nLastUpdateTime = 0; m_nLastWantedLevelChange = 0; @@ -34,10 +31,12 @@ CWanted::Initialise() m_bArmyRequired = false; m_fCrimeSensitivity = 1.0f; m_nWantedLevel = 0; - m_CopsBeatingSuspect = 0; - for(i = 0; i < 10; i++) + m_CopsBeatingSuspect = 0; + + for (int i = 0; i < ARRAY_SIZE(m_pCops); i++) m_pCops[i] = nil; - ClearQdCrimes(); + + ClearQdCrimes(); } bool @@ -61,7 +60,7 @@ CWanted::AreArmyRequired() int32 CWanted::NumOfHelisRequired() { - if (m_bIgnoredByCops) + if (m_bIgnoredByCops || m_bIgnoredByEveryone) return 0; switch (m_nWantedLevel) { @@ -79,9 +78,10 @@ CWanted::NumOfHelisRequired() void CWanted::SetWantedLevel(int32 level) { - ClearQdCrimes(); if (level > MaximumWantedLevel) level = MaximumWantedLevel; + + ClearQdCrimes(); switch (level) { case 0: m_nChaos = 0; @@ -360,10 +360,107 @@ CWanted::WorkOutPolicePresence(CVector posn, float radius) return numPolice; } +void +CWanted::Update(void) +{ + if (CTimer::GetTimeInMilliseconds() - m_nLastUpdateTime > 1000) { + if (m_nWantedLevel > 1) { + m_nLastUpdateTime = CTimer::GetTimeInMilliseconds(); + } else { + float radius = 18.0f; + CVector playerPos = FindPlayerCoors(); + if (WorkOutPolicePresence(playerPos, radius) == 0) { + m_nLastUpdateTime = CTimer::GetTimeInMilliseconds(); + m_nChaos = max(0, m_nChaos - 1); + UpdateWantedLevel(); + } + } + UpdateCrimesQ(); + bool orderMessedUp = false; + int currCopNum = 0; + bool foundEmptySlot = false; + for (int i = 0; i < ARRAY_SIZE(m_pCops); i++) { + if (m_pCops[i]) { + ++currCopNum; + if (foundEmptySlot) + orderMessedUp = true; + } else { + foundEmptySlot = true; + } + } + if (currCopNum != m_CurrentCops) { + printf("CopPursuit total messed up: re-setting\n"); + m_CurrentCops = currCopNum; + } + if (orderMessedUp) { + printf("CopPursuit pointer list messed up: re-sorting\n"); + bool fixed = true; + for (int i = 0; i < ARRAY_SIZE(m_pCops); i++) { + if (!m_pCops[i]) { + for (int j = i; j < ARRAY_SIZE(m_pCops); j++) { + if (m_pCops[j]) { + m_pCops[i] = m_pCops[j]; + m_pCops[j] = nil; + fixed = false; + break; + } + } + if (fixed) + break; + } + } + } + } +} + +void +CWanted::ResetPolicePursuit(void) +{ + for(int i = 0; i < ARRAY_SIZE(m_pCops); i++) { + CCopPed *cop = m_pCops[i]; + if (!cop) + continue; + + cop->m_bIsInPursuit = false; + cop->m_objective = OBJECTIVE_NONE; + cop->m_prevObjective = OBJECTIVE_NONE; + cop->m_nLastPedState = PED_NONE; + if (!cop->DyingOrDead()) { + cop->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + } + m_pCops[i] = nil; + } + m_CurrentCops = 0; +} + +void +CWanted::Reset(void) +{ + ResetPolicePursuit(); + Initialise(); +} + +void +CWanted::UpdateCrimesQ(void) +{ + for(int i = 0; i < ARRAY_SIZE(m_aCrimes); i++) { + + CCrimeBeingQd &crime = m_aCrimes[i]; + if (crime.m_nType != CRIME_NONE) { + if (CTimer::GetTimeInMilliseconds() > crime.m_nTime + 500 && !crime.m_bReported) { + ReportCrimeNow(crime.m_nType, crime.m_vecPosn, crime.m_bPoliceDoesntCare); + crime.m_bReported = true; + } + if (CTimer::GetTimeInMilliseconds() > crime.m_nTime + 10000) + crime.m_nType = CRIME_NONE; + } + } +} + STARTPATCHES InjectHook(0x4AD6E0, &CWanted::Initialise, PATCH_JUMP); -// InjectHook(0x4AD790, &CWanted::Reset, PATCH_JUMP); -// InjectHook(0x4AD7B0, &CWanted::Update, PATCH_JUMP); + InjectHook(0x4AD790, &CWanted::Reset, PATCH_JUMP); + InjectHook(0x4AD7B0, &CWanted::Update, PATCH_JUMP); InjectHook(0x4AD900, &CWanted::UpdateWantedLevel, PATCH_JUMP); InjectHook(0x4AD9F0, &CWanted::RegisterCrime, PATCH_JUMP); InjectHook(0x4ADA10, &CWanted::RegisterCrime_Immediately, PATCH_JUMP); @@ -374,10 +471,10 @@ STARTPATCHES InjectHook(0x4ADBC0, &CWanted::AreFbiRequired, PATCH_JUMP); InjectHook(0x4ADBE0, &CWanted::AreArmyRequired, PATCH_JUMP); InjectHook(0x4ADC00, &CWanted::NumOfHelisRequired, PATCH_JUMP); -// InjectHook(0x4ADC40, &CWanted::ResetPolicePursuit, PATCH_JUMP); + InjectHook(0x4ADC40, &CWanted::ResetPolicePursuit, PATCH_JUMP); InjectHook(0x4ADD00, &CWanted::WorkOutPolicePresence, PATCH_JUMP); InjectHook(0x4ADF20, &CWanted::ClearQdCrimes, PATCH_JUMP); InjectHook(0x4ADFD0, &CWanted::AddCrimeToQ, PATCH_JUMP); -// InjectHook(0x4AE090, &CWanted::UpdateCrimesQ, PATCH_JUMP); + InjectHook(0x4AE090, &CWanted::UpdateCrimesQ, PATCH_JUMP); InjectHook(0x4AE110, &CWanted::ReportCrimeNow, PATCH_JUMP); ENDPATCHES diff --git a/src/core/Wanted.h b/src/core/Wanted.h index f6dbe8d0..9823529c 100644 --- a/src/core/Wanted.h +++ b/src/core/Wanted.h @@ -30,7 +30,7 @@ class CCrimeBeingQd public: eCrimeType m_nType; uint32 m_nId; - int32 m_nTime; + uint32 m_nTime; CVector m_vecPosn; bool m_bReported; bool m_bPoliceDoesntCare; @@ -78,6 +78,8 @@ public: void ReportCrimeNow(eCrimeType type, const CVector &coors, bool policeDoesntCare); void UpdateWantedLevel(); void Reset(); + void ResetPolicePursuit(); + void UpdateCrimesQ(); void Update(); bool IsIgnored(void) { return m_bIgnoredByCops || m_bIgnoredByEveryone; } diff --git a/src/core/World.cpp b/src/core/World.cpp index cbceb292..4a0230ce 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -19,12 +19,14 @@ #include "Messages.h" #include "Replay.h" #include "Population.h" +#include "Fire.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; @@ -38,6 +40,7 @@ bool &CWorld::bProcessCutsceneOnly = *(bool*)0x95CD8B; bool &CWorld::bDoingCarCollisions = *(bool*)0x95CD8C; bool &CWorld::bIncludeCarTyres = *(bool*)0x95CDAA; +WRAPPER void CWorld::ClearForRestart(void) { EAXJMP(0x4AE850); } WRAPPER void CWorld::AddParticles(void) { EAXJMP(0x4B4010); } WRAPPER void CWorld::ShutDown(void) { EAXJMP(0x4AE450); } WRAPPER void CWorld::RepositionCertainDynamicObjects() { EAXJMP(0x4B42B0); } @@ -52,6 +55,7 @@ WRAPPER void CWorld::FindObjectsOfTypeInRangeSectorList(uint32, CPtrList&, CVect WRAPPER void CWorld::FindMissionEntitiesIntersectingCube(const CVector&, const CVector&, int16*, int16, CEntity**, bool, bool, bool) { EAXJMP(0x4B3680); } WRAPPER void CWorld::ClearCarsFromArea(float, float, float, float, float, float) { EAXJMP(0x4B50E0); } WRAPPER void CWorld::ClearPedsFromArea(float, float, float, float, float, float) { EAXJMP(0x4B52B0); } +WRAPPER void CWorld::CallOffChaseForArea(float, float, float, float) { EAXJMP(0x4B5530); } void CWorld::Initialise() @@ -609,9 +613,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) { @@ -625,7 +629,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; } @@ -636,22 +640,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 @@ -665,48 +669,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 @@ -719,47 +723,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; } @@ -806,7 +810,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 && @@ -1051,6 +1055,19 @@ CWorld::ExtinguishAllCarFiresInArea(CVector point, float range) } void +CWorld::SetCarsOnFire(float x, float y, float z, float radius, CEntity *reason) +{ + int poolSize = CPools::GetVehiclePool()->GetSize(); + for (int poolIndex = poolSize - 1; poolIndex >= 0; poolIndex--) { + CVehicle *veh = CPools::GetVehiclePool()->GetSlot(poolIndex); + if (veh && veh->m_status != STATUS_WRECKED && !veh->m_pCarFire && !veh->bFireProof) { + if (Abs(veh->GetPosition().z - z) < 5.0f && Abs(veh->GetPosition().x - x) < radius && Abs(veh->GetPosition().y - y) < radius) + gFireManager.StartFire(veh, reason, 0.8f, true); + } + } +} + +void CWorld::Process(void) { if (!(CTimer::GetFrameCounter() & 63)) diff --git a/src/core/World.h b/src/core/World.h index 1ad65ac4..c4103eb2 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); @@ -117,6 +115,7 @@ public: static void FindMissionEntitiesIntersectingCube(const CVector&, const CVector&, int16*, int16, CEntity**, bool, bool, bool); static void ClearCarsFromArea(float, float, float, float, float, float); static void ClearPedsFromArea(float, float, float, float, float, float); + static void CallOffChaseForArea(float, float, float, float); static float GetSectorX(float f) { return ((f - WORLD_MIN_X)/SECTOR_SIZE_X); } static float GetSectorY(float f) { return ((f - WORLD_MIN_Y)/SECTOR_SIZE_Y); } @@ -132,15 +131,19 @@ public: static void StopAllLawEnforcersInTheirTracks(); static void SetAllCarsCanBeDamaged(bool); static void ExtinguishAllCarFiresInArea(CVector, float); + static void SetCarsOnFire(float, float, float, float, CEntity*); static void Initialise(); static void AddParticles(); static void ShutDown(); + static void ClearForRestart(void); static void RepositionCertainDynamicObjects(); static void RemoveStaticObjects(); 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..b58b93af 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; @@ -202,6 +215,7 @@ void re3_assert(const char *expr, const char *filename, unsigned int lineno, con #define ABS(a) (((a) < 0) ? (-(a)) : (a)) #define norm(value, min, max) (((value) < (min)) ? 0 : (((value) > (max)) ? 1 : (((value) - (min)) / ((max) - (min))))) +#define lerp(norm, min, max) ( (norm) * ((max) - (min)) + (min) ) #define STRINGIFY(x) #x #define STR(x) STRINGIFY(x) diff --git a/src/core/config.h b/src/core/config.h index 9235e744..373fca2f 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -94,12 +94,17 @@ enum Config { NUM_GARAGES = 32, NUM_PROJECTILES = 32, + NUM_GLASSPANES = 45, + NUM_GLASSENTITIES = 32, NUM_WATERCANNONS = 3, NUMPEDROUTES = 200, NUMPHONES = 50, NUMPEDGROUPS = 31, NUMMODELSPERPEDGROUP = 8, + NUMSHOTINFOS = 100, + + NUMROADBLOCKS = 600, NUMVISIBLEENTITIES = 2000, NUMINVISIBLEENTITIES = 150, @@ -114,6 +119,8 @@ enum Config { NUM_AUDIO_REFLECTIONS = 5, NUM_SCRIPT_MAX_ENTITIES = 40, + + NUM_GARAGE_STORED_CARS = 6 }; // We'll use this once we're ready to become independent of the game @@ -164,15 +171,19 @@ enum Config { // not in any game # define NASTY_GAME // nasty game for all languages # define NO_MOVIES // disable intro videos -# define NO_CDCHECK +# define NO_CDCHECK # define CHATTYSPLASH // print what the game is loading +//# define TIMEBARS // print debug timers #endif #define FIX_BUGS // fixes bugs that we've came across during reversing, 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 +#define MORE_LANGUAGES // Add more translations to the game // 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 @@ -199,5 +210,9 @@ 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 + +// Camera +#define IMPROVED_CAMERA // Better Debug cam, and maybe more in the future +#define FREE_CAM // Rotating cam diff --git a/src/core/main.cpp b/src/core/main.cpp index 2a15e20e..674527f5 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -51,6 +51,7 @@ #include "Script.h" #include "Debug.h" #include "Console.h" +#include "timebars.h" #define DEFAULT_VIEWWINDOW (Tan(DEGTORAD(CDraw::GetFOV() * 0.5f))) @@ -90,7 +91,6 @@ void DoFade(void); void Render2dStuffAfterFade(void); CSprite2d *LoadSplash(const char *name); -void DestroySplashScreen(void); extern void (*DebugMenuProcess)(void); @@ -142,6 +142,11 @@ Idle(void *arg) #endif CTimer::Update(); + +#ifdef TIMEBARS + tbInit(); +#endif + CSprite2d::InitPerFrame(); CFont::InitPerFrame(); @@ -156,16 +161,39 @@ Idle(void *arg) FrontEndMenuManager.Process(); } else { CPointLights::InitPerFrame(); +#ifdef TIMEBARS + tbStartTimer(0, "CGame::Process");
+#endif CGame::Process(); +#ifdef TIMEBARS + tbEndTimer("CGame::Process"); + tbStartTimer(0, "DMAudio.Service");
+#endif DMAudio.Service(); + +#ifdef TIMEBARS + tbEndTimer("DMAudio.Service");
+#endif } if (RsGlobal.quit) return; #else CPointLights::InitPerFrame(); +#ifdef TIMEBARS + tbStartTimer(0, "CGame::Process");
+#endif CGame::Process(); +#ifdef TIMEBARS + tbEndTimer("CGame::Process"); + tbStartTimer(0, "DMAudio.Service");
+#endif + DMAudio.Service(); + +#ifdef TIMEBARS + tbEndTimer("DMAudio.Service");
+#endif #endif if(CGame::bDemoMode && CTimer::GetTimeInMilliseconds() > (3*60 + 30)*1000 && !CCutsceneMgr::IsCutsceneProcessing()){ @@ -193,8 +221,18 @@ Idle(void *arg) RsMouseSetPos(&pos); } #endif +#ifdef TIMEBARS + tbStartTimer(0, "CnstrRenderList");
+#endif CRenderer::ConstructRenderList(); +#ifdef TIMEBARS + tbEndTimer("CnstrRenderList"); + tbStartTimer(0, "PreRender");
+#endif CRenderer::PreRender(); +#ifdef TIMEBARS + tbEndTimer("PreRender");
+#endif if(CWeather::LightningFlash && !CCullZones::CamNoRain()){ if(!DoRWStuffStartOfFrame_Horizon(255, 255, 255, 255, 255, 255, 255)) @@ -212,16 +250,31 @@ Idle(void *arg) RwCameraSetFarClipPlane(Scene.camera, CTimeCycle::GetFarClip()); RwCameraSetFogDistance(Scene.camera, CTimeCycle::GetFogStart()); +#ifdef TIMEBARS + tbStartTimer(0, "RenderScene");
+#endif RenderScene(); +#ifdef TIMEBARS + tbEndTimer("RenderScene");
+#endif RenderDebugShit(); RenderEffects(); +#ifdef TIMEBARS
+ tbStartTimer(0, "RenderMotionBlur");
+#endif if((TheCamera.m_BlurType == MBLUR_NONE || TheCamera.m_BlurType == MBLUR_NORMAL) && TheCamera.m_ScreenReductionPercentage > 0.0f) TheCamera.SetMotionBlurAlpha(150); TheCamera.RenderMotionBlur(); - +#ifdef TIMEBARS + tbEndTimer("RenderMotionBlur"); + tbStartTimer(0, "Render2dStuff");
+#endif Render2dStuff(); +#ifdef TIMEBARS + tbEndTimer("Render2dStuff");
+#endif }else{ float viewWindow = DEFAULT_VIEWWINDOW; #ifdef ASPECT_RATIO_SCALE @@ -239,10 +292,29 @@ Idle(void *arg) if (FrontEndMenuManager.m_bMenuActive) DefinedState(); #endif +#ifdef TIMEBARS + tbStartTimer(0, "RenderMenus");
+#endif RenderMenus(); +#ifdef TIMEBARS + tbEndTimer("RenderMenus"); + tbStartTimer(0, "DoFade");
+#endif DoFade(); +#ifdef TIMEBARS + tbEndTimer("DoFade"); + tbStartTimer(0, "Render2dStuff-Fade");
+#endif Render2dStuffAfterFade(); +#ifdef TIMEBARS + tbEndTimer("Render2dStuff-Fade");
+#endif CCredits::Render(); + +#ifdef TIMEBARS + tbDisplay(); +#endif + DoRWStuffEndOfFrame(); // if(g_SlowMode) @@ -325,8 +397,9 @@ DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 void DoRWStuffEndOfFrame(void) { + CDebug::DisplayScreenStrings(); // custom CDebug::DebugDisplayTextBuffer(); - // FlushObrsPrintfs(); + FlushObrsPrintfs(); RwCameraEndUpdate(Scene.camera); RsCameraShowRaster(Scene.camera); } diff --git a/src/core/main.h b/src/core/main.h index 570189b3..5e9401b9 100644 --- a/src/core/main.h +++ b/src/core/main.h @@ -28,6 +28,7 @@ void InitialiseGame(void); void LoadingScreen(const char *str1, const char *str2, const char *splashscreen); void LoadingIslandScreen(const char *levelName); CSprite2d *LoadSplash(const char *name); +void DestroySplashScreen(void); char *GetLevelSplashScreen(int level); char *GetRandomSplashScreen(void); void LittleTest(void); diff --git a/src/core/obrstr.cpp b/src/core/obrstr.cpp new file mode 100644 index 00000000..3663d134 --- /dev/null +++ b/src/core/obrstr.cpp @@ -0,0 +1,119 @@ +#include "common.h"
+#include "Debug.h"
+#include "obrstr.h"
+
+char obrstr[128];
+char obrstr2[128];
+
+void ObrInt(int32 n1)
+{
+ IntToStr(n1, obrstr);
+ CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt2(int32 n1, int32 n2)
+{
+ IntToStr(n1, obrstr);
+ strcat(obrstr, " ");
+ IntToStr(n2, obrstr2);
+ strcat(obrstr, obrstr2);
+ CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt3(int32 n1, int32 n2, int32 n3)
+{
+ IntToStr(n1, obrstr);
+ strcat(obrstr, " ");
+ IntToStr(n2, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n3, obrstr2);
+ strcat(obrstr, obrstr2);
+ CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt4(int32 n1, int32 n2, int32 n3, int32 n4)
+{
+ IntToStr(n1, obrstr);
+ strcat(obrstr, " ");
+ IntToStr(n2, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n3, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n4, obrstr2);
+ strcat(obrstr, obrstr2);
+ CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt5(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5)
+{
+ IntToStr(n1, obrstr);
+ strcat(obrstr, " ");
+ IntToStr(n2, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n3, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n4, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n5, obrstr2);
+ strcat(obrstr, obrstr2);
+ CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt6(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6)
+{
+ IntToStr(n1, obrstr);
+ strcat(obrstr, " ");
+ IntToStr(n2, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n3, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n4, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n5, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n6, obrstr2);
+ strcat(obrstr, obrstr2);
+ CDebug::DebugAddText(obrstr);
+}
+
+void IntToStr(int32 inNum, char *outStr)
+{
+ bool isNeg = inNum < 0;
+
+ if (isNeg) {
+ inNum = -inNum;
+ *outStr = '-';
+ }
+
+ int16 digits = 1;
+
+ if (inNum > 9) {
+ int32 _inNum = inNum;
+ do {
+ digits++;
+ _inNum /= 10;
+ } while (_inNum > 9);
+ }
+
+ int32 strSize = digits;
+ if (isNeg)
+ strSize++;
+
+ char *pStr = &outStr[strSize];
+ int32 i = 0;
+ do {
+ *(pStr-- - 1) = (inNum % 10) + '0';
+ inNum /= 10;
+ } while (++i < strSize);
+ outStr[strSize] = '\0';
+}
\ No newline at end of file diff --git a/src/core/obrstr.h b/src/core/obrstr.h new file mode 100644 index 00000000..6838afb5 --- /dev/null +++ b/src/core/obrstr.h @@ -0,0 +1,9 @@ +#pragma once
+
+void ObrInt(int32 n1);
+void ObrInt2(int32 n1, int32 n2);
+void ObrInt3(int32 n1, int32 n2, int32 n3);
+void ObrInt4(int32 n1, int32 n2, int32 n3, int32 n4);
+void ObrInt5(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5);
+void ObrInt6(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6);
+void IntToStr(int32 inNum, char *outStr);
\ No newline at end of file diff --git a/src/core/patcher.cpp b/src/core/patcher.cpp index 5fdbdf8b..19ca5f07 100644 --- a/src/core/patcher.cpp +++ b/src/core/patcher.cpp @@ -1,6 +1,11 @@ #include "common.h" #include "patcher.h" +#include <algorithm> +#include <vector> + +#include <Windows.h> + StaticPatcher *StaticPatcher::ms_head; StaticPatcher::StaticPatcher(Patcher func) @@ -20,3 +25,55 @@ StaticPatcher::Apply() } ms_head = nil; } + +std::vector<uint32> 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 value == address; })) { + debug("Used address %#06x twice when injecting hook\n", address); + } + + usedAddresses.push_back(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*)(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]); +}
\ No newline at end of file diff --git a/src/core/patcher.h b/src/core/patcher.h index 87a6bea4..2722b6fd 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,30 @@ 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) +template <typename T> inline void +InjectHook(uintptr_t address, T hook, unsigned int nType = PATCH_NOTHING) { - if(std::any_of(usedAddresses.begin(), usedAddresses.end(), - [address](AT value) { return (int32)value == address; })) { - debug("Used address %#06x twice when injecting hook\n", address); - } - - usedAddresses.push_back((int32)address); - - DWORD dwProtect[2]; - switch ( nType ) - { - case PATCH_JUMP: - VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); - *(BYTE*)address = 0xE9; - break; - case PATCH_CALL: - VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); - *(BYTE*)address = 0xE8; - break; - default: - VirtualProtect((void*)((DWORD)address + 1), 4, PAGE_EXECUTE_READWRITE, &dwProtect[0]); - break; - } - DWORD dwHook; - _asm - { - mov eax, hook - mov dwHook, eax - } - - *(ptrdiff_t*)((DWORD)address + 1) = (DWORD)dwHook - (DWORD)address - 5; - if ( nType == PATCH_NOTHING ) - VirtualProtect((void*)((DWORD)address + 1), 4, dwProtect[0], &dwProtect[1]); - else - VirtualProtect((void*)address, 5, dwProtect[0], &dwProtect[1]); + InjectHook_internal(address, reinterpret_cast<uintptr_t>((void *&)hook), nType); } inline void ExtractCall(void *dst, uint32_t a) diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 6f0a4682..6d4ff252 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -20,12 +20,10 @@ #include "debugmenu_public.h" #include "Particle.h" #include "Console.h" +#include "Debug.h" -#include <vector> #include <list> -std::vector<int32> usedAddresses; - void **rwengine = *(void***)0x5A10E1; DebugMenuAPI gDebugMenuAPI; @@ -114,13 +112,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 +131,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 +202,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 +369,21 @@ DebugMenuPopulate(void) DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start); DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop); - + + extern bool PrintDebugCode; + extern int16 &DebugCamMode; + DebugMenuAddVarBool8("Cam", "Use mouse Cam", (int8*)&CCamera::m_bUseMouse3rdPerson, nil); +#ifdef FREE_CAM + DebugMenuAddVarBool8("Cam", "Free Cam", (int8*)&CCamera::bFreeCam, nil); +#endif + 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 +458,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/core/timebars.cpp b/src/core/timebars.cpp new file mode 100644 index 00000000..30421731 --- /dev/null +++ b/src/core/timebars.cpp @@ -0,0 +1,121 @@ +#ifndef MASTER
+#include "common.h"
+#include "Font.h"
+#include "Frontend.h"
+#include "Timer.h"
+#include "Text.h"
+
+#define MAX_TIMERS (50)
+#define MAX_MS_COLLECTED (40)
+
+// enables frame time output
+#define FRAMETIME
+
+struct sTimeBar
+{
+ char name[20];
+ float startTime;
+ float endTime;
+ int32 unk;
+};
+
+struct
+{
+ sTimeBar Timers[MAX_TIMERS];
+ uint32 count;
+} TimerBar;
+float MaxTimes[MAX_TIMERS];
+float MaxFrameTime;
+
+uint32 curMS;
+uint32 msCollected[MAX_MS_COLLECTED];
+#ifdef FRAMETIME
+float FrameInitTime;
+#endif
+
+void tbInit()
+{
+ TimerBar.count = 0;
+ uint32 i = CTimer::GetFrameCounter() & 0x7F;
+ if (i == 0) {
+ do
+ MaxTimes[i++] = 0.0f;
+ while (i != MAX_TIMERS);
+#ifdef FRAMETIME
+ MaxFrameTime = 0.0f;
+#endif
+ }
+#ifdef FRAMETIME
+ FrameInitTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
+#endif
+}
+
+void tbStartTimer(int32 unk, char *name)
+{
+ strcpy(TimerBar.Timers[TimerBar.count].name, name);
+ TimerBar.Timers[TimerBar.count].unk = unk;
+ TimerBar.Timers[TimerBar.count].startTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
+ TimerBar.count++;
+}
+
+void tbEndTimer(char* name)
+{
+ uint32 n = 1500;
+ for (uint32 i = 0; i < TimerBar.count; i++) {
+ if (strcmp(name, TimerBar.Timers[i].name) == 0)
+ n = i;
+ }
+ assert(n != 1500);
+ TimerBar.Timers[n].endTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
+}
+
+float Diag_GetFPS()
+{
+ return 39000.0f / (msCollected[(curMS - 1) % MAX_MS_COLLECTED] - msCollected[curMS % MAX_MS_COLLECTED]);
+}
+
+void tbDisplay()
+{
+ char temp[200];
+ wchar wtemp[200];
+
+#ifdef FRAMETIME
+ float FrameEndTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
+#endif
+
+ msCollected[(curMS++) % MAX_MS_COLLECTED] = RsTimer();
+ CFont::SetBackgroundOff();
+ CFont::SetBackgroundColor(CRGBA(0, 0, 0, 128));
+ CFont::SetScale(0.48f, 1.12f);
+ CFont::SetCentreOff();
+ CFont::SetJustifyOff();
+ CFont::SetWrapx(640.0f);
+ CFont::SetRightJustifyOff();
+ CFont::SetPropOn();
+ CFont::SetFontStyle(FONT_BANK);
+ sprintf(temp, "FPS: %.2f", Diag_GetFPS());
+ AsciiToUnicode(temp, wtemp);
+ CFont::SetColor(CRGBA(255, 255, 255, 255));
+ if (!CMenuManager::m_PrefsMarketing || !CMenuManager::m_PrefsDisableTutorials) {
+ CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * (4.0f / DEFAULT_SCREEN_HEIGHT), wtemp);
+
+#ifndef FINAL
+ // Timers output (my own implementation)
+ for (uint32 i = 0; i < TimerBar.count; i++) {
+ MaxTimes[i] = max(MaxTimes[i], TimerBar.Timers[i].endTime - TimerBar.Timers[i].startTime);
+ sprintf(temp, "%s: %.2f", &TimerBar.Timers[i].name[0], MaxTimes[i]);
+ AsciiToUnicode(temp, wtemp);
+ CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * ((8.0f * (i + 2)) / DEFAULT_SCREEN_HEIGHT), wtemp);
+ }
+
+#ifdef FRAMETIME
+ MaxFrameTime = max(MaxFrameTime, FrameEndTime - FrameInitTime);
+ sprintf(temp, "Frame Time: %.2f", MaxFrameTime);
+ AsciiToUnicode(temp, wtemp);
+
+ CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * ((8.0f * (TimerBar.count + 4)) / DEFAULT_SCREEN_HEIGHT), wtemp);
+#endif // FRAMETIME
+#endif // !FINAL
+ }
+}
+#endif // !MASTER
\ No newline at end of file diff --git a/src/core/timebars.h b/src/core/timebars.h new file mode 100644 index 00000000..8ffccd8e --- /dev/null +++ b/src/core/timebars.h @@ -0,0 +1,6 @@ +#pragma once
+
+void tbInit();
+void tbStartTimer(int32, char*);
+void tbEndTimer(char*);
+void tbDisplay();
\ No newline at end of file |