#include "common.h" #include "main.h" #include "Draw.h" #include "World.h" #include "Vehicle.h" #include "Automobile.h" #include "Boat.h" #include "Bones.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 "Timecycle.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" #include "Bike.h" #include "Pickups.h" bool PrintDebugCode = false; int16 DebugCamMode; extern float fRangePlayerRadius; extern float fCloseNearClipLimit; #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 = false; m_iDoCollisionChecksOnFrameNum = 1; m_iDoCollisionCheckEveryNumOfFrames = 9; m_iFrameNumWereAt = 0; m_bCollisionChecksOn = false; 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 = nil; m_pLastPedLookedAt = nil; ResetStatics = true; Beta = 0.0f; m_fTilt = 0.0f; m_fTiltSpeed = 0.0f; m_bFixingBeta = false; CA_MIN_DISTANCE = 0.0f; CA_MAX_DISTANCE = 0.0f; LookingBehind = false; LookingLeft = false; LookingRight = false; m_fPlayerInFrontSyphonAngleOffSet = DEGTORAD(20.0f); m_fSyphonModeTargetZOffSet = 0.5f; m_fRadiusForDead = 1.5f; DirectionWasLooking = LOOKING_FORWARD; LookBehindCamWasInFront = false; 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; } float PLAYERPED_LEVEL_SMOOTHING_CONST_INV = 0.6f; float PLAYERPED_TREND_SMOOTHING_CONST_INV = 0.8f; void CCam::Process(void) { CVector CameraTarget; float TargetSpeedVar = 0.0f; float TargetOrientation = 0.0f; static CVector SmoothedPos(0.0f, 0.0f, 10000.0f); static CVector SmoothedSpeed(0.0f, 0.0f, 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); /* LCS: removed CVector Fwd(0.0f, 0.0f, 0.0f); Fwd.x = CamTargetEntity->GetForward().x; Fwd.y = CamTargetEntity->GetForward().y; Fwd.Normalise(); float FwdLength = Fwd.Magnitude2D(); if(FwdLength != 0.0f){ Fwd.x /= FwdLength; Fwd.y /= FwdLength; } 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; */ SpeedVar = 0.0f; TargetSpeedVar = 0.0f; }else{ if(CamTargetEntity == FindPlayerPed()){ // Some fancy smoothing of player position and speed float LevelSmoothing = 1.0f - Pow(PLAYERPED_LEVEL_SMOOTHING_CONST_INV, CTimer::GetTimeStep()); float TrendSmoothing = 1.0f - Pow(PLAYERPED_TREND_SMOOTHING_CONST_INV, CTimer::GetTimeStep()); CVector NewSmoothedPos, NewSmoothedSpeed; if((SmoothedPos - CamTargetEntity->GetPosition()).MagnitudeSqr() > SQR(3.0f) || CTimer::GetTimeStep() < 0.2f || Using3rdPersonMouseCam()){ // Reset values NewSmoothedPos = CamTargetEntity->GetPosition(); NewSmoothedSpeed = CVector(0.0f, 0.0f, 0.0f); }else{ NewSmoothedPos = LevelSmoothing*CamTargetEntity->GetPosition() + (1.0f-LevelSmoothing)*(SmoothedPos + SmoothedSpeed*CTimer::GetTimeStep()); NewSmoothedSpeed = TrendSmoothing*(NewSmoothedPos-SmoothedPos)/CTimer::GetTimeStep() + (1.0f-TrendSmoothing)*SmoothedSpeed; } CameraTarget = NewSmoothedPos; SmoothedPos = NewSmoothedPos; SmoothedSpeed = NewSmoothedSpeed; }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: #ifdef PC_PLAYER_CONTROLS if(CCamera::m_bUseMouse3rdPerson) Process_FollowPedWithMouse(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); else #endif #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: case MODE_CAMERA: 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: // case MODE_FOLLOW_PED_WITH_BIND: // case MODE_CHRIS: 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: 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_LIGHTHOUSE: Process_LightHouse(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; #ifdef GTA_SCENE_EDIT case MODE_EDITOR: Process_Editor(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); break; #endif 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(DistOnGround, TargetToCam.z); 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 || Mode == MODE_BEHINDCAR) && CamTargetEntity->IsVehicle()){ bool bDisableLR = CamTargetEntity && (((CVehicle*)CamTargetEntity)->GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI || CamTargetEntity->GetModelIndex() == MI_RCBARON); if(CPad::GetPad(0)->GetLookBehindForCar()){ LookBehind(); if(DirectionWasLooking != LOOKING_BEHIND) TheCamera.m_bJust_Switched = true; DirectionWasLooking = LOOKING_BEHIND; }else if(bDisableLR){ if(DirectionWasLooking != LOOKING_FORWARD) TheCamera.m_bJust_Switched = true; DirectionWasLooking = LOOKING_FORWARD; }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 || Mode == MODE_CAMERA || 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; bool StandingOnBoat = false; static bool PreviouslyFailedRoadHeightCheck = false; CVector CamToTarget, CamToPed; float DistOnGround, BetaAngle; CPed *Player; float PedZDist; CColPoint colPoint; CamToTarget = TheCamera.pTargetEntity->GetPosition() - TheCamera.GetGameCamPosition(); DistOnGround = CamToTarget.Magnitude2D(); BetaAngle = CGeneral::GetATanOfXY(CamToTarget.x, CamToTarget.y); m_bTheHeightFixerVehicleIsATrain = false; // 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; float FoundPedZ = -100.0f; // Move up the camera if there is a ped close to it if(Mode == MODE_FOLLOWPED || Mode == MODE_FIGHT_CAM || Mode == MODE_PILLOWS_PAPS){ // Find highest ped close to camera for(i = 0; i < Player->m_numNearPeds; i++){ CPed *nearPed = Player->m_nearPeds[i]; if(nearPed && nearPed->GetPedState() != PED_DEAD){ CamToPed = nearPed->GetPosition() - TheCamera.GetGameCamPosition(); if(Abs(CamToPed.z) < 1.0f){ float DistSq = CamToPed.MagnitudeSqr(); if(DistSq < SQR(2.1f)){ if(nearPed->GetPosition().z > FoundPedZ) FoundPedZ = nearPed->GetPosition().z; }else{ float Dist = Sqrt(DistSq); CamToPed /= Dist; // strange calculation CVector PlayerCamSpeed = DotProduct(Front, Player->m_vecMoveSpeed)*Front; float SpeedDiff = DotProduct(PlayerCamSpeed - nearPed->m_vecMoveSpeed, CamToPed); if(SpeedDiff > 0.01f && (m_fPedBetweenCameraHeightOffset > 0.0f && (Dist-2.1f)/SpeedDiff < 75.0f || m_fPedBetweenCameraHeightOffset <= 0.0f && (Dist-2.1f)/SpeedDiff < 75.0f * 0.1f)) if(nearPed->GetPosition().z > FoundPedZ) FoundPedZ = nearPed->GetPosition().z; } } } } if(FoundPedZ > -99.0f){ float Offset = 0.0f; PedZDist = 0.0f; if(FoundPedZ > Player->GetPosition().z) PedZDist = FoundPedZ - Player->GetPosition().z; if(Mode == MODE_FOLLOWPED){ if(TheCamera.PedZoomIndicator == CAM_ZOOM_1 && ((CPed*)CamTargetEntity)->GetPedState() != PED_ENTER_CAR && ((CPed*)CamTargetEntity)->GetPedState() != PED_CARJACK) Offset = 0.45f + PedZDist; // BUG: overrides this ^ case if(TheCamera.PedZoomIndicator == CAM_ZOOM_2 || TheCamera.PedZoomIndicator == CAM_ZOOM_1) Offset = 0.35f + PedZDist; if(TheCamera.PedZoomIndicator == CAM_ZOOM_3) Offset = 0.25f + PedZDist; m_fPedBetweenCameraHeightOffset = Offset + 1.3f; }else if(Mode == MODE_FIGHT_CAM) m_fPedBetweenCameraHeightOffset = PedZDist + 1.3f + 0.5f; else if(Mode == MODE_PILLOWS_PAPS) m_fPedBetweenCameraHeightOffset = PedZDist + 1.3f + 0.45f; }else{ m_fPedBetweenCameraHeightOffset = 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; if(m_fDimensionOfHighestNearCar > 0.0f) TestDist += 0.3f; 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; } } if(StandingOnBoat){ 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); } bool CCam::GetBoatLook_L_R_HeightOffset(float &Offset) { if(CamTargetEntity == nil) return false; CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex()); tBoatHandlingData *handling = mod_HandlingManager.GetBoatPointer(mi->m_handlingId); if(handling){ Offset = handling->fLook_L_R_BehindCamHeight; return true; } return false; // can't happen, we always get a boat pointer back } void CCam::LookBehind(void) { float Dist, DeltaBeta, TargetOrientation, Angle; CVector TargetCoors, TargetFwd, TestCoors; TargetCoors = CamTargetEntity->GetPosition(); Front = CamTargetEntity->GetPosition() - Source; if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_BEHINDBOAT || Mode == MODE_BEHINDCAR) && 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; CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, TargetCoors, Source, FOV); 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; if(((CVehicle*)CamTargetEntity)->GetVehicleAppearance() == VEHICLE_APPEARANCE_BIKE){ float FrontDist = 1.1f; if(((CVehicle*)CamTargetEntity)->pDriver){ CVector ExtraFwd(0.0f, 0.0f, 0.0f); ((CVehicle*)CamTargetEntity)->pDriver->m_pedIK.GetComponentPosition(ExtraFwd, PED_HEAD); ExtraFwd += ((CVehicle*)CamTargetEntity)->m_vecMoveSpeed*CTimer::GetTimeStep() - CamTargetEntity->GetPosition(); FrontDist += 0.2f + Max(DotProduct(ExtraFwd, CamTargetEntity->GetForward()), 0.0f); } Source += FrontDist*Front; Front = -Front; }else if(((CVehicle*)CamTargetEntity)->GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI){ Front = -1.0f*CamTargetEntity->GetUp(); Up = CamTargetEntity->GetForward(); Source += 0.25f*Front; }else{ Source += 0.25f*Front; Front = -Front; } } 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; CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, TargetCoors, Source, FOV); Front = TargetCoors - Source; GetVectorsReadyForRW(); } } float BOAT_1STPERSON_L_OFFSETX = 0.7f; float BOAT_1STPERSON_R_OFFSETX = 0.3f; float BOAT_1STPERSON_LR_OFFSETZ = 0.2f; void CCam::LookLeft(void) { float Dist, TargetOrientation; CVector TargetCoors, TargetFwd; if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_BEHINDBOAT || Mode == MODE_BEHINDCAR) && CamTargetEntity->IsVehicle()){ LookingLeft = true; TargetCoors = CamTargetEntity->GetPosition(); Front = CamTargetEntity->GetPosition() - Source; if(Mode == MODE_CAM_ON_A_STRING) Dist = CA_MAX_DISTANCE; else if(Mode == MODE_BEHINDBOAT){ Dist = 9.0f; float Offset = 0.0f; if(GetBoatLook_L_R_HeightOffset(Offset) && !CCullZones::Cam1stPersonForPlayer()) Source.z = TargetCoors.z + Offset; }else Dist = 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; CColModel *colModel = CamTargetEntity->GetColModel(); CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, TargetCoors, Source, FOV); CVector TopRight = CamTargetEntity->GetPosition() + CamTargetEntity->GetRight()*colModel->boundingBox.max.x + CamTargetEntity->GetUp()*colModel->boundingBox.max.z; float Height = Min(Max(m_cvecTargetCoorsForFudgeInter.z, TopRight.z)+0.1f, OrigSource.z); Source.z = Max(Height, Source.z); 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()){ if(((CVehicle*)CamTargetEntity)->pDriver){ CVector neck(0.0f, 0.0f, 0.0f); CPed *driver = ((CVehicle*)CamTargetEntity)->pDriver; driver->SetPedPositionInCar(); driver->GetMatrix().UpdateRW(); driver->UpdateRwFrame(); driver->UpdateRpHAnim(); driver->m_pedIK.GetComponentPosition(neck, PED_NECK); Source = neck + BOAT_1STPERSON_L_OFFSETX*CamTargetEntity->GetRight() + BOAT_1STPERSON_LR_OFFSETZ*CamTargetEntity->GetUp(); }else Source.z -= 0.5f; } Up = CamTargetEntity->GetUp(); Up.Normalise(); Front = CamTargetEntity->GetForward(); Front.Normalise(); Front = -CrossProduct(Front, Up); Front.Normalise(); if(((CVehicle*)CamTargetEntity)->GetVehicleAppearance() == VEHICLE_APPEARANCE_BIKE) Source -= 1.45f*Front; } } void CCam::LookRight(void) { float Dist, TargetOrientation; CVector TargetCoors, TargetFwd; CColPoint colPoint; if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_BEHINDBOAT) && CamTargetEntity->IsVehicle()){ LookingRight = true; TargetCoors = CamTargetEntity->GetPosition(); Front = CamTargetEntity->GetPosition() - Source; if(Mode == MODE_CAM_ON_A_STRING) Dist = CA_MAX_DISTANCE; else if(Mode == MODE_BEHINDBOAT){ Dist = 9.0f; float Offset = 0.0f; if(GetBoatLook_L_R_HeightOffset(Offset) && !CCullZones::Cam1stPersonForPlayer()) Source.z = TargetCoors.z + Offset; }else Dist = 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; CColModel *colModel = CamTargetEntity->GetColModel(); CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, TargetCoors, Source, FOV); CVector TopLeft = CamTargetEntity->GetPosition() + CamTargetEntity->GetRight()*colModel->boundingBox.min.x + CamTargetEntity->GetUp()*colModel->boundingBox.max.z; float Height = Min(Max(m_cvecTargetCoorsForFudgeInter.z, TopLeft.z)+0.1f, OrigSource.z); Source.z = Max(Height, Source.z); 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()){ if(((CVehicle*)CamTargetEntity)->pDriver){ CVector neck(0.0f, 0.0f, 0.0f); CPed *driver = ((CVehicle*)CamTargetEntity)->pDriver; driver->SetPedPositionInCar(); driver->GetMatrix().UpdateRW(); driver->UpdateRwFrame(); driver->UpdateRpHAnim(); driver->m_pedIK.GetComponentPosition(neck, PED_NECK); Source = neck + BOAT_1STPERSON_R_OFFSETX*CamTargetEntity->GetRight() + BOAT_1STPERSON_LR_OFFSETZ*CamTargetEntity->GetUp(); }else Source.z -= 0.5f; } Up = CamTargetEntity->GetUp(); Up.Normalise(); Front = CamTargetEntity->GetForward(); Front.Normalise(); Front = CrossProduct(Front, Up); Front.Normalise(); if(((CVehicle*)CamTargetEntity)->GetVehicleAppearance() == VEHICLE_APPEARANCE_BIKE) Source -= 1.45f*Front; } } 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 = vDist.Magnitude2D(); 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 = source - PreviousSource; m_cvecTargetSpeedOverOneFrame = target - PreviousTarget; m_cvecUpOverOneFrame = up - PreviousUp; 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; } bool CCam::GetWeaponFirstPersonOn(void) { return CamTargetEntity && CamTargetEntity->IsPed() && ((CPed*)CamTargetEntity)->GetWeapon()->m_bAddRotOffset; } bool CCam::IsTargetInWater(const CVector &CamCoors) { if(CamTargetEntity){ float WaterZ = -6000.0f; CWaterLevel::GetWaterLevel(CamTargetEntity->GetPosition(), &WaterZ, false); if(CamTargetEntity->IsPed()){ if(((CPed*)CamTargetEntity)->bIsDrowning || ((CPed*)CamTargetEntity)->bIsInWater && CamTargetEntity->GetPosition().z < WaterZ) return true; }else{ assert(CamTargetEntity->IsVehicle()); if(((CVehicle*)CamTargetEntity)->bIsDrowning || ((CVehicle*)CamTargetEntity)->bIsInWater && CamTargetEntity->GetPosition().z < WaterZ) return true; } } m_vecLastAboveWaterCamPosition = Source; return false; } void CCam::PrintMode(void) { // Doesn't do anything char buf[256]; if(PrintDebugCode){ sprintf(buf, " "); sprintf(buf, " "); sprintf(buf, " "); static Const 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", "Lighthouse", "Sniper run about", "Rocket run about", "1st Person run about", "M16 run about", "Fight run about", "Editor", "Helicannon", "Camera" }; 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 = CVector(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; } float DefaultAcceleration = 0.045f; float DefaultMaxStep = 0.15f; float fDefaultSpeedStep = 0.025f; float fDefaultSpeedMultiplier = 0.09f; float fDefaultSpeedLimit = 0.15f; float fDefaultSpeedStep4Avoid = 0.02f; float fDefaultSpeedMultiplier4Avoid = 0.05f; float fDefaultSpeedLimit4Avoid = 0.25f; float fAvoidGeomThreshhold = 1.5f; float fMiniGunBetaOffset = 0.3f; void CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float) { if(!CamTargetEntity->IsPed()) return; CVector TargetCoors, Dist, IdealSource; float Length = 0.0f; static bool PickedASide; static float FixedTargetOrientation = 0.0f; float AngleToGoTo = 0.0f; bool StandingInTrain = false; float ZoomGroundTarget = 0.0f; float ZoomZTarget = 0.0f; static int TimeIndicatedWantedToGoDown = 0; static bool StartedCountingForGoDown = false; static float ZoomGround = 0.0f; static float ZoomGroundSpeed = 0.0f; static float ZoomZ = 0.0f; static float ZoomZSpeed = 0.0f; float DeltaBeta; m_bFixingBeta = false; bBelowMinDist = false; bBehindPlayerDesired = false; FOV = DefaultFOV; if(ResetStatics){ Rotating = false; m_bCollisionChecksOn = true; FixedTargetOrientation = 0.0f; PickedASide = false; StartedCountingForGoDown = false; AngleToGoTo = 0.0f; ZoomGround = 0.0f; ZoomGroundSpeed = 0.0f; ZoomZ = 0.0f; ZoomZSpeed = 0.0f; Distance = 500.0f; } TargetCoors = CameraTarget; // Take speed of thing we're standing on into account CVector GroundMovement(0.0f, 0.0f, 0.0f); CPhysical *ground = (CPhysical*)((CPed*)CamTargetEntity)->m_pCurSurface; if(ground && (ground->IsVehicle() || ground->IsObject())) GroundMovement += ground->GetSpeed(CamTargetEntity->GetPosition() - ground->GetPosition()) * CTimer::GetTimeStep(); Source += GroundMovement; IdealSource = Source; TargetCoors.z += m_fSyphonModeTargetZOffSet; TargetCoors.z = DoAverageOnVector(TargetCoors).z; 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 * m_fMinRealGroundDist; IdealSource.z += GroundMovement.z; }else IdealSource = TargetCoors + CVector(1.0f, 1.0f, 0.0f); if(TheCamera.m_bUseTransitionBeta && ResetStatics){ CVector VecDistance; IdealSource.x = TargetCoors.x + m_fMinRealGroundDist*Cos(m_fTransitionBeta); IdealSource.y = TargetCoors.y + m_fMinRealGroundDist*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) StandingInTrain = true; if(TheCamera.m_bCamDirectlyInFront){ m_bCollisionChecksOn = true; Beta = TargetOrientation; } while(Beta >= PI) Beta -= 2.0f * PI; while(Beta < -PI) Beta += 2.0f * PI; if(TheCamera.PedZoomIndicator == CAM_ZOOM_1 && ((CPed*)CamTargetEntity)->GetPedState() != PED_ENTER_CAR && ((CPed*)CamTargetEntity)->GetPedState() != PED_CARJACK){ ZoomGroundTarget = m_fTargetZoomGroundOne; ZoomZTarget = m_fTargetZoomOneZExtra; }else if(TheCamera.PedZoomIndicator == CAM_ZOOM_2 || TheCamera.PedZoomIndicator == CAM_ZOOM_1){ ZoomGroundTarget = m_fTargetZoomGroundTwo; ZoomZTarget = m_fTargetZoomTwoZExtra; }else if(TheCamera.PedZoomIndicator == CAM_ZOOM_3){ ZoomGroundTarget = m_fTargetZoomGroundThree; ZoomZTarget = m_fTargetZoomThreeZExtra; } if(m_fCloseInPedHeightOffset > 0.00001f){ ZoomGroundTarget = m_fTargetCloseInDist; ZoomZTarget = m_fTargetZoomZCloseIn; } if(ResetStatics){ ZoomGround = ZoomGroundTarget; ZoomZ = ZoomZTarget; } float SpeedStep = fDefaultSpeedStep; float SpeedMultiplier = fDefaultSpeedMultiplier; float SpeedLimit = fDefaultSpeedLimit; 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; // Figure out if and where we want to rotate if(CPad::GetPad(0)->ForceCameraBehindPlayer() && !CPickups::PlayerOnWeaponPickup || Shooting){ // Center cam behind player if(PickedASide){ if(AngleToGoTo == 0.0f){ FixedTargetOrientation = TargetOrientation + PI; if(Shooting && ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_MINIGUN) FixedTargetOrientation -= fMiniGunBetaOffset; } Rotating = true; }else{ FixedTargetOrientation = TargetOrientation + PI; Rotating = true; PickedASide = true; if(Shooting && ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_MINIGUN) FixedTargetOrientation -= fMiniGunBetaOffset; } }else if(Abs(TheCamera.m_fAvoidTheGeometryProbsTimer) > fAvoidGeomThreshhold && !Rotating ){ if(TheCamera.m_fAvoidTheGeometryProbsTimer < 0.0f) FixedTargetOrientation = TargetOrientation; else FixedTargetOrientation = TargetOrientation + PI; float dist = (Source - TargetCoors).Magnitude(); float mult = dist > 0.1f ? 1.0f/dist : 10.0f; SpeedStep = mult * fDefaultSpeedStep4Avoid; SpeedMultiplier = mult * fDefaultSpeedMultiplier4Avoid; SpeedLimit = mult * fDefaultSpeedLimit4Avoid; } int MoveState = ((CPed*)CamTargetEntity)->m_nMoveState; if(MoveState != PEDMOVE_NONE && MoveState != PEDMOVE_STILL && !(CPad::GetPad(0)->ForceCameraBehindPlayer() && !CPickups::PlayerOnWeaponPickup) && !Shooting){ Rotating = false; if(TheCamera.m_fAvoidTheGeometryProbsTimer <= fAvoidGeomThreshhold) BetaSpeed = 0.0f; } // Now do the Beta rotation float RotDistance = m_fMinRealGroundDist; if(Rotating || TheCamera.m_fAvoidTheGeometryProbsTimer > fAvoidGeomThreshhold){ 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 - unfortunately modified so we can't just call it { DeltaBeta = FixedTargetOrientation - Beta; while(DeltaBeta >= PI) DeltaBeta -= 2*PI; while(DeltaBeta < -PI) DeltaBeta += 2*PI; // this is the added bit if(!Rotating){ if(TheCamera.m_nAvoidTheGeometryProbsDirn == -1 && DeltaBeta > 0.0f || TheCamera.m_nAvoidTheGeometryProbsDirn == 1 && DeltaBeta < 0.0f) DeltaBeta *= -1.0f; } float ReqSpeed = DeltaBeta * SpeedMultiplier; // this is also added ReqSpeed = clamp(ReqSpeed, -SpeedLimit, SpeedLimit); // 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()); } 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 || StandingInTrain || Rotating || TheCamera.m_bUseTransitionBeta && ResetStatics || Abs(TheCamera.m_fAvoidTheGeometryProbsTimer) > fAvoidGeomThreshhold){ if(TheCamera.m_bUseTransitionBeta){ Beta = m_fTransitionBeta; Source.x = TargetCoors.x + RotDistance * Cos(m_fTransitionBeta); Source.y = TargetCoors.y + RotDistance * Sin(m_fTransitionBeta); } 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(StandingInTrain){ 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; } if(StandingInTrain){ 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; } Source.z = IdealSource.z; // Zoom out camera Front = TargetCoors - Source; Front.Normalise(); WellBufferMe(ZoomGroundTarget, &ZoomGround, &ZoomGroundSpeed, 0.2f, 0.07f, false); WellBufferMe(ZoomZTarget, &ZoomZ, &ZoomZSpeed, 0.2f, 0.07f, false); Source.x -= Front.x*ZoomGround; Source.y -= Front.y*ZoomGround; Source.z += ZoomZ; // Process height offset to avoid peds and cars float TargetZOffSet = Max(m_fDimensionOfHighestNearCar, 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 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; TargetCoors.z += Min(1.0f, m_fCamBufferedHeight/2.0f); m_cvecTargetCoorsForFudgeInter = TargetCoors; CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, TargetCoors, Source, FOV); float TargetDist = (TargetCoors - Source).Magnitude(); if(TargetDist < Distance) Distance = TargetDist; else{ float f = Pow(0.97f, CTimer::GetTimeStep()); Distance = (1.0f - f)*TargetDist + f*Distance; if(TargetDist > 0.05f) Source = TargetCoors + (Source-TargetCoors)*Distance/TargetDist; float clip = Distance-fRangePlayerRadius; if(clip < RwCameraGetNearClipPlane(Scene.camera)) RwCameraSetNearClipPlane(Scene.camera, Max(clip, fCloseNearClipLimit)); } Front = TargetCoors - Source; m_fRealGroundDist = Front.Magnitude2D(); m_fMinDistAwayFromCamWhenInterPolating = m_fRealGroundDist; Front.Normalise(); GetVectorsReadyForRW(); TheCamera.m_bCamDirectlyBehind = false; TheCamera.m_bCamDirectlyInFront = false; ResetStatics = false; } float fBaseDist = 1.7f; float fAngleDist = 2.0f; float fFalloff = 3.0f; float fStickSens = 0.01f; float fTweakFOV = 1.1f; float fTranslateCamUp = 0.8f; int16 nFadeControlThreshhold = 45; float fDefaultAlphaOrient = -0.22f; float fMouseAvoidGeomReturnRate = 0.92f; 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(); TargetCoors = CameraTarget; TargetCoors.z += fTranslateCamUp; float AlphaOffset, BetaOffset; if(CPad::GetPad(0)->IsPlayerControlsDisabledBy(PLAYERCONTROL_PLAYERINFO)){ CVector ToCam = Source - TargetCoors; ToCam.Normalise(); if(ToCam.z < -0.9f) BetaOffset = TargetOrientation + PI; else BetaOffset = Atan2(ToCam.y, ToCam.x); BetaOffset -= Beta; AlphaOffset = 0.0f; }else{ // 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(); } if(UseMouse){ BetaOffset = LookLeftRight * TheCamera.m_fMouseAccelHorzntl * FOV/80.0f; AlphaOffset = LookUpDown * TheCamera.m_fMouseAccelVertical * FOV/80.0f; }else{ BetaOffset = LookLeftRight * fStickSens * (1.0f/14.0f) * FOV/80.0f * CTimer::GetTimeStep(); AlphaOffset = LookUpDown * fStickSens * (0.6f/14.0f) * FOV/80.0f * CTimer::GetTimeStep(); } } if(TheCamera.GetFading() && TheCamera.GetFadingDirection() == FADE_IN && nFadeControlThreshhold < CDraw::FadeValue || CDraw::FadeValue > 200 || CPad::GetPad(0)->IsPlayerControlsDisabledBy(PLAYERCONTROL_PLAYERINFO)){ 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); else if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f); // 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 = m_fTransitionBeta; if(TheCamera.m_bCamDirectlyBehind) Beta = TheCamera.m_PedOrientForBehindOrInFront + PI; if(TheCamera.m_bCamDirectlyInFront) Beta = TheCamera.m_PedOrientForBehindOrInFront; 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 > DEFAULT_NEAR + 0.1f){ // 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::CalculateAspectRatio() * 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; Near = RwCameraGetNearClipPlane(Scene.camera); #ifndef FIX_BUGS // this is wrong...DEGTORAD missing radius = Tan(FOV / 2.0f) * CDraw::CalculateAspectRatio() * fTweakFOV * Near; #else radius = ViewPlaneWidth*Near; #endif // Keep testing entity = CWorld::TestSphereAgainstWorld(Source + Front*Near, radius, nil, true, true, false, true, false, false); i++; if(i > 5) entity = nil; } float TargetDist = (TargetCoors - Source).Magnitude(); if(TargetDist < Distance) Distance = TargetDist; else{ float f = Pow(fMouseAvoidGeomReturnRate, CTimer::GetTimeStep()); Distance = (1.0f - f)*TargetDist + f*Distance; if(TargetDist > 0.05f) Source = TargetCoors + (Source-TargetCoors)*Distance/TargetDist; float clip = Distance-fRangePlayerRadius; if(clip < RwCameraGetNearClipPlane(Scene.camera)) RwCameraSetNearClipPlane(Scene.camera, Max(clip, fCloseNearClipLimit)); } TheCamera.m_bCamDirectlyInFront = false; TheCamera.m_bCamDirectlyBehind = false; GetVectorsReadyForRW(); if(((CPed*)CamTargetEntity)->CanStrafeOrMouseControl() && CDraw::FadeValue < 250 && (TheCamera.GetFadingDirection() != FADE_OUT || CDraw::FadeValue <= 100) && !CPad::GetPad(0)->IsPlayerControlsDisabledBy(PLAYERCONTROL_PLAYERINFO)){ float Heading = Front.Heading(); ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Heading; ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Heading; TheCamera.pTargetEntity->SetHeading(Heading); TheCamera.pTargetEntity->GetMatrix().UpdateRW(); } } float fBillsBetaOffset; // made up name, actually in CCam 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); #ifdef TOGGLEABLE_BETA_FEATURES // This is completely made up but Bill's cam manipulates an angle before calling this // and otherwise calculating Beta doesn't make much sense. Beta += fBillsBetaOffset; fBillsBetaOffset = 0.0f; Dist.x = -Length*Cos(Beta); Dist.y = -Length*Sin(Beta); Source = TargetCoors + Dist; #endif 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; Alpha = DEGTORAD(25.0f); Source.z = TargetCoors.z + CA_MAX_DISTANCE*Sin(Alpha); RotCamIfInFrontCar(TargetCoors, TargetOrientation); m_cvecTargetCoorsForFudgeInter = TargetCoors; CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, m_cvecTargetCoorsForFudgeInter, Source, FOV); Front = TargetCoors - Source; ResetStatics = false; GetVectorsReadyForRW(); } float ZmOneAlphaOffset[] = { -0.01f, 0.1f, 0.125f, -0.1f, -0.06f }; float ZmTwoAlphaOffset[] = { 0.045f, 0.12f, 0.045f, 0.045f, -0.035f }; float ZmThreeAlphaOffset[] = { 0.005f, 0.005f, 0.15f, 0.005f, 0.12f }; float INIT_RC_HELI_HORI_EXTRA = 6.0f; float INIT_RC_PLANE_HORI_EXTRA = 9.5f; float INIT_RC_HELI_ALPHA_EXTRA = 0.2f; float INIT_RC_PLANE_ALPHA_EXTRA = 0.295f; void CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight) { if(!CamTargetEntity->IsVehicle()) return; static float AlphaOffset = 0.0; static float AlphaOffsetSpeed = 0.0; static float AlphaDec = 0.0f; bool isHeli = false; bool isBike = false; int appearance = ((CVehicle*)CamTargetEntity)->GetVehicleAppearance(); if(appearance == VEHICLE_APPEARANCE_BIKE) isBike = true; if(appearance == VEHICLE_APPEARANCE_HELI) isHeli = true; int index = 0; TheCamera.GetArrPosForVehicleType(appearance, index); float ExtraOffset = 0.0f; int id = CamTargetEntity->GetModelIndex(); if(id == MI_RCRAIDER || id == MI_RCGOBLIN) ExtraOffset = INIT_RC_HELI_ALPHA_EXTRA; else if(id == MI_RCBARON) ExtraOffset = INIT_RC_PLANE_ALPHA_EXTRA; if(ResetStatics){ AlphaOffset = 0.0f; AlphaOffsetSpeed = 0.0f; AlphaDec = 0.0f; if(TheCamera.CarZoomIndicator == CAM_ZOOM_1) AlphaOffset = ZmOneAlphaOffset[index] + ExtraOffset; else if(TheCamera.CarZoomIndicator == CAM_ZOOM_2) AlphaOffset = ZmTwoAlphaOffset[index] + ExtraOffset; else if(TheCamera.CarZoomIndicator == CAM_ZOOM_3) AlphaOffset = ZmThreeAlphaOffset[index] + ExtraOffset; } if(TheCamera.CarZoomIndicator == CAM_ZOOM_1) WellBufferMe(ZmOneAlphaOffset[index] + ExtraOffset, &AlphaOffset, &AlphaOffsetSpeed, 0.17f, 0.08f, false); else if(TheCamera.CarZoomIndicator == CAM_ZOOM_2) WellBufferMe(ZmTwoAlphaOffset[index] + ExtraOffset, &AlphaOffset, &AlphaOffsetSpeed, 0.17f, 0.08f, false); else if(TheCamera.CarZoomIndicator == CAM_ZOOM_3) WellBufferMe(ZmThreeAlphaOffset[index] + ExtraOffset, &AlphaOffset, &AlphaOffsetSpeed, 0.17f, 0.08f, false); float Length = (Source - TargetCoors).Magnitude2D(); 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; float fwdSpeed = DotProduct(((CPhysical*)CamTargetEntity)->m_vecMoveSpeed, CamTargetEntity->GetForward())*180.0f; if(CamTargetEntity->GetModelIndex() == MI_FIRETRUCK && CPad::GetPad(0)->GetCarGunFired()){ CarAlpha = DEGTORAD(10.0f); }else if(isHeli){ CarAlpha = 0.0f; float heliFwdZ = CamTargetEntity->GetForward().z; float heliFwdXY = CamTargetEntity->GetForward().Magnitude2D(); float alphaAmount = Min(Abs(fwdSpeed/90.0f), 1.0f); if(heliFwdXY != 0.0f || heliFwdZ != 0.0f) CarAlpha = CGeneral::GetATanOfXY(heliFwdXY, Abs(heliFwdZ)) * alphaAmount; CColPoint point; CEntity *entity = nil; CVector Test = Source; Test.z = TargetCoors.z + 0.2f + Length*Sin(CarAlpha+AlphaOffset) + m_fCloseInCarHeightOffset; if(CWorld::ProcessVerticalLine(Test, CamTargetEntity->GetPosition().z, point, entity, true, false, false, false, false, false, nil)){ float sin = (point.point.z - TargetCoors.z - 0.2f - m_fCloseInCarHeightOffset)/Length; CarAlpha = Asin(clamp(sin, -1.0f, 1.0f)) - AlphaOffset; if(CarAlpha < 0.0f) AlphaOffset += CarAlpha; } } CarAlpha = CGeneral::LimitRadianAngle(CarAlpha); if(CarAlpha < 0.0f) CarAlpha = 0.0f; if(CarAlpha > DEGTORAD(89.0f)) CarAlpha = DEGTORAD(89.0f); if(ResetStatics) Alpha = CarAlpha; float TargetAlpha = Alpha; float DeltaAlpha = CarAlpha - TargetAlpha; while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI; while(DeltaAlpha < -PI) DeltaAlpha += 2*PI; if(Abs(DeltaAlpha) > 0.0f && !TheCamera.m_bVehicleSuspenHigh) TargetAlpha = CarAlpha; if(isBike) WellBufferMe(TargetAlpha, &Alpha, &AlphaSpeed, 0.09f, 0.04f, true); else if(isHeli) WellBufferMe(TargetAlpha, &Alpha, &AlphaSpeed, 0.09f, 0.04f, true); else WellBufferMe(TargetAlpha, &Alpha, &AlphaSpeed, 0.15f, 0.07f, true); Source.z = TargetCoors.z + Sin(Alpha + AlphaOffset)*Length + m_fCloseInCarHeightOffset; AlphaOffset -= AlphaDec; } // Rotate cam behind the car when the car is moving forward bool CCam::RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation) { float BetaMaxSpeed = 0.15f; float BetaAcceleration = 0.007f; bool MovingForward = false; float MaxDiffBeta = DEGTORAD(160.0f); CPhysical *phys = (CPhysical*)CamTargetEntity; float ForwardSpeed = DotProduct(phys->GetForward(), phys->GetSpeed(CVector(0.0f, 0.0f, 0.0f))); if(ForwardSpeed > 0.02f) MovingForward = true; if(phys->IsVehicle() && (phys->GetModelIndex() == MI_SPARROW || phys->GetModelIndex() == MI_HUNTER)){ MaxDiffBeta = DEGTORAD(160.0f); BetaMaxSpeed = 0.1f; BetaAcceleration = 0.003f; CVector speed = phys->GetSpeed(CVector(0.0f, 0.0f, 0.0f)); speed.z = 0.0f; if(50.0f*speed.Magnitude() > 3.13f) TargetOrientation = CGeneral::GetATanOfXY(speed.x, speed.y); } float Dist = (Source - TargetCoors).Magnitude2D(); float DeltaBeta = TargetOrientation - Beta; while(DeltaBeta >= PI) DeltaBeta -= 2*PI; while(DeltaBeta < -PI) DeltaBeta += 2*PI; if(Abs(DeltaBeta) > PI-MaxDiffBeta && 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, BetaMaxSpeed, BetaAcceleration, 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; } float FIRETRUCK_TRACKING_MULT = 0.1f; float fTestShiftHeliCamTarget = 0.6f; float TiltTopSpeed[] = { 0.035f, 0.035f, 0.001f, 0.005f, 0.035f }; float TiltSpeedStep[] = { 0.016f, 0.016f, 0.0002f, 0.0014f, 0.016f }; float TiltOverShoot[] = { 1.05f, 1.05f, 0.0f, 0.0f, 1.0f }; void CCam::Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float) { if(!CamTargetEntity->IsVehicle()) return; // unused // ((CVehicle*)CamTargetEntity)->GetVehicleAppearance(); FOV = DefaultFOV; if(ResetStatics){ AlphaSpeed = 0.0f; m_fTilt = 0.0f; m_fTiltSpeed = 0.0; } CBaseModelInfo *mi = CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex()); CVector Dimensions = mi->GetColModel()->boundingBox.max - mi->GetColModel()->boundingBox.min; CVector TargetCoors = CameraTarget; float BaseDist = Dimensions.Magnitude(); if(((CVehicle*)CamTargetEntity)->IsBike()) BaseDist *= 1.45f; if(((CVehicle*)CamTargetEntity)->GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI && CamTargetEntity->GetStatus() != STATUS_PLAYER_REMOTE) TargetCoors += fTestShiftHeliCamTarget * CamTargetEntity->GetUp() * Dimensions.z; else TargetCoors.z += 0.8f*Dimensions.z; Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y); Alpha = CGeneral::LimitRadianAngle(Alpha); Beta = CGeneral::LimitRadianAngle(Beta); if(CamTargetEntity->GetModelIndex() == MI_FIRETRUCK && CPad::GetPad(0)->GetCarGunFired() && ((CVehicle*)CamTargetEntity)->m_vecMoveSpeed.Magnitude2D() < 0.01f){ float TargetBeta = CamTargetEntity->GetForward().Heading() - ((CAutomobile*)CamTargetEntity)->m_fCarGunLR + HALFPI; TargetBeta = CGeneral::LimitRadianAngle(TargetBeta); float DeltaBeta = TargetBeta - Beta; if(DeltaBeta > PI) DeltaBeta -= TWOPI; else if(DeltaBeta < -PI) DeltaBeta += TWOPI; float dist = (TargetCoors - Source).Magnitude(); dist = FIRETRUCK_TRACKING_MULT*dist*clamp(DeltaBeta, -0.8f, 0.8f); Source += dist*CrossProduct(Front, CVector(0.0f, 0.0f, 1.0f)); } m_fDistanceBeforeChanges = (Source - TargetCoors).Magnitude2D(); Cam_On_A_String_Unobscured(TargetCoors, BaseDist); WorkOutCamHeight(TargetCoors, TargetOrientation, Dimensions.z); RotCamIfInFrontCar(TargetCoors, TargetOrientation); FixCamWhenObscuredByVehicle(TargetCoors); m_cvecTargetCoorsForFudgeInter = TargetCoors; CVector OrigSource = Source; if(CWorld::GetIsLineOfSightClear(CamTargetEntity->GetPosition(), m_cvecTargetCoorsForFudgeInter, true, false, false, true, false, false, true)) TheCamera.AvoidTheGeometry(OrigSource, m_cvecTargetCoorsForFudgeInter, Source, FOV); else TheCamera.AvoidTheGeometry(OrigSource, CamTargetEntity->GetPosition(), Source, FOV); Front = TargetCoors - Source; Front.Normalise(); int appearance = ((CVehicle*)CamTargetEntity)->GetVehicleAppearance(); int index = 0; TheCamera.GetArrPosForVehicleType(appearance, index); if(appearance == VEHICLE_APPEARANCE_HELI){ float TargetTilt = DotProduct(Front, ((CVehicle*)CamTargetEntity)->GetSpeed(CVector(0.0f, 0.0f, 0.0f))); CVector UpTarget = CamTargetEntity->GetUp(); UpTarget.Normalise(); int dir = TargetTilt < 0.0f ? -1 : 1; if(m_fTilt != 0.0f) TargetTilt += TiltOverShoot[index]*TargetTilt/m_fTilt * dir; WellBufferMe(TargetTilt, &m_fTilt, &m_fTiltSpeed, TiltTopSpeed[index], TiltSpeedStep[index], false); Up = CVector(0.0f, 0.0f, 1.0f) - (CVector(0.0f, 0.0f, 1.0f) - UpTarget)*m_fTilt; Up.Normalise(); Front.Normalise(); CVector Left = CrossProduct(Up, Front); Up = CrossProduct(Front, Left); Up.Normalise(); }else{ float TargetRoll; if(CPad::GetPad(0)->GetDPadLeft() || CPad::GetPad(0)->GetDPadRight()){ float fwdSpeed = 180.0f*DotProduct(((CVehicle*)CamTargetEntity)->m_vecMoveSpeed, CamTargetEntity->GetForward()); if(fwdSpeed > 210.0f) fwdSpeed = 210.0f; if(CPad::GetPad(0)->GetDPadLeft()) TargetRoll = DEGTORAD(10.0f)*TiltOverShoot[index] + f_max_role_angle; else TargetRoll = -(DEGTORAD(10.0f)*TiltOverShoot[index] + f_max_role_angle); CVector FwdTarget = CamTargetEntity->GetForward(); FwdTarget.Normalise(); float AngleDiff = DotProduct(FwdTarget, Front); AngleDiff = Acos(Min(Abs(AngleDiff), 1.0f)); TargetRoll *= fwdSpeed/210.0f * Sin(AngleDiff); }else{ float fwdSpeed = 180.0f*DotProduct(((CVehicle*)CamTargetEntity)->m_vecMoveSpeed, CamTargetEntity->GetForward()); if(fwdSpeed > 210.0f) fwdSpeed = 210.0f; TargetRoll = CPad::GetPad(0)->GetLeftStickX()/128.0f * fwdSpeed/210.0f; CVector FwdTarget = CamTargetEntity->GetForward(); FwdTarget.Normalise(); float AngleDiff = DotProduct(FwdTarget, Front); AngleDiff = Acos(Min(Abs(AngleDiff), 1.0f)); TargetRoll *= (DEGTORAD(10.0f)*TiltOverShoot[index] + f_max_role_angle) * Sin(AngleDiff); } WellBufferMe(TargetRoll, &f_Roll, &f_rollSpeed, 0.15f, 0.07f, false); Up = CVector(Cos(f_Roll + HALFPI), 0.0f, Sin(f_Roll + HALFPI)); Up.Normalise(); Front.Normalise(); CVector Left = CrossProduct(Up, Front); Left.Normalise(); Up = CrossProduct(Front, Left); Up.Normalise(); } ResetStatics = false; } // Basic Cam on a string algorithm void CCam::Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist) { int id = CamTargetEntity->GetModelIndex(); float ExtraDist = 0.0f; if(id == MI_RCRAIDER || id == MI_RCGOBLIN) ExtraDist = INIT_RC_HELI_HORI_EXTRA; else if(id == MI_RCBARON) ExtraDist = INIT_RC_PLANE_HORI_EXTRA; CA_MAX_DISTANCE = BaseDist + 0.1f + TheCamera.CarZoomValueSmooth + ExtraDist; CA_MIN_DISTANCE = Min(BaseDist*0.6f, 3.5f); if(CA_MIN_DISTANCE > CA_MAX_DISTANCE) CA_MIN_DISTANCE = CA_MAX_DISTANCE - 0.05f; CVector Dist = Source - TargetCoors; if(ResetStatics) Source = TargetCoors + Dist*(CA_MAX_DISTANCE + 1.0f); Dist = Source - TargetCoors; 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 = nil; 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; } void CCam::Process_Rocket(const CVector &CameraTarget, float, float, float) { if(!CamTargetEntity->IsPed()) return; float BackOffset = 0.19f; 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; } if(((CPed*)CamTargetEntity)->bIsDucking) BackOffset = 0.8f; CamTargetEntity->GetMatrix().UpdateRW(); CamTargetEntity->UpdateRwFrame(); CamTargetEntity->UpdateRpHAnim(); ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(HeadPos, PED_HEAD); Source = HeadPos; Source.z += 0.1f; Source.x -= BackOffset*Cos(m_fInitialPlayerOrientation); Source.y -= BackOffset*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*0.8f/14.0f * FOV/80.0f * CTimer::GetTimeStep(); Alpha += SQR(LookUpDown/150.0f)*ydir*1.0f/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); else 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; } float fDuckingBackOffset = 0.5f; float fDuckingRightOffset = 0.18f; void CCam::Process_M16_1stPerson(const CVector &CameraTarget, float, float, float) { if(!CamTargetEntity->IsPed()) return; float BackOffset = 0.3f; static bool FailedTestTwelveFramesAgo = false; RwV3d HeadPos; CVector TargetCoors; bool isAttached = ((CPed*)CamTargetEntity)->IsPlayer() && ((CPed*)CamTargetEntity)->m_attachedTo; FOV = DefaultFOV; TargetCoors = CameraTarget; if(ResetStatics){ if(isAttached) Beta = 0.0f; else 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; } // 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 if(Mode == MODE_HELICANNON_1STPERSON){ LookLeftRight /= 128.0f; LookUpDown /= 128.0f; Beta += LookLeftRight*Abs(LookLeftRight)*0.56f/14.0f * FOV/80.0f * CTimer::GetTimeStep(); Alpha += LookUpDown*Abs(LookUpDown)*0.48f/14.0f * FOV/80.0f * CTimer::GetTimeStep(); }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*0.8f/14.0f * FOV/80.0f * CTimer::GetTimeStep(); Alpha += SQR(LookUpDown/150.0f)*ydir*1.0f/14.0f * FOV/80.0f * CTimer::GetTimeStep(); } if (!isAttached) { while(Beta >= TWOPI) Beta -= TWOPI; while(Beta < 0) Beta += TWOPI; } if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f); else if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f); if(((CPed*)CamTargetEntity)->bIsDucking) BackOffset = 0.8f; if(isAttached){ CMatrix mat, rot; CPed *TargetPed = (CPed*)CamTargetEntity; TargetPed->PositionAttachedPed(); CamTargetEntity->GetMatrix().UpdateRW(); CamTargetEntity->UpdateRwFrame(); CamTargetEntity->UpdateRpHAnim(); HeadPos.x = 0.0f; HeadPos.y = 0.0f; HeadPos.z = 0.0f; TargetPed->m_pedIK.GetComponentPosition(HeadPos, PED_HEAD); Source = HeadPos; Source += 0.1f*CamTargetEntity->GetUp(); Source -= BackOffset*CamTargetEntity->GetForward(); if(TargetPed->m_attachRotStep < PI){ if(Beta > TargetPed->m_attachRotStep){ Beta = TargetPed->m_attachRotStep; CAutomobile *heli = (CAutomobile*)TargetPed->m_attachedTo; if(heli->IsVehicle() && heli->IsCar() && heli->IsRealHeli() && heli->m_fHeliOrientation > 0.0f){ float heliOrient = heli->m_fHeliOrientation + CTimer::GetTimeStep()*0.01f; if(heliOrient < 0.0f) heliOrient += TWOPI; else if(heliOrient > TWOPI) heliOrient -= TWOPI; heli->SetHeliOrientation(heliOrient); } }else if(Beta < -TargetPed->m_attachRotStep){ Beta = -TargetPed->m_attachRotStep; CAutomobile *heli = (CAutomobile*)TargetPed->m_attachedTo; if(heli->IsVehicle() && heli->IsCar() && heli->IsRealHeli() && heli->m_fHeliOrientation > 0.0f){ float heliOrient = heli->m_fHeliOrientation - CTimer::GetTimeStep()*0.01f; if(heliOrient < 0.0f) heliOrient += TWOPI; else if(heliOrient > TWOPI) heliOrient -= TWOPI; heli->SetHeliOrientation(heliOrient); } } }else{ while(Beta < -PI) Beta += TWOPI; while(Beta >= PI) Beta -= TWOPI; } mat = TargetPed->m_attachedTo->GetMatrix(); rot.SetRotateX(Alpha); switch(TargetPed->m_attachType){ case 0: rot.RotateZ(Beta); break; case 1: rot.RotateZ(Beta + HALFPI); break; case 2: rot.RotateZ(Beta + PI); break; case 3: rot.RotateZ(Beta - HALFPI); break; } mat = mat * rot; Front = mat.GetForward(); Up = mat.GetUp(); TargetCoors = Source + 3.0f*Front; RwCameraSetNearClipPlane(Scene.camera, 0.4f); float Rotation = CGeneral::GetATanOfXY(Front.x, Front.y) - HALFPI; ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Rotation; ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Rotation; }else{ CamTargetEntity->GetMatrix().UpdateRW(); CamTargetEntity->UpdateRwFrame(); CamTargetEntity->UpdateRpHAnim(); HeadPos.x = 0.0f; HeadPos.y = 0.0f; HeadPos.z = 0.0f; ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(HeadPos, PED_HEAD); Source = HeadPos; Source.z += 0.1f; if(((CPed*)CamTargetEntity)->bIsDucking){ Source.x -= fDuckingBackOffset*CamTargetEntity->GetForward().x; Source.y -= fDuckingBackOffset*CamTargetEntity->GetForward().y; Source.x -= fDuckingRightOffset*CamTargetEntity->GetRight().x; Source.y -= fDuckingRightOffset*CamTargetEntity->GetRight().y; }else{ Source.x -= BackOffset*CamTargetEntity->GetForward().x; Source.y -= BackOffset*CamTargetEntity->GetForward().y; } 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; } } float fBike1stPersonOffsetZ = 0.15f; void CCam::Process_1stPerson(const CVector &CameraTarget, float TargetOrientation, float SpeedVar, float TargetSpeedVar) { float BackOffset = 0.3f; 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; } TheCamera.m_fAvoidTheGeometryProbsTimer = 0.0f; 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; } CamTargetEntity->GetMatrix().UpdateRW(); CamTargetEntity->UpdateRwFrame(); CamTargetEntity->UpdateRpHAnim(); ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(HeadPos, PED_HEAD); Source = HeadPos; Source.z += 0.1f; if(((CPed*)CamTargetEntity)->bIsDucking){ Source.x -= fDuckingBackOffset*CamTargetEntity->GetForward().x; Source.y -= fDuckingBackOffset*CamTargetEntity->GetForward().y; Source.x -= fDuckingRightOffset*CamTargetEntity->GetRight().x; Source.y -= fDuckingRightOffset*CamTargetEntity->GetRight().y; }else{ Source.x -= BackOffset*CamTargetEntity->GetForward().x; Source.y -= BackOffset*CamTargetEntity->GetForward().y; } 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*0.8f/14.0f * FOV/80.0f * CTimer::GetTimeStep(); Alpha += SQR(LookUpDown/150.0f)*ydir*1.0f/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); else 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()); if(((CVehicle*)CamTargetEntity)->IsBike() && (((CBike*)CamTargetEntity)->bWheelieCam || TheCamera.m_fAvoidTheGeometryProbsTimer > 0.0f)){ if(CPad::GetPad(0)->GetLeftShoulder2() || CPad::GetPad(0)->GetRightShoulder2()){ TheCamera.m_fAvoidTheGeometryProbsTimer = 0.0f; ((CBike*)CamTargetEntity)->bWheelieCam = false; }else if(Process_WheelCam(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar)){ if(((CBike*)CamTargetEntity)->bWheelieCam) TheCamera.m_fAvoidTheGeometryProbsTimer = 50.0f; else{ TheCamera.m_fAvoidTheGeometryProbsTimer -= CTimer::GetTimeStep(); ((CBike*)CamTargetEntity)->bWheelieCam = true; } return; }else{ TheCamera.m_fAvoidTheGeometryProbsTimer = 0.0f; ((CBike*)CamTargetEntity)->bWheelieCam = false; } } CMatrix *matrix = &CamTargetEntity->GetMatrix(); if(((CVehicle*)CamTargetEntity)->IsBike()){ ((CBike*)CamTargetEntity)->CalculateLeanMatrix(); matrix = &((CBike*)CamTargetEntity)->m_leanMatrix; } CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex()); CVector CamPos = mi->GetFrontSeatPosn(); CamPos.x = 0.0f; CamPos.y += 0.08f; CamPos.z += 0.62f; FOV = 60.0f; Source = Multiply3x3(*matrix, CamPos); Source += CamTargetEntity->GetPosition(); if(((CVehicle*)CamTargetEntity)->IsBoat()) Source.z += 0.5f; else if(((CVehicle*)CamTargetEntity)->IsBike() && ((CVehicle*)CamTargetEntity)->pDriver){ CVector Neck(0.0f, 0.0f, 0.0f); ((CVehicle*)CamTargetEntity)->pDriver->m_pedIK.GetComponentPosition(Neck, PED_NECK); Neck += ((CVehicle*)CamTargetEntity)->m_vecMoveSpeed * CTimer::GetTimeStep(); Source.z = Neck.z + fBike1stPersonOffsetZ; } 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 = matrix->GetForward(); Front.Normalise(); Up = matrix->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 CVector HeadPos = vecHeadCamOffset; CVector TargetCoors; ((CPed*)CamTargetEntity)->TransformToNode(HeadPos, PED_HEAD); RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(CamTargetEntity->GetClump()); int32 idx = RpHAnimIDGetIndex(hier, ConvertPedNode2BoneTag(PED_HEAD)); RwMatrix *mats = RpHAnimHierarchyGetMatrixArray(hier); RwV3dTransformPoints(&HeadPos, &HeadPos, 1, &mats[idx]); RwV3d scl = { 0.0f, 0.0f, 0.0f }; RwMatrixScale(&mats[idx], &scl, rwCOMBINEPRECONCAT); 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 = (CamTargetEntity->GetMatrix() * m_vecBufferedPlayerBodyOffset); }else{ float HeadDelta = (HeadPos - InitialHeadPos).Magnitude2D(); CVector Fwd = CamTargetEntity->GetForward(); Fwd.z = 0.0f; Fwd.Normalise(); HeadPos = 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*0.8f/14.0f * FOV/80.0f * CTimer::GetTimeStep(); Alpha += SQR(LookUpDown/150.0f)*ydir*1.0f/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); else if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f); if(((CPed*)CamTargetEntity)->IsPlayer() && ((CPed*)CamTargetEntity)->m_attachedTo){ CPed *pedTarget = ((CPed*)CamTargetEntity); float NewBeta; switch(pedTarget->m_attachType){ case 0: NewBeta = pedTarget->GetForward().Heading() + HALFPI; break; case 1: NewBeta = pedTarget->GetForward().Heading() + PI; break; case 2: NewBeta = pedTarget->GetForward().Heading() - HALFPI; break; case 3: NewBeta = pedTarget->GetForward().Heading(); break; } float BetaOffset = Beta - NewBeta; if(BetaOffset > PI) BetaOffset -= TWOPI; else if(BetaOffset < PI) BetaOffset += TWOPI; BetaOffset = clamp(BetaOffset, -pedTarget->m_attachRotStep, pedTarget->m_attachRotStep); Beta = NewBeta + BetaOffset; } 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, MOTION_BLUR_SNIPER); if(FOV > DefaultFOV) FOV = DefaultFOV; if(FOV < 15.0f) FOV = 15.0f; } } ResetStatics = false; RwCameraSetNearClipPlane(Scene.camera, 0.05f); } float fCameraNearClipMult = 0.15f; void CCam::Process_Sniper(const CVector &CameraTarget, float TargetOrientation, float, float) { if(!CamTargetEntity->IsPed()) return; float BackOffset = 0.19f; static bool FailedTestTwelveFramesAgo = false; RwV3d HeadPos; CVector TargetCoors; TargetCoors = CameraTarget; static float TargetFOV = 0.0f; 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; FOVSpeed = 0.0f; TargetFOV = FOV; ResetStatics = false; } if(((CPed*)CamTargetEntity)->bIsDucking) BackOffset = 0.8f; CamTargetEntity->GetMatrix().UpdateRW(); CamTargetEntity->UpdateRwFrame(); CamTargetEntity->UpdateRpHAnim(); ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(HeadPos, PED_HEAD); Source = HeadPos; Source.z += 0.1f; if(((CPed*)CamTargetEntity)->bIsDucking){ Source.x -= fDuckingBackOffset*CamTargetEntity->GetForward().x; Source.y -= fDuckingBackOffset*CamTargetEntity->GetForward().y; Source.x -= fDuckingRightOffset*CamTargetEntity->GetRight().x; Source.y -= fDuckingRightOffset*CamTargetEntity->GetRight().y; }else{ Source.x -= BackOffset*CamTargetEntity->GetForward().x; Source.y -= BackOffset*CamTargetEntity->GetForward().y; } // 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*0.8f/14.0f * FOV/80.0f * CTimer::GetTimeStep(); Alpha += SQR(LookUpDown/150.0f)*ydir*1.0f/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); else 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); if(ZoomInButton == rsMOUSEWHEELUPBUTTON || ZoomInButton == rsMOUSEWHEELDOWNBUTTON || ZoomOutButton == rsMOUSEWHEELUPBUTTON || ZoomOutButton == rsMOUSEWHEELDOWNBUTTON){ 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, MOTION_BLUR_SNIPER); if(FOV > DefaultFOV) FOV = DefaultFOV; if(Mode == MODE_CAMERA){ if(FOV < 3.0f) FOV = 3.0f; }else{ 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); else if(Mode == MODE_CAMERA) RwCameraSetNearClipPlane(Scene.camera, ((15.0f - Min(FOV, 15.0f))*fCameraNearClipMult + 1.0f)*DEFAULT_NEAR); 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; } float INIT_SYPHON_GROUND_DIST = 2.419f; float INIT_SYPHON_ALPHA_OFFSET = -DEGTORAD(3.0f); float INIT_SYPHON_DEGREE_OFFSET = -DEGTORAD(30.0f); float FrontOffsetSyphon = -DEGTORAD(25.5f); // unused float INIT_SYPHON_Z_OFFSET = -0.5f; 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 = INIT_SYPHON_DEGREE_OFFSET; // unused AngleToGoTo // unused AngleToGoToSpeed // unused DistBetweenPedAndPlayerPreviouslyOn static float HeightDown = INIT_SYPHON_Z_OFFSET; static float AlphaOffset = INIT_SYPHON_ALPHA_OFFSET; static bool NegateBetaOffset = true; CVector TargetCoors; float fAimingDist; float TargetAlpha; bool StandingOnMovingThing = false; TargetCoors = CameraTarget; AlphaOffset = INIT_SYPHON_ALPHA_OFFSET; float GroundDist = INIT_SYPHON_GROUND_DIST; 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){ BetaOffset = INIT_SYPHON_DEGREE_OFFSET; Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y); // some unuseds ResetStatics = false; } if(NegateBetaOffset) BetaOffset = -INIT_SYPHON_DEGREE_OFFSET; Beta = NewBeta + BetaOffset; Source = TargetCoors; Source.x += GroundDist*Cos(Beta); Source.y += GroundDist*Sin(Beta); CPhysical *ground = (CPhysical*)((CPed*)CamTargetEntity)->m_pCurSurface; if(ground && (ground->IsVehicle() || ground->IsObject())) StandingOnMovingThing = true; TargetCoors.z += m_fSyphonModeTargetZOffSet; bool PlayerTooClose = false; fAimingDist = (TheCamera.m_cvecAimingTargetCoors - TargetCoors).Magnitude2D(); if(fAimingDist < 6.5f){ fAimingDist = 6.5f; PlayerTooClose = true; } TargetAlpha = CGeneral::GetATanOfXY(fAimingDist, TheCamera.m_cvecAimingTargetCoors.z - TargetCoors.z); if(ResetStatics) // BUG: can never happen Alpha = -TargetAlpha; while(TargetAlpha >= PI) TargetAlpha -= 2*PI; while(TargetAlpha < -PI) TargetAlpha += 2*PI; while(Alpha >= PI) Alpha -= 2*PI; while(Alpha < -PI) Alpha += 2*PI; // inlined if(StandingOnMovingThing) WellBufferMe(-TargetAlpha, &Alpha, &AlphaSpeed, 0.07f/2.0f, 0.015f/2.0f, true); else WellBufferMe(-TargetAlpha, &Alpha, &AlphaSpeed, 0.07f, 0.015f, true); Source.z += GroundDist*Sin(Alpha+AlphaOffset) + GroundDist*0.2f; if(Source.z < TargetCoors.z + HeightDown) Source.z = TargetCoors.z + HeightDown; if(!PlayerTooClose){ CColPoint point; CEntity *entity = nil; CWorld::pIgnoreEntity = CamTargetEntity; if(CWorld::ProcessLineOfSight(TheCamera.m_cvecAimingTargetCoors, Source, point, entity, true, false, false, true, false, false, true)){ CVector TestFront = TheCamera.m_cvecAimingTargetCoors - Source; TestFront.Normalise(); CVector CamToPlayer = CameraTarget - Source; CVector CamToCol = point.point - Source; if(DotProduct(TestFront, CamToCol) > DotProduct(TestFront, CamToPlayer)){ // collision is beyond player float ColDist = (TheCamera.m_cvecAimingTargetCoors - point.point).Magnitude(); CVector PlayerToTarget = TheCamera.m_cvecAimingTargetCoors - CameraTarget; float PlayerToTargetDist = PlayerToTarget.Magnitude(); PlayerToTarget.Normalise(); CVector Center = TheCamera.m_cvecAimingTargetCoors - ColDist*PlayerToTarget; float Radius = (point.point - Center).Magnitude(); if(CWorld::TestSphereAgainstWorld(Center, Radius, nil, true, false, false, true, false, true)){ CVector LineToCol = gaTempSphereColPoints[0].point - Center; LineToCol -= DotProduct(LineToCol, PlayerToTarget)*PlayerToTarget; // unused CVector LineToPrevCol = point.point - Center; LineToPrevCol -= DotProduct(LineToPrevCol, PlayerToTarget)*PlayerToTarget; float LineDist = LineToCol.Magnitude(); float NewBetaOffset = 0.0f; if(LineDist > 0.0f && ColDist > 0.1f){ // scale offset at center to offset at player float DistOffset = LineDist/ColDist * PlayerToTargetDist; // turn into an angle NewBetaOffset = 0.9f*Asin(Min(DistOffset/GroundDist, 1.0f)); } if(NewBetaOffset < BetaOffset){ float Ratio = NewBetaOffset / BetaOffset; BetaOffset = NewBetaOffset; Beta = NewBeta + NewBetaOffset; GroundDist *= Max(Ratio, 0.5f); Source.x = TargetCoors.x + GroundDist*Cos(Beta); Source.y = TargetCoors.y + GroundDist*Sin(Beta); Source.z += (1.0f-Ratio)*0.5f; } } } } CWorld::pIgnoreEntity = nil; } Front = TheCamera.m_cvecAimingTargetCoors - Source; float TargetDistGround = Front.Magnitude2D(); Front.Normalise(); m_cvecTargetCoorsForFudgeInter = Source + TargetDistGround*Front; m_cvecTargetCoorsForFudgeInter.z = TargetCoors.z; CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, CameraTarget + CVector(0.0f, 0.0f, 0.75f), Source, FOV); Source.z = OrigSource.z; 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; 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(ResetStatics){ if(AimingAngle > 0.0f) m_fPlayerInFrontSyphonAngleOffSet = -m_fPlayerInFrontSyphonAngleOffSet; ResetStatics = false; } 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; TargetCoors = CameraTarget; TargetCoors.z += m_fSyphonModeTargetZOffSet; m_cvecTargetCoorsForFudgeInter = TargetCoors; CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, TargetCoors, Source, FOV); Front = TargetCoors - Source; GetVectorsReadyForRW(); } float MAX_HEIGHT_UP = 15.0f; float WATER_Z_ADDITION = 2.75f; float WATER_Z_ADDITION_MIN = 1.5f; float SMALLBOAT_CLOSE_ALPHA_MINUS = 0.2f; float afBoatBetaDiffMult[3] = { 0.15f, 0.07f, 0.01f }; float afBoatBetaSpeedDiffMult[3] = { 0.02f, 0.015f, 0.005f }; 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 float TargetWhenChecksWereOn = 0.0f; static float CenterObscuredWhenChecksWereOn = 0.0f; static float WaterZAddition = 2.75f; float WaterLevel = 0.0f; float MaxHeightUp = MAX_HEIGHT_UP; static float WaterLevelBuffered = 0.0f; static float WaterLevelSpeed = 0.0f; float BetaDiffMult = 0.0f; float BetaSpeedDiffMult = 0.0f; Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y); FOV = DefaultFOV; float TargetAlpha = 0.0f; if(ResetStatics){ CenterObscuredWhenChecksWereOn = 0.0f; TargetWhenChecksWereOn = 0.0f; }else if(DirectionWasLooking != LOOKING_FORWARD) Beta = TargetOrientation; if(!CWaterLevel::GetWaterLevelNoWaves(TargetCoors.x, TargetCoors.y, TargetCoors.z, &WaterLevel)) WaterLevel = TargetCoors.z - 0.5f; if(ResetStatics){ WaterLevelBuffered = WaterLevel; WaterLevelSpeed = 0.0f; } WellBufferMe(WaterLevel, &WaterLevelBuffered, &WaterLevelSpeed, 0.2f, 0.07f, false); static float FixerForGoingBelowGround = 0.4f; if(-FixerForGoingBelowGround < TargetCoors.z-WaterLevelBuffered+WATER_Z_ADDITION) WaterLevelBuffered += TargetCoors.z-WaterLevelBuffered+WATER_Z_ADDITION - FixerForGoingBelowGround; CVector BoatDimensions = CamTargetEntity->GetColModel()->boundingBox.GetSize(); float BoatSize = BoatDimensions.Magnitude2D(); int index = 0; TheCamera.GetArrPosForVehicleType(((CVehicle*)CamTargetEntity)->GetVehicleAppearance(), index); if(TheCamera.CarZoomIndicator == CAM_ZOOM_1){ TargetAlpha = ZmOneAlphaOffset[index]; BetaDiffMult = afBoatBetaDiffMult[0]; BetaSpeedDiffMult = afBoatBetaSpeedDiffMult[0]; }else if(TheCamera.CarZoomIndicator == CAM_ZOOM_2){ TargetAlpha = ZmTwoAlphaOffset[index]; BetaDiffMult = afBoatBetaDiffMult[1]; BetaSpeedDiffMult = afBoatBetaSpeedDiffMult[1]; }else if(TheCamera.CarZoomIndicator == CAM_ZOOM_3){ TargetAlpha = ZmThreeAlphaOffset[index]; BetaDiffMult = afBoatBetaDiffMult[2]; BetaSpeedDiffMult = afBoatBetaSpeedDiffMult[2]; } if(TheCamera.CarZoomIndicator == CAM_ZOOM_1 && BoatSize < 10.0f){ TargetAlpha -= SMALLBOAT_CLOSE_ALPHA_MINUS; BoatSize = 10.0f; }else if(CCullZones::Cam1stPersonForPlayer()){ float Water = 0.0f; // useless call //CWaterLevel::GetWaterLevelNoWaves(TargetCoors.x, TargetCoors.y, TargetCoors.z, &Water); Water = (WaterLevel + WATER_Z_ADDITION_MIN - WaterLevelBuffered - WATER_Z_ADDITION)/(BoatDimensions.z/2.0f + MaxHeightUp); TargetAlpha = Asin(clamp(Water, -1.0f, 1.0f)); } if(ResetStatics){ Alpha = TargetAlpha; AlphaSpeed = 0.0f; } WellBufferMe(TargetAlpha, &Alpha, &AlphaSpeed, 0.15f, 0.07f, true); if(ResetStatics){ Beta = TargetOrientation; DeltaBeta = 0.0f; } // inlined WellBufferMe(TargetOrientation, &Beta, &BetaSpeed, BetaDiffMult * ((CVehicle*)CamTargetEntity)->m_vecMoveSpeed.Magnitude(), BetaSpeedDiffMult, true); Source = (TheCamera.CarZoomValueSmooth+BoatSize) * CVector(-Cos(Beta), -Sin(Beta), 0.0f) + TargetCoors; Source.z = WaterLevelBuffered + WATER_Z_ADDITION + (BoatDimensions.z/2.0f + MaxHeightUp) * Sin(Alpha); m_cvecTargetCoorsForFudgeInter = TargetCoors; CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, TargetCoors, Source, FOV); Front = TargetCoors - Source; Front.Normalise(); float TargetRoll; if(CPad::GetPad(0)->GetDPadLeft() || CPad::GetPad(0)->GetDPadRight()){ #ifdef FIX_BUGS float fwdSpeed = 180.0f*DotProduct(((CVehicle*)CamTargetEntity)->m_vecMoveSpeed, CamTargetEntity->GetForward()); if(fwdSpeed > 210.0f) fwdSpeed = 210.0f; #endif if(CPad::GetPad(0)->GetDPadLeft()) TargetRoll = DEGTORAD(10.0f)*TiltOverShoot[index] + f_max_role_angle; else TargetRoll = -(DEGTORAD(10.0f)*TiltOverShoot[index] + f_max_role_angle); CVector FwdTarget = CamTargetEntity->GetForward(); FwdTarget.Normalise(); float AngleDiff = DotProduct(FwdTarget, Front); AngleDiff = Acos(Min(Abs(AngleDiff), 1.0f)); #ifdef FIX_BUGS TargetRoll *= fwdSpeed/210.0f * Sin(AngleDiff); #else TargetRoll *= Sin(AngleDiff); #endif }else{ float fwdSpeed = 180.0f*DotProduct(((CVehicle*)CamTargetEntity)->m_vecMoveSpeed, CamTargetEntity->GetForward()); if(fwdSpeed > 210.0f) fwdSpeed = 210.0f; TargetRoll = CPad::GetPad(0)->GetLeftStickX()/128.0f * fwdSpeed/210.0f; CVector FwdTarget = CamTargetEntity->GetForward(); FwdTarget.Normalise(); float AngleDiff = DotProduct(FwdTarget, Front); AngleDiff = Acos(Min(Abs(AngleDiff), 1.0f)); TargetRoll *= (DEGTORAD(10.0f)*TiltOverShoot[index] + f_max_role_angle) * Sin(AngleDiff); } WellBufferMe(TargetRoll, &f_Roll, &f_rollSpeed, 0.15f, 0.07f, false); Up = CVector(Cos(f_Roll + HALFPI), 0.0f, Sin(f_Roll + HALFPI)); Up.Normalise(); Front.Normalise(); CVector Left = CrossProduct(Up, Front); Left.Normalise(); Up = CrossProduct(Front, Left); Up.Normalise(); ResetStatics = false; } float FIGHT_HORIZ_DIST = 3.0f; float FIGHT_VERT_DIST = 1.0f; float FIGHT_BETA_ANGLE = 125.0f; void CCam::Process_Fight_Cam(const CVector &CameraTarget, float TargetOrientation, float, float) { if(!CamTargetEntity->IsPed()) return; FOV = DefaultFOV; float HorizDist = FIGHT_HORIZ_DIST; float VertDist = FIGHT_VERT_DIST; float BetaLeft, BetaRight, DeltaBetaLeft, DeltaBetaRight; static bool PreviouslyFailedBuildingChecks = false; float TargetCamHeight; CVector TargetCoors; m_fMinDistAwayFromCamWhenInterPolating = FIGHT_HORIZ_DIST; Front = Source - CameraTarget; if(ResetStatics) 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 - DEGTORAD(FIGHT_BETA_ANGLE); BetaRight = TargetOrientation + DEGTORAD(FIGHT_BETA_ANGLE); 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; } WellBufferMe(m_fTargetBeta, &Beta, &BetaSpeed, 0.015f, 0.007f, true); Source = CameraTarget + HorizDist*CVector(Cos(Beta), Sin(Beta), 0.0f); Source.z += VertDist; WellBufferMe(TargetOrientation, &m_fBufferedTargetOrientation, &m_fBufferedTargetOrientationSpeed, 0.07f, 0.004f, true); TargetCoors = CameraTarget + 0.1f*CVector(Cos(m_fBufferedTargetOrientation), Sin(m_fBufferedTargetOrientation), 0.0f); TargetCamHeight = CameraTarget.z - Source.z + Max(m_fPedBetweenCameraHeightOffset, m_fDimensionOfHighestNearCar) + VertDist; 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; CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, TargetCoors, Source, FOV); 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; #ifdef FIX_BUGS // this would crash, not nice when cycling debug mode if(TheCamera.m_arrPathArray[0].m_arr_PathData == nil) return; #endif Up = CVector(0.0f, 0.0f, 1.0f); if(TheCamera.m_bStartingSpline) m_fTimeElapsedFloat += CTimer::GetTimeStepNonClippedInMilliseconds(); 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(); }else if(uiTime >= uiFinishTime){ // 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; } CVector vecWheelCamBoatOffset(-0.5f, -0.8f, 0.3f); CVector vecWheelCamBoatOffsetAlt(0.2f, -0.2f, -0.3f); float fWheelCamCarXOffset = 0.33f; float fWheelCamBikeXOffset = 0.2f; bool CCam::Process_WheelCam(const CVector&, float, float, float) { FOV = DefaultFOV; CVector WheelPos; 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{ WheelPos = CamTargetEntity->GetColModel()->boundingBox.min; WheelPos.x -= 0.33f; WheelPos.y = -2.3f; WheelPos.z = 0.3f; Source = CamTargetEntity->GetMatrix() * WheelPos; Front = CamTargetEntity->GetForward(); } CVector NewUp, Right; if(CamTargetEntity->IsVehicle() && (((CVehicle*)CamTargetEntity)->GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI || ((CVehicle*)CamTargetEntity)->GetVehicleAppearance() == VEHICLE_APPEARANCE_PLANE)){ WheelPos.x = -1.55f; Right = CamTargetEntity->GetRight(); NewUp = CamTargetEntity->GetUp(); Source = CamTargetEntity->GetMatrix() * WheelPos; }else if(CamTargetEntity->IsVehicle() && ((CVehicle*)CamTargetEntity)->IsBoat()){ NewUp = CVector(0.0f, 0.0f, 1.0f); Right = CrossProduct(Front, NewUp); Right.Normalise(); NewUp = CrossProduct(Right, Front); NewUp.Normalise(); CVector BoatCamPos(0.0f, 0.0f, 0.0f); if(((CVehicle*)CamTargetEntity)->pDriver){ ((CVehicle*)CamTargetEntity)->pDriver->m_pedIK.GetComponentPosition(BoatCamPos, PED_HEAD); BoatCamPos += ((CVehicle*)CamTargetEntity)->m_vecMoveSpeed * CTimer::GetTimeStep(); BoatCamPos += vecWheelCamBoatOffset.x * Right; BoatCamPos += vecWheelCamBoatOffset.y * CamTargetEntity->GetForward(); BoatCamPos.z += vecWheelCamBoatOffset.z; if(CamTargetEntity->GetModelIndex() == MI_PREDATOR){ BoatCamPos += vecWheelCamBoatOffsetAlt.x * Right; BoatCamPos += vecWheelCamBoatOffsetAlt.y * CamTargetEntity->GetForward(); BoatCamPos.z += vecWheelCamBoatOffsetAlt.z; } Source = BoatCamPos; }else Source.z += 2.0f*vecWheelCamBoatOffset.z; }else if(CamTargetEntity->IsVehicle() && ((CVehicle*)CamTargetEntity)->IsBike()){ NewUp = CVector(0.0f, 0.0f, 1.0f); Right = CrossProduct(Front, NewUp); Right.Normalise(); NewUp = CrossProduct(Right, Front); NewUp.Normalise(); WheelPos.z += fWheelCamCarXOffset - fWheelCamBikeXOffset; Source = CamTargetEntity->GetPosition(); Source += WheelPos.x * CamTargetEntity->GetRight(); Source += WheelPos.y * Front; Source += WheelPos.z * Up; }else{ NewUp = CVector(0.0f, 0.0f, 1.0f); Right = CrossProduct(Front, NewUp); Right.Normalise(); NewUp = CrossProduct(Right, Front); NewUp.Normalise(); } float Roll = Cos((CTimer::GetTimeInMilliseconds()&0x1FFFF)/(float)0x1FFFF * TWOPI); Up = Cos(Roll*0.4f)*NewUp + Sin(Roll*0.4f)*Right; CEntity *entity = nil; CColPoint point; CWorld::pIgnoreEntity = CamTargetEntity; bool blocked = CWorld::ProcessLineOfSight(Source, CamTargetEntity->GetPosition(), point, entity, true, false, false, true, false, false, true); CWorld::pIgnoreEntity = nil; return !blocked; } int BOAT_UNDERWATER_CAM_BLUR = 20; float BOAT_UNDERWATER_CAM_COLORMAG_LIMIT = 10.0f; //--MIAIM: done void CCam::Process_Fixed(const CVector &CameraTarget, float, float, float) { if(DirectionWasLooking != LOOKING_FORWARD) DirectionWasLooking = LOOKING_FORWARD; Source = m_cvecCamFixedModeSource; Front = CameraTarget - Source; Front.Normalise(); 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; float WaterZ = 0.0f; if(CWaterLevel::GetWaterLevel(Source, &WaterZ, true) && Source.z < WaterZ){ float WaterLum = Sqrt(SQR(CTimeCycle::GetWaterRed()) + SQR(CTimeCycle::GetWaterGreen()) + SQR(CTimeCycle::GetWaterBlue())); if(WaterLum > BOAT_UNDERWATER_CAM_COLORMAG_LIMIT){ float f = BOAT_UNDERWATER_CAM_COLORMAG_LIMIT/WaterLum; TheCamera.SetMotionBlur(CTimeCycle::GetWaterRed()*f, CTimeCycle::GetWaterGreen()*f, CTimeCycle::GetWaterBlue()*f, BOAT_UNDERWATER_CAM_BLUR, MOTION_BLUR_LIGHT_SCENE); }else{ TheCamera.SetMotionBlur(CTimeCycle::GetWaterRed(), CTimeCycle::GetWaterGreen(), CTimeCycle::GetWaterBlue(), BOAT_UNDERWATER_CAM_BLUR, MOTION_BLUR_LIGHT_SCENE); } } #ifdef PC_PLAYER_CONTROLS if(FrontEndMenuManager.m_ControlMethod == CONTROL_STANDARD && 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(); } } #endif } void CCam::Process_LightHouse(const CVector &CameraTarget, float, float, float) { static float Timer; Source = CameraTarget; Source.x = 474.3f; Source.y = -1717.6f; int CamMode; if(CameraTarget.z > 57.0f && (CameraTarget-Source).Magnitude2D() > 3.2f){ // Outside at top if(Timer > 0.0f){ Timer -= CTimer::GetTimeStep(); CamMode = 1; }else{ Timer = -24.0f; CamMode = 2; } }else if(CameraTarget.z > 57.0f){ // Inside at top if(Timer < 0.0f){ Timer += CTimer::GetTimeStep(); CamMode = 2; }else{ Timer = 24.0f; CamMode = 1; } }else{ Timer = 0.0f; CamMode = 0; } if(CamMode == 2){ Source.z = 57.5f; Front = Source - CameraTarget; Front.Normalise(); Source.x = CameraTarget.x - 5.0f*Front.x; Source.y = CameraTarget.y - 5.0f*Front.y; }else if(CamMode == 1){ Front = CameraTarget - Source; Front.Normalise(); Source.x = CameraTarget.x - 2.0f*Front.x; Source.y = CameraTarget.y - 2.0f*Front.y; }else{ Source.z += 4.0f; Front = CameraTarget - Source; Front.Normalise(); Source -= 4.0f*Front; Source.z = Min(Source.z, 55.0f); 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) // uh, sure... FOV = TheCamera.m_fFovForTrain; } void CCam::Process_Player_Fallen_Water(const CVector &CameraTarget, float TargetOrientation, float, float) { CColPoint colPoint; CEntity *entity = nil; FOV = DefaultFOV; Source = m_vecLastAboveWaterCamPosition; Source.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(); } void CCam::Process_SpecialFixedForSyphon(const CVector &CameraTarget, float, float, float) { Source = m_cvecCamFixedModeSource; m_cvecTargetCoorsForFudgeInter = CameraTarget; m_cvecTargetCoorsForFudgeInter.z += m_fSyphonModeTargetZOffSet; Front = CameraTarget - Source; CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, m_cvecTargetCoorsForFudgeInter, Source, FOV); 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) * Sin(Beta) * 7.0f; TargetCoors.y = Source.y + Cos(Alpha) * Cos(Beta) * 7.0f; TargetCoors.z = Source.z + Sin(Alpha) * 3.0f; if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f); else 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->SetPosition(Source); } // stay inside sectors while(CWorld::GetSectorX(Source.x) > NUMSECTORS_X-5.0f) Source.x -= 1.0f; while(CWorld::GetSectorX(Source.x) < 5.0f) Source.x += 1.0f; while(CWorld::GetSectorY(Source.y) > NUMSECTORS_X-5.0f) Source.y -= 1.0f; while(CWorld::GetSectorY(Source.y) < 5.0f) Source.y += 1.0f; GetVectorsReadyForRW(); #ifdef FIX_BUGS CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_CAMERA); #else CPad::GetPad(0)->DisablePlayerControls = PLAYERCONTROL_CAMERA; #endif 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, nil, false); 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) * Sin(Beta) * 7.0f; TargetCoors.y = Source.y + Cos(Alpha) * Cos(Beta) * 7.0f; TargetCoors.z = Source.z + Sin(Alpha) * 3.0f; if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f); else 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->SetPosition(Source); } // stay inside sectors while(CWorld::GetSectorX(Source.x) > NUMSECTORS_X-5.0f) Source.x -= 1.0f; while(CWorld::GetSectorX(Source.x) < 5.0f) Source.x += 1.0f; while(CWorld::GetSectorY(Source.y) > NUMSECTORS_X-5.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, nil, 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 #ifdef GTA_SCENE_EDIT 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) * Sin(Beta) * 7.0f; TargetCoors.y = Source.y + Cos(Alpha) * Cos(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); else 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->SetPosition(Source); } // stay inside sectors while(CWorld::GetSectorX(Source.x) > NUMSECTORS_X-5.0f) Source.x -= 1.0f; while(CWorld::GetSectorX(Source.x) < 5.0f) Source.x += 1.0f; while(CWorld::GetSectorY(Source.y) > NUMSECTORS_X-5.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, nil, false); 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_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; #ifdef IMPROVED_CAMERA if(CPad::GetPad(0)->GetLeftMouse()){ Distance += DEGTORAD(CPad::GetPad(0)->GetMouseY()/2.0f); Angle += DEGTORAD(CPad::GetPad(0)->GetMouseX()/2.0f); } #endif 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(); } float DEADCAM_HEIGHT_START = 2.0f; float DEADCAM_HEIGHT_RATE = 0.04f; float DEADCAM_WAFT_AMPLITUDE = 2.0f; float DEADCAM_WAFT_RATE = 600.0f; float DEADCAM_WAFT_TILT_AMP = -0.35f; void CCam::ProcessPedsDeadBaby(void) { CVector TargetCoors; CVector CamPos; if(TheCamera.pTargetEntity->IsPed()) ((CPed*)TheCamera.pTargetEntity)->m_pedIK.GetComponentPosition(TargetCoors, PED_MID); else if(TheCamera.pTargetEntity->IsVehicle()){ TargetCoors = TheCamera.pTargetEntity->GetPosition(); TargetCoors.z += TheCamera.pTargetEntity->GetColModel()->boundingBox.max.z; }else return; if(ResetStatics){ TheCamera.m_uiTimeLastChange = CTimer::GetTimeInMilliseconds(); CamPos = TargetCoors; CamPos.z += DEADCAM_HEIGHT_START; float WaterZ = 0.0f; if(CWaterLevel::GetWaterLevelNoWaves(TargetCoors.x, TargetCoors.y, TargetCoors.z, &WaterZ)){ if(WaterZ + 1.5f > CamPos.z) CamPos.z = WaterZ + 1.5f; } CVector Right = CrossProduct(TheCamera.pTargetEntity->GetForward(), CVector(0.0f, 0.0f, 1.0f)); Right.z = 0.0f; Right.Normalise(); Front = TargetCoors - CamPos; Front.Normalise(); Up = CrossProduct(Right, Front); Up.Normalise(); ResetStatics = false; }else{ CamPos = Source; if(CWorld::TestSphereAgainstWorld(CamPos+CVector(0.0f, 0.0f, 0.2f), 0.3f, TheCamera.pTargetEntity, true, true, false, true, false, true) == nil) CamPos.z += DEADCAM_HEIGHT_RATE*CTimer::GetTimeStep(); CVector Right = CrossProduct(TheCamera.pTargetEntity->GetForward(), CVector(0.0f, 0.0f, 1.0f)); Right.z = 0.0f; Right.Normalise(); float Time = CTimer::GetTimeInMilliseconds() - TheCamera.m_uiTimeLastChange; CVector WaftOffset = DEADCAM_WAFT_AMPLITUDE * Min(1000.0f,Time)/1000.0f * Sin(Time/DEADCAM_WAFT_RATE) * Right; CVector WaftPos = TargetCoors + WaftOffset; WaftPos.z = CamPos.z; CVector WaftFront = WaftPos - CamPos; WaftFront.Normalise(); if(CWorld::TestSphereAgainstWorld(CamPos+0.2f*WaftFront, 0.3f, TheCamera.pTargetEntity, true, true, false, true, false, true) == nil) CamPos = WaftPos; Front = CVector(0.0f, 0.0f, -1.0f); Front += Cos(Time/DEADCAM_WAFT_RATE) * DEADCAM_WAFT_TILT_AMP * Min(2000.0f,Time)/2000.0f * Right; Front.Normalise(); Up = CrossProduct(Right, Front); Up.Normalise(); } Source = CamPos; CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, TargetCoors, Source, FOV); TheCamera.m_bMoveCamToAvoidGeom = false; } float ARRESTDIST_BEHIND_COP = 5.0f; float ARRESTDIST_RIGHTOF_COP = 3.0f; float ARRESTDIST_ABOVE_COP = 1.4f; // unused float ARRESTDIST_MINFROM_PLAYER = 8.0f; float ARRESTCAM_LAMP_BEST_DIST = 17.0f; float ARRESTCAM_ROTATION_SPEED = 0.1f; float ARRESTCAM_ROTATION_UP = 0.05f; float ARRESTCAM_S_ROTATION_UP = 0.1f; float ARRESTDIST_ALONG_GROUND = 5.0f; float ARRESTDIST_SIDE_GROUND = 10.0f; float ARRESTDIST_ABOVE_GROUND = 0.7f; float ARRESTCAM_LAMPPOST_ROTATEDIST = 10.0f; float ARRESTCAM_LAMPPOST_TRANSLATE = 0.1f; bool CCam::GetLookAlongGroundPos(CEntity *Target, CPed *Cop, CVector &TargetCoors, CVector &SourceOut) { if(Target == nil || Cop == nil) return false; CVector CopToTarget = TargetCoors - Cop->GetPosition(); CopToTarget.z = 0.0f; CopToTarget.Normalise(); SourceOut = TargetCoors + ARRESTDIST_ALONG_GROUND*CopToTarget; CVector Side = CrossProduct(CopToTarget, CVector(0.0f, 0.0f, 1.0f)); SourceOut += ARRESTDIST_SIDE_GROUND*Side; SourceOut.z += 5.0f; bool found = false; float ground = CWorld::FindGroundZFor3DCoord(SourceOut.x, SourceOut.y, SourceOut.z, &found); if(found) SourceOut.z = ground + ARRESTDIST_ABOVE_GROUND; return true; } bool CCam::GetLookFromLampPostPos(CEntity *Target, CPed *Cop, CVector &TargetCoors, CVector &SourceOut) { int i; int16 NumObjects; CEntity *Objects[16]; CEntity *NearestLampPost = nil; CWorld::FindObjectsInRange(TargetCoors, 30.0f, true, &NumObjects, 15, Objects, false, false, false, true, true); float NearestDist = 10000.0f; for(i = 0; i < NumObjects; i++){ if(Objects[i]->GetIsStatic() && Objects[i]->GetUp().z > 0.9f && IsLampPost(Objects[i]->GetModelIndex())){ float Dist = (Objects[i]->GetPosition() - TargetCoors).Magnitude2D(); if(Abs(ARRESTCAM_LAMP_BEST_DIST - Dist) < NearestDist){ CVector TestStart = Objects[i]->GetColModel()->boundingBox.max; TestStart = Objects[i]->GetMatrix() * TestStart; CVector TestEnd = TestStart - TargetCoors; TestEnd.Normalise(); TestEnd += TargetCoors; if(CWorld::GetIsLineOfSightClear(TestStart, TestEnd, true, false, false, false, false, true, true)){ NearestDist = Abs(ARRESTCAM_LAMP_BEST_DIST - Dist); NearestLampPost = Objects[i]; SourceOut = TestStart; } } } } return NearestLampPost != nil; } bool CCam::GetLookOverShoulderPos(CEntity *Target, CPed *Cop, CVector &TargetCoors, CVector &SourceOut) { if(Target == nil || Cop == nil) return false; CVector CopCoors = Cop->GetPosition(); CVector CopToTarget = TargetCoors - CopCoors; CVector Side = CrossProduct(CopToTarget, CVector(0.0f, 0.0f, 1.0f)); Side.Normalise(); CopCoors += ARRESTDIST_RIGHTOF_COP * Side; CopToTarget.Normalise(); if(CopToTarget.z < -0.7071f){ CopToTarget.z = -0.7071f; float GroundDist = CopToTarget.Magnitude2D(); if(GroundDist > 0.0f){ CopToTarget.x *= 0.7071f/GroundDist; CopToTarget.y *= 0.7071f/GroundDist; } CopToTarget.Normalise(); }else{ if(CopToTarget.z > 0.0f){ CopToTarget.z = 0.0f; CopToTarget.Normalise(); } } CopCoors -= ARRESTDIST_BEHIND_COP * CopToTarget; CopToTarget = TargetCoors - CopCoors; float Dist = CopToTarget.Magnitude(); if(Dist < ARRESTDIST_MINFROM_PLAYER && Dist > 0.0f) CopToTarget *= ARRESTDIST_MINFROM_PLAYER/Dist; SourceOut = TargetCoors - CopToTarget; return true; } enum { ARRESTCAM_OVERSHOULDER = 1, ARRESTCAM_ALONGGROUND, ARRESTCAM_ALONGGROUND_RIGHT, ARRESTCAM_ALONGGROUND_RIGHT_UP, ARRESTCAM_ALONGGROUND_LEFT, ARRESTCAM_ALONGGROUND_LEFT_UP, ARRESTCAM_LAMPPOST, }; int nUsingWhichCamera; CPed *pStoredCopPed; bool CCam::ProcessArrestCamOne(void) { CVector TargetPos; CVector CamSource; CPed *cop = nil; FOV = 45.0f; bool foundPos = false; int ArrestModes[5] = { -1, -1, -1, -1, -1 }; if(ResetStatics){ CPed *targetPed = (CPed*)TheCamera.pTargetEntity; nUsingWhichCamera = 0; if(TheCamera.pTargetEntity->IsPed()){ ((CPed*)TheCamera.pTargetEntity)->m_pedIK.GetComponentPosition(TargetPos, PED_MID); if(FindPlayerPed() && FindPlayerPed()->m_pArrestingCop) cop = FindPlayerPed()->m_pArrestingCop; if(cop && CGeneral::GetRandomNumberInRange(0.0f, 1.0f) > 0.5f){ ArrestModes[0] = ARRESTCAM_OVERSHOULDER; ArrestModes[1] = ARRESTCAM_ALONGGROUND; ArrestModes[2] = ARRESTCAM_OVERSHOULDER; ArrestModes[3] = ARRESTCAM_LAMPPOST; }else{ ArrestModes[0] = ARRESTCAM_ALONGGROUND; ArrestModes[1] = ARRESTCAM_OVERSHOULDER; ArrestModes[2] = ARRESTCAM_LAMPPOST; } }else if(TheCamera.pTargetEntity->IsVehicle()){ CVehicle *targetVehicle = (CVehicle*)TheCamera.pTargetEntity; if(targetVehicle->pDriver && targetVehicle->pDriver->IsPlayer()){ targetPed = targetVehicle->pDriver; targetPed->m_pedIK.GetComponentPosition(TargetPos, PED_MID); }else{ targetPed = nil; TargetPos = targetVehicle->GetPosition(); } if(FindPlayerPed() && FindPlayerPed()->m_pArrestingCop) cop = FindPlayerPed()->m_pArrestingCop; if(cop && CGeneral::GetRandomNumberInRange(0.0f, 1.0f) > 0.65f){ ArrestModes[0] = ARRESTCAM_OVERSHOULDER; ArrestModes[1] = ARRESTCAM_LAMPPOST; ArrestModes[2] = ARRESTCAM_ALONGGROUND; ArrestModes[3] = ARRESTCAM_OVERSHOULDER; }else{ ArrestModes[0] = ARRESTCAM_LAMPPOST; ArrestModes[1] = ARRESTCAM_ALONGGROUND; ArrestModes[2] = ARRESTCAM_OVERSHOULDER; } }else return false; for(int i = 0; nUsingWhichCamera == 0 && i < ARRAY_SIZE(ArrestModes) && ArrestModes[i] > 0; i++){ switch(ArrestModes[i]){ case ARRESTCAM_OVERSHOULDER: if(cop){ foundPos = GetLookOverShoulderPos(TheCamera.pTargetEntity, cop, TargetPos, CamSource); pStoredCopPed = cop; cop = nil; }else if(targetPed){ for(int j = 0; j < targetPed->m_numNearPeds; j++){ CPed *nearPed = targetPed->m_nearPeds[j]; if(nearPed->GetPedState() == PED_ARREST_PLAYER) foundPos = GetLookOverShoulderPos(TheCamera.pTargetEntity, nearPed, TargetPos, CamSource); if(foundPos){ pStoredCopPed = nearPed; break; } } } break; case ARRESTCAM_ALONGGROUND: if(cop){ foundPos = GetLookAlongGroundPos(TheCamera.pTargetEntity, cop, TargetPos, CamSource); pStoredCopPed = cop; cop = nil; }else if(targetPed){ for(int j = 0; j < targetPed->m_numNearPeds; j++){ CPed *nearPed = targetPed->m_nearPeds[j]; if(nearPed->GetPedState() == PED_ARREST_PLAYER) foundPos = GetLookAlongGroundPos(TheCamera.pTargetEntity, nearPed, TargetPos, CamSource); if(foundPos){ pStoredCopPed = nearPed; break; } } } break; case ARRESTCAM_LAMPPOST: foundPos = GetLookFromLampPostPos(TheCamera.pTargetEntity, cop, TargetPos, CamSource); break; } if(foundPos){ if(pStoredCopPed) pStoredCopPed->RegisterReference((CEntity**)&pStoredCopPed); nUsingWhichCamera = ArrestModes[i]; if(ArrestModes[i] == ARRESTCAM_ALONGGROUND){ float rnd = CGeneral::GetRandomNumberInRange(0.0f, 5.0f); if(rnd < 1.0f) nUsingWhichCamera = ARRESTCAM_ALONGGROUND; else if(rnd < 2.0f) nUsingWhichCamera = ARRESTCAM_ALONGGROUND_RIGHT; else if(rnd < 3.0f) nUsingWhichCamera = ARRESTCAM_ALONGGROUND_RIGHT_UP; else if(rnd < 4.0f) nUsingWhichCamera = ARRESTCAM_ALONGGROUND_LEFT; else nUsingWhichCamera = ARRESTCAM_ALONGGROUND_LEFT_UP; } }else pStoredCopPed = nil; } Source = CamSource; CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, TargetPos, Source, FOV); Front = TargetPos - Source; Front.Normalise(); Up = CVector(0.0f, 0.0f, 1.0f); CVector Right = CrossProduct(Front, Up); Right.Normalise(); Up = CrossProduct(Right, Front); if(nUsingWhichCamera != 0) ResetStatics = false; return true; } if(TheCamera.pTargetEntity->IsPed()){ ((CPed*)TheCamera.pTargetEntity)->m_pedIK.GetComponentPosition(TargetPos, PED_MID); }else if(TheCamera.pTargetEntity->IsVehicle()){ CPed *driver = ((CVehicle*)TheCamera.pTargetEntity)->pDriver; if(driver && driver->IsPlayer()) driver->m_pedIK.GetComponentPosition(TargetPos, PED_MID); else TargetPos = TheCamera.pTargetEntity->GetPosition(); }else return false; if(nUsingWhichCamera == ARRESTCAM_OVERSHOULDER && pStoredCopPed){ foundPos = GetLookOverShoulderPos(TheCamera.pTargetEntity, pStoredCopPed, TargetPos, CamSource); float newZ = Source.z + ARRESTCAM_S_ROTATION_UP*CTimer::GetTimeStep(); if(CamSource.z > newZ) CamSource.z = newZ; }else if(nUsingWhichCamera >= ARRESTCAM_ALONGGROUND_RIGHT && nUsingWhichCamera <= ARRESTCAM_ALONGGROUND_LEFT_UP){ CamSource = Source; Front = TargetPos - CamSource; Front.Normalise(); Up = CVector(0.0f, 0.0f, 1.0f); CVector Right = CrossProduct(Front, Up); if(nUsingWhichCamera == ARRESTCAM_ALONGGROUND_LEFT || nUsingWhichCamera == ARRESTCAM_ALONGGROUND_LEFT_UP) Right *= -1.0f; if(CWorld::TestSphereAgainstWorld(CamSource + 0.5f*Right, 0.4f, TheCamera.pTargetEntity, true, true, false, true, false, true) == nil){ foundPos = true; CamSource += Right*ARRESTCAM_ROTATION_SPEED*CTimer::GetTimeStep(); if(nUsingWhichCamera == ARRESTCAM_ALONGGROUND_RIGHT_UP || nUsingWhichCamera == ARRESTCAM_ALONGGROUND_LEFT_UP){ CamSource.z += ARRESTCAM_ROTATION_UP*CTimer::GetTimeStep(); }else{ bool found = false; float ground = CWorld::FindGroundZFor3DCoord(CamSource.x, CamSource.y, CamSource.z, &found); if(found) CamSource.z = ground + ARRESTDIST_ABOVE_GROUND; } } }else if(nUsingWhichCamera == ARRESTCAM_LAMPPOST){ CamSource = Source; Front = TargetPos - CamSource; Front.z = 0.0f; Front.Normalise(); Up = CVector(0.0f, 0.0f, 1.0f); CVector Right = CrossProduct(Front, Up); Right.Normalise(); Front = TargetPos - CamSource + Right*ARRESTCAM_LAMPPOST_ROTATEDIST; Front.z = 0.0f; Front.Normalise(); if(CWorld::TestSphereAgainstWorld(CamSource + 0.5f*Front, 0.4f, TheCamera.pTargetEntity, true, true, false, true, false, true) == nil){ foundPos = true; CamSource += Front*ARRESTCAM_LAMPPOST_TRANSLATE*CTimer::GetTimeStep(); } } if(foundPos){ Source = CamSource; CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, TargetPos, Source, FOV); Front = TargetPos - Source; Front.Normalise(); Up = CVector(0.0f, 0.0f, 1.0f); CVector Right = CrossProduct(Front, Up); Right.Normalise(); Up = CrossProduct(Right, Front); }else{ CVector OrigSource = Source; TheCamera.AvoidTheGeometry(OrigSource, TargetPos, Source, FOV); } 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; if(&TheCamera.Cams[TheCamera.ActiveCam] == this){ SourceX = TheCamera.Cams[(TheCamera.ActiveCam + 1) % 2].Source.x; SourceY = TheCamera.Cams[(TheCamera.ActiveCam + 1) % 2].Source.y; }else{ SourceX = TheCamera.Cams[TheCamera.ActiveCam].Source.x; SourceY = TheCamera.Cams[TheCamera.ActiveCam].Source.y; } for(int i = 0; i <= 1; i++){ int Dir = i == 0 ? 1 : -1; FOV = 60.0f; 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; } #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 * (1.0f/20.0f) * FOV/80.0f * CTimer::GetTimeStep(); AlphaOffset = LookUpDown * fStickSens * (0.6f/20.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); else 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; } if(TheCamera.m_bUseTransitionBeta) Beta = CGeneral::GetATanOfXY(-Cos(m_fTransitionBeta), -Sin(m_fTransitionBeta)); if(TheCamera.m_bUseTransitionBeta) Beta = CGeneral::GetATanOfXY(-Cos(m_fTransitionBeta), -Sin(m_fTransitionBeta)); 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 > DEFAULT_NEAR + 0.1f){ // 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::CalculateAspectRatio() * 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 Near = RwCameraGetNearClipPlane(Scene.camera); radius = ViewPlaneWidth*Near; 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->GetVehicleAppearance() == VEHICLE_APPEARANCE_PLANE; bool isHeli = car->GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI; bool isBike = car->GetVehicleAppearance() == VEHICLE_APPEARANCE_BIKE; 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->GetModelIndex() == MI_FIRETRUCK) { camSetArrPos = 7; } else if (car->GetModelIndex() == MI_RCBANDIT || car->GetModelIndex() == MI_RCBARON) { camSetArrPos = 5; } else if (car->GetModelIndex() == MI_RCGOBLIN || car->GetModelIndex() == MI_RCRAIDER) { camSetArrPos = 6; } 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->GetStatus() == STATUS_PLAYER_REMOTE) zoomModeAlphaOffset = ZmTwoAlphaOffsetLCS[alphaArrPos]; else { switch ((int)TheCamera.CarZoomIndicator) { // near case CAM_ZOOM_1: zoomModeAlphaOffset = ZmOneAlphaOffsetLCS[alphaArrPos]; break; // mid case CAM_ZOOM_2: zoomModeAlphaOffset = ZmTwoAlphaOffsetLCS[alphaArrPos]; break; // far case CAM_ZOOM_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; // Taken from VC CCam::Cam_On_A_String_Unobscured. If we don't this, we will end up seeing the world from the inside of RC Goblin/Raider. // I couldn't find where SA does that. It's possible that they've increased the size of these veh.'s collision bounding box. if (car->m_modelIndex == MI_RCRAIDER || car->m_modelIndex == MI_RCGOBLIN) newDistance += INIT_RC_HELI_HORI_EXTRA; else if (car->m_modelIndex == MI_RCBARON) newDistance += INIT_RC_PLANE_HORI_EXTRA; float minDistForThisCar = approxCarLength * CARCAM_SET[camSetArrPos][3]; if (!isHeli || car->GetStatus() == 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 += 0.6f * car->GetUp() * colMaxZ; } if (car->m_modelIndex == MI_RCGOBLIN) zoomModeAlphaOffset += 0.178997f; float minDistForVehType = CARCAM_SET[camSetArrPos][4]; if (TheCamera.CarZoomIndicator == CAM_ZOOM_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; } 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; FOV = clamp(FOV, DefaultFOV, 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; if (!TheCamera.m_bJustCameOutOfGarage) { 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) 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->GetModelIndex() != MI_FIRETRUCK) if (!isBike || ((CBike*)car)->m_nWheelsOnGround > 3) if (!isHeli && (!isPlane || ((CAutomobile*)car)->m_nWheelsOnGround)) { 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. To make it work better with III/VC, check for actual pad state instead if (!CPad::IsAffectedByController && !isCar) stickY = 0.0f; else if (CPad::bInvertLook4Pad) stickY = -stickY; 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->GetModelIndex() != MI_VOODOO) { correctAlpha = false; } else { xMovement = 0.0f; yMovement = 0.0f; } // } else // yMovement = 0.0; if (!nextDirectionIsForward) { yMovement = 0.0f; xMovement = 0.0f; } 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_CAR) { 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 && ((CBike*)car)->m_nWheelsOnGround > 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) { // LCS uses exactly the same collision code as FollowPedWithMouse, so we will do so. // This is only in LCS! float timestepFactor = Pow(0.99f, CTimer::GetTimeStep()); dontCollideWithCars = (timestepFactor * dontCollideWithCars) + ((1.0f - timestepFactor) * car->m_vecMoveSpeed.Magnitude()); // Our addition #define IS_TRAFFIC_LIGHT(ent) (ent->IsObject() && IsLightObject(ent->GetModelIndex())) // Clip Source and fix near clip CColPoint colPoint; CEntity* entity; CWorld::pIgnoreEntity = CamTargetEntity; if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, dontCollideWithCars < 0.1f, false, true, false, true, true) && !IS_TRAFFIC_LIGHT(entity)){ float PedColDist = (TargetCoors - colPoint.point).Magnitude(); float ColCamDist = newDistance - PedColDist; if(entity->IsPed() && ColCamDist > DEFAULT_NEAR + 0.1f){ // Ped in the way but not clipping through if(CWorld::ProcessLineOfSight(colPoint.point, Source, colPoint, entity, true, dontCollideWithCars < 0.1f, false, true, false, true, true) || IS_TRAFFIC_LIGHT(entity)){ 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; // If we're seeing blue hell due to camera intersects some surface, fix it. // SA and LCS have this unrolled. float ViewPlaneHeight = Tan(DEGTORAD(FOV) / 2.0f); float ViewPlaneWidth = ViewPlaneHeight * CDraw::CalculateAspectRatio() * fTweakFOV; float Near = RwCameraGetNearClipPlane(Scene.camera); float radius = ViewPlaneWidth*Near; entity = CWorld::TestSphereAgainstWorld(Source + Front*Near, radius, nil, true, true, false, true, false, true); int i = 0; while(entity){ if (IS_TRAFFIC_LIGHT(entity)) break; 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 Near = RwCameraGetNearClipPlane(Scene.camera); radius = ViewPlaneWidth*Near; entity = CWorld::TestSphereAgainstWorld(Source + Front*Near, radius, nil, true, true, false, true, false, true); i++; if(i > 5) entity = nil; } #undef IS_TRAFFIC_LIGHT } 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; // CCam::FixSourceAboveWaterLevel if (CameraTarget.z >= -2.0f) { float level = -6000.0; if (CWaterLevel::GetWaterLevelNoWaves(Source.x, Source.y, Source.z, &level)) { if (Source.z < level) Source.z = level; } } Front = TargetCoors - Source; // -------- LCS specific part ends GetVectorsReadyForRW(); // SA // gTargetCoordsForLookingBehind = TargetCoors; // SA code from CAutomobile::TankControl/FireTruckControl. if (car->GetModelIndex() == MI_RHINO || car->GetModelIndex() == 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->GetModelIndex() == 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->GetModelIndex() == MI_FIRETRUCK ? 0.05f : 0.015f); if (neededTurn <= turnPerFrame) { if (neededTurn < -turnPerFrame) angleToFace = carGunLR - turnPerFrame; } else { angleToFace = turnPerFrame + carGunLR; } if (car->GetModelIndex() == 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->GetModelIndex() == 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