Mostly Harmless

Legacy:VitalOverdose/ONSVehicleBooster

From Unreal Wiki, The Unreal Engine Documentation Site
Jump to: navigation, search
UT2004 :: Actor >> Trigger >> ONSVehicleBooster (Package: custom )

by VitalOverdose - Updated Oct 2007

Concept[edit]

  • The ONSVehicleBooster launches a vehicle when touched by using the KAddImpulse() function.
  • The Boost will not directly hurt the vehicle in any way unless it collides with something at high speed.

User Properties.[edit]

Globals[edit]

  • Default properties will be used to boost a vehicle but the mapper can also set individual properties for a specific vehicle type.
  • To stop the ONSVehicleBooster from boosting a specific vehicle type/types just create a VehicleSpecific set of values for the vehicle/vehicles(in the actor properties in unrealed) and leave the 'AppliedBoostForce' values at (x=0,y=0,z=0).

Boost Direction[edit]

The applied boost force is a vector. Thats a point in space with direction and force.

(x=1.0,y=0.0,z=0.0) = Tiny push forward.

(x=-1,y=0.0,z=0.0) = tiny push backwards.

(x=0.0,y=1.0,z=0.0) = tiny push to the left.

(x=0.0,y=-1.0,z=0.0) = tiny push to the right.

(x=0.0,y=0.0,z=1.0) = tiny push Upwards.

(x=0.0,y=0.0,z=-1.0) = tiny push Downwards.

Note: 1 is way to small to move a vehicle , 1000000 is closer to the kind of values you will need.

Option to apply the boost force in relation to either;

  • The direction the vehicle is facing when it touches the Booster (Bdirectional = false)
  • The direction the Booster actor is facing (Bdirectional = true)

BotLock[edit]

If a bot is driving when a vehicle is boosted it will instantly try to jump out. To stop this from happening any bot driven vehicle that gets boosted is locked until the vehicle has landed and is traveling under a speed that wont panic non-human players .

  • The vehicle will get locked until 2 conditions have been met:-
    • 1 - The vehicle is not airborne
    • 2 - The vehicle is traveling < a certain speed ( ReleaseVelocity : default = 800.000000)
  • Option to lock human players the same as bots ( bLockHumanPlayers = true ).

More info on how the BotLock works can be found here: BotLock Info

Boosting backwards[edit]

Var bCanBoostBackwards : Option to let vehicles be boosted backwards if they reverse into the booster.

Re-Boosting[edit]

Var bReBoosts : Is an option to NOT boost a vehicle if its already in flight from another booster. This is very handy for having 2 boosters facing each other over an obstacle.

Change the Weight of the vehicles[edit]

Option to be able to alter the Gravity scale of a vehicle for the duration of the boost. The same rules apply here as with the BotLock system, the weight will be altered on the boosting vehicle until The vehicle is not airborne && the vehicle is traveling < a specified speed (default 900). The default for this property is -1 this disables the weight altering system. This is only designed to alter the gravity scale of a vehicle very slightly so that all vehicles can be made to travel the same distance before landing.

Boost Empty vehicles[edit]

The default for this property is bBoosts_emptyVechicles = false.

Change the Size of the vehicles[edit]

This could be used to boost a vehicle though a small opening. Its original size will be returned when then vehicle has safely landed.

Optional Spin[edit]

This is for making the vehicle spin during the flight. This works exactly the same way as a boost, you have to specify a direction for the kick and a point on the vehicle to apply the that kick to.

Example;

The center of the vehicle has a vector of (x=0.0,y=0.0,z=0.0).

If a vehicle was 150uu long ;

  • The front center of the vehicle would be at (x=75.0,y=0.0,z=0.0)
  • The back center of the vehicle would be at (x=-75.0,y=0.0,z=0.0)

If a vehicle was 100uu wide ;

  • The Left center of the vehicle would be at (x=0.0,y=-50.0,z=0.0)
  • The right center of the vehicle would be at (x=0.0,y=50.0,z=0.0)

So if you wanted to flip an ONSRV completely over backwards during a boost you would need a big upwards push and you need to apply the upwards push to the front of the vehicle.

  • Spin_AppliedBoostForce = (x=0,y=50,z=1000000.000000);
  • Spin_PointOfBoostForce = (x=0.0,y=75.0,z=0.0);

