| Home Page | Recent Changes

WeaponSystemFramework

The Vehicle Weapon System Framework

I've written up this class to make implementation of weapons for vehicles both easily and quickly. A configurable zoom option and automated projectile firing/timing is already implemented and toggleable with use of the defaultproperties section.

A note about the zoom, in order to ensure the behavior intended, both the zoom and await variables needs to be set to true. It should still *work* but i don't suggest it.

Key Concepts

The server will exclusively call the TimerUpdateWithoutDriver and TimerUpdateWithDriver. The First every tick ( Be careful ), and the other every tick while a player is in the vehicle.

All of the Server* functions will be executed exclusively on the server.

All of the Client* functions will be executed exclusively on network-clients.

All of the base functions of this same family ( I.E. ServerPriFireInactive, ClientPriFireInactive, *PriFireInactive* ) are executed on the local machine of the person in the turret.

All client effects/rendering should be done in the base functions (PriFireInactive). This is the first function called, and is called locally on the client before any replication takes place, this will both be the fastest/most frequent to execute code.

Client* functions may not actually have a practical use but if you come up with something that should really be done in there let me know.

To make your primary fire spawn a projectile.

defaultproperties
{
bPriFireSpawnProject=true
bRepeatedPriFire=true //optional
PrimaryProjectileClass=MyPackage.MyClass
FireInterval=1.0
}

To make your alternate fire zoom.

defaultproperties
{
  bDoAltZoom=true
  bShouldAwaitAltRelease=true
  ZoomMinFov=25.000
  ZoomMaxFov=120.0
  ZoomIncrement=0.5
}

Note that setting zoomIncrement to a negative value makes a zoom out. A positive ZoomIncrement zooms in. (FOV-ZoomIncrement)

Here are all of the new default properties, with what i have thought to be fairly intuitive names.

defaultproperties
{
     TimerUpdateFrequency=0.01;
     bDoPriZoom=false
     bDoAltZoom=false
     bPriFireSpawnProjectile=false
     bAltFireSpawnProjectile=false
     bShouldAwaitPriRelease=false
     bShouldAwaitAltRelease=false
     bRepeatedPriFire=false
     bRepeatedAltFire=false
     ZoomMinFov=25.000
     ZoomMaxFov=120.0
     ZoomIncrement=0.5
     FireInterval=1.0
     AltFireInterval=0.0
     PrimaryProjectileClass=none
     SecondaryProjectileClass=none
}
class MTPBaseStationaryWeapon extends ONSWeapon;

// Real-Time Key Press Variables
var bool bIsAltFiring, bWasAltFiring;
var bool bIsPriFiring, bWasPriFiring;
var bool bAwaitingAltRelease, bAwaitingPriRelease;

// Realtime Zoom Variables
var float ZoomLevel;
var bool bZooming;

// Real-Time Weapon Variables
var float LastPriFireTime, LastAltFireTime;

// Configuration Weapon Variables
var float TimerUpdateFrequency;
var class<Projectile> PrimaryProjectileClass;
var class<Projectile> SecondaryProjectileClass;
var bool bPriFireSpawnProjectile, bAltFireSpawnProjectile;
var bool bRepeatedPriFire, bRepeatedAltFire;

// Configuration Key Press Variables
var bool bShouldAwaitAltRelease, bShouldAwaitPriRelease;

// Config/Default Oriented Zoom Variables
var float ZoomMinFov, ZoomMaxFov, ZoomIncrement;
var bool bDoPriZoom, bDoAltZoom;

replication
{
    reliable if( Role == Role_Authority )
        LastPriFireTime, LastAltFireTime, bAwaitingAltRelease, bAwaitingPriRelease;
    reliable if( Role < Role_Authority )
        ServerPriFirePressed, ServerPriFireReleased, ServerPriFireInactive, ServerPriFireActive,
        ServerAltFirePressed, ServerAltFireReleased, ServerAltFireInactive, ServerAltFireActive,
        ServerTimerUpdateWithDriver, ServerTimerUpdateWithoutDriver,
        ServerCantPriFire, ServerCantAltFire, ServerAwaitRelease;
    reliable if( Role == Role_Authority )
        ClientPriFirePressed, ClientPriFireReleased, ClientPriFireInactive, ClientPriFireActive,
        ClientAltFirePressed, ClientAltFireReleased, ClientAltFireInactive, ClientAltFireActive,
        ClientTimerUpdateWithDriver, ClientTimerUpdateWithoutDriver,
        ClientCantPriFire, ClientCantAltFire;
}

