seenooh
08-18-2010, 10:38 AM
Hello all!
In the past week, I've been researching how to delay the weapon firing instead of immediately when the firing animation starts. This is useful for melee attacks or if your weapon actually shoots in the middle/end of the firing animation.
Initially, I used AnimNotify_Script, it worked for me but it wasn't convenient since alot of the weapons that I'll be developing will require delay. So ultimately I managed to develop a super class which provides this functionality, and all my weapons that need delay can inherit from it, tweak a couple of variables, and you're up and running! :)
So this is the super class, lots of comments explaining every step:
/**
* ************************************************** ************************************************** *********
* OCWeapon. The shared Weapon class implementation.
*
* By Hamad Al-Hasan (aka seenooh) for The Outcasts project (http://www.the-outcasts.tk/).
*
* ************************************************** ************************************************** *********
* Version: 1.0
*
* Description: This class will be subclassed by all our weapon implementations. It will have
* all the common functional features between all weapons.
*
* Last Modified by: Hamad Al-Hasan
* Last Modify Date: Aug, 16th 2010
*
*/
class OCWeapon extends UTWeapon;
/** This is an array of two elements (fire/alt fire) containing how much (in seconds) we can delay fire after the fire animation starts */
var array<float> DelayFireTime;
/*
* The WeaponFiring state is overriden to provide the delay fire functionality. The uncommented functions are stock implementations
*
* Workflow:
*
* 1- Once we fire, WeaponFiring state is activated, and BeginState is immediately executed.
* 2- If we don't have delay, we'll fire immediately and refire according to FireInterval.
* 3- If we have delay, we'll play the firing animation first. Then activate the delay timer,
* which will delay the firing logic according to DelayFireTime[FireNumMode].
* 4- Once we fire, the refire logic will start.
*/
simulated state WeaponFiring
{
simulated event bool IsFiring()
{
return true;
}
/**
* Timer event, call is set up in Weapon::TimeWeaponFiring().
* The weapon is given a chance to evaluate if another shot should be fired.
* This event defines the weapon's rate of fire.
*/
simulated function RefireCheckTimer()
{
// if switching to another weapon, abort firing and put down right away
if( bWeaponPutDown )
{
`LogInv("Weapon put down requested during fire, put it down now");
PutDownWeapon();
return;
}
// If weapon should keep on firing, then do not leave state and fire again.
if( ShouldRefire() )
{
//Hamad: If we have delay, refire according to our delay logic
if (DelayFireTime[CurrentFireMode] > 0)
{
ClearTimer('DelayFire');
PlayFireEffects( CurrentFireMode );
}
else
FireAmmunition(); //Else, follow the default implementation
return;
}
// Otherwise we're done firing
HandleFinishedFiring();
}
simulated event BeginState( Name PreviousStateName )
{
`LogInv("PreviousStateName:" @ PreviousStateName);
//If we don't have delays, resume with default implementation
if (DelayFireTime[CurrentFireMode] <= 0)
{
FireAmmunition();
TimeWeaponFiring( CurrentFireMode );
}
else
PlayFireEffects( CurrentFireMode ); //Otherwise, use ours
}
simulated event EndState( Name NextStateName )
{
`LogInv("NextStateName:" @ NextStateName);
// Set weapon as not firing
ClearFlashCount();
ClearFlashLocation();
ClearTimer('RefireCheckTimer');
NotifyWeaponFinishedFiring( CurrentFireMode );
}
}
simulated function TimeWeaponFiring( byte FireModeNum )
{
// if weapon is not firing, then start timer. Firing state is responsible to stopping the timer.
if( !IsTimerActive('RefireCheckTimer') )
{
SetTimer( GetFireInterval(FireModeNum) , true, nameof(RefireCheckTimer) );
}
}
//Hamad: This is the delay timer function. It'll fire the default implementation and clear itself.
simulated function DelayFire()
{
FireAmmunition();
TimeWeaponFiring( CurrentFireMode );
ClearTimer('DelayFire');
}
//Hamad: Play the animation and activate the delay timer if we are in delay mode
simulated function PlayFireEffects( byte FireModeNum, optional vector HitLocation )
{
if (DelayFireTime[FireModeNum] > 0) // Do we have delay?
{
/* Is the timer active already? if yes, don't do anything. This is a tricky part.
* We injected this function at the BeginState, which is originally fired by Pawn.WeaponFired()
* I wanted to remove this effect without touching the pawn's base code, so I could do it
* by checking if the timer is active or not (caused by our BeginState). If it does, then
* the second call by Pawn.WeaponFired() will have no effect, this avoid duplication.
*/
if( !IsTimerActive('DelayFire') )
{
SetTimer( DelayFireTime[FireModeNum] , true, 'DelayFire' );
super.PlayFireEffects(FireModeNum, HitLocation);
}
}
else
{
//No delay. Resume default implementation.
super.PlayFireEffects(FireModeNum, HitLocation);
}
}
DefaultProperties
{
DelayFireTime(0) = 0; //By default, no delay for the main fire.
DelayFireTime(1) = 0; //By default, no delay for the alt fire.
}
Now all you have to do is extend this class and you can delay your fire easily. I hope you find this useful. :)
Enjoy!
In the past week, I've been researching how to delay the weapon firing instead of immediately when the firing animation starts. This is useful for melee attacks or if your weapon actually shoots in the middle/end of the firing animation.
Initially, I used AnimNotify_Script, it worked for me but it wasn't convenient since alot of the weapons that I'll be developing will require delay. So ultimately I managed to develop a super class which provides this functionality, and all my weapons that need delay can inherit from it, tweak a couple of variables, and you're up and running! :)
So this is the super class, lots of comments explaining every step:
/**
* ************************************************** ************************************************** *********
* OCWeapon. The shared Weapon class implementation.
*
* By Hamad Al-Hasan (aka seenooh) for The Outcasts project (http://www.the-outcasts.tk/).
*
* ************************************************** ************************************************** *********
* Version: 1.0
*
* Description: This class will be subclassed by all our weapon implementations. It will have
* all the common functional features between all weapons.
*
* Last Modified by: Hamad Al-Hasan
* Last Modify Date: Aug, 16th 2010
*
*/
class OCWeapon extends UTWeapon;
/** This is an array of two elements (fire/alt fire) containing how much (in seconds) we can delay fire after the fire animation starts */
var array<float> DelayFireTime;
/*
* The WeaponFiring state is overriden to provide the delay fire functionality. The uncommented functions are stock implementations
*
* Workflow:
*
* 1- Once we fire, WeaponFiring state is activated, and BeginState is immediately executed.
* 2- If we don't have delay, we'll fire immediately and refire according to FireInterval.
* 3- If we have delay, we'll play the firing animation first. Then activate the delay timer,
* which will delay the firing logic according to DelayFireTime[FireNumMode].
* 4- Once we fire, the refire logic will start.
*/
simulated state WeaponFiring
{
simulated event bool IsFiring()
{
return true;
}
/**
* Timer event, call is set up in Weapon::TimeWeaponFiring().
* The weapon is given a chance to evaluate if another shot should be fired.
* This event defines the weapon's rate of fire.
*/
simulated function RefireCheckTimer()
{
// if switching to another weapon, abort firing and put down right away
if( bWeaponPutDown )
{
`LogInv("Weapon put down requested during fire, put it down now");
PutDownWeapon();
return;
}
// If weapon should keep on firing, then do not leave state and fire again.
if( ShouldRefire() )
{
//Hamad: If we have delay, refire according to our delay logic
if (DelayFireTime[CurrentFireMode] > 0)
{
ClearTimer('DelayFire');
PlayFireEffects( CurrentFireMode );
}
else
FireAmmunition(); //Else, follow the default implementation
return;
}
// Otherwise we're done firing
HandleFinishedFiring();
}
simulated event BeginState( Name PreviousStateName )
{
`LogInv("PreviousStateName:" @ PreviousStateName);
//If we don't have delays, resume with default implementation
if (DelayFireTime[CurrentFireMode] <= 0)
{
FireAmmunition();
TimeWeaponFiring( CurrentFireMode );
}
else
PlayFireEffects( CurrentFireMode ); //Otherwise, use ours
}
simulated event EndState( Name NextStateName )
{
`LogInv("NextStateName:" @ NextStateName);
// Set weapon as not firing
ClearFlashCount();
ClearFlashLocation();
ClearTimer('RefireCheckTimer');
NotifyWeaponFinishedFiring( CurrentFireMode );
}
}
simulated function TimeWeaponFiring( byte FireModeNum )
{
// if weapon is not firing, then start timer. Firing state is responsible to stopping the timer.
if( !IsTimerActive('RefireCheckTimer') )
{
SetTimer( GetFireInterval(FireModeNum) , true, nameof(RefireCheckTimer) );
}
}
//Hamad: This is the delay timer function. It'll fire the default implementation and clear itself.
simulated function DelayFire()
{
FireAmmunition();
TimeWeaponFiring( CurrentFireMode );
ClearTimer('DelayFire');
}
//Hamad: Play the animation and activate the delay timer if we are in delay mode
simulated function PlayFireEffects( byte FireModeNum, optional vector HitLocation )
{
if (DelayFireTime[FireModeNum] > 0) // Do we have delay?
{
/* Is the timer active already? if yes, don't do anything. This is a tricky part.
* We injected this function at the BeginState, which is originally fired by Pawn.WeaponFired()
* I wanted to remove this effect without touching the pawn's base code, so I could do it
* by checking if the timer is active or not (caused by our BeginState). If it does, then
* the second call by Pawn.WeaponFired() will have no effect, this avoid duplication.
*/
if( !IsTimerActive('DelayFire') )
{
SetTimer( DelayFireTime[FireModeNum] , true, 'DelayFire' );
super.PlayFireEffects(FireModeNum, HitLocation);
}
}
else
{
//No delay. Resume default implementation.
super.PlayFireEffects(FireModeNum, HitLocation);
}
}
DefaultProperties
{
DelayFireTime(0) = 0; //By default, no delay for the main fire.
DelayFireTime(1) = 0; //By default, no delay for the alt fire.
}
Now all you have to do is extend this class and you can delay your fire easily. I hope you find this useful. :)
Enjoy!