The vehicles property bEjectPassengersWhenFlipped is set to false for the duration of the jump is spin is used.Used together with the weight changing features in this class you can come up with some awesome looking stunts.

Note[edit]

  • Some special care has to be taken when boosting near thin static meshes like lampposts and trees etc .The static meshe default collision mesh should be reinforced by adding a blocking volume to avoid vehicles getting stuck inside static meshes.
  • Using to much boost force can cause a vehicle to vanish when boosted and may cause replication errors during an online game, if you want to boost a long distance try altering the weight of the vehicle to help reduce the amount of boost force needed for the jump.

The Script[edit]

Last Updated : Oct 2007

class ONSVehicleBooster extends triggers
placeable;
 
// Default values: if a valid vehicle touches the booster and doesn't
// have any specific properties set for that vehicle type set by the mapper
// then these values will be used for the boost
var (BoostGlobalValues) bool   bLockHumanPlayers;
var (BoostGlobalValues) bool   bDirectionalBoost;
var (BoostGlobalValues) bool   bCanBoostBackwards;
var (BoostGlobalValues) bool   bReBoosts;
var (BoostGlobalValues) float  VehicleDrawscale;
var (BoostGlobalValues) bool   bBoosts_emptyVechicles;
var (BoostGlobalValues) float  ReleaseVelocity;
var (BoostGlobalValues) sound  VOC_Boost;
var (BoostGlobalValues) int    Actor_gravScale;
 
var (BoostGlobalValues) vector AppliedBoostForce;
var                     vector PointOfBoostForce;
 
var (BoostGlobalValues) vector Spin_AppliedBoostForce;
var (BoostGlobalValues) vector Spin_PointOfBoostForce;
 
//var(test) class<emitter>   testfx;
//var emitter                emittedtestfx;
 
// Creating a custom variable type to hold the values for each boost that the mapper sets
// on a specific vehicle.
struct VecSpec
{
var () class <OnsVehicle>  VecType;
var () bool                bLockHumanPlayers;
var () bool                bDirectionalBoost;
var () bool                bCanBoostBackwards;
var () bool                bBoosts_emptyVechicles;
var () bool                bReBoosts;
var () float               ReleaseVelocity;
var () float               Actor_gravScale;
var () float               VehicleDrawscale;
var () vector              Spin_AppliedBoostForce;
var () vector              Spin_PointOfBoostForce;
var () vector              AppliedBoostForce;
var    vector              PointOfBoostForce;
var () sound               VOC_Boost;
};
// the dynamic array containing the new variable type. this is available to the mapper in
// Unrealed in the actor properties for this class
var (BotVecBooster) array<VecSpec>      VehicleSpecific;
 
var string BoosterID;
 
//The rate at which the timer will check the status of any vehicles it may be tracking
var (BotVecBooster) float ScanRate;
 
// Creating a custom variable type to store some details about each vehicle we are tracking
struct VRefArray
{
var OnsVehicle            AVecRef;
var int                   VecSpecRecNo;
var float                 OrigActorGravScale;
var float                 OrigVehicleDrawScale;
};
// the dynamic array of the custom VRefArray variable type.
// This will be a list of all vecs being tracked by the booster
var array<VRefArray>      VecRefArray< SEMI >
 
// Generic function -Overwriting
simulated function PostBeginPlay() // called just after start of game play :takes the default values from the
{                        // previous class and adds then to the vecspecific array in position 0
VehicleSpecific.insert(0,1);
VehicleSpecific[0].AppliedBoostForce      = AppliedBoostForce;  //
VehicleSpecific[0].PointOfBoostForce      = PointOfBoostForce;  // this now frees up the variables
 
VehicleSpecific[0].Spin_AppliedBoostForce = Spin_AppliedBoostForce;
VehicleSpecific[0].Spin_PointOfBoostForce = Spin_PointOfBoostForce;
 
VehicleSpecific[0].bDirectionalBoost      = bDirectionalBoost;  // so we can use the genericvecboost
VehicleSpecific[0].bBoosts_emptyVechicles = bBoosts_emptyVechicles;
VehicleSpecific[0].bCanBoostBackwards     = bCanBoostBackwards;
 
VehicleSpecific[0].bLockHumanPlayers      = bLockHumanPlayers;  // without having to change the code
VehicleSpecific[0].ReleaseVelocity        = ReleaseVelocity;
VehicleSpecific[0].Actor_gravScale        = Actor_gravScale;
VehicleSpecific[0].VehicleDrawscale       = VehicleDrawscale;
VehicleSpecific[0].VOC_Boost              = VOC_Boost;
VehicleSpecific[0].bReBoosts              = bReBoosts;
super.PostBeginPlay();
}
 