simulated function CalcWeaponFire()
{
    Super.CalcWeaponFire()

    DualFireOffset*=-1;
}

event bool AttemptFire(Controller C, bool bAltFire)
{
    local bool bCanFire;

    if(Role != ROLE_Authority || bForceCenterAim)
        return False;

    if( !bAltFire && CanPriFire() )
        bCanFire = True;

    if( bAltFire && CanAltFire() )
        bCanFire = true;

    if( bCanFire )
    {
        if (bCorrectAim)
            WeaponFireRotation = AdjustAim(bAltFire);
        if (Spread > 0)
            WeaponFireRotation = rotator(vector(WeaponFireRotation) + VRand()*FRand()*Spread);

        Instigator.MakeNoise(1.0);

        if (bAltFire)
        {
            AltFire(C);
        }
        else
        {
            Fire(C);
        }

        AimLockReleaseTime = Level.TimeSeconds + FireCountdown * FireIntervalAimLock;
    }

    return bCanFire;
}

function class<Projectile> GetProjectileClass(bool bAltFire)
{
    if( bAltFire )
        return GetSecondaryProjectileClass();
    else
        return GetPrimaryProjectileClass();
}

function class<Projectile> GetPrimaryProjectileClass()
{
    return PrimaryProjectileClass;
}

function class<Projectile> GetSecondaryProjectileClass()
{
    return SecondaryProjectileClass;
}

function SpawnProjectileNone(bool bAltFire)
{
    if( bAltFire )
        SpawnProjectileNoneAltFire();
    else
        SpawnProjectileNonePriFire();
}

function SpawnProjectileNoneAltFire()
{
}

function SpawnProjectileNonePriFire()
{
}

function Projectile SpawnProjectileInit(Projectile P, bool bAltFire)
{
    return P;
}

// You'll Probably Never Want To Super.Call() this when overriding
function PlayFiringAnimations()
{
    if (!Level.bDropDetail && Level.DetailMode != DM_Low)
    {
        if (DualFireOffset < 0)
            PlayAnim('RightFire');
        else
            PlayAnim('LeftFire');
    }
}

function Projectile SpawnProjectile(class<Projectile> ProjClass, bool bAltFire)
{
    local Projectile P;
    local class<Projectile> ProClass;

    PlayFiringAnimations();

    ProClass = GetProjectileClass(bAltFire);

    // Get Current Client Weapon Rotation
    CalcWeaponFire();

    if( ProClass != none )
        P = Super.SpawnProjectile(ProClass, bAltFire);

    if( P == none )
    {
        SpawnProjectileNone(bAltFire);
        return none;
    }

    P.SetOwner(self);

    return SpawnProjectileInit(P, bAltFire);
}

simulated function WeaponInit()
{
    LastPriFireTime=Level.TimeSeconds;
    LastAltFireTime=Level.TimeSeconds;
    bAwaitingPriRelease=false;
    bAwaitingAltRelease=false;
}

simulated function bool PriFireWaitingRelease()
{
    return bAwaitingPriRelease && bShouldAwaitPriRelease;
}

simulated function bool AltFireWaitingRelease()
{
    return bAwaitingAltRelease && bShouldAwaitAltRelease;
}

/////////////////////////////////////////////////////////
// Entry Point Timer Functions, Called On Client OR Server
simulated function PriFirePressed()
{
    if( ShouldPriZoom() )
        StartZoom(false);

    ServerPriFirePressed();
}

simulated function PriFireReleased()
{
    if( bDoPriZoom )
        EndZoom();

    ServerPriFireReleased();
}

