As I'm sure most of you are well aware of, the UT2004 Navy was released a little while ago. Oddly enough, my computer was down during this time and so I was unable to finish the boat code I was working on. So, I'm going to release the source code I was writing to this forum and, as long as I'm credited, you may extend off of it and create your own boats. No special volumes are required (except for water ones of course :-P). If you want to add any functionality go ahead and subclass. Either way, here you go, as you can see everything is well documented. This is still a beta release that I will be finishing up for the Kopholus team with an example boat, but I figured anybody who wants to use this instead of the navy code, go right ahead as it is (As far as i know) fully operational.
Code:
//----------------------------------------------------------- // ONSSpeedBoat // Justin "Mr-Slate" Breitfeller // Test Subject (August 11/2004) //----------------------------------------------------------- class ONSSpeedBoat extends ONSVehicle abstract; //Basically how fast you can go var() float MaxThrust; //Basically how fast you can turn and how quick var() float MaxSteerTorque; //The amount your forward motion is damped var() float ForwardDampFactor; //The amount your MaxThrust is damped when in reverse (Default: 0.4 is 40% of normal speed || 1 is 100% (reg speed)) var() float ReverseSpeedFactor; /*Set this to 0 to not increase the slow down length at all... Otherwise make it a high number as you divide your forward velocity by this and add it to the current force (only added when not hitting any throttle) */ var() float FactorToDivideVelocityByToSlowDownSlower; //The damping factor of your movement when you exit the vehicle var() float ParkingDampFactor; //Increasing this value affects how fast the actual boat spins (Torque Damping) var() float SteerDampFactor; //How much your forward velocity is damped when turning, even a small value here shows a noticable hit to your forward momentum var() float TurnDampFactor; //How far down you have to hold the reverse key to invert the steering... (-0.1 is a good value as you dont want it inverted at 0[idle]) var() float InvertSteeringThrottleThreshold; //How much lateral movement forces are damped var() float LateralDampFactor; //This is implemented but doesnt seem to do much var() float BankTorqueFactor; //This is implemented but doesnt seem to do much var() float BankDampFactor; //Should prevent pitch from changing too much var() float PitchDampFactor; //When not pressing throttle will increase the drag on forward velocity on top of ForwardDampFactor var() float WaterDampFactor; //Should be the value by which you slide forward if turning (Keep values very subtle otherwise NASTY results) var() float SlideFactor; //the factor by which the output thrust is damped on land(ie .8 is about 80% of normal movement) //Radius based land damping and other things obviously use this value as well as just basic land damping var() float LandDampingFactor; //if this is true the land damping will increase to the value over the time specified //This is not applied if water is found under the boat using WaterSearchDistance var() bool bTimeBasedLandDamping; //if bTimeBasedLandDamping is true then this is the time until the full land damping is applied var() float TimeUntilFullLandDamping; //if this is true the land damping will be applied after you are out of this radius unless you have //bTimeBasedLandDamping true, in which case it will then start the trigger for that (Spherical searching) //This is not applied if water is found under the boat using WaterSearchDistance var() bool bRadiusBasedLandDamping; /* this rquires bRadiusBasedLandDamping to be true.. this will cause the land damping to increase along inside the radius until 100% on the very outer edge of the radius and outside of it... closer to center is a less percentage (1/2 radius = 1/2 land damping) */ var() bool bAffectLandDampingEvenInRadius; //the radius for the RadiusBasedLandDamping if it is true var() float RadiusUntilFullLandDamping; //If you always want to use the WaterSearchDistance (search for water under the boat) before you do the radius and/or time //based checks set this to true (Trace every update vehicle if doesnt have a watervolume for physicsvolume or touchingone so try to avoid) //there is no need to set this to true if not using time or radius based land damping var() bool bAlwaysUseWaterSearch; //Min velocity size needed to unlock turning var() float MinVelocityToTurn; //distnace off top of water to scan for water (for bumping on waves and not wanting kill thrust) var() float WaterSearchDistance; //if true the boats will be able to thrust in the air (they are out of range of water under them set by above variable var() bool bApplyForceInAir; //if true as soon as the drivers head goes under water the controls lock up and the boat will rise to the top var() bool bKillControlsUnderWater; //if left at 0, as soon as head hits the water, otherwise must be this far underwater var() float MinimumDistanceUnderWaterToKillControls; //Set this value to true if you still want the boat to spin when you are under the minimum velocity var() bool bApplyTurnTorqueUnderMinVelocity; //This the damping factor set to spinning when you are under the minimum velocity (set to 1 for regular turning) //Requires: bApplyTurnTorqueUnderMinVelocity var() float LowVelocityTurnDampFactor; //Set this to true if you want the LowVelocityTurnDampFactor scaled by the velocity under the min velocity... //ie if velocity is 150 and min is 300... the turn damp factor is only 50% of normal var() bool bScaleLowVelocityTurnDampFactor; //if this is true damage (set by DamagePerSecondOnLand) will be applied var() bool bApplyDamageOnLand; //if this is true damage will be applied to the boat even if a driver is present when they are on land //otherwise boats on land will not get hit with damage until the driver leaves var() bool bApplyDamageOnLandEvenWithADriver; //If the boat is on land (meaning if the bRadiusBasedLandDamping is true || bTimeBasedLandDamping is true you are not //considred on land until you are out of the radius and/or out of time var() float DamagePerSecondOnLand; //how often land damage is applied.. for instance 1 is once every second... (0.33 is every 1/3 a second) var() float LandDamageTimerFrequencyInSeconds; //if this is set to true... then regardless of the fact if you have radius based land damping or time based land damping //bOnLand will be set to true when you are on land no matter what var() bool bApplyDamageRegardlessOfLandDamping; //If this is true the boat will bob (must setup the few following variables in a subclass) var() bool bShouldBob; //This value is how likely a bob will occur (ie .75 is 75% chance) var() float BobLikelihood; //This value is how hard down the boat is pushed var() float BobForceDownward; //This value is the time in seconds it is before the boat can bob again var() float BobInterval; //This value is the minimum velocity the boat needs to have to have the bob force applied (only in water) var() float MinimumVelocityToBob; //If set to true the boat will tilt up if going forward var() bool bAlterBoatsTippingWithThrottle; //This alters the force applied to the boat's rear when accelerating var() float TiltForceDownwardFromThrottle; //The name of the bone you apply the tilt down force too var() name BoneToApplyTiltForceTo; //The distance you have to be underwater for an increase in your floating up var float MinimumDistanceToStartIncreasedFloatUp; //How fast you have to have to be going before the float up forces stop getting added var float MaximumFloatUpVelocity; //The force that is applied to the boat when it is getting an extra boost up (Set this force in a subclass to fit your boat) var float FloatUpForce; //If you are this deep under water you will have your float up force increased by the IncreasedForceFloatUpFactor var float DistanceUntilIncreasedForceFloatUp; //The factor by which FloatUpForce is increased when you are farther down then DistanceUntilIncreasedForceFloatUp var float IncreasedForceFloatUpFactor; //The buoyancy set to the boat when it dies to allow it to sink var() float DeathBuoyancy; /* -----INTERNAL DO NOT SET OR CHANGE FROM HERE DOWN----- */ //Simply holds the value of throttle (-1 for back, 0 for none, 1 for forward) var float OutputThrust; //Holds the value of turning (-1 for right, 0 for none, 1 for left) var float OutputTurn; //Self explanatory var() float BoatMPH; //The values that are added to the vehicle by this code var vector NewForce,NewTorque; //This value holds the time since you last seen water (used with bTimeBasedLandDamping) var float TimeSinceLastInWater; //This will contain the last water volume touching var WaterVolume LastTouchedWaterVolume; //This will contain the Location of the boat the last time it touched a water volume var vector LastBoatLocationInWaterVolume; //true if on land (this is affected by a few bools up farther and should NOT be set) -interal workings var bool bOnLand; //also should not be altered / this will be true when we are applying damage var bool bApplyingLandDamage; //internal storing of last bob time var float LastBobTime; //Replicated variables about this thing struct BoatMovementState { var vector ChassisPosition; var Quat ChassisQuaternion; var vector ChassisLinVel; var vector ChassisAngVel; var byte ServerThrust; var byte ServerTurn; var int ServerViewPitch; var int ServerViewYaw; }; //references to the current state of this thing var BoatMovementState OldMovementState, MovementState; //the state of this boat var KRigidBodyState ChassisState; //marks a new movement state var bool bNewMovementState; //marks a driver change var bool bNewDriver; //is used to force struct to be replicated var bool bReplicationBuddy; replication { reliable if(Role == Role_Authority) MovementState; reliable if(!bNetOwner || (bNetOwner && !bNewDriver) && Role == Role_Authority) bReplicationBuddy; reliable if(bNetOwner && bNewDriver && Role == Role_Authority) LastBoatLocationInWaterVolume; //should only have to replicate this when new driver so s/he is not stuck reliable if(Role < Role_Authority) ServerSetNewDriver; //sets bNewDriver to false once client receives it } simulated function PostNetBeginPlay() { local WaterVolume WV; local vector HitLoc, HitNorm; Super.PostNetBeginPlay(); /* Do basic water search so damage can be applied */ bOnLand = true; if(PhysicsVolume.bWaterVolume || TouchingWaterVolume()) { bOnLand = false; LastTouchedWaterVolume = WV; LastBoatLocationInWaterVolume = Location; } else { foreach TraceActors(class'WaterVolume',WV,HitLoc,HitNorm,Location - ((vect(0,0,1)>>Rotation)*WaterSearchDistance),Location) { if(WV!=None) { bOnLand = false; TimeSinceLastInWater = 0.0; LastTouchedWaterVolume = WV; LastBoatLocationInWaterVolume = HitLoc; break; } } } } simulated function Tick(float DT) { Super.Tick(DT); if(Role == ROLE_Authority) { OutputThrust = Throttle; OutputTurn = Steering; if (OutputThrust != 0.0 || OutputTurn != 0.0) KWake(); if(PlayerController(Controller) != None && Controller.Pawn !=None && !(PlayerController(Controller).IsInState('PlayerDriving'))) PlayerController(Controller).GoToState('PlayerDriving'); PackState(); //replication related } } function PackState() { local KRigidBodyState RBState; local rotator ViewRot; if( !KIsAwake() ) return; KGetRigidBodyState(RBState); MovementState.ChassisPosition.X = RBState.Position.X; MovementState.ChassisPosition.Y = RBState.Position.Y; MovementState.ChassisPosition.Z = RBState.Position.Z; MovementState.ChassisQuaternion = RBState.Quaternion; MovementState.ChassisLinVel.X = 10.f * RBState.LinVel.X; MovementState.ChassisLinVel.Y = 10.f * RBState.LinVel.Y; MovementState.ChassisLinVel.Z = 10.f * RBState.LinVel.Z; MovementState.ChassisAngVel.X = 1000.f * RBState.AngVel.X; MovementState.ChassisAngVel.Y = 1000.f * RBState.AngVel.Y; MovementState.ChassisAngVel.Z = 1000.f * RBState.AngVel.Z; MovementState.ServerThrust = FloatToRangeByte(OutputThrust); MovementState.ServerTurn = FloatToRangeByte(OutputTurn); if (Controller != None) { if (IsHumanControlled()) { DriverViewPitch = Controller.Rotation.Pitch; DriverViewYaw = Controller.Rotation.Yaw; } else { ViewRot = rotator(Normal((Controller.FocalPoint - Location))); DriverViewPitch = ViewRot.Pitch; DriverViewYaw = ViewRot.Yaw; } } else { DriverViewPitch = Rotation.Pitch; DriverViewYaw = Rotation.Yaw; } MovementState.ServerViewPitch = DriverViewPitch; MovementState.ServerViewYaw = DriverViewYaw; bReplicationBuddy = !bReplicationBuddy; } simulated event DrivingStatusChanged() { Super.DrivingStatusChanged(); if(bDriving) bNewDriver = true; } simulated event PostNetReceive() { if(bNewDriver && bDriving && bNetOwner) //Received the LastBoatLocationInWaterVolume { bNewDriver = false; ServerSetNewDriver(); } if( OldMovementState.ChassisPosition == MovementState.ChassisPosition && OldMovementState.ChassisQuaternion.X == MovementState.ChassisQuaternion.X && OldMovementState.ChassisQuaternion.Y == MovementState.ChassisQuaternion.Y && OldMovementState.ChassisQuaternion.Z == MovementState.ChassisQuaternion.Z && OldMovementState.ChassisQuaternion.W == MovementState.ChassisQuaternion.W && OldMovementState.ChassisLinVel == MovementState.ChassisLinVel && OldMovementState.ChassisAngVel == MovementState.ChassisAngVel && OldMovementState.ServerThrust == MovementState.ServerThrust && OldMovementState.ServerTurn == MovementState.ServerTurn && OldMovementState.ServerViewPitch == MovementState.ServerViewPitch && OldMovementState.ServerViewYaw == MovementState.ServerViewYaw ) return; ChassisState.Position.X = MovementState.ChassisPosition.X; ChassisState.Position.Y = MovementState.ChassisPosition.Y; ChassisState.Position.Z = MovementState.ChassisPosition.Z; ChassisState.Quaternion = MovementState.ChassisQuaternion; ChassisState.LinVel.X = 0.1f * MovementState.ChassisLinVel.X; ChassisState.LinVel.Y = 0.1f * MovementState.ChassisLinVel.Y; ChassisState.LinVel.Z = 0.1f * MovementState.ChassisLinVel.Z; ChassisState.AngVel.X = 0.001f * MovementState.ChassisAngVel.X; ChassisState.AngVel.Y = 0.001f * MovementState.ChassisAngVel.Y; ChassisState.AngVel.Z = 0.001f * MovementState.ChassisAngVel.Z; // Set OldMovementState to MovementState OldMovementState.ChassisPosition = MovementState.ChassisPosition; OldMovementState.ChassisQuaternion = MovementState.ChassisQuaternion; OldMovementState.ChassisLinVel = MovementState.ChassisLinVel; OldMovementState.ChassisAngVel = MovementState.ChassisAngVel; OldMovementState.ServerThrust = MovementState.ServerThrust; OldMovementState.ServerTurn = MovementState.ServerTurn; OldMovementState.ServerViewPitch = MovementState.ServerViewPitch; OldMovementState.ServerViewYaw = MovementState.ServerViewYaw; bNewMovementState = true; OutputThrust = RangeByteToFloat(MovementState.ServerThrust); OutputTurn = RangeByteToFloat(MovementState.ServerTurn); DriverViewPitch = MovementState.ServerViewPitch; DriverViewYaw = MovementState.ServerViewYaw; Super.PostNetReceive(); } function ServerSetNewDriver() { bNewDriver = false; } simulated event bool KUpdateState(out KRigidBodyState newState) { if(Role == ROLE_Authority || !bNewMovementState) return false; newState = ChassisState; bNewMovementState = false; return true; } event UpdateVehicle(float DeltaTime) { local vector X,Y,Z, AngularVelocity, HitLoc,HitNorm; local KRigidBodyState RBodyState; local float UseForwardDamp, ForwardVelMag, UseTurn,UseLatDamp,VelMag; local bool bWaterNearby; local WaterVolume WV; local vector TempLastBoatLoc, TempCurrentBoatLoc; BoatMPH = 0.0; NewForce = vect(0,0,0); NewTorque = vect(0,0,0); if(bOnLand && !bApplyingLandDamage && (Controller == None || bApplyDamageOnLandEvenWithADriver)) { Timer(); SetTimer(LandDamageTimerFrequencyInSeconds,true); bApplyingLandDamage = true; } else if(bApplyingLandDamage && !bOnLand) { SetTimer(0,false); bApplyingLandDamage = false; } if( !KIsAwake()) return; X = vect(1, 0, 0) >> Rotation; Y = vect(0, 1, 0) >> Rotation; Z = vect(0, 0, 1) >> Rotation; KGetRigidBodyState(RBodyState); AngularVelocity.X = RBodyState.AngVel.X; AngularVelocity.Y = RBodyState.AngVel.Y; AngularVelocity.Z = RBodyState.AngVel.Z; if(bDriving) { if(HeadVolume.bWaterVolume && bKillControlsUnderWater) //if underwater { if(VSize(Driver.Location - LastBoatLocationInWaterVolume) > MinimumDistanceToStartIncreasedFloatUp && VSize(Velocity) < MaximumFloatUpVelocity) { if(VSize(Driver.Location - LastBoatLocationInWaterVolume) < DistanceUntilIncreasedForceFloatUp) NewForce += (FloatUpForce * Z); //Pop up affect tries to help the boat rush to the surface else NewForce += (FloatUpForce * IncreasedForceFloatUpFactor * Z); } bOnLand = false; if(MinimumDistanceUnderWaterToKillControls ~= 0.0) { OutputThrust = 0.0; OutputTurn = 0.0; return; } else { TempCurrentBoatLoc = Driver.Location; TempLastBoatLoc = LastBoatLocationInWaterVolume; if(VSize(TempCurrentBoatLoc - TempLastBoatLoc) > MinimumDistanceUnderWaterToKillControls) { OutputThrust = 0.0; OutputTurn = 0.0; return; } } } //This is the setting of the initial forces && handles land damping bWaterNearby = false; //apply the damped reverse if(OutputThrust < 0) { OutputThrust *= ReverseSpeedFactor; } if(PhysicsVolume.bWaterVolume || TouchingWaterVolume()) { NewForce += (OutputThrust * MaxThrust * X); bWaterNearby = true; bOnLand = false; TimeSinceLastInWater = 0.0; if(PhysicsVolume.bWaterVolume) LastTouchedWaterVolume = WaterVolume(PhysicsVolume); else { ForEach TouchingActors(class'WaterVolume',WV) { if ( WV != None) { LastTouchedWaterVolume = WaterVolume(PhysicsVolume); break; } } } if(!HeadVolume.bWaterVolume) //dont want to update last location if drowning LastBoatLocationInWaterVolume = Location; } //end of if else if((!bRadiusBasedLandDamping && !bTimeBasedLandDamping) || bAlwaysUseWaterSearch) { foreach TraceActors(class'WaterVolume',WV,HitLoc,HitNorm,Location - (Z*WaterSearchDistance),Location) { if(WV!=None) { bWaterNearby = true; bOnLand = false; TimeSinceLastInWater = 0.0; LastTouchedWaterVolume = WV; LastBoatLocationInWaterVolume = HitLoc; break; } } if(bWaterNearby) NewForce += (OutputThrust * MaxThrust * X); } //will cut the force on land by the factor if(bRadiusBasedLandDamping && !bWaterNearby) { if(VSize(LastBoatLocationInWaterVolume - Location) < RadiusUntilFullLandDamping) { bWaterNearby = true; if(!bApplyDamageRegardlessOfLandDamping) bOnLand = false; else bOnLand = true; TimeSinceLastInWater = 0.0; // still in radius and so timebasedlanddamping should be reset at least once } if(bWaterNearby) { if(!bAffectLandDampingEvenInRadius) NewForce += (OutputThrust * MaxThrust * X); else { NewForce += (OutputThrust * MaxThrust * X); NewForce += (-1.0f * FClamp(VSize(LastBoatLocationInWaterVolume - Location) / RadiusUntilFullLandDamping,0.0,1.0) * LandDampingFactor * OutputThrust * MaxThrust * X); } } } if(bTimeBasedLandDamping && !bWaterNearby) { TimeSinceLastInWater += DeltaTime; NewForce += (OutputThrust * MaxThrust * X); NewForce += (-1.0f * FClamp(TimeSinceLastInWater / TimeUntilFullLandDamping, 0.0, 1.0) * LandDampingFactor * OutputThrust * MaxThrust * X); if(TimeSinceLastInWater / TimeUntilFullLandDamping > 0.999) { bOnLand = true; } else if(TimeSinceLastInWater / TimeUntilFullLandDamping < 0.999 && !bApplyDamageRegardlessOfLandDamping) bOnLand = false; else if(bApplyDamageRegardlessOfLandDamping) bOnLand = true; } if(!bWaterNearby && !bTimeBasedLandDamping) { NewForce += (OutputThrust * MaxThrust * X); if(!bApplyForceInAir && ImpactInfo.Other == None) //no water nearby and in air.. kill forces return; NewForce += (-1.0f * OutputThrust * LandDampingFactor * MaxThrust * X); bOnLand = true; } //Pitch damping VelMag = AngularVelocity dot Y; NewTorque += (-1.0f * VelMag * PitchDampFactor * Y); // Forward damping ForwardVelMag = Velocity dot X; UseForwardDamp = ForwardDampFactor; if(OutputThrust == 0.0 && !bOnLand) //slide factor forward (slower slow downs) { NewForce += ForwardVelMag / FactorToDivideVelocityByToSlowDownSlower * X; } if(Controller == None) UseForwardDamp += ParkingDampFactor; else if(OutputThrust == 0) UseForwardDamp += WaterDampFactor; else if(ForwardVelMag > 0 && OutputThrust < 0) //increase damping if moving forward and trying to go backwards UseForwardDamp += WaterDampFactor*2; NewForce += (-1.0f * ForwardVelMag * UseForwardDamp * X); //Implementation of sliding when turning TODO: FIX ME... or remove if(Abs(ForwardVelMag) > 100 && Abs(OutputTurn) > 0) NewForce += (Abs(OutputTurn) * ForwardVelMag * SlideFactor * X); //Turn damping to my force NewForce += (-1.0f * Abs(OutputTurn) * ForwardVelMag * TurnDampFactor * X); // Invert steering when we are going backwards if( OutputThrust < InvertSteeringThrottleThreshold ) UseTurn = -1.0f * OutputTurn; else UseTurn = OutputTurn; // Lateral damping for sideways movement which is ....most likely nothing except for things that dodge VelMag = Velocity dot Y; UseLatDamp = LateralDampFactor; if(Controller == None) //stop me on parking (practically) UseLatDamp += ParkingDampFactor; NewForce += (-1.0f * VelMag * UseLatDamp * Y); // Turn damping VelMag = AngularVelocity dot Z; NewTorque += (-1.0f * SteerDampFactor * VelMag * Z); // Steer Torque being applied as long as we are moving (like a real boat) if(VSize(Velocity) > MinVelocityToTurn) NewTorque += (-1.0f * MaxSteerTorque * UseTurn * Z); else if(bApplyTurnTorqueUnderMinVelocity && !bScaleLowVelocityTurnDampFactor) { NewTorque += (-1.0f * MaxSteerTorque * UseTurn * Z); NewTorque += (MaxSteerTorque * LowVelocityTurnDampFactor * UseTurn * Z); } else if(bApplyTurnTorqueUnderMinVelocity && bScaleLowVelocityTurnDampFactor) { NewTorque += (-1.0f * MaxSteerTorque * UseTurn * Z); NewTorque += (MaxSteerTorque * FClamp(VSize(Velocity) / MinVelocityToTurn, 0.0, 1.0) * LowVelocityTurnDampFactor * UseTurn * Z); } // Banking Torque NewTorque += (BankTorqueFactor * UseTurn * X); // Bank (roll) Damping VelMag = AngularVelocity dot X; NewTorque += (-1.0f * VelMag * BankDampFactor * X); //TILTING (Up/Down) if(bAlterBoatsTippingWithThrottle && OutputThrust > 0) { KAddImpulse(-1.0f * FClamp(OutputThrust,0,1.0) * TiltForceDownwardFromThrottle * Z, GetBoneCoords(BoneToApplyTiltForceTo).Origin); } //This may help stop the climbing I hope NewForce.Z = 0.0; //BOBBING if(bShouldBob && VSize(Velocity) > MinimumVelocityToBob && Level.TimeSeconds > (LastBobTime + BobInterval) && FRand() > (1-BobLikelihood) && !bOnLand) { NewForce += (-1.0f * BobForceDownward * Z); LastBobTime = Level.TimeSeconds; } // Set current boat speed. Convert from units per sec to miles per hour. BoatMPH = Abs( (ForwardVelMag * 3600.0f) / 140800.0f ); ModifyAppliedForce(NewForce, NewTorque); } Super.UpdateVehicle(DeltaTime); } //hook for subclass to alter forces function ModifyAppliedForce(out vector ModifiedForce, out vector ModifiedTorque); function Timer() { TakeDamage(DamagePerSecondOnLand * LandDamageTimerFrequencyInSeconds, None, Location + CollisionHeight * vect(0,0,0.5), vect(0,0,0), class'Corroded'); } simulated function KApplyForce(out vector Force, out vector Torque) { if (bDriving) { Force += NewForce; Torque += NewTorque; } Super.KApplyForce(Force, Torque); } simulated event DestroyAppearance() { Super.DestroyAppearance(); KarmaParams(KParams).KBuoyancy = DeathBuoyancy; } simulated function byte FloatToRangeByte(float inFloat) { return (inFloat * 255); } simulated function float RangeByteToFloat(byte inByte) { return (inByte / 255); } defaultproperties { ReverseSpeedFactor=0.400000 ParkingDampFactor=0.800000 WaterDampFactor=0.005000 TimeSinceLastInWater = 0.0 InvertSteeringThrottleThreshold=-0.100000 WaterSearchDistance=750.000000 bKillControlsUnderWater=True MinimumDistanceUnderWaterToKillControls=1500.000000 bApplyTurnTorqueUnderMinVelocity=True bApplyDamageOnLand=True DamagePerSecondOnLand=15.000000 LandDamageTimerFrequencyInSeconds=0.330000 bShouldBob=False //setup the following in a subclass bTimeBasedLandDamping=False bRadiusBasedLandDamping = False bAlterBoatsTippingWithThrottle=True MinimumDistanceToStartIncreasedFloatUp=1500.000000 MaximumFloatUpVelocity=1000.000000 DistanceUntilIncreasedForceFloatUp=4000.000000 IncreasedForceFloatUpFactor=1.500000 WaterDamage=0.000000 bNetNotify=True bTraceWater=True bNewDriver = True LastBoatLocationInWaterVolume =(x=0.0,y=0.0,z=0.0); FactorToDivideVelocityByToSlowDownSlower= 10.00 //reset this to work well with your ships speed }
Comment