// Generic function -Overwriting
simulated function Touch( Actor Other )
{
super.Touch(Other);                    // adds all the contained code from the parent function to this point.
if ( Other.isa('ONSVehicle') && ((ONSVehicle(other).Driver != none ) || (bBoosts_emptyVechicles)))         // first checks if its been touched by an onsvehicle
   {
    //log ("--------------touched by a vec with tag "$Other.tag);
    BoostVec( ONSVehicle( Other ) );  // calls BoostVec() and passes the actor ref of what touched
   }
}                                      // us to the function by 'typecasting' it to onsvehicle
 
// New custom function
function int Match_2_VehicleSpecificRec( ONSVehicle A_Vec )
{
local int I;
for ( i = 1 ; i < VehicleSpecific.length ; I++ )       // cycles though all the vehicle refs in the array
     if ( VehicleSpecific[i].VecType == A_Vec.class )  // if the passed vehicle type matches the one in the current record
          return I;                                    // returns the value stored in I
return 0;            // if no match is found the default values are used by return in a 0
}
 
// New custom function
function int Already_Tracking( ONSVehicle A_Vec )  // checks to see if we are already tracking a vehicle
{                                                  // by checking all the records of the vehicle currently being tracked
local int I;                                       // for a match in the valid vehicle ref
for ( i = 0 ; i < VecRefArray.length ; I++ )       // cycles though all the vehicle refs in the array
      if ( VecRefArray[i].AVecRef == A_Vec )
           return i;
return -1;          // if no match is found a flag of 01 is returned
}
 