simulated function PriFireInactive()
{
    ServerPriFireInactive();
}

simulated function PriFireActive()
{
    if( ShouldPriZoom() )
        DoZoom();

    ServerPriFireActive();
}

simulated function AltFirePressed()
{
    if( ShouldAltZoom() )
        StartZoom(true);

    ServerAltFirePressed();
}

simulated function AltFireReleased()
{
    if( bDoAltZoom )
        EndZoom();

    ServerAltFireReleased();
}

simulated function AltFireInactive()
{
    ServerAltFireInactive();
}

simulated function AltFireActive()
{
    if( ShouldAltZoom() )
        DoZoom();

    ServerAltFireActive();
}

simulated function TimerUpdateWithDriver()
{
    ServerTimerUpdateWithDriver();
}

simulated function TimerUpdateWithoutDriver()
{
    ServerTimerUpdateWithoutDriver();
}
// End Entry Point Timer Functions
////////////////////////////////////////

function ServerAwaitRelease( bool bAltFire )
{
    if( bAltFire )
        bAwaitingAltRelease=true;
    else
        bAwaitingPriRelease=true;
}

/////////////////////////////////////////////////
// Zooming Functions
//
// Only One Zoom Feature Per Weapon
simulated function StartZoom(bool bAltFire)
{
    if( ZoomLevel != 0.0 )
    {
        RevertZoom();

        ServerAwaitRelease( bAltFire );
    }
    else
    {
        ZoomInit();
        DoZoom();
    }
}

simulated function ZoomInit()
{
        bZooming=True;
}

simulated function RevertZoom()
{
      EndZoom();
      ZoomLevel = 0.0;

      if( Instigator != none && Instigator.Controller != none && PlayerController(Instigator.Controller) != none )
           PlayerController(Instigator.Controller).DesiredFOV = PlayerController(Instigator.Controller).DefaultFOV;
}

simulated function EndZoom()
{
      bZooming=False;
}

simulated function bool IsZooming()
{
    return bZooming;
}

simulated function DoZoom()
{
    if( !IsZooming() )
        return;

    PreZoom();

    ZoomLevel += ZoomIncrement;

    if( 90.0 - ZoomLevel < ZoomMinFov )
        ZoomLevel = 90 - ZoomMinFov;

    if( 90.0 - ZoomLevel > ZoomMaxFov )
        ZoomLevel = 90 - ZoomMaxFov;

    if( Instigator != none && Instigator.Controller != none && PlayerController(Instigator.Controller) != none )
      PlayerController(Instigator.Controller).DesiredFOV = FClamp(90.0 - ZoomLevel, 1, 170);

    PostZoom();
}

simulated function PreZoom()
{
}

simulated function PostZoom()
{
}

simulated function bool ShouldAltZoom()
{
    return bDoAltZoom && !AltFireWaitingRelease();
}

simulated function bool ShouldPriZoom()
{
    return bDoPriZoom && !PriFireWaitingRelease();
}

/////////////////////////////////////////
// Begin Server Side Timer Functions
// These Must Be Super.Called()
// Or The Client Functions Won't Be Replicated
function ServerPriFirePressed()
{
    ServerTryPriFire();
    ClientPriFirePressed();
}

function ServerTryPriFire()
{
    if( CanPriFire() )
        ServerPriFire();
    else
       ServerCantPriFire();
}

// This Is Not The Place For (House Keeping), use Inactive,
// This is for specific thigns happening when the mouse is released
// I.E. Fire On Release.
function ServerPriFireReleased()
{
    ClientPriFireReleased();
    ServerPriFireInactive();
}

function ServerPriFireInactive()
{
    if( PriFireWaitingRelease() )
    {
        bAwaitingPriRelease=false;
    }

    ClientPriFireInactive();
}

function ServerPriFireActive()
{
    if( bRepeatedPriFire )
        ServerTryPriFire();

    ClientPriFireActive();
}

/////////////////////////
// Server Alt Fire Routines
function ServerAltFirePressed()
{
    ServerTryAltFire();
    ClientAltFirePressed();
}

