2020-12-13 15:01:13 +00:00
//=============================================================================
// KFWeap_DualBase
//=============================================================================
// Dual weapon base class
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
// Jeff Robinson
//=============================================================================
class KFWeap _DualBase extends KFWeap _PistolBase
native ; // trader needs this to be native for now (6/10/15) so we can access SingleClass
/** Animations to play when the weapon is fired */
var ( Animations ) const editconst name LeftFireAnim ;
/** Animation to play when the weapon is fired */
var ( Animations ) const editconst array < name > LeftFireSightedAnims ;
/** A muzzle flash instance for left weapon */
var KFMuzzleFlash LeftMuzzleFlash ;
/** Holds an offest for spawning protectile effects for left weapon */
var ( ) vector LeftFireOffset ;
/** Whether we should fire from the right-side weapon (alternates right and left fire) */
var transient bool bFireFromRightWeapon ;
/** class of the single variant of this weapon */
var class < KFWeapon > SingleClass ;
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @ name Animations ( Using const anim names to reduce instanced data cost )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
/** Cached anim nodes */
var AnimNodeBlendPerBone EmptyMagBlendNode _L ;
/** array of bones to lock when out of ammo */
var array < name > BonesToLockOnEmpty _L ;
/** Anims for ironsight and alternate ironsight mode **/
var ( Animations ) const editconst name IdleToIronSightAnim ;
var ( Animations ) const editconst name IdleToIronSightAnim _Alt ;
var ( Animations ) const editconst name IronSightToIdleAnim ;
var ( Animations ) const editconst name IronSightToIdleAnim _Alt ;
var ( Animations ) const editconst array < name > IdleSightedAnims _Alt ;
var ( Animations ) const editconst name FireSightedAnim _Alt ;
var ( Animations ) const editconst name LeftFireSightedAnim _Alt ;
var ( Animations ) const editconst name EquipAnimIS ;
var ( Animations ) const editconst name EquipAnimISAlt ;
var ( Animations ) const editconst name LeftFireLastAnim ;
var ( Animations ) const editconst name LeftFireLastSightedAnim ;
var ( Animations ) const editconst name FireLastSightedAnim _Alt ;
var ( Animations ) const editconst name LeftFireLastSightedAnim _Alt ;
const ReloadOneEmptyAnim = 'Reload_Empty_Half' ;
const ReloadOneEmptyEliteAnim = 'Reload_Empty_Half_Elite' ;
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @ name Revolver vars
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
var CylinderRotationInfo CylinderRotInfo _L ;
cpptext
{
virtual void PreBeginPlay ( ) ;
virtual void RefreshSkinItemId ( ) ;
// cylinder is incrementally rotated
virtual void TickSpecial ( FLOAT DeltaSeconds ) ;
} ;
/ * * C a c h e A n i m N o d e s f r o m t h e t r e e
* @ note : skipped on server because AttachComponent / AttachWeaponTo is not called
* /
simulated event PostInitAnimTree ( SkeletalMeshComponent SkelComp )
{
local KFGameEngine KFGEngine ;
super . PostInitAnimTree ( SkelComp ) ;
EmptyMagBlendNode _L = AnimNodeBlendPerBone ( SkelComp . FindAnimNode ( 'EmptyMagBlend_L' ) ) ;
if ( EmptyMagBlendNode _L != none && BonesToLockOnEmpty _L . Length > 0 )
{
BuildEmptyMagNodeWeightList ( EmptyMagBlendNode _L , BonesToLockOnEmpty _L ) ;
}
KFGEngine = KFGameEngine ( Class 'KFGameEngine' . static . GetEngine ( ) ) ;
if ( KFGEngine != none )
{
bUseAltFireMode = KFGEngine . bUseAltAimOnDual ;
}
if ( ! bRevolver )
{
return ;
}
CylinderRotInfo _L . Control = SkelControlSingleBone ( SkelComp . FindSkelControl ( 'CylinderControl_L' ) ) ;
if ( CylinderRotInfo _L . Control != none )
{
CylinderRotInfo _L . Control . SetSkelControlActive ( true ) ;
}
}
/ * *
* Called on a client , this function Attaches the WeaponAttachment
* to the Mesh .
*
* Overridden to attach LeftMuzzleFlash
* /
simulated function AttachMuzzleFlash ( )
{
super . AttachMuzzleFlash ( ) ;
if ( MySkelMesh != none )
{
if ( MuzzleFlashTemplate != None )
{
LeftMuzzleFlash = new ( self ) Class 'KFMuzzleFlash' ( MuzzleFlashTemplate ) ;
LeftMuzzleFlash . AttachMuzzleFlash ( MySkelMesh , 'MuzzleFlash_L' , 'ShellEject_L' ) ;
}
}
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* State Active
* A Weapon this is being held by a pawn should be in the active state . In this state ,
* a weapon should loop any number of idle animations , as well as check the PendingFire flags
* to see if a shot has been fired .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
simulated state Active
{
simulated function ZoomIn ( bool bAnimateTransition , float ZoomTimeToGo )
{
GotoState ( 'ActiveIronSights' ) ;
}
simulated function PlayIdleAnim ( )
{
local int IdleIndex ;
if ( Instigator . IsFirstPerson ( ) )
{
if ( bUsingSights && IdleSightedAnims . Length > 0 )
{
if ( bUseAltFireMode )
{
IdleIndex = Rand ( IdleSightedAnims _Alt . Length ) ;
PlayAnimation ( IdleSightedAnims _Alt [ IdleIndex ] , 0.0 , true , 0.1 ) ;
}
else
{
IdleIndex = Rand ( IdleSightedAnims . Length ) ;
PlayAnimation ( IdleSightedAnims [ IdleIndex ] , 0.0 , true , 0.1 ) ;
}
}
else if ( IdleAnims . Length > 0 )
{
IdleIndex = Rand ( IdleAnims . Length ) ;
PlayAnimation ( IdleAnims [ IdleIndex ] , 0.0 , true , 0.2 ) ;
}
StartIdleFidgetTimer ( ) ;
ToggleAdditiveBobAnim ( ! bUsingSights ) ;
}
}
simulated function bool CanPlayIdleFidget ( optional bool bOnReload )
{
// Make sure we can't play idle fidget if one of the pistols is empty.
if ( AmmoCount [ 0 ] < 2 )
{
return false ;
}
return Super . CanPlayIdleFidget ( bOnReload ) ;
}
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* State WeaponEquipping
* The Weapon is in this state while transitioning from Inactive to Active state .
* Typically , the weapon will remain in this state while its selection animation is being played .
* While in this state , the weapon cannot be fired .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
/** Get equip anim name (overridden as necessary) */
simulated function name GetEquipAnimName ( )
{
// since duals use anims to get into / out of iron sights,
// we need to play equip anims that blend to iron sight idle (including alt iron)
if ( bIronSightOnBringUp )
{
return bUseAltFireMode ? EquipAnimISAlt : EquipAnimIS ;
}
else
{
return EquipAnim ;
}
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* State ActiveIronSights
* Only duals play an animation when transitioning to or from iron sights , but this animation
* should only be played in the "Active" state . This state allows us to encapsulate this
* functionality .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
simulated state ActiveIronSights extends Active
{
simulated function ZoomOut ( bool bAnimateTransition , float ZoomTimeToGo )
{
local name IronToIdleAnimName ;
IronToIdleAnimName = GetIronToIdleAnim ( ) ;
ZoomTimeToGo = MySkelMesh . GetAnimLength ( IronToIdleAnimName ) ;
Global . ZoomOut ( true , ZoomTimeToGo ) ;
PlayAnimation ( IronToIdleAnimName , ZoomTime , false ) ;
GotoState ( 'Active' ) ;
}
simulated function BeginState ( Name PreviousStateName )
{
local float ZoomTimeToGo ;
local name IdleToIronAnimName ;
IdleToIronAnimName = GetIdleToIronAnim ( ) ;
ZoomTimeToGo = MySkelMesh . GetAnimLength ( IdleToIronAnimName ) ;
Global . ZoomIn ( true , ZoomTimeToGo ) ;
PlayAnimation ( IdleToIronAnimName , ZoomTime , false ) ;
}
}
/** Gets idle-to-iron anim with regard to "stance" (toggle by alt fire) */
simulated function name GetIdleToIronAnim ( )
{
return bUseAltFireMode ? IdleToIronSightAnim _Alt : IdleToIronSightAnim ;
}
/** Gets iron-to-idle anim with regard to "stance" (toggle by alt fire) */
simulated function name GetIronToIdleAnim ( )
{
return bUseAltFireMode ? IronSightToIdleAnim _Alt : IronSightToIdleAnim ;
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* State WeaponSingleFiring
* Fire must be released between every shot .
*
* Overridden to alternate between right and left fire before calculated muzzle positions , etc .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
simulated state WeaponSingleFiring
{
simulated function FireAmmunition ( )
{
bFireFromRightWeapon = ! bFireFromRightWeapon ;
Super . FireAmmunition ( ) ;
}
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* State Reloading
* This is the default Reloading State . It ' s performed on both the client and the server .
*
* Overridden to reset our alternating weapon fire
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
simulated state Reloading
{
simulated function BeginState ( name PreviousStateName )
{
super . BeginState ( PreviousStateName ) ;
bFireFromRightWeapon = false ;
if ( bRevolver )
{
ResetCylinderLeft ( ) ;
}
}
simulated function byte GetWeaponStateId ( )
{
local KFPerk Perk ;
local bool bTacticalReload ;
Perk = GetPerk ( ) ;
bTacticalReload = ( Perk != None && Perk . GetUsingTactialReload ( self ) ) ;
if ( AmmoCount [ 0 ] == 1 )
{
return bTacticalReload ? WEP _ReloadDualsOneEmpty _Elite : WEP _ReloadDualsOneEmpty ;
}
return super . GetWeaponStateId ( ) ;
}
}
/** Returns animation to play based on reload type and status */
simulated function name GetReloadAnimName ( bool bTacticalReload )
{
if ( AmmoCount [ 0 ] == 1 )
{
// if one gun is empty (always the right), play our half empty reload
return bTacticalReload ? ReloadOneEmptyEliteAnim : ReloadOneEmptyAnim ;
}
else
{
return super . GetReloadAnimName ( bTacticalReload ) ;
}
}
/ * *
* Increment Pawn ' s FlashCount variable .
* This is used to play weapon fire effects on remote clients .
* Call this on the server and local player .
*
* Network : Server and Local Player
*
* COMPLETELY OVERRIDDEN to set FlashCount to an even number for left fire .
* Also copies implementation of Pawn : : IncrementFlashCount ( usually called from super )
* /
simulated function IncrementFlashCount ( )
{
if ( Instigator != none )
{
if ( Instigator . FlashCount > 0 || bFireFromRightWeapon )
{
Instigator . FlashCount += 1 ;
}
else
{
Instigator . FlashCount += 2 ;
}
//// BEGIN PAWN.INCREMENTFLASHCOUNT
Instigator . SetFiringMode ( Self , CurrentFireMode ) ;
// This weapon has fired.
Instigator . FlashCountUpdated ( Self , Instigator . FlashCount , FALSE ) ;
//// END PAWN.INCREMENTFLASHCOUNT
}
}
/** Return true if this weapon should play the fire last animation for this shoot animation */
simulated function bool ShouldPlayFireLast ( byte FireModeNum )
{
if ( bHasFireLastAnims )
{
if ( bFireFromRightWeapon )
{
if ( ( ! bAllowClientAmmoTracking && Role < ROLE _Authority && AmmoCount [ GetAmmoType ( FireModeNum ) ] <= 2 )
|| ( ( bAllowClientAmmoTracking || Role == ROLE _Authority ) && AmmoCount [ GetAmmoType ( FireModeNum ) ] == 1 ) )
{
return true ;
}
}
else
{
if ( ( ! bAllowClientAmmoTracking && Role < ROLE _Authority && AmmoCount [ GetAmmoType ( FireModeNum ) ] <= 1 )
|| ( ( bAllowClientAmmoTracking || Role == ROLE _Authority ) && AmmoCount [ GetAmmoType ( FireModeNum ) ] == 0 ) )
{
return true ;
}
}
}
return false ;
}
/ * * G e t n a m e o f t h e a n i m a t i o n t o p l a y f o r P l a y F i r e E f f e c t s
*
* Overridden to allow for left weapon anims
* /
simulated function name GetWeaponFireAnim ( byte FireModeNum )
{
local bool bPlayFireLast ;
bPlayFireLast = ShouldPlayFireLast ( FireModeNum ) ;
if ( bFireFromRightWeapon )
{
if ( bUsingSights )
{
if ( bPlayFireLast )
{
return bUseAltFireMode ? FireLastSightedAnim _Alt : FireLastSightedAnim ;
}
else
{
return bUseAltFireMode ? FireSightedAnim _Alt : FireSightedAnims [ Rand ( LeftFireSightedAnims . Length ) ] ;
}
}
else
{
if ( bPlayFireLast )
{
return FireLastAnim ;
}
else
{
return FireAnim ;
}
}
}
else
{
return GetLeftWeaponFireAnim ( FireModeNum , bPlayFireLast ) ;
}
}
/** Get name of the animation to play for PlayFireEffects */
simulated function name GetLeftWeaponFireAnim ( byte FireModeNum , bool bPlayFireLast )
{
// ironsights animations
if ( bUsingSights )
{
if ( bPlayFireLast )
{
return bUseAltFireMode ? LeftFireLastSightedAnim _Alt : LeftFireLastSightedAnim ;
}
else
{
return bUseAltFireMode ? LeftFireSightedAnim _Alt : LeftFireSightedAnims [ Rand ( LeftFireSightedAnims . Length ) ] ;
}
}
else
{
if ( bPlayFireLast )
{
return LeftFireLastAnim ;
}
else
{
return LeftFireAnim ;
}
}
}
/ * *
* This function returns the world location for spawning the visual effects
*
* Overridden to allow for left weapon location
* /
simulated event vector GetMuzzleLoc ( )
{
if ( bFireFromRightWeapon )
{
return super . GetMuzzleLoc ( ) ;
}
else
{
return GetLeftMuzzleLoc ( ) ;
}
}
/ * *
* This function returns the world location for spawning the visual effects .
* Uses both X and Y position of LeftFireOffset .
* /
simulated event vector GetLeftMuzzleLoc ( )
{
local Rotator ViewRotation ;
if ( Instigator != none )
{
ViewRotation = Instigator . GetViewRotation ( ) ;
// Add in the free-aim rotation
if ( KFPlayerController ( Instigator . Controller ) != None )
{
ViewRotation += KFPlayerController ( Instigator . Controller ) . WeaponBufferRotation ;
}
if ( bUsingSights )
{
return Instigator . GetWeaponStartTraceLocation ( ) + ( LeftFireOffset >> ViewRotation ) ;
}
else
{
return Instigator . GetPawnViewLocation ( ) + ( LeftFireOffset >> ViewRotation ) ;
}
}
return Location ;
}
/ * *
* Causes the muzzle flash to turn on and setup a time to
* turn it back off again .
*
* Overridden to cause left weapon flash
* /
simulated function CauseMuzzleFlash ( byte FireModeNum )
{
if ( MuzzleFlash == None || LeftMuzzleFlash == None )
{
AttachMuzzleFlash ( ) ;
}
if ( bFireFromRightWeapon )
{
if ( MuzzleFlash != None )
{
MuzzleFlash . CauseMuzzleFlash ( FireModeNum ) ;
if ( MuzzleFlash . bAutoActivateShellEject )
{
MuzzleFlash . CauseShellEject ( ) ;
}
}
}
else
{
if ( LeftMuzzleFlash != None )
{
LeftMuzzleFlash . CauseMuzzleFlash ( FireModeNum ) ;
if ( LeftMuzzleFlash . bAutoActivateShellEject )
{
LeftMuzzleFlash . CauseShellEject ( ) ;
}
}
}
}
/ * *
* Remove / Detach the muzzle flash components
* /
simulated function DetachMuzzleFlash ( )
{
super . DetachMuzzleFlash ( ) ;
if ( MySkelMesh != none && LeftMuzzleFlash != None )
{
LeftMuzzleFlash . DetachMuzzleFlash ( MySkelMesh ) ;
LeftMuzzleFlash = None ;
}
}
/ * *
* Adjust the FOV for the first person weapon and arms .
* /
simulated event SetFOV ( float NewFOV )
{
super . SetFOV ( NewFOV ) ;
if ( LeftMuzzleFlash != none )
{
LeftMuzzleFlash . SetFOV ( NewFOV ) ;
}
}
simulated function StopFireEffects ( byte FireModeNum )
{
super . StopFireEffects ( FireModeNum ) ;
if ( LeftMuzzleFlash != None )
{
LeftMuzzleFlash . StopMuzzleFlash ( ) ;
}
}
/** Returns ID of muzzle to spawn projectile at / play effects at
* Overrides super
* /
simulated function byte GetCurrentMuzzleID ( )
{
return bFireFromRightWeapon ? 0 : 1 ;
}
/** Overridden to spawn a single and set the pickup class to single */
function SetupDroppedPickup ( out DroppedPickup P , vector StartVelocity )
{
local KFWeapon NewSingle ;
local KFInventoryManager KFIM ;
local vector X , Y , Z ;
local int NewSingleUpgradeIndex ;
local int SingleSpareAmmoCount ;
// For now, force the dropped single to be un-upgraded by setting this dual's upgrade index to 0.
// But remember what the upgrade index was so we can give the player a correctly upgraded single.
// SetWeaponUpgradeLevel(0) must be called before the super, because the pickup mesh is set there.
NewSingleUpgradeIndex = CurrentWeaponUpgradeIndex ;
SetWeaponUpgradeLevel ( 0 ) ;
super . SetupDroppedPickup ( P , StartVelocity ) ;
if ( Instigator != None && Instigator . InvManager != None )
{
KFIM = KFInventoryManager ( Instigator . InvManager ) ;
KFIM . bSuppressPickupMessages = true ;
KFIM . bInfiniteWeight = true ; // force CanCarryWeapon() to succeed
NewSingle = KFWeapon ( KFIM . CreateInventory ( SingleClass , true ) ) ;
KFIM . bInfiniteWeight = false ;
KFIM . bSuppressPickupMessages = false ;
}
if ( NewSingle != none )
{
// divide ammo between make sure we don't lose a round due to truncation.
NewSingle . AmmoCount [ 0 ] = ( AmmoCount [ 0 ] & 1 ) == 0 ? ( AmmoCount [ 0 ] / 2 ) : ( AmmoCount [ 0 ] / 2 ) + 1 ;
AmmoCount [ 0 ] /= 2 ;
SingleSpareAmmoCount = Min ( SpareAmmoCount [ 0 ] , NewSingle . SpareAmmoCapacity [ 0 ] ) ;
NewSingle . SpareAmmoCount [ 0 ] = SingleSpareAmmoCount ;
SpareAmmoCount [ 0 ] -= SingleSpareAmmoCount ;
// tell client about our modification
NewSingle . ClientForceAmmoUpdate ( NewSingle . AmmoCount [ 0 ] , NewSingle . SpareAmmoCount [ 0 ] ) ;
NewSingle . ClientForceSecondaryAmmoUpdate ( NewSingle . AmmoCount [ 1 ] ) ;
NewSingle . SetWeaponUpgradeLevel ( NewSingleUpgradeIndex ) ;
if ( NewSingleUpgradeIndex > 0 )
{
KFInventoryManager ( InvManager ) . AddCurrentCarryBlocks ( NewSingle . static . GetUpgradeWeight ( NewSingleUpgradeIndex ) ) ;
KFPawn ( Instigator ) . NotifyInventoryWeightChanged ( ) ;
}
NewSingle . bGivenAtStart = bGivenAtStart ;
// Drop second gun on death
if ( Instigator . bPlayedDeath || Instigator . Health <= 0 )
{
GetAxes ( Instigator . Rotation , X , Y , Z ) ;
NewSingle . DropFrom ( P . Location + Y * 20 , StartVelocity * ( 1. f + fRand ( ) * 0.1 f ) ) ;
}
else
{
Instigator . InvManager . SetCurrentWeapon ( NewSingle ) ;
}
}
P . InventoryClass = SingleClass ;
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @ name Ammo
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
// /** Performs actual ammo reloading */
simulated function PerformReload ( optional byte FireModeNum )
{
super . PerformReload ( FireModeNum ) ;
if ( ! bRevolver )
{
return ;
}
// reset cylinder rotation
CylinderRotInfo _L . PrevDegrees = 0 ;
CylinderRotInfo _L . NextDegrees = 0 ;
}
/ * * L o c k s t h e b o l t b o n e i n p l a c e t o t h e o p e n p o s i t i o n ( C a l l e d b y a n i m n o t i f y )
* Completely overrides super to pick which bolt to lock back
* /
simulated function ANIMNOTIFY _LockBolt ( )
{
UpdateOutOfAmmoEffects ( 0. f ) ;
}
/** Unlocks the bolt bone (Called by animnotify) */
simulated function ANIMNOTIFY _UnLockBolt ( )
{
super . ANIMNOTIFY _UnLockBolt ( ) ;
EmptyMagBlendNode _L . SetBlendTarget ( 0 , 0 ) ;
}
/** Check AmmoCount and update anim tree nodes if needed */
simulated function UpdateOutOfAmmoEffects ( float BlendTime )
{
if ( WorldInfo . NetMode == NM _DedicatedServer )
return ;
if ( EmptyMagBlendNode != None )
{
// Differentiate Left/Right
if ( bAllowClientAmmoTracking && AmmoCount [ 0 ] <= 1 )
{
EmptyMagBlendNode . SetBlendTarget ( 1 , 0 ) ;
if ( AmmoCount [ 0 ] == 0 )
{
EmptyMagBlendNode _L . SetBlendTarget ( 1 , 0 ) ;
}
}
}
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @ name Revolver
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
simulated event PostInitAnimTreeRevolver ( SkeletalMeshComponent SkelComp )
{
super . PostInitAnimTreeRevolver ( SkelComp ) ;
CylinderRotInfo _L . Control = SkelControlSingleBone ( SkelComp . FindSkelControl ( 'CylinderControl' ) ) ;
if ( CylinderRotInfo _L . Control != none )
{
CylinderRotInfo _L . Control . SetSkelControlActive ( true ) ;
}
}
simulated function ConsumeAmmoRevolver ( )
{
// no super
if ( bFireFromRightWeapon )
{
CheckCylinderRotation ( CylinderRotInfo _L ) ;
CylinderRotInfo . State = CYLINDERSTATE _PENDING ;
}
else
{
CheckCylinderRotation ( CylinderRotInfo ) ;
CylinderRotInfo _L . State = CYLINDERSTATE _PENDING ;
}
}
/** Initiate cylinder rotation (rotation occurs in tickspecial in native) */
simulated function ANIMNOTIFY _RotateCylinder ( )
{
if ( bFireFromRightWeapon )
{
super . ANIMNOTIFY _RotateCylinder ( ) ;
return ;
}
RotateCylinder ( CylinderRotInfo _L ) ;
}
simulated function InitializeReload ( )
{
// call kfweapon super so we don't rotate the other cylinder too
super ( KFWeapon ) . InitializeReload ( ) ;
CheckCylinderRotation ( CylinderRotInfo _L , true ) ;
}
simulated function ANIMNOTIFY _ResetBulletMeshesLeft ( )
{
ResetBulletMeshesLeft ( ) ;
}
/** Resets cylinder orientation to initial state and repositions bullet meshes to line up with their pre-reset locations */
simulated function ResetCylinder ( )
{
local int UsedStartIdx , UsedEndIdx , UsedBullets ;
// reset cylinder rotation
SetCylinderRotation ( CylinderRotInfo , 0 ) ;
ResetCylinderInfo ( CylinderRotInfo ) ;
// now, we need to make sure the used bullets are still in the correct positions
// if we fired all our ammo, it doesn't matter where the bullets are, because they're all the same (used)
if ( AmmoCount [ DEFAULT _FIREMODE ] <= 1 )
{
return ;
}
// find the range of bullets that have been used
UsedStartIdx = BulletMeshComponents . Length - 2 ;
UsedBullets = FCeil ( float ( MagazineCapacity [ DEFAULT _FIREMODE ] - AmmoCount [ DEFAULT _FIREMODE ] ) / 2. f ) ;
UsedEndIdx = UsedStartIdx - UsedBullets * 2 ;
RepositionUsedBullets ( 0 , UsedStartIdx , UsedEndIdx ) ;
}
/** Resets cylinder orientation to initial state and repositions bullet meshes to line up with their pre-reset locations */
simulated function ResetCylinderLeft ( )
{
local int UsedStartIdx , UsedEndIdx , UsedBullets ;
// reset cylinder rotation (skel control needs to be reset to initial state while bullet casings are not on screen)
SetCylinderRotation ( CylinderRotInfo _L , 0 ) ;
ResetCylinderInfo ( CylinderRotInfo _L ) ;
// now, we need to make sure the used bullets are still in the correct positions
// if we fired all our ammo, it doesn't matter where the bullets are, because they're all the same (used)
if ( AmmoCount [ DEFAULT _FIREMODE ] <= 0 )
{
return ;
}
// find the range of bullets that have been used
UsedStartIdx = BulletMeshComponents . Length - 1 ;
UsedBullets = FFloor ( float ( MagazineCapacity [ DEFAULT _FIREMODE ] - AmmoCount [ DEFAULT _FIREMODE ] ) / 2. f ) ;
UsedEndIdx = UsedStartIdx - UsedBullets * 2 ;
RepositionUsedBullets ( 1 , UsedStartIdx , UsedEndIdx ) ;
}
/** Sets correct bullet mesh (used/unused) in each slot after resetting cylinder */
simulated function RepositionUsedBullets ( int FirstIndex , int UsedStartIdx , int UsedEndIdx )
{
local int i ;
if ( BulletMeshComponents . length == 0 )
{
return ;
}
if ( FirstIndex >= 0 && FirstIndex < BulletMeshComponents . length )
{
// after cylinder reset, top-most bullet will be unused
BulletMeshComponents [ FirstIndex ] . SetSkeletalMesh ( UnusedBulletMeshTemplate ) ;
}
else
{
` warn(self @ "-" @ GetFuncName() @ "- First Index is out of bounds - FirstIndex:" @ FirstIndex @ "BulletMeshComponents.Length:" @ BulletMeshComponents.length);
}
// set used bullets to used mesh
for ( i = UsedStartIdx ; i > UsedEndIdx ; i -= 2 )
{
if ( i >= 0 && i < BulletMeshComponents . length )
{
BulletMeshComponents [ i ] . SetSkeletalMesh ( UsedBulletMeshTemplate ) ;
}
}
// set the rest of the bullets to unused
for ( i = UsedEndIdx ; i > FirstIndex ; i -= 2 )
{
if ( i >= 0 && i < BulletMeshComponents . length )
{
BulletMeshComponents [ i ] . SetSkeletalMesh ( UnusedBulletMeshTemplate ) ;
}
}
}
/** Sets all bullet casing meshes back to unused state */
simulated function ResetBulletMeshes ( )
{
local int i ;
for ( i = 0 ; i < BulletMeshComponents . Length ; i += 2 )
{
BulletMeshComponents [ i ] . SetSkeletalMesh ( UnusedBulletMeshTemplate ) ;
}
}
/** Sets all bullet casing meshes back to unused state */
simulated function ResetBulletMeshesLeft ( )
{
local int i ;
for ( i = 1 ; i < BulletMeshComponents . Length ; i += 2 )
{
BulletMeshComponents [ i ] . SetSkeletalMesh ( UnusedBulletMeshTemplate ) ;
}
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* State WeaponPuttingDown
* Putting down weapon in favor of a new one .
* Weapon is transitioning to the Inactive state .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
simulated state WeaponPuttingDown
{
simulated function EndState ( Name NextStateName )
{
super . EndState ( NextStateName ) ;
CheckCylinderRotation ( CylinderRotInfo _L , true ) ;
}
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Trader
//
///////////////////////////////////////////////////////////////////////////////////////////
/** Adds ammo to (or subtracts ammo from) the trader transaction single that gets created when selling a dual */
native simulated function AddAmmoToSingleOnSell ( KFInventoryManager KFIM , int DefaultSingleAmmo , int TraderItemIndex ) ;
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @ name Firing / Projectile
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
/ * *
* @ brief Checks if weapon should be auto - reloaded - overwritten to allow gunslinger insta switch
*
* @ param FireModeNum Current fire mode
* @ return auto reload or not
* /
simulated function bool ShouldAutoReload ( byte FireModeNum )
{
return ShouldAutoReloadGunslinger ( FireModeNum ) ;
}
/ * *
* Toggle between DEFAULT and ALTFIRE
* /
simulated function AltFireMode ( )
{
super . AltFireMode ( ) ;
PlayIdleAnim ( ) ;
}
/ * *
* @ see Weapon : : StartFire
* /
simulated function StartFire ( byte FireModeNum )
{
// These weapons only have a mode toggle, so if we have alt-fire
// bound (e.g. gamepad, custom bindings) then perform the toggle
if ( FireModeNum == ALTFIRE _FIREMODE )
{
AltFireMode ( ) ;
return ;
}
Super . StartFire ( FireModeNum ) ;
}
2024-01-23 16:25:12 +00:00
function bool DenyPickupQuery ( class < Inventory > ItemClass , Actor Pickup )
{
if ( ItemClass == class || ItemClass == SingleClass )
{
return DenyPickupQuery _Internal ( ItemClass , Pickup ) ;
}
return false ;
}
2020-12-13 15:01:13 +00:00
defaultproperties
{
InventoryGroup = IG _Primary
Begin Object Name = FirstPersonMesh
AnimTreeTemplate = AnimTree 'CHR_1P_Arms_ARCH.WEP_1stP_Dual_Animtree_Master'
End Object
bSkipZoomInRotation = true
BonesToLockOnEmpty _L = ( LW _Bolt )
// Animations
FireAnim = Shoot _RW
LeftFireAnim = Shoot _LW
IdleSightedAnims = ( Idle _IronOG )
FireSightedAnims = ( Shoot _IronOG _RW )
LeftFireSightedAnims = ( Shoot _IronOG _LW )
IdleToIronSightAnim = Idle _To _IronOG
IronSightToIdleAnim = IronOG _To _Idle
EquipAnimIS = Equip _IronOG
// IdleSightedAnims=(Idle_Iron)
// FireSightedAnims=(Shoot_Iron_RW)
// LeftFireSightedAnims=(Shoot_Iron_LW)
// IdleToIronSightAnim=Idle_To_Iron
// IronSightToIdleAnim=Iron_To_Idle
// EquipAnimIS=Equip_Iron
IdleSightedAnims _Alt = ( Idle _Iron )
FireSightedAnim _Alt = Shoot _Iron _RW
LeftFireSightedAnim _Alt = Shoot _Iron _LW
IdleToIronSightAnim _Alt = Idle _To _Iron
IronSightToIdleAnim _Alt = Iron _To _Idle
EquipAnimISAlt = Equip _Iron
// IdleSightedAnims_Alt=(Idle_IronOG)
// FireSightedAnim_Alt=Shoot_IronOG_RW
// LeftFireSightedAnim_Alt=Shoot_IronOG_LW
// IdleToIronSightAnim_Alt=Idle_To_IronOG
// IronSightToIdleAnim_Alt=IronOG_To_Idle
// EquipAnimISAlt=Equip_IronOG
FireLastAnim = Shoot _RW _Last
LeftFireLastAnim = Shoot _LW _Last
FireLastSightedAnim = Shoot _IronOG _RW _Last
LeftFireLastSightedAnim = Shoot _IronOG _LW _Last
FireLastSightedAnim _Alt = Shoot _Iron _RW _Last
LeftFireLastSightedAnim _Alt = Shoot _Iron _LW _Last
// DEFAULT_FIREMODE
FireModeIconPaths [ DEFAULT _FIREMODE ] = Texture2D 'ui_firemodes_tex.UI_FireModeSelect_BulletSingle'
FiringStatesArray ( DEFAULT _FIREMODE ) = WeaponFiring
WeaponFireTypes ( DEFAULT _FIREMODE ) = EWFT _InstantHit
FireInterval ( DEFAULT _FIREMODE ) = + 1.0
InstantHitDamageTypes ( DEFAULT _FIREMODE ) = class 'KFDT_Ballistic'
InstantHitMomentum ( DEFAULT _FIREMODE ) = 1.0
PenetrationPower ( DEFAULT _FIREMODE ) = 0.0
PenetrationDamageReductionCurve ( DEFAULT _FIREMODE ) = ( Points = ( ( InVal = 0. f , OutVal = 0. f ) , ( InVal = 1. f , OutVal = 1. f ) ) )
//ALTFIRE_FIREMODE
FireModeIconPaths [ ALTFIRE _FIREMODE ] = Texture2D 'ui_firemodes_tex.UI_FireModeSelect_BulletSingle'
FiringStatesArray ( ALTFIRE _FIREMODE ) = WeaponFiring
WeaponFireTypes ( ALTFIRE _FIREMODE ) = EWFT _InstantHit
FireInterval ( ALTFIRE _FIREMODE ) = + 1.0
InstantHitDamageTypes ( ALTFIRE _FIREMODE ) = class 'KFDT_Ballistic'
InstantHitMomentum ( ALTFIRE _FIREMODE ) = 1.0
PenetrationPower ( ALTFIRE _FIREMODE ) = 0.0
PenetrationDamageReductionCurve ( ALTFIRE _FIREMODE ) = ( Points = ( ( InVal = 0. f , OutVal = 0. f ) , ( InVal = 1. f , OutVal = 1. f ) ) )
}