// New custom function
simulated function BoostVec(ONSVehicle AVec)  // this function qualifies any actor that touches us
{                                   // + files them into an array of vehicles being tracked
local int VecTypeRecNumb;           // then retrieves any Specific vehicle type data if needed
//log ("--------------function BoostVec(ONSVehicle AVec)");                                    // checks if botlock is needed
 
if ( Already_Tracking(Avec) > -1 )  // then finally calls the boost function to kick the vehicle
    {
     //log ("--------------( Already_Tracking(Avec) > -1 )");
     return;
    }
 
VecTypeRecNumb     = Match_2_VehicleSpecificRec(Avec);
 
// log ("--------------VecTypeRecNumb = "$VecTypeRecNumb);
 
AppliedBoostForce      = VehicleSpecific[VecTypeRecNumb].AppliedBoostForce; // re-using the old values that contained the defaults
PointOfBoostForce      = VehicleSpecific[VecTypeRecNumb].PointOfBoostForce; // as these values are now being stored in position 0
bDirectionalBoost      = VehicleSpecific[VecTypeRecNumb].bDirectionalBoost; // of the VecSpecArray.
bCanBoostBackwards     = VehicleSpecific[VecTypeRecNumb].bCanBoostBackwards;
Spin_AppliedBoostForce = VehicleSpecific[VecTypeRecNumb].Spin_AppliedBoostForce;
Spin_PointOfBoostForce = VehicleSpecific[VecTypeRecNumb].Spin_PointOfBoostForce;
VehicleDrawscale       = VehicleSpecific[VecTypeRecNumb].VehicleDrawscale;
bLockHumanPlayers      = VehicleSpecific[VecTypeRecNumb].bLockHumanPlayers;
ReleaseVelocity        = VehicleSpecific[VecTypeRecNumb].ReleaseVelocity;
VOC_Boost              = VehicleSpecific[VecTypeRecNumb].VOC_Boost;
Actor_gravScale        = VehicleSpecific[VecTypeRecNumb].Actor_gravScale;
VehicleDrawscale       = VehicleSpecific[VecTypeRecNumb].VehicleDrawscale;
bReBoosts              = VehicleSpecific[VecTypeRecNumb].bReBoosts;
 
        if ( Avec.tag == 'Boosting')
           {
            if ( bReBoosts )
               {
                //log ("-------------- ( Avec.tag == 'Boosting')");
                Avec.tag ='Stolen';          // log (" -------------- bReBoosts Avec.tag ='Stolen'");
               }
            else
               return;
            }
       else
         Avec.tag = 'Boosting';
 
    ////log ("--------------Actor_gravScale"$Actor_gravScale);
 
    VecRefArray.insert(0,1);                             // Inserts a new blank slot into the array.
    VecRefArray[0].AVecRef            = Avec;            // assigns the valid onsvehicle ref to the array
    VecRefArray[0].VecSpecRecNo       = VecTypeRecNumb;
 
 if (!Avec.isplayerpawn())
    {
     AVec.bDriverCannotLeaveVehicle    = true;            // lock the vec
     //log ("-------------- (!Avec.isplayerpawn())....locking the vec ");
    }
 
 if (VehicleDrawscale > 0)
    {
     VecRefArray[0].OrigVehicleDrawScale = Avec.Drawscale;
     Avec.SetDrawscale(VehicleDrawscale);
     //log ("-------------- (VehicleDrawscale > 0) setting actor VehicleDrawscale to "$VehicleDrawscale);
    }
 
 if (Actor_gravScale > 0)
    {
     VecRefArray[0].OrigActorGravScale = Avec.kGetActorGravScale();
     Avec.kSetActorGravScale(Actor_gravScale);
     //log ("-------------- (Actor_gravScale > 0) setting actor grav scale to "$Actor_gravScale);
    }
 
 if ( VecRefArray.length == 1 )                    // if this is the only record call the timer() function
    {
     SetTimer( ScanRate , true );                 // call the timer() function in 'timerfrequncy'seconds
    //log ("-------------- ( VecRefArray.length == 1 ) ");
    }
 
GenericVehicleBoost(AVec); // calls the boost fuction
}
 
// New custom function                         -+
function  GenericVehicleBoost(onsvehicle TheTargetVec)
{
local float VecThrottle;
 
//log ("--------------GenericVehicleBoost(onsvehicle "$TheTargetVec$")");
 
if ( VOC_Boost!= None )
     Playsound ( VOC_Boost ) ;                                  // plays the boost sound fx
 
VecThrottle = TheTargetVec.Throttle;
 
if ( ( VecThrottle < 0 ) && (bCanBoostBackwards))
     AppliedBoostForce.X = AppliedBoostForce.X *(-1);
 
if ( bDirectionalBoost == True)
     TheTargetVec.KAddImpulse( AppliedBoostForce >> self.Rotation, PointOfBoostForce >> self.Rotation ) ;   // boosts in the direction the boosters facing
else
     TheTargetVec.KAddImpulse( AppliedBoostForce >> TheTargetVec.Rotation , PointOfBoostForce >> TheTargetVec.Rotation ) ;  // boosts in the direction the vehicles facing
 
if ( Spin_AppliedBoostForce == vect(0,0,0) )
     return;
 
TheTargetVec.KAddImpulse( Spin_AppliedBoostForce >> TheTargetVec.Rotation , Spin_PointOfBoostForce >> TheTargetVec.Rotation ) ;  // boosts in the direction the vehicles facing
TheTargetVec.bEjectPassengersWhenFlipped = False;
}
 