function ServerTryAltFire()
{
    if( CanAltFire() )
        ServerAltFire();
    else
        ServerCantAltFire();
}

function ServerAltFireReleased()
{
    ClientAltFireReleased();
    ServerAltFireInactive();
}

function ServerAltFireInactive()
{
    if( AltFireWaitingRelease() )
    {
        bAwaitingAltRelease=false;
    }

    ClientAltFireInactive();
}

function ServerAltFireActive()
{
    if( bRepeatedAltFire )
        ServerTryAltFire();

    ClientAltFireActive();
}

function ServerTimerUpdateWithDriver()
{
    ClientTimerUpdateWithDriver();
}

function ServerTimerUpdateWithoutDriver()
{
    ClientTimerUpdateWithoutDriver();
}
// End Server Side Timer Functions
//////////////////////////////////////////

/////////////////////////////////////////////
// Pri Fire Guts
simulated function bool CanPriFire()
{
    return (LastPriFireTime + FireInterval) <= Level.TimeSeconds && !PriFireWaitingRelease();
}

// Overriding Should Call Super After All Other Functions
// Use ServerPostPriFire To Do Modifications After Projectile Exists
function ServerPriFire()
{
    LastPriFireTime=Level.TimeSeconds;

    if( bPriFireSpawnProjectile )
        SpawnProjectile(none, false);

    ServerPostPriFire();
}

function ServerCantPriFire()
{
    ClientCantPriFire();
}

simulated function ClientCantPriFire()
{
}

function ServerPostPriFire()
{
}

////////////////////////////////////////
//Alt Fire Guts
simulated function bool CanAltFire()
{
    return (LastAltFireTime + AltFireInterval) <= Level.TimeSeconds && !AltFireWaitingRelease();
}

// Overriding Should Call super After All Other Commands
// Use ServerPostAltFire To Do Modifications After Projectile Exists
function ServerAltFire()
{
    LastAltFireTime=Level.TimeSeconds;

    if( bAltFireSpawnProjectile )
        SpawnProjectile(none, true);

    ServerPostAltFire();
}

function ServerPostAltFire()
{
}

function ServerCantAltFire()
{
    ClientCantAltFire();
}

simulated function ClientCantAltFire()
{
}

//////////////////////////////////////////
// Begin Client Side Timer Functions
simulated function ClientPriFirePressed()
{
}

simulated function ClientPriFireReleased()
{
}

simulated function ClientPriFireInactive()
{
}

simulated function ClientPriFireActive()
{
}

simulated function ClientAltFirePressed()
{
}

simulated function ClientAltFireReleased()
{
}

simulated function ClientAltFireInactive()
{
}

simulated function ClientAltFireActive()
{
}

simulated function ClientTimerUpdateWithDriver()
{
}

simulated function ClientTimerUpdateWithoutDriver()
{
}
// End Client Side Timer Functions
//////////////////////////////////////

