//============================================================================= // Vehicle // this abstract base class contains gameplay and AI code for vehicles //============================================================================= class Vehicle extends Pawn native nativereplication abstract; var globalconfig bool bVehicleShadows; // Global config option for vehicle shadows var bool bDriving; // Vehicle is being driven var bool bOldDriving; var bool bDrawVehicleShadow; // Vehicle Shadow var (Vehicle) bool bDrawDriverInTP; // Whether to draw the driver when in 3rd person mode. var (Vehicle) bool bDriverCollideActors; // if driver is drawn in vehicle, is Driver.bCollideActors true ? var (Vehicle) bool bRelativeExitPos; // relative vector to vehicle? var bool bDefensive; // should be used by defenders var bool bAutoTurret; // controlled by AI if no player controlling (FIXME Move to subclass) var bool bRemoteControlled; // destroying vehicle won't kill player var bool bEjectDriver; // If vehicle is destroyed, don't kill and eject driver(s) var bool bTurnInPlace; // whether vehicle can turn in place var bool bFollowLookDir; // used by AI to know that controller's rotation determines vehicle rotation var bool bNonHumanControl; // Cannot be controlled by humans var bool bStalled; // Vehicle is stalled (can't apply acceleration) var bool bVehicleDestroyed; // Vehicle has been destroyed (no more need to simulate special vehicle physics) var bool bShowDamageOverlay; // Vehicle should display the normal pawn damage overlay when hit by a weapon var bool bDropDetail; // Vehicle should reduce its detail level var bool bNoFriendlyFire; // FriendlyFire disabled for this vehicle var bool bCanHover; // Actor can hover above water var bool bCanDoTrickJumps; // AI hint // Cameras var (Vehicle) bool bDrawMeshInFP; // Whether to draw the vehicle mesh when in 1st person mode. var (Vehicle) bool bZeroPCRotOnEntry; // If true, set camera rotation to zero on entering vehicle. If false, set it to the vehicle rotation. var bool bPCRelativeFPRotation; // In 1st person, PlayerController rotation is relative to vehicle rotation var bool bWeaponisFiring; var bool bWeaponisAltFiring; var bool bTeamLocked; // Team defines which players are allowed to enter the vehicle var bool bEnterringUnlocks; // Vehicle is unlocked when a player enterred it.. var bool bCanFlip; var bool bAllowViewChange; var bool bAllowWeaponToss; //if the driver dies, will he toss his weapon? var(Vehicle) bool bHUDTrackVehicle; // If true, Vehicle will tracked on HUD. (For Objectives in Assault) var bool bHasRadar; var bool bHasHandbrake; // hint for AI var bool bScriptedRise; // hint for AI var bool bKeyVehicle; // hint for AI var bool bSeparateTurretFocus; // hint for AI (for tank type turreted vehicles) var() bool bHighScoreKill; // vehicle is considered important, and awards 5 points upon destruction. var bool bAdjustDriversHead; // rotate driver's head depending on view rotation var bool bEnemyLockedOn; var config bool bDesiredBehindView; var bool bHideRemoteDriver; // If Set to true, the remote controlling driver will be hidden var bool bShowChargingBar; var bool bDriverHoldsFlag; var bool bCanCarryFlag; var bool bSpawnProtected; // Cannot be destroyed by a player before its been possessed. var() bool bFPNoZFromCameraPitch; // Ignore any vehicle-space Z due to FPCamViewOffset (so looking up and down doesn't change camera Z rel to vehicle) var byte StuckCount; // used by AI var() byte Team; var byte OldTeam, PrevTeam; // OldTeam is used for replication purposes, PrevTeam is the team of the previous driver. var Rotator PlayerEnterredRotation; // Original rotation when player enterred vehicle var float EjectMomentum; var class AutoTurretControllerClass; // generic controls (set by controller, used by concrete derived classes) var (Vehicle) float Steering; // between -1 and 1 var (Vehicle) float Throttle; // between -1 and 1 var (Vehicle) float Rise; // between -1 and 1 var int DriverViewPitch; // The driver's view pitch var int DriverViewYaw; // The driver's view yaw var float ThrottleTime; // last time at which throttle was 0 (used by AI) var float StuckTime; var float VehicleMovingTime; // used by AI C++ var (Vehicle) vector DrivePos; // Position (rel to vehicle) to put player while driving. var (Vehicle) rotator DriveRot; // Rotation (rel to vehicle) to put driver while driving. var (Vehicle) name DriveAnim; // Animation to play while driving. //Info for EntryPositions var (Vehicle) array ExitPositions; // Positions (rel to vehicle) to try putting the player when exiting. var (Vehicle) vector EntryPosition; // Offset for the entry trigger var (Vehicle) float EntryRadius; // Radius for the entry trigger var (Vehicle) vector FPCamPos; // Position of camera when driving first person. var (Vehicle) vector FPCamViewOffset; // Offset in reference frame of camera. //clientside settings var config float TPCamDistance; // force feedback var string CenterSpringForce; var int CenterSpringRangePitch; var int CenterSpringRangeRoll; var (Vehicle) vector TPCamLookat; // Look at location in vehicle space var (Vehicle) vector TPCamWorldOffset; // Applied in world space after vehicle transform. var float DesiredTPCamDistance, LastCameraCalcTime, CameraSpeed; //for smoothly interpolating TPCamDistance to new value var (Vehicle) Range TPCamDistRange; var (Vehicle) int MaxViewYaw; // Maximum amount you can look left and right var (Vehicle) int MaxViewPitch; // Maximum amount you can look up and down var Pawn Driver; // Can be None if Controller spawns right away with vehicle var SVehicleFactory ParentFactory; // FX var String TransEffects[2]; // Spawning effects var ShadowProjector VehicleShadow; // Shadow projector var float ShadowMaxTraceDist; var float ShadowCullDistance; var float MomentumMult; //damage momentum multiplied by this value before being applied to vehicle var float DriverDamageMult; //damage to the driver is multiplied by this value // Missle warning var String LockOnClassString; var float LastLockWarningTime; var float LockWarningInterval; var Vehicle NextVehicle; var localized string VehiclePositionString; var localized cache string VehicleNameString; var localized cache string VehicleDescription; var Texture TeamBeaconTexture, NoEntryTexture; var Material TeamBeaconBorderMaterial; var AIMarker myMarker; // used for stationary turrets //VEHICULAR MANSLAUGHTER var float MinRunOverSpeed; //speed must be greater than this for running into someone to do damage var class RanOverDamageType, CrushedDamageType; var sound RanOverSound; var name StolenAnnouncement; var sound StolenSound; var float LinkHealMult; // If > 0, Link Gun secondary heals an amount equal to its damage times this var float OldSteering; var float VehicleLostTime, TeamUseTime, PlayerStartTime; var float MaxDesireability; var const float AIMoveCheckTime; var float ObjectiveGetOutDist; //if AI controlled and bot needs to trigger an objective not triggerable by vehicles, it will try to get out this far away var name FlagBone; var vector FlagOffset; var rotator FlagRotation; var float WheelsScale; // HORN var array HornSounds; var float LastHornTime; // BULLET HITS var() array BulletSounds; // WATER DAMAGE var() float WaterDamage; var class VehicleDrowningDamType; // HUD OVERLAY var class HUDOverlayClass; var Actor HUDOverlay; var() vector HUDOverlayOffset; var() float HUDOverlayFOV; // SPAWN OVERLAY MATERIAL var() Material SpawnOverlay[2]; struct native SVehicleIcon { var Material Material; var float X, Y, SizeX, SizeY; var bool bIsGreyScale; }; var SVehicleIcon VehicleIcon; // if _RO_ // Interpolated throttle var float ThrottleAmount; //Client side only. Used by the PlayerController to smoothly interpolate the throttle rather than having it be all or nothing var bool bKeepDriverAuxCollision; // Keep the auxilary collision turned on for the driver of this vehicle - used only for ROPawn drivers (or ROPawn subclasses) cpptext { virtual void PreNetReceive(); virtual void PostNetReceive(); void performPhysics(FLOAT DeltaSeconds); virtual UBOOL moveToward(const FVector &Dest, AActor *GoalActor); virtual void rotateToward(AActor *Focus, FVector FocalPoint); virtual void PostRender(FLevelSceneNode* SceneNode, FRenderInterface* RI); virtual UBOOL IsStuck(); INT* GetOptimizedRepList(BYTE* Recent, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map, UActorChannel* Channel); INT AddMyMarker(AActor *S); void SteerVehicle(FVector Direction); UBOOL IsNetRelevantFor( APlayerController* RealViewer, AActor* Viewer, FVector SrcLocation ); virtual FVector GetDestination(AController *C); virtual void setMoveTimer(FVector MoveDir); virtual UBOOL Tick(FLOAT DeltaTime, enum ELevelTick TickType); virtual UBOOL AdjustFlight(FLOAT ZDiff, UBOOL bFlyingDown, FLOAT Distance, AActor* GoalActor); } replication { reliable if ( Role==ROLE_Authority ) ClientKDriverEnter, ClientKDriverLeave, FixPCRotation, ClientClearController; unreliable if( bNetDirty && Role==ROLE_Authority ) bDriving, bTeamLocked, Driver, Team, bVehicleDestroyed, WheelsScale; unreliable if( bNetInitial && Role==ROLE_Authority ) bHUDTrackVehicle; reliable if ( Role < ROLE_Authority ) VehicleFire, VehicleCeaseFire; } function PreBeginPlay() { if ( !Level.Game.bAllowVehicles && !bDeleteMe ) { Destroy(); return; } Super.PreBeginPlay(); } // if _RO_ // Ammo interface // Implemented in sublclasses. Returns true if this vehicle's ammo was successfully resupplied function bool ResupplyAmmo(){return false;} function EnteredResupply(); function LeftResupply(); // end _RO_ function PlayerChangedTeam() { if ( Driver != None ) Driver.KilledBy(Driver); else Super.PlayerChangedTeam(); } simulated function SetBaseEyeheight() { BaseEyeheight = Default.BaseEyeheight; Eyeheight = BaseEyeheight; } simulated function string GetVehiclePositionString() { return VehiclePositionString; } function Suicide() { if ( Driver != None ) Driver.KilledBy(Driver); else KilledBy(self); } function bool CheatWalk() { return false; } function bool CheatGhost() { return false; } function bool CheatFly() { return false; } simulated function PostBeginPlay() { local controller NewController; super.PostBeginPlay(); if ( bDeleteMe ) return; // if _RO_ /* // end if _RO_ // Glue a shadow projector on VehicleShadow = Spawn(class'ShadowProjector', self, '', Location); VehicleShadow.ShadowActor = Self; VehicleShadow.bBlobShadow = false; VehicleShadow.LightDirection = Normal(vect(1,1,6)); VehicleShadow.LightDistance = 1200; VehicleShadow.MaxTraceDistance = ShadowMaxTraceDist; VehicleShadow.CullDistance = ShadowCullDistance; VehicleShadow.InitShadow(); // if _RO_ */ UpdateShadow(); // end if _RO_ if ( Role == Role_Authority ) { if ( bAutoTurret && (Controller == None) && (AutoTurretControllerClass != None) ) { NewController = spawn(AutoTurretControllerClass); if ( NewController != None ) NewController.Possess(self); } if ( !bAutoTurret && !bNonHumanControl && IndependentVehicle() ) Level.Game.RegisterVehicle(self); } OldTeam = Team; PrevTeam = Team; } // if _RO_ simulated function UpdateShadow() { if ( bVehicleShadows && bDrawVehicleShadow && (Level.NetMode != NM_DedicatedServer) ) { if (VehicleShadow != none) return; // Glue a shadow projector on VehicleShadow = Spawn(class'ShadowProjector', self, '', Location); VehicleShadow.ShadowActor = Self; VehicleShadow.bBlobShadow = false; VehicleShadow.LightDirection = Normal(vect(1,1,6)); VehicleShadow.LightDistance = 1200; VehicleShadow.MaxTraceDistance = ShadowMaxTraceDist; VehicleShadow.CullDistance = ShadowCullDistance; VehicleShadow.InitShadow(); } else if (VehicleShadow != none && Level.NetMode != NM_DedicatedServer) { VehicleShadow.Destroy(); VehicleShadow = none; } } // end if _RO_ simulated event SetInitialState() { Super.SetInitialState(); Disable('Tick'); } function bool StronglyRecommended(Actor S, int TeamIndex, Actor Objective) { return bKeyVehicle; } //return a value indicating how useful this vehicle is to bots function float BotDesireability(Actor S, int TeamIndex, Actor Objective) { local bool bSameTeam; local PlayerController P; bSameTeam = ( GetTeamNum() == TeamIndex ); if ( bSameTeam ) { if ( Level.TimeSeconds < TeamUseTime ) return 0; if ( !bKeyVehicle && (Level.TimeSeconds < PlayerStartTime) ) { P = Level.GetLocalPlayerController(); if ( (P == None) || ((P.Pawn != None) && (Vehicle(P.Pawn) == None)) ) return 0; } } if ( !bKeyVehicle && !bStationary && (Level.TimeSeconds < VehicleLostTime) ) return 0; else if (Health <= 0 || Occupied() || (bTeamLocked && !bSameTeam)) return 0; if (bKeyVehicle) return 100; return ((MaxDesireability * 0.5) + (MaxDesireability * 0.5 * (float(Health) / HealthMax))); } simulated function Destroyed() { local Vehicle V, Prev; if ( ParentFactory != None ) ParentFactory.VehicleDestroyed( Self ); // Notify parent factory of death if ( VehicleShadow != None ) VehicleShadow.Destroy(); // Destroy shadow projector if ( bAutoTurret && (Controller != None) && ClassIsChildOf(Controller.Class, AutoTurretControllerClass) && !Controller.bDeleteMe ) { Controller.Destroy(); Controller = None; } if ( Driver != None ) Destroyed_HandleDriver(); if ( Level.Game != None ) { if ( Level.Game.VehicleList == Self ) Level.Game.VehicleList = NextVehicle; else { Prev = Level.Game.VehicleList; if ( Prev != None ) for ( V=Level.Game.VehicleList.NextVehicle; V!=None; V=V.NextVehicle ) { if ( V == self ) { Prev.NextVehicle = NextVehicle; break; } else Prev = V; } } } super.Destroyed(); } simulated function Destroyed_HandleDriver() { local Pawn OldDriver; Driver.LastRenderTime = LastRenderTime; if ( Role == ROLE_Authority ) { // if Driver wasn't visible in vehicle, destroy it if ( Driver != None && !bRemoteControlled && !bEjectDriver && !bDrawDriverInTP && Driver.Health > 0 ) { OldDriver = Driver; Driver = None; OldDriver.DrivenVehicle = None; if ( !OldDriver.bDeleteMe ) OldDriver.Destroy(); } else if ( !bRemoteControlled && !bEjectDriver ) { // otherwise spawn dead karma body if (!bDrawDriverInTP && PlaceExitingDriver()) { Driver.StopDriving(self); Driver.DrivenVehicle = self; } Driver.TearOffMomentum = Velocity * 0.25; Driver.Died(Controller, class'DamRanOver', Driver.Location); } } else if ( Driver.DrivenVehicle == self ) Driver.StopDriving(self); } simulated function vector GetCameraLocationStart() { return Location; } simulated function SpecialCalcBehindView(PlayerController PC, out actor ViewActor, out vector CameraLocation, out rotator CameraRotation ) { local vector CamLookAt, HitLocation, HitNormal, OffsetVector; local Actor HitActor; local vector x, y, z; if (DesiredTPCamDistance < TPCamDistance) TPCamDistance = FMax(DesiredTPCamDistance, TPCamDistance - CameraSpeed * (Level.TimeSeconds - LastCameraCalcTime)); else if (DesiredTPCamDistance > TPCamDistance) TPCamDistance = FMin(DesiredTPCamDistance, TPCamDistance + CameraSpeed * (Level.TimeSeconds - LastCameraCalcTime)); GetAxes(PC.Rotation, x, y, z); ViewActor = self; CamLookAt = GetCameraLocationStart() + (TPCamLookat >> Rotation) + TPCamWorldOffset; OffsetVector = vect(0, 0, 0); OffsetVector.X = -1.0 * TPCamDistance; CameraLocation = CamLookAt + (OffsetVector >> PC.Rotation); HitActor = Trace(HitLocation, HitNormal, CameraLocation, CamLookAt, true, vect(40, 40, 40)); if ( HitActor != None && (HitActor.bWorldGeometry || HitActor == GetVehicleBase() || Trace(HitLocation, HitNormal, CameraLocation, CamLookAt, false, vect(40, 40, 40)) != None) ) CameraLocation = HitLocation; CameraRotation = Normalize(PC.Rotation + PC.ShakeRot); CameraLocation = CameraLocation + PC.ShakeOffset.X * x + PC.ShakeOffset.Y * y + PC.ShakeOffset.Z * z; } simulated function SpecialCalcFirstPersonView(PlayerController PC, out actor ViewActor, out vector CameraLocation, out rotator CameraRotation ) { local quat CarQuat, LookQuat, ResultQuat; local vector VehicleZ, CamViewOffsetWorld, x, y, z; local float CamViewOffsetZAmount; GetAxes(PC.Rotation, x, y, z); ViewActor = self; if (bPCRelativeFPRotation) { CarQuat = QuatFromRotator(Rotation); CameraRotation = Normalize(PC.Rotation); LookQuat = QuatFromRotator(CameraRotation); ResultQuat = QuatProduct(LookQuat, CarQuat); CameraRotation = QuatToRotator(ResultQuat); } else CameraRotation = PC.Rotation; // Camera position is locked to car CamViewOffsetWorld = FPCamViewOffset >> CameraRotation; CameraLocation = GetCameraLocationStart() + (FPCamPos >> Rotation) + CamViewOffsetWorld; if(bFPNoZFromCameraPitch) { VehicleZ = vect(0,0,1) >> Rotation; CamViewOffsetZAmount = CamViewOffsetWorld Dot VehicleZ; CameraLocation -= CamViewOffsetZAmount * VehicleZ; } CameraRotation = Normalize(CameraRotation + PC.ShakeRot); CameraLocation = CameraLocation + PC.ShakeOffset.X * x + PC.ShakeOffset.Y * y + PC.ShakeOffset.Z * z; } // Special calc-view for vehicles simulated function bool SpecialCalcView(out actor ViewActor, out vector CameraLocation, out rotator CameraRotation ) { local PlayerController pc; pc = PlayerController(Controller); // Only do this mode we have a playercontroller if( (pc == None) || (pc.Viewtarget != self) ) return false; if( pc.bBehindView ) SpecialCalcBehindView(PC,ViewActor,CameraLocation,CameraRotation); else SpecialCalcFirstPersonView(PC,ViewActor,CameraLocation,CameraRotation); LastCameraCalcTime = Level.TimeSeconds; return true; } simulated function bool SpectatorSpecialCalcView(PlayerController Viewer, out Actor ViewActor, out vector CameraLocation, out rotator CameraRotation) { local rotator DummyRotation; if (Viewer.ViewTarget != self) return false; if (Viewer.bBehindView) { DesiredTPCamDistance = (TPCamDistRange.Max - TPCamDistRange.Min) * (Viewer.CameraDist / Viewer.CameraDistRange.Max) + TPCamDistRange.Min; SpecialCalcBehindView(Viewer, ViewActor, CameraLocation, CameraRotation); } else SpecialCalcFirstPersonView(Viewer, ViewActor, CameraLocation, DummyRotation); //use rotation set by playercontroller LastCameraCalcTime = Level.TimeSeconds; Viewer.SetLocation(CameraLocation); return true; } // Events called on driver entering/leaving vehicle function Vehicle FindEntryVehicle(Pawn P) { if ( AIController(P.Controller) != None ) return self; if (VSize(P.Location - (Location + (EntryPosition >> Rotation))) < EntryRadius) return self; return None; } // The pawn Driver has tried to take control of this vehicle function bool TryToDrive(Pawn P) { if ( P.bIsCrouched || bNonHumanControl || (P.Controller == None) || (Driver != None) || (P.DrivenVehicle != None) || !P.Controller.bIsPlayer || P.IsA('Vehicle') || Health <= 0 ) return false; if( !Level.Game.CanEnterVehicle(self, P) ) return false; // Check vehicle Locking.... if ( !bTeamLocked || P.GetTeamNum() == Team ) { if ( bEnterringUnlocks && bTeamLocked ) bTeamLocked = false; KDriverEnter( P ); return true; } else { VehicleLocked( P ); return false; } } event VehicleLocked( Pawn P ); // Pawn tried to enter vehicle, but it's locked!! function PossessedBy(Controller C) { local PlayerController PC; if ( bAutoTurret && (Controller != None) && ClassIsChildOf(Controller.Class, AutoTurretControllerClass) && !Controller.bDeleteMe ) { Controller.Destroy(); Controller = None; } super.PossessedBy( C ); // Stole another team's vehicle, so set Team to new owner's team if ( C.GetTeamNum() != Team ) { //add stat tracking event/variable here? if ( Team != 255 && PlayerController(C) != None ) { if( StolenAnnouncement != '' ) PlayerController(C).PlayRewardAnnouncement(StolenAnnouncement, 1); if( StolenSound != None ) PlaySound( StolenSound,, 2.5*TransientSoundVolume,, 400); } if ( C.GetTeamNum() != 255 ) SetTeamNum( C.GetTeamNum() ); } NetPriority = 3; NetUpdateFrequency = 100; ThrottleTime = Level.TimeSeconds; bSpawnProtected = false; PC = PlayerController(C); if ( PC != None ) ClientKDriverEnter( PC ); if ( ParentFactory != None && ( !bAutoTurret || !ClassIsChildOf(C.Class, AutoTurretControllerClass) ) ) ParentFactory.VehiclePossessed( Self ); // Notify parent factory } function UnPossessed() { local PlayerController PC; local Controller NewController; local bool bWasPlayer; StopWeaponFiring(); PC = PlayerController(Controller); if ( PC != None ) { bWasPlayer = true; ClientKDriverLeave(PC); if (bPCRelativeFPRotation && !PC.bBehindView) FixPCRotation(PC); } else ClientClearController(); NetPriority = Default.NetPriority; // restore original netpriority changed when possessing NetUpdateTime = Level.TimeSeconds - 1; NetUpdateFrequency = 8; super.UnPossessed(); if ( ParentFactory != None && ( !bAutoTurret || (Controller == None) || !ClassIsChildOf(Controller.Class, AutoTurretControllerClass) ) ) ParentFactory.VehicleUnPossessed( Self ); // Notify parent of UnPossessed() if ( Health > 0 && !bDeleteMe ) { if ( bWasPlayer && bAutoTurret && (AutoTurretControllerClass != None) ) { Controller = None; NewController = spawn(AutoTurretControllerClass); if ( NewController != None ) NewController.Possess( Self ); } } } function KDriverEnter(Pawn P) { local Controller C; bDriving = True; StuckCount = 0; // We don't have pre-defined exit positions here, so we use the original player location as an exit point if ( !bRelativeExitPos ) { PlayerEnterredRotation = P.Rotation; ExitPositions[0] = P.Location + Vect(0,0,16); } // Set pawns current controller to control the vehicle pawn instead C = P.Controller; if ( !bCanCarryFlag && (C.PlayerReplicationInfo.HasFlag != None) ) P.DropFlag(); Driver = P; Driver.StartDriving( Self ); // Disconnect PlayerController from Driver and connect to SVehicle. C.bVehicleTransition = true; // to keep Bots from doing Restart() C.Unpossess(); Driver.SetOwner( Self ); // This keeps the driver relevant. C.Possess( Self ); C.bVehicleTransition = false; DrivingStatusChanged(); if ( PlayerController(C) != None ) VehicleLostTime = 0; AttachFlag(PlayerReplicationInfo.HasFlag); Level.Game.DriverEnteredVehicle(self, P); } function AttachFlag(Actor FlagActor) { if ( !bDriverHoldsFlag && (FlagActor != None) ) { AttachToBone(FlagActor,FlagBone); FlagActor.SetRelativeRotation(FlagRotation); FlagActor.SetRelativeLocation(FlagOffset); } } simulated event SetWheelsScale(float NewScale) { WheelsScale = NewScale; } // Called from the PlayerController when player wants to get out. event bool KDriverLeave( bool bForceLeave ) { local Controller C; local PlayerController PC; local bool havePlaced; if( !bForceLeave && !Level.Game.CanLeaveVehicle(self, Driver) ) return false; if ( (PlayerReplicationInfo != None) && (PlayerReplicationInfo.HasFlag != None) ) Driver.HoldFlag(PlayerReplicationInfo.HasFlag); // Do nothing if we're not being driven if (Controller == None ) return false; // Before we can exit, we need to find a place to put the driver. // Iterate over array of possible exit locations. if ( (Driver != None) && (!bRemoteControlled || bHideRemoteDriver) ) { Driver.bHardAttach = false; Driver.bCollideWorld = true; Driver.SetCollision(true, true); havePlaced = PlaceExitingDriver(); // If we could not find a place to put the driver, leave driver inside as before. if (!havePlaced && !bForceLeave ) { Driver.bHardAttach = true; Driver.bCollideWorld = false; Driver.SetCollision(false, false); return false; } } bDriving = False; // Reconnect Controller to Driver. C = Controller; if (C.RouteGoal == self) C.RouteGoal = None; if (C.MoveTarget == self) C.MoveTarget = None; C.bVehicleTransition = true; Controller.UnPossess(); if ( (Driver != None) && (Driver.Health > 0) ) { Driver.SetOwner( C ); C.Possess( Driver ); PC = PlayerController(C); if ( PC != None ) PC.ClientSetViewTarget( Driver ); // Set playercontroller to view the person that got out Driver.StopDriving( Self ); } C.bVehicleTransition = false; if ( C == Controller ) // If controller didn't change, clear it... Controller = None; Level.Game.DriverLeftVehicle(self, Driver); // Car now has no driver Driver = None; DriverLeft(); // Put brakes on before you get out :) Throttle = 0; Steering = 0; Rise = 0; return true; } // DriverLeft() called by KDriverLeave() function DriverLeft() { DrivingStatusChanged(); } simulated event UpdateTiltForceFeedback() { local rotator SpringCenter; local float pitch, roll; local PlayerController PC; PC = PlayerController(Controller); if ( PC != None ) { SpringCenter = rotation; pitch = Clamp(SpringCenter.Pitch, -CenterSpringRangePitch, CenterSpringRangePitch); roll = Clamp(SpringCenter.Roll, -CenterSpringRangeRoll, CenterSpringRangeRoll); pitch /= CenterSpringRangePitch; roll /= CenterSpringRangeRoll; PC.ChangeSpringFeedbackEffect(CenterSpringForce, roll, pitch); } } simulated function ClientKDriverEnter(PlayerController PC) { // PC.bFreeCamera = true; // Set rotation of camera when getting into vehicle based on bZeroPCRotOnEntry if ( bZeroPCRotOnEntry ) PC.SetRotation( rot(0, 0, 0) ); //set starting camera distance to local player's preferences TPCamDistance = default.TPCamDistance; DesiredTPCamDistance = TPCamDistance; if (!PC.bBehindView) ActivateOverlay(True); if ( PC.bEnableGUIForceFeedback && PC.bForceFeedbackSupported && (Viewport(PC.Player) != None) ) { if ( (CenterSpringRangePitch > 0) && (CenterSpringRangeRoll > 0) ) UpdateTiltForceFeedback(); PC.ClientPlayForceFeedback(CenterSpringForce); } if (Driver!=None) { Driver.AmbientSound=none; if (Driver.Weapon!=None) Driver.Weapon.AmbientSound=none; } } simulated function ClientClearController() { ActivateOverlay(False); } simulated function ClientKDriverLeave(PlayerController PC) { // PC.bFreeCamera = false; // Stop messing with bOwnerNoSee if ( Driver != None ) Driver.bOwnerNoSee = Driver.default.bOwnerNoSee; if (PC.bEnableGUIForceFeedback) PC.StopForceFeedback(CenterSpringForce); bWeaponisFiring = False; bWeaponisAltFiring = False; ActivateOverlay(False); } simulated function ActivateOverlay(bool bActive) { if (bActive) { if (HUDOverlayClass != None && HUDOverlay == None) HUDOverlay = spawn(HUDOverlayClass); } else if (HUDOverlay != None) HUDOverlay.Destroy(); } //seperate replicated function called from UnPossessed() to make PC rotation no longer relative to vehicle //needed because PC.bBehindView will get screwed around with as a result of unpossessing vehicle and repossessing Driver simulated function FixPCRotation(PlayerController PC) { PC.SetRotation(rotator(vector(PC.Rotation) >> Rotation)); } simulated function AttachDriver(Pawn P) { local vector AttachPos; P.bHardAttach = true; AttachPos = Location + (DrivePos >> Rotation); P.SetLocation( AttachPos ); P.SetPhysics( PHYS_None ); P.SetBase( Self ); P.SetRelativeRotation( DriveRot ); } simulated function DetachDriver(Pawn P) {} function bool PlaceExitingDriver() { local int i, j; local vector tryPlace, Extent, HitLocation, HitNormal, ZOffset, RandomSphereLoc; local float BestDir, NewDir; if ( Driver == None ) return false; Extent = Driver.default.CollisionRadius * vect(1,1,0); Extent.Z = Driver.default.CollisionHeight; ZOffset = Driver.default.CollisionHeight * vect(0,0,1); //avoid running driver over by placing in direction perpendicular to velocity if ( VSize(Velocity) > 100 ) { tryPlace = Normal(Velocity cross vect(0,0,1)) * (CollisionRadius + Driver.default.CollisionRadius ) * 1.25 ; if ( (Controller != None) && (Controller.DirectionHint != vect(0,0,0)) ) { if ( (tryPlace dot Controller.DirectionHint) < 0 ) tryPlace *= -1; } else if ( FRand() < 0.5 ) tryPlace *= -1; //randomly prefer other side if ( (Trace(HitLocation, HitNormal, Location + tryPlace + ZOffset, Location + ZOffset, false, Extent) == None && Driver.SetLocation(Location + tryPlace + ZOffset)) || (Trace(HitLocation, HitNormal, Location - tryPlace + ZOffset, Location + ZOffset, false, Extent) == None && Driver.SetLocation(Location - tryPlace + ZOffset)) ) return true; } if ( (Controller != None) && (Controller.DirectionHint != vect(0,0,0)) ) { // first try best position tryPlace = Location; BestDir = 0; for( i=0; i BestDir ) { BestDir = NewDir; tryPlace = ExitPositions[i]; } } Controller.DirectionHint = vect(0,0,0); if ( tryPlace != Location ) { if ( bRelativeExitPos ) { if ( ExitPositions[0].Z != 0 ) ZOffset = Vect(0,0,1) * ExitPositions[0].Z; else ZOffset = Driver.default.CollisionHeight * vect(0,0,2); tryPlace = Location + ( (tryPlace-ZOffset) >> Rotation) + ZOffset; // First, do a line check (stops us passing through things on exit). if ( (Trace(HitLocation, HitNormal, tryPlace, Location + ZOffset, false, Extent) == None) && Driver.SetLocation(tryPlace) ) return true; } else if ( Driver.SetLocation(tryPlace) ) return true; } } if ( !bRelativeExitPos ) { for( i=0; i> Rotation) + ZOffset; // First, do a line check (stops us passing through things on exit). if ( Trace(HitLocation, HitNormal, tryPlace, Location + ZOffset, false, Extent) != None ) continue; // Then see if we can place the player there. if ( !Driver.SetLocation(tryPlace) ) continue; return true; } return false; } function Pawn CheckForHeadShot(Vector loc, Vector ray, float AdditionalScale) { return None; } function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, class damageType, optional int HitIndex) { local int ActualDamage; local Controller Killer; // Spawn Protection: Cannot be destroyed by a player until possessed if ( bSpawnProtected && instigatedBy != None && instigatedBy != Self ) return; NetUpdateTime = Level.TimeSeconds - 1; // force quick net update if (DamageType != None) { if ((instigatedBy == None || instigatedBy.Controller == None) && DamageType.default.bDelayedDamage && DelayedDamageInstigatorController != None) instigatedBy = DelayedDamageInstigatorController.Pawn; Damage *= DamageType.default.VehicleDamageScaling; momentum *= DamageType.default.VehicleMomentumScaling * MomentumMult; if (bShowDamageOverlay && DamageType.default.DamageOverlayMaterial != None && Damage > 0 ) SetOverlayMaterial( DamageType.default.DamageOverlayMaterial, DamageType.default.DamageOverlayTime, false ); } if (bRemoteControlled && Driver!=None) { ActualDamage = Damage; if (Weapon != None) Weapon.AdjustPlayerDamage(ActualDamage, InstigatedBy, HitLocation, Momentum, DamageType ); if (InstigatedBy != None && InstigatedBy.HasUDamage()) ActualDamage *= 2; ActualDamage = Level.Game.ReduceDamage(ActualDamage, self, instigatedBy, HitLocation, Momentum, DamageType); if (Health - ActualDamage <= 0) KDriverLeave(false); } if ( Physics != PHYS_Karma ) { super.TakeDamage(Damage,InstigatedBy,HitLocation,Momentum,DamageType); return; } if (Weapon != None) Weapon.AdjustPlayerDamage(Damage, InstigatedBy, HitLocation, Momentum, DamageType ); if (InstigatedBy != None && InstigatedBy.HasUDamage()) Damage *= 2; ActualDamage = Level.Game.ReduceDamage(Damage, self, instigatedBy, HitLocation, Momentum, DamageType); Health -= ActualDamage; PlayHit(actualDamage, InstigatedBy, hitLocation, damageType, Momentum); // The vehicle is dead! if ( Health <= 0 ) { if ( Driver!=None && (bEjectDriver || bRemoteControlled) ) { if ( bEjectDriver ) EjectDriver(); else KDriverLeave( false ); } // pawn died if ( instigatedBy != None ) Killer = instigatedBy.GetKillerController(); if ( Killer == None && (DamageType != None) && DamageType.Default.bDelayedDamage ) Killer = DelayedDamageInstigatorController; Died(Killer, damageType, HitLocation); } else if ( Controller != None ) Controller.NotifyTakeHit(instigatedBy, HitLocation, actualDamage, DamageType, Momentum); MakeNoise(1.0); if ( !bDeleteMe ) { if ( Location.Z > Level.StallZ ) Momentum.Z = FMin(Momentum.Z, 0); KAddImpulse(Momentum, hitlocation); } } function bool HealDamage(int Amount, Controller Healer, class DamageType) { if ( PlayerController(Healer) != None ) PlayerStartTime = Level.TimeSeconds + 3; if (Health <= 0 || Health >= HealthMax || Amount <= 0 || Healer == None || !TeamLink(Healer.GetTeamNum())) return false; Health = Min(Health + (Amount * LinkHealMult), HealthMax); NetUpdateTime = Level.TimeSeconds - 1; return true; } //determine if radius damage that hit the vehicle should damage the driver function DriverRadiusDamage(float DamageAmount, float DamageRadius, Controller EventInstigator, class DamageType, float Momentum, vector HitLocation) { local float damageScale, dist; local vector dir; //if driver has collision, whatever is causing the radius damage will hit the driver by itself if (EventInstigator == None || Driver == None || Driver.bCollideActors || bRemoteControlled) return; dir = Driver.Location - HitLocation; dist = FMax(1, VSize(dir)); dir = dir/dist; damageScale = 1 - FMax(0,(dist - Driver.CollisionRadius)/DamageRadius); if (damageScale <= 0) return; Driver.SetDelayedDamageInstigatorController(EventInstigator); Driver.TakeDamage( damageScale * DamageAmount, EventInstigator.Pawn, Driver.Location - 0.5 * (Driver.CollisionHeight + Driver.CollisionRadius) * dir, damageScale * Momentum * dir, DamageType ); } function DriverDied() { local Controller C; Level.Game.DiscardInventory( Driver ); if (PlayerReplicationInfo != None && PlayerReplicationInfo.HasFlag != None) PlayerReplicationInfo.HasFlag.Drop(0.5 * Velocity); if ( Driver == None ) return; C = Controller; Driver.StopDriving( Self ); Driver.Controller = C; Driver.DrivenVehicle = self; //for in game stats, so it knows pawn was killed inside a vehicle if ( Controller == None ) return; if ( PlayerController(Controller) != None ) { Controller.SetLocation(Location); PlayerController(Controller).SetViewTarget( Driver ); PlayerController(Controller).ClientSetViewTarget( Driver ); } Controller.Unpossess(); if ( Controller == C ) Controller = None; C.Pawn = Driver; Level.Game.DriverLeftVehicle(self, Driver); // Car now has no driver Driver = None; bDriving = false; // Put brakes on before you get out :) Throttle = 0; Steering = 0; Rise = 0; } function Died(Controller Killer, class damageType, vector HitLocation) { local PlayerController PC; local Controller C; if ( bDeleteMe || Level.bLevelChange ) return; // already destroyed, or level is being cleaned up if ( Physics != PHYS_Karma ) { super.Died(Killer, damageType, HitLocation); return; } if ( Level.Game.PreventDeath(self, Killer, damageType, HitLocation) ) { Health = max(Health, 1); //mutator should set this higher return; } Health = Min(0, Health); if ( Controller != None ) { C = Controller; C.WasKilledBy(Killer); Level.Game.Killed(Killer, C, self, damageType); if( C.bIsPlayer ) { PC = PlayerController(C); if ( PC != None ) ClientKDriverLeave(PC); // Just to reset HUD etc. else ClientClearController(); if ( (bRemoteControlled || bEjectDriver) && (Driver != None) && (Driver.Health > 0) ) { C.Unpossess(); C.Possess(Driver); if ( bEjectDriver ) EjectDriver(); Driver = None; } else C.PawnDied(self); } if ( !C.bIsPlayer && !C.bDeleteMe ) C.Destroy(); } else Level.Game.Killed(Killer, Controller(Owner), self, damageType); if ( Killer != None ) TriggerEvent(Event, self, Killer.Pawn); else TriggerEvent(Event, self, None); if ( IsHumanControlled() ) PlayerController(Controller).ForceDeathUpdate(); if ( !bDeleteMe ) Destroy(); // Destroy the vehicle itself (see Destroyed) } function AdjustDriverDamage(out int Damage, Pawn InstigatedBy, Vector HitLocation, out Vector Momentum, class DamageType) { if ( InGodMode() ) Damage = 0; else Damage *= DriverDamageMult; } function EjectDriver() { local Pawn OldPawn; local vector EjectVel; OldPawn = Driver; KDriverLeave( true ); if ( OldPawn == None ) return; EjectVel = VRand(); EjectVel.Z = 0; EjectVel = (Normal(EjectVel)*0.2 + Vect(0,0,1)) * EjectMomentum; OldPawn.Velocity = EjectVel; // Spawn Protection OldPawn.SpawnTime = Level.TimeSeconds; OldPawn.PlayTeleportEffect( false, false); } // Input function UsedBy( Pawn user ) { if ( Driver != None ) return; // Enter vehicle code TryToDrive( User ); } function Fire( optional float F ) { VehicleFire( false ); bWeaponIsFiring = true; } function AltFire( optional float F ) { VehicleFire( true ); bWeaponIsAltFiring = true; } function ClientVehicleCeaseFire(bool bWasAltFire) { if (bWasAltFire) bWeaponIsAltFiring = false; else bWeaponIsFiring = false; VehicleCeaseFire(bWasAltFire); } // Do some server-side vehicle firing stuff function VehicleFire(bool bWasAltFire) { if ( bWasAltFire ) bWeaponIsAltFiring = true; else bWeaponIsFiring = true; } function VehicleCeaseFire(bool bWasAltFire) { if ( bWasAltFire ) bWeaponIsAltFiring = false; else bWeaponIsFiring = false; } state UnDeployed { function VehicleFire(bool bWasAltFire) { Global.VehicleFire(bWasAltFire); } function VehicleCeaseFire(bool bWasAltFire) { Global.VehicleCeaseFire(bWasAltFire); } } state Deployed { function VehicleFire(bool bWasAltFire) { Global.VehicleFire(bWasAltFire); } function VehicleCeaseFire(bool bWasAltFire) { Global.VehicleCeaseFire(bWasAltFire); } } function bool StopWeaponFiring() { local bool bResult; if ( bWeaponIsFiring ) { ClientVehicleCeaseFire( false ); bWeaponIsFiring = false; bResult = true; } if ( bWeaponIsAltFiring ) { ClientVehicleCeaseFire( true ); bWeaponIsAltFiring = false; bResult = true; } return bResult; } event UpdateEyeHeight( float DeltaTime ) { local Controller C; if ( Controller != None && Controller.IsA('PlayerController') ) Controller.AdjustView( DeltaTime ); for ( C=Level.ControllerList; C!=None; C=C.NextController ) if ( C.IsA('PlayerController') && (PlayerController(C).ViewTarget == self) ) return; bUpdateEyeHeight =false; Eyeheight = BaseEyeheight; } // Vehicles ignore 'face rotation'. simulated function FaceRotation( rotator NewRotation, float DeltaTime ) {} simulated event SetAnimAction(name NewAction) { if ( bDrawDriverInTP && (Driver != None) ) Driver.SetAnimAction(NewAction); } // Vehicles dont get telefragged. event EncroachedBy(Actor Other) {} // RanInto() called for encroaching actors which successfully moved the other actor out of the way event RanInto(Actor Other) { local vector Momentum; local float Speed; if (Pawn(Other) == None || Vehicle(Other) != None || Other == Instigator || Other.Role != ROLE_Authority) return; Speed = VSize(Velocity); if (Speed > MinRunOverSpeed) { Momentum = Velocity * 0.25 * Other.Mass; if (Controller != None && Controller.SameTeamAs(Pawn(Other).Controller)) Momentum += Speed * 0.25 * Other.Mass * Normal(Velocity cross vect(0,0,1)); if (RanOverSound != None) PlaySound(RanOverSound,,TransientSoundVolume*2.5); Other.TakeDamage(int(Speed * 0.075), Instigator, Other.Location, Momentum, RanOverDamageType); } } // This will get called if we couldn't move a pawn out of the way. function bool EncroachingOn(Actor Other) { if ( Other == None || Other == Instigator || Other.Role != ROLE_Authority || (!Other.bCollideActors && !Other.bBlockActors) || VSize(Velocity) < 10 ) return false; // If its a non-vehicle pawn, do lots of damage. if( (Pawn(Other) != None) && (Vehicle(Other) == None) ) { Other.TakeDamage(10000, Instigator, Other.Location, Velocity * Other.Mass, CrushedDamageType); return false; } } simulated function bool FindValidTaunt( out name Sequence ) { if ( !bDrawDriverInTP || (Driver == None) ) return false; return Driver.FindValidTaunt(Sequence); } simulated function bool CheckTauntValid( name Sequence ) { if ( !bDrawDriverInTP || (Driver == None) ) return false; return Driver.CheckTauntValid(Sequence); } // AI code function bool Occupied() { return ( Controller != None ); } function float ReservationCostMultiplier() { return 1.0; } function float NewReservationCostMultiplier(Pawn P) { return ReservationCostMultiplier(); } function bool ChangedReservation(Pawn P) { return false; } function bool SpokenFor(Controller C) { return false; } function SetReservation(controller C); function Vehicle OpenPositionFor(Pawn P) { if ( Controller == None ) return self; return None; } simulated function bool IndependentVehicle() { return true; } function Actor GetBestEntry(Pawn P) { return self; } function Vehicle GetMoveTargetFor(Pawn P) { return self; } simulated event DrivingStatusChanged() { local PlayerController PC; PC = Level.GetLocalPlayerController(); if (bDriving && PC != None && (PC.ViewTarget == None || !(PC.ViewTarget.IsJoinedTo(self)))) bDropDetail = (Level.bDropDetail || (Level.DetailMode == DM_Low)); else bDropDetail = False; if (bDriving) Enable('Tick'); else Disable('Tick'); } // TakeWaterDamage() called every tick when WaterDamage>0 and PhysicsVolume.bWaterVolume=true event TakeWaterDamage(float DeltaTime) { local vector HitLocation,HitNormal; local actor EntryActor; TakeDamage(WaterDamage * DeltaTime, Self, vect(0,0,0), vect(0,0,0), VehicleDrowningDamType); if ( (Level.TimeSeconds - SplashTime > 0.3) && (PhysicsVolume.PawnEntryActor != None) && !Level.bDropDetail && (Level.DetailMode != DM_Low) && EffectIsRelevant(Location,false) && (VSize(Velocity) > 300) ) { SplashTime = Level.TimeSeconds; if ( !PhysicsVolume.TraceThisActor(HitLocation, HitNormal, Location - CollisionHeight*vect(0,0,1), Location + CollisionHeight*vect(0,0,1)) ) { EntryActor = Spawn(PhysicsVolume.PawnEntryActor,self,,HitLocation,rot(16384,0,0)); } } } // LockOnWarning() called every LockWarningInterval when bEnemyLockedOn is true (on server/standalone) event LockOnWarning() { local class LockOnClass; LockOnClass = class(DynamicLoadObject(LockOnClassString, class'class')); PlayerController(Controller).ReceiveLocalizedMessage(LockOnClass, 12); LastLockWarningTime = Level.TimeSeconds; } /* PointOfView() called by controller when possessing this pawn false = 1st person, true = 3rd person */ simulated function bool PointOfView() { if (!bAllowViewChange) return true; return default.bDesiredBehindView; } // Spawn FX function PlayTeleportEffect( bool bOut, bool bSound) { local Actor A; local class TransEffect; if ( (GetTeam() == None) || (GetTeam().TeamIndex == 0) ) TransEffect = class(DynamicLoadObject(TransEffects[0], class'Class')); else TransEffect = class(DynamicLoadObject(TransEffects[1], class'Class')); if ( TransEffect != None ) A = Spawn(TransEffect,,,Location + CollisionHeight * vect(0,0,0.75)); // for fast moving vehicles, make the effect sticky if ( A != None ) A.SetBase( Self ); super.PlayTeleportEffect( bOut, bSound ); } simulated event PlayDying(class DamageType, vector HitLoc) {} simulated function int GetTeamNum() { if ( Role == Role_Authority && Team == 255 && (Controller != None) ) SetTeamNum( Controller.GetTeamNum() ); return Team; } //Notify vehicle that an enemy has locked on to it event NotifyEnemyLockedOn() { bEnemyLockedOn = true; } function IncomingMissile(Projectile P); //Notify vehicle that an enemy has lost the lock event NotifyEnemyLostLock() { bEnemyLockedOn = false; } /* Team is changed when vehicle is possessed and PrevTeam is restored when vehicle is unpossessed */ function SetTeamNum(byte T) { PrevTeam = Team; Team = T; if ( PrevTeam != Team ) TeamChanged(); } simulated event TeamChanged() {} simulated function DisplayDebug(Canvas Canvas, out float YL, out float YPos) { super.DisplayDebug(Canvas, YL, YPos); Canvas.SetDrawColor(255,255,255); Canvas.DrawText("Steering "$Steering$" throttle "$Throttle$" rise "$Rise); if ( Driver != None ) { YPos += YL; YPos += YL; Canvas.SetPos(0, YPos); Canvas.SetDrawColor(0,0,255); Canvas.DrawText("--- DRIVER"); Canvas.SetPos(4, YPos); Driver.DisplayDebug( Canvas, YL, YPos ); } } function Actor ShootSpecial(Actor A) { local Controller OldController; if ( !Controller.bCanDoSpecial || (Weapon == None) ) return None; Controller = OldController; if ( KDriverLeave(false) && (OldController.Pawn != None) ) { OldController.Pawn.SetRotation(rotator(A.Location - OldController.Pawn.Location)); OldController.Focus = A; OldController.FireWeaponAt(A); } return A; } //Vehicles stall when they go above the level's StallZ simulated event Stalled(); simulated event UnStalled(); simulated function NextWeapon() { local PlayerController PC; if ( Level.Pauser != None ) return; PC = PlayerController(Controller); if (PC == None) return; if (!PC.bBehindView) { PC.BehindView(true); DesiredTPCamDistance = TPCamDistRange.Min; TPCamDistance = DesiredTPCamDistance; } else DesiredTPCamDistance = Min(DesiredTPCamDistance + 100, TPCamDistRange.Max); default.TPCamDistance = DesiredTPCamDistance; StaticSaveConfig(); } simulated function PrevWeapon() { local PlayerController PC; if ( Level.Pauser != None ) return; PC = PlayerController(Controller); if (PC == None || !PC.bBehindView) return; if (DesiredTPCamDistance ~= TPCamDistRange.Min) PC.BehindView(false); else { DesiredTPCamDistance = Max(DesiredTPCamDistance - 100, TPCamDistRange.Min); default.TPCamDistance = DesiredTPCamDistance; StaticSaveConfig(); } } function bool TeamLink(int TeamNum) { return (LinkHealMult > 0 && Team == TeamNum && Health > 0); } event bool NeedsFlip() { local vector worldUp, gravUp; local float GravMag; GravMag = VSize(PhysicsVolume.Gravity); if( GravMag < 0.1 ) gravUp = vect(0,0,1); else gravUp = -1.0 * (PhysicsVolume.Gravity/GravMag); worldUp = vect(0,0,1) >> Rotation; if (worldUp Dot gravUp < -0.5) return true; return false; } function Flip(vector HitNormal, float ForceScale); simulated function float ChargeBar(); simulated function ClientPlayForceFeedback( String EffectName ) { local PlayerController PC; PC = PlayerController(Controller); //if ( PC != None && PC.bEnableVehicleForceFeedback ) if ( PC != None && PC.bEnableGUIForceFeedback ) { PC.ClientPlayForceFeedback( EffectName ); } } simulated function StopForceFeedback( String EffectName ) { local PlayerController PC; PC = PlayerController(Controller); //if ( PC != None && PC.bEnableVehicleForceFeedback ) if ( PC != None && PC.bEnableGUIForceFeedback ) { PC.StopForceFeedback( EffectName ); } } function ServerPlayHorn(int HornIndex) { if( (Level.TimeSeconds - LastHornTime > 3.0) && (HornIndex >= 0) && (HornIndex < HornSounds.Length) ) { if(HornSounds[HornIndex] != none ) PlaySound( HornSounds[HornIndex],, 3.5*TransientSoundVolume,, 800); LastHornTime = Level.TimeSeconds; } } simulated function int NumPassengers() { if ( Driver != None ) return 1; return 0; } function Pawn GetInstigator() { return Self; } function AIController GetBotPassenger() { return AIController(Controller); } event bool IsVehicleEmpty() { return (Driver == None); } function bool HasOccupiedTurret() { return false; } function float AdjustedStrength() { if (bStationary && bDefensive) return 1.0; return 0; } static function StaticPrecache(LevelInfo L); function int GetSpree() { if (Driver != None) return Driver.GetSpree(); return 0; } function IncrementSpree() { if (Driver != None) Driver.IncrementSpree(); } simulated function POVChanged(PlayerController PC, bool bBehindViewChanged) { if (PC.bBehindView) { if (bBehindViewChanged && bPCRelativeFPRotation) PC.SetRotation(rotator(vector(PC.Rotation) >> Rotation)); bOwnerNoSee = false; if (Driver != None) { if (bDrawDriverInTP) Driver.bOwnerNoSee = false; else Driver.bOwnerNoSee = true; } if (PC == Controller) // No overlays for spectators ActivateOverlay(False); } else { if (bPCRelativeFPRotation) PC.SetRotation(rotator(vector(PC.Rotation) << Rotation)); if (bDrawMeshInFP) bOwnerNoSee = false; else bOwnerNoSee = true; if (Driver != None) { Driver.bOwnerNoSee = true; } if (bDriving && PC == Controller) // No overlays for spectators ActivateOverlay(True); } } function PlayTakeHit(vector HitLocation, int Damage, class DamageType) { local int SoundNum; if (IndependentVehicle() && DamageType.Default.bBulletHit && BulletSounds.Length > 0) { SoundNum = Rand(BulletSounds.Length); if (Controller != None && Controller == Level.GetLocalPlayerController()) PlayOwnedSound(BulletSounds[SoundNum], SLOT_None, 2.0, False, 400); else PlayOwnedSound(BulletSounds[SoundNum], SLOT_None, 2.0, False, 100); } } function array GetTurrets(); function CheckSuperBerserk(); // Used to override locking actors. Returns who the aggressor really should lock on to event bool VerifyLock(actor Aggressor, out actor NewTarget) { return true; } // Returns any alternate target actor for this vehicle if it has one simulated function actor AlternateTarget() { return None; } function ShouldTargetMissile(Projectile P) { local AIController C; C = AIController(Controller); if (C != None && C.Skill >= 5.0 && (C.Enemy == None || !C.LineOfSightTo(C.Enemy)) ) ShootMissile(P); } function ShootMissile(Projectile P) { Controller.Focus = P; Controller.FireWeaponAt(P); } function bool ImportantVehicle() { return false; } function bool IsArtillery() { return false; } //============================================================================= // defaultproperties //============================================================================= defaultproperties { bAdjustDriversHead=true LandMovementState=PlayerDriving bVehicleShadows=true bDrawVehicleShadow=true bDontPossess=true bUseCompressedPosition=false bCanPickupInventory=false Team=255 OldTeam=255 PrevTeam=255 Steering=0 Throttle=0 EjectMomentum=1000 ExitPositions(0)=(X=0,Y=0,Z=0) EntryPosition=(X=0,Y=0,Z=0) EntryRadius=100.0 DrivePos=(X=0,Y=0,Z=0) bZeroPCRotOnEntry=true bRelativeExitPos=true bPCRelativeFPRotation=true TPCamLookat=(X=-100,Y=0,Z=100) TPCamWorldOffset=(X=0,Y=0,Z=0) TPCamDistance=600 TPCamDistRange=(Min=50,Max=1500) CameraSpeed=500 bDesiredBehindView=true MaxViewYaw=16000 MaxViewPitch=16000 TransEffects(0)="XEffects.TransEffectRed" TransEffects(1)="XEffects.TransEffectBlue" DriveAnim=Vehicle_Driving CollisionRadius=+120.0 CollisionHeight=+50.0 SightRadius=+8000.0 ShadowMaxTraceDist=+350 ShadowCullDistance=1500.0 bForceSkelUpdate=true bCanBeBaseForPawns=True MomentumMult=4.0 DriverDamageMult=1.0 VehiclePositionString="in a vehicle" VehicleNameString="Vehicle" LockOnClassString="Onslaught.ONSOnslaughtMessage" RanOverDamageType=class'DamRanOver' CrushedDamageType=class'Crushed' bAllowViewChange=true LinkHealMult=0.35 VehicleLostTime=0.0 NetUpdateFrequency=4 NetPriority=1 CenterSpringForce="SpringONSHoverBike" CenterSpringRangePitch=2000 CenterSpringRangeRoll=2000 bDriverHoldsFlag=true bCanCarryFlag=true WalkingPct=+1.0 CrouchedPct=+1.0 MaxDesireability=0.5 ObjectiveGetOutDist=1000.0 WaterDamage=0.0 LockWarningInterval=+1.5 }