// The Timer function
// ==================
// the timer function here is used rather like a radar.
// The scan rate is the amount of sweeps it does a second.
//
// It only gets called if there are vehicles being tracked. Otherwise it shuts down
//
// On each sweep it;-
//                  checks all the vehicles being tracked to see if they are;
//                    dead : if so the record is removed from the array
//       On the ground yet : if so
//                           are they < the (mapper)set velocity
//                                      if they are < (mapper)set Vellocity
//                                                    remove from the array
//                                                    Unlock the vehicle
// Generic function - Overwriting
simulated function Timer()
{
 local int             VecSpecRecNo;
 local bool            bVehicleDead;
 local bool            bVecGrounded;
 local float           VehicleVel;
 local float           VehicleDScale;
 local float           ReleaseVel;
 local ONSVehicle      VehicleRef;
 local int             I;
 
 //log ("--------------Timer(): Tracking "$VecRefArray.length$" Vehicles).");
 
 for (I = 0 ; I < VecRefArray.length ; I++ )
     {
     VehicleRef    =  VecRefArray[I].AVecRef;                         // retrieves the Vehicle ref
 
     //log ("--------------Timer(): Checking status of ":$VecRefArray[I].AVecRef);
 
     VecSpecRecNo  =  VecRefArray[I].VecSpecRecNo;                    // matches vecspecific rec to the Vehicle ref
     bVecGrounded  =  VehicleRef.bVehicleOnGround;                    // retrieves  ir the vec is airborn or not
     bVehicleDead  =  VehicleRef.bVehicleDestroyed;                   // Assigns status of the vec to bDead
     VehicleVel    =  Vsize(VehicleRef.Velocity);                     // Gets the Vehicle Velocity
     ReleaseVel    =  VehicleSpecific[VecSpecRecNo].ReleaseVelocity;
     VehicleDScale =  VehicleSpecific[VecSpecRecNo].VehicleDrawscale;
 
     // assigning the values to variables in this way makes the decision making in the rest of this
     // function easier to understand and modify at a later date.
 
     if (VehicleRef == None || bVehicleDead )      // removes any invalid records (records with no VecRef)
        {
         //log ("-------------- (VehicleRef == none || bVehicleDead ). removing"$I$" from the array");
         VecRefArray.remove(I , 1);                // removes the record from the array
         I -= 1;                                   // adjusts the counter to move back 1 place
        }
   else
      if ( VehicleRef.Tag=='Stolen')
         {
          // log ("-------------- ( VehicleRef.Tag=='Stolen')..removing from the array and setting its tag to BOOSTING ");
          VehicleRef.Tag = 'Boosting';
          VecRefArray.remove(I , 1);                // removes the record from the array
          I -= 1;                                   // adjusts the counter to move back 1 place
         }
  else
     if (( bVecGrounded == true ) && ( VehicleVel < ReleaseVel ) ) // checks if its on the ground and under the
        {                                                          // release velocity
         //log ("-------------- (( bVecGrounded == true ) && ( VehicleVel < ReleaseVel ) )..RETURNING orig properties to the vehicle ");
 
         if (VehicleRef.KGetActorGravScale() ~= VecRefArray[I].OrigActorGravScale)
             VehicleRef.kSetActorGravScale(VecRefArray[I].OrigActorGravScale);
 
         if (VehicleDScale > 0)
             VehicleRef.SetDrawScale ( VecRefArray[I].OrigVehicleDrawScale );
 
         VehicleRef.bEjectPassengersWhenFlipped = true;
         VehicleRef.bDriverCannotLeaveVehicle   = false; // unlocks the vec
         VehicleRef.Tag                         = 'tag';
         VecRefArray.remove(I , 1);                                // removes the record from the array
         I -= 1;                                                   // adjusts the counter to move back 1 place
        }
      }
 
if ( VecRefArray.length > 0 )
   {
   SetTimer( ScanRate , false );           // will only call the timer() once ,if its tracking
   //log("end of timer function and the vecref array was > 0 so im setting timer again");
   }
}
 
defaultproperties
{
     bBoosts_emptyVechicles=false 
     bCanBoostBackwards=True
     VehicleDrawscale=-1.000000
     ReleaseVelocity=800.000000
     VOC_Boost=Sound'AnnouncerEvil.Booster'
     Actor_gravScale=-1
     AppliedBoostForce=(X=9000000.000000,Z=2000000.000000)
     ScanRate=0.500000
     Texture=Texture'XEffectMat.Shock.Shock_ring_a'
     CollisionRadius=150.000000
     CollisionHeight=150.000000
     bUseCylinderCollision=True
}

Related Topics[edit]


Discussion[edit]