simulated state ProjectileFireMode
{
    simulated function BeginState()
    {
        super.BeginState();

        SetTimer(TimerUpdateFrequency,true);

        //Input Var Initializations
        bIsAltFiring = false;
        bIsPriFiring = false;

        // Zoom Init
        RevertZoom();

        WeaponInit();
    }

    simulated function EndState()
    {
        SetTimer(0.0, false);
        super.EndState();
    }

    // For Bot Support
    function Fire(Controller C)
    {
        PriFirePressed();
    }

    function AltFire(Controller C)
    {
        AltFirePressed();
    }

    simulated function Timer()
    {
        if( ROLE == ROLE_Authority )
            TimerUpdateWithoutDriver();

        // Re-Init If  We Are An Un-Powered Turret On The Server
        if( Role == ROLE_Authority && ONSStationaryWeaponPawn(Owner) != none &&
                !ONSStationaryWeaponPawn(Owner).bPowered )
        {
            WeaponInit();
        }

        if( Instigator == none || Instigator.Controller == none )
            return;

        if( ROLE == ROLE_Authority )
            TimerUpdateWithDriver();

        if( !Instigator.IsLocallyControlled() )
            return;

        ///////////////////////////////////////////
        // Key Input Data Initilization

        bWasAltFiring = bIsAltFiring;
        bIsAltFiring = !(Instigator.Controller.bAltFire == 0);

        bWasPriFiring = bIsPriFiring;
        bIsPriFiring = !(Instigator.Controller.bFire == 0);

        //////////////////////////////////////////

        if( bIsPriFiring && !bWasPriFiring ) // Primary Fire Was Just Pressed
        {
        //      log("["$Level.TimeSeconds@"] MTPBaseStationaryWeapon: Pri Fire Pressed");
              PriFirePressed();
        }
        else
        if( !bIsPriFiring && bWasPriFiring ) // Primary Fire Was Just Released
        {
         //   log("["$Level.TimeSeconds@"] MTPBaseStationaryWeapon: Pri Fire Released");
            PriFireReleased();
        }
        else
        if( !bIsPriFiring )  // Code Executed When Primary Fire is Not Pressed
        {
         //   log("["$Level.TimeSeconds@"] MTPBaseStationaryWeapon: Pri Fire Inactive");

            PriFireInactive();
        }
        else // Primary Fire Is Pressed
        {
         //   log("["$Level.TimeSeconds@"] MTPBaseStationaryWeapon: Pri Fire Active");

            PriFireActive();
        }

        if( bIsAltFiring && !bWasAltFiring )  // Alt Fire Was Just Pressed
        {
         //   log("["$Level.TimeSeconds@"] MTPBaseStationaryWeapon: Alt Fire Pressed");
            AltFirePressed();
        }
        else
        if( !bIsAltFiring && bWasAltFiring )  // Alt Fire Was Just Released
        {
         //    log("["$Level.TimeSeconds@"] MTPBaseStationaryWeapon: Alt Fire Released");
             AltFireReleased();
        }
        else
        if( !bIsAltFiring ) // Code Executed When Alt Fire is Not Pressed
        {
        //    log("["$Level.TimeSeconds@"] MTPBaseStationaryWeapon: Alt Fire Inactive");
             AltFireInactive();
        }
        else  // Alt Fire Is Pressed
        {
        //    log("["$Level.TimeSeconds@"] MTPBaseStationaryWeapon: Alt Fire Active");

             AltFireActive();
        }
    }
}

defaultproperties
{
     YawBone="TurretBase"
     PitchBone="Dummy01"
     PitchUpLimit=15000
     PitchDownLimit=52500
     WeaponFireAttachmentBone="TurretCockpit"
     GunnerAttachmentBone="TurretCockpit"
     WeaponFireOffset=25.000000
     DualFireOffset=75.000000
     bInstantRotation=True
     bInstantFire=False
     bDualIndependantTargeting=True
     AIInfo(0)=(bInstantHit=False,aimerror=750.000000)
     Mesh=SkeletalMesh'ONSWeapons-A.NewManualGun'
     CollisionRadius=50.000000
     CollisionHeight=70.000000
     TimerUpdateFrequency=0.01;
     bDoPriZoom=false
     bDoAltZoom=false
     bPriFireSpawnProjectile=false
     bAltFireSpawnProjectile=false
     bShouldAwaitPriRelease=false
     bShouldAwaitAltRelease=false
     bRepeatedPriFire=false
     bRepeatedAltFire=false
     ZoomMinFov=25.000
     ZoomMaxFov=120.0
     ZoomIncrement=0.5
     FireInterval=1.0
     AltFireInterval=0.0
     PrimaryProjectileClass=none
     SecondaryProjectileClass=none
}

The Unreal Engine Documentation Site

Wiki Community

Topic Categories

Recent Changes

Offline Wiki

Unreal Engine

Console Commands

Terminology

FAQs

Help Desk

Mapping Topics

Mapping Lessons

UnrealEd Interface

UnrealScript Topics

UnrealScript Lessons

Making Mods

Class Tree

Modeling Topics

Chongqing Page

Log In