734 lines
22 KiB
Ucode
734 lines
22 KiB
Ucode
//=============================================================================
|
|
// KFWeap_HRG_BarrierRifle
|
|
//=============================================================================
|
|
// A modified version of the Stoner63A rifle.
|
|
//=============================================================================
|
|
// Killing Floor 2
|
|
// Copyright (C) 2021 Tripwire Interactive LLC
|
|
//=============================================================================
|
|
class KFWeap_HRG_BarrierRifle extends KFWeap_LMG_Stoner63A;
|
|
|
|
`define BARRIERRIFLE_MIC_SHIELD_INDEX 4
|
|
|
|
/** Amount of shield charge that is consumed per second */
|
|
var (Shield) float ShieldConsumptionPerSecond;
|
|
|
|
/** Amount of shield chared that is recharged per second */
|
|
var (Shield) float ShieldRechargePerSecond;
|
|
|
|
/** Cooldown to apply after the shield is destroyed */
|
|
var (Shield) float CooldownAfterShieldDepleted;
|
|
|
|
/** Cooldown to apply after the shield depleted the charge */
|
|
var (Shield) float CooldownAfterShieldDestroyed;
|
|
|
|
/** VFX and SFX for blocking damage */
|
|
var (Shield) AkBaseSoundObject BlockSound;
|
|
var (Shield) ParticleSystem BlockParticleSystem;
|
|
var (Shield) name BlockEffectsSocketName;
|
|
|
|
/** Blocking information per damage type */
|
|
var (Shield) array<BlockEffectInfo> BlockDamageTypes;
|
|
|
|
/** Modifier applied to the damage received by the character */
|
|
var (Shield) float BlockDamageModifier;
|
|
|
|
/** Modifier applied to the damager that will affect the shield charge */
|
|
var (Shield) float ShieldDamageAbsorbtionModifier;
|
|
|
|
/** Angle to block with the shield */
|
|
var (Shield) float BlockingAngle;
|
|
|
|
/** Turn ON/OFF VFX duration */
|
|
var (Shield) float ShieldFXDuration;
|
|
|
|
/** Shield Block VFX duration */
|
|
var (Shield) float ShieldBlockVFXDuration;
|
|
|
|
/** Is shield active */
|
|
var protected transient bool bIsShieldActive;
|
|
|
|
/** Was shield charge depleted */
|
|
var protected transient bool bWasShieldDepleted;
|
|
|
|
/** Was the shield destroyed */
|
|
var protected transient bool bWasShielDestroyed;
|
|
|
|
/** Self explanatory */
|
|
var protected transient bool bCanRechargeShield;
|
|
|
|
/** float containing the shield charge to not be lost in the next frame
|
|
due to int conversion.
|
|
*/
|
|
var protected transient float ShieldRechargeIncrement;
|
|
var protected transient float ShieldConsumptionIncrement;
|
|
|
|
/** Cos of the blocking angle (Rads) */
|
|
var protected transient float BlockingAngleCos;
|
|
|
|
/** Wether the timer for activating the shield has expired (using the fire interval) */
|
|
var protected transient bool bShieldActionAvailable;
|
|
|
|
/** Indicates wheter we are activating/deactivating the shield fx */
|
|
var protected bool bActivatingShield;
|
|
var protected bool bDeactivatingShield;
|
|
var protected transient float FXDelta;
|
|
|
|
var transient float RedOverlayMax;
|
|
var transient float RedOverlayMin;
|
|
var protected transient float OverlayDelta;
|
|
|
|
var WeaponFireSndInfo ShieldActivateSound;
|
|
var WeaponFireSndInfo ShieldDeactivateSound;
|
|
var WeaponFireSndInfo ShieldEndSound;
|
|
|
|
var repnotify byte ShieldAmmo;
|
|
|
|
replication
|
|
{
|
|
if (bNetDirty && Role == ROLE_Authority)
|
|
bActivatingShield, bDeactivatingShield;
|
|
|
|
if (bNetDirty && Role == ROLE_Authority && bAllowClientAmmoTracking)
|
|
ShieldAmmo;
|
|
}
|
|
|
|
simulated event ReplicatedEvent(name VarName)
|
|
{
|
|
if (VarName == nameof(ShieldAmmo))
|
|
{
|
|
AmmoCount[ALTFIRE_FIREMODE] = ShieldAmmo;
|
|
}
|
|
else
|
|
{
|
|
Super.ReplicatedEvent(VarName);
|
|
}
|
|
}
|
|
|
|
simulated event PostBeginPlay()
|
|
{
|
|
super.PostBeginPlay();
|
|
BlockingAngleCos = cos((BlockingAngle / 2.f) * DegToRad);
|
|
}
|
|
|
|
simulated function Activate()
|
|
{
|
|
super.Activate();
|
|
|
|
if (WorldInfo.NetMode != NM_DedicatedServer)
|
|
{
|
|
UpdateShieldFXValue(0.0f);
|
|
}
|
|
}
|
|
|
|
simulated function UpdateShieldFXValue(float Value)
|
|
{
|
|
if( WeaponMICs.Length > `BARRIERRIFLE_MIC_SHIELD_INDEX )
|
|
{
|
|
WeaponMICs[`BARRIERRIFLE_MIC_SHIELD_INDEX].SetScalarParameterValue('Opacity', Value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Instead of a toggle, just immediately fire alternate fire.
|
|
*/
|
|
simulated function AltFireMode()
|
|
{
|
|
// LocalPlayer Only
|
|
if ( !Instigator.IsLocallyControlled() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( Role < Role_Authority )
|
|
{
|
|
// if we're a client, synchronize server
|
|
UseShield();
|
|
}
|
|
|
|
CustomFire();
|
|
}
|
|
|
|
reliable server function UseShield()
|
|
{
|
|
CustomFire();
|
|
}
|
|
|
|
/** Shield deploying */
|
|
simulated function CustomFire()
|
|
{
|
|
if (bWasShieldDepleted || bWasShielDestroyed || !bShieldActionAvailable || AmmoCount[ALTFIRE_FIREMODE] == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
bIsShieldActive ? DeactivateShield() : ActivateShield();
|
|
bIsShieldActive = !bIsShieldActive;
|
|
|
|
bShieldActionAvailable = false;
|
|
}
|
|
|
|
simulated function ActivateShield()
|
|
{
|
|
WeaponPlayFireSound(ShieldActivateSound.DefaultCue, ShieldActivateSound.FirstPersonCue);
|
|
bActivatingShield = true;
|
|
bDeactivatingShield = false;
|
|
bNetDirty = true;
|
|
NotifyShieldActive(true);
|
|
SetTimer(FireInterval[ALTFIRE_FIREMODE], false, nameof(ShieldActivationCompleted));
|
|
}
|
|
|
|
simulated function DeactivateShield()
|
|
{
|
|
WeaponPlayFireSound(ShieldDeactivateSound.DefaultCue, ShieldDeactivateSound.FirstPersonCue);
|
|
bDeactivatingShield = true;
|
|
bActivatingShield = false;
|
|
bCanRechargeShield = false;
|
|
bNetDirty=true;
|
|
NotifyShieldActive(false);
|
|
SetTimer(FireInterval[ALTFIRE_FIREMODE], false, nameof(ShieldDeactivatedTimerCompleted));
|
|
}
|
|
|
|
simulated function ShieldActivationCompleted()
|
|
{
|
|
bShieldActionAvailable = true;
|
|
}
|
|
|
|
simulated function ShieldDeactivatedTimerCompleted()
|
|
{
|
|
bShieldActionAvailable = true;
|
|
bCanRechargeShield = true;
|
|
}
|
|
|
|
/** Update shield charge - client and server */
|
|
simulated event Tick(float DeltaTime)
|
|
{
|
|
// Update Shield visuals
|
|
if (WorldInfo.NetMode != NM_DedicatedServer)
|
|
{
|
|
if (bActivatingShield && FXDelta < ShieldFXDuration)
|
|
{
|
|
FXDelta = FMin(FXDelta + DeltaTime, ShieldFXDuration);
|
|
UpdateShieldFXValue(FXDelta / ShieldFXDuration);
|
|
if (FXDelta == ShieldFXDuration)
|
|
{
|
|
bActivatingShield = false;
|
|
}
|
|
}
|
|
else if (bDeactivatingShield && FXDelta > 0.0f)
|
|
{
|
|
FXDelta = FMax(FXDelta - DeltaTime, 0.0f);
|
|
UpdateShieldFXValue(FXDelta / ShieldFXDuration);
|
|
if (FXDelta == 0.0f)
|
|
{
|
|
bDeactivatingShield = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OverlayDelta > RedOverlayMin)
|
|
{
|
|
OverlayDelta = FMax(OverlayDelta - DeltaTime, RedOverlayMin);
|
|
UpdateShieldBlockVFX(RedOverlayMax * (OverlayDelta / ShieldBlockVFXDuration));
|
|
}
|
|
|
|
if ( Role == Role_Authority )
|
|
{
|
|
// If shield is active it needs to consume charge, otherwise it recharges itself.
|
|
if (bIsShieldActive)
|
|
{
|
|
ConsumeShield(DeltaTime);
|
|
}
|
|
else if (bCanRechargeShield && AmmoCount[ALTFIRE_FIREMODE] < MagazineCapacity[ALTFIRE_FIREMODE])
|
|
{
|
|
RechargeShield(DeltaTime);
|
|
}
|
|
}
|
|
|
|
Super.Tick(DeltaTime);
|
|
}
|
|
|
|
simulated function ConsumeShield(float DeltaTime)
|
|
{
|
|
local int Charge;
|
|
|
|
if (Role == ROLE_Authority)
|
|
{
|
|
ShieldRechargeIncrement = 0.0f;
|
|
|
|
ShieldConsumptionIncrement += ShieldConsumptionPerSecond * DeltaTime;
|
|
|
|
if (ShieldConsumptionIncrement >= 1.0f && AmmoCount[ALTFIRE_FIREMODE] > 0)
|
|
{
|
|
Charge = int(ShieldConsumptionIncrement);
|
|
AmmoCount[ALTFIRE_FIREMODE] = Max(AmmoCount[ALTFIRE_FIREMODE] - Charge, 0);
|
|
ShieldConsumptionIncrement -= Charge;
|
|
|
|
ShieldAmmo = AmmoCount[ALTFIRE_FIREMODE];
|
|
|
|
if (AmmoCount[ALTFIRE_FIREMODE] == 0)
|
|
{
|
|
OnShieldDepleted();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function RechargeShield(float DeltaTime)
|
|
{
|
|
local int Charge;
|
|
|
|
if (Role == ROLE_Authority)
|
|
{
|
|
ShieldConsumptionIncrement = 0.0f;
|
|
ShieldRechargeIncrement += ShieldRechargePerSecond * DeltaTime;
|
|
if (ShieldRechargeIncrement >= 1.0f && AmmoCount[ALTFIRE_FIREMODE] < MagazineCapacity[ALTFIRE_FIREMODE])
|
|
{
|
|
Charge = int(ShieldRechargeIncrement);
|
|
AmmoCount[ALTFIRE_FIREMODE] = Min(AmmoCount[ALTFIRE_FIREMODE] + Charge, MagazineCapacity[ALTFIRE_FIREMODE]);
|
|
ShieldRechargeIncrement -= Charge;
|
|
|
|
ShieldAmmo = AmmoCount[ALTFIRE_FIREMODE];
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Shield consumed all the charge by itself */
|
|
simulated function OnShieldDepleted()
|
|
{
|
|
bWasShieldDepleted = true;
|
|
bActivatingShield = false;
|
|
bDeactivatingShield = true;
|
|
bCanRechargeShield = false;
|
|
bIsShieldActive = false;
|
|
ShieldAmmo = 0;
|
|
bNetDirty = true;
|
|
NotifyShieldActive(false);
|
|
WeaponPlayFireSound(ShieldEndSound.DefaultCue, ShieldEndSound.FirstPersonCue);
|
|
SetTimer(CooldownAfterShieldDepleted, false, nameof(ShieldRepletedTimerCompleted));
|
|
}
|
|
|
|
simulated function ShieldRepletedTimerCompleted()
|
|
{
|
|
bWasShieldDepleted = false;
|
|
bCanRechargeShield = true;
|
|
}
|
|
|
|
/** Shield was destroyed by attacks */
|
|
simulated function OnShieldDestroyed()
|
|
{
|
|
bWasShielDestroyed = true;
|
|
bActivatingShield = false;
|
|
bDeactivatingShield = true;
|
|
bCanRechargeShield = false;
|
|
bIsShieldActive = false;
|
|
ShieldAmmo = 0;
|
|
bNetDirty = true;
|
|
NotifyShieldActive(false);
|
|
WeaponPlayFireSound(ShieldEndSound.DefaultCue, ShieldEndSound.FirstPersonCue);
|
|
SetTimer(CooldownAfterShieldDestroyed, false, nameof(ShieldDestroyedTimerCompleted));
|
|
}
|
|
|
|
simulated function ShieldDestroyedTimerCompleted()
|
|
{
|
|
bWasShielDestroyed = false;
|
|
bCanRechargeShield = true;
|
|
}
|
|
|
|
/** Update HUD ammo icon for shield */
|
|
simulated function int GetSecondaryAmmoForHUD()
|
|
{
|
|
return AmmoCount[ALTFIRE_FIREMODE];
|
|
}
|
|
|
|
simulated function ShieldAbsorbDamage(int DamageBase)
|
|
{
|
|
local int Damage;
|
|
// Use the carried shield reduction by time
|
|
ShieldConsumptionIncrement += DamageBase*ShieldDamageAbsorbtionModifier;
|
|
Damage = int(ShieldConsumptionIncrement);
|
|
AmmoCount[ALTFIRE_FIREMODE] = Max(AmmoCount[ALTFIRE_FIREMODE] - Damage, 0);
|
|
ShieldConsumptionIncrement -= Damage;
|
|
|
|
// Check if shield is destroyed.
|
|
if (AmmoCount[ALTFIRE_FIREMODE] == 0)
|
|
{
|
|
OnShieldDestroyed();
|
|
}
|
|
}
|
|
|
|
/**
|
|
Reduce the damage received and apply it to the shield
|
|
*/
|
|
function AdjustDamage(out int InDamage, class<DamageType> DamageType, Actor DamageCauser)
|
|
{
|
|
local KFPerk InstigatorPerk;
|
|
local byte BlockTypeIndex;
|
|
local float DmgCauserDot;
|
|
|
|
if (!bIsShieldActive)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Don't apply block effects for teammates
|
|
if (Instigator.IsSameTeam(DamageCauser.Instigator))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (CanBlockDamageType(DamageType, BlockTypeIndex))
|
|
{
|
|
if (ClassIsChildOf(DamageCauser.class, class'Projectile'))
|
|
{
|
|
// Projectile might be beyond/behind player, resulting in bad dot
|
|
// Projectile won't have a velocity to check against, either
|
|
// Assume velocity is the vector between projectile and instigator
|
|
DmgCauserDot = Normal(DamageCauser.Instigator.Location - DamageCauser.Location) dot vector(Instigator.Rotation);
|
|
}
|
|
else
|
|
{
|
|
DmgCauserDot = Normal(DamageCauser.Location - Instigator.Location) dot vector(Instigator.Rotation);
|
|
}
|
|
|
|
if (DmgCauserDot > BlockingAngleCos)
|
|
{
|
|
ShieldAbsorbDamage(InDamage);
|
|
InDamage *= BlockDamageModifier;
|
|
|
|
ClientPlayBlockEffects(BlockTypeIndex);
|
|
NotifyShieldBlockActive(true);
|
|
SetTimer(0.1f, false, nameof(ResetShieldBlockVFX));
|
|
|
|
InstigatorPerk = GetPerk();
|
|
if (InstigatorPerk != none)
|
|
{
|
|
InstigatorPerk.SetSuccessfullBlock();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Only DT added to BlockDamageTypes can be blocked. Check if the current one is in the list. */
|
|
function bool CanBlockDamageType(class<DamageType> DamageType, optional out byte out_Idx)
|
|
{
|
|
local int Idx;
|
|
|
|
for (Idx = 0; Idx < BlockDamageTypes.length; ++Idx)
|
|
{
|
|
if (ClassIsChildOf(DamageType, BlockDamageTypes[Idx].DmgType))
|
|
{
|
|
out_Idx = Idx;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
out_Idx = INDEX_NONE;
|
|
return false;
|
|
}
|
|
|
|
unreliable client function ClientPlayBlockEffects(optional byte BlockDTIndex=255)
|
|
{
|
|
local AkBaseSoundObject Sound;
|
|
local ParticleSystem PSTemplate;
|
|
|
|
GetBlockEffects(BlockDTIndex, Sound, PSTemplate);
|
|
PlayLocalBlockEffects(Sound, PSTemplate);
|
|
UpdateShieldBlockVFX(RedOverlayMax);
|
|
OverlayDelta = ShieldBlockVFXDuration;
|
|
}
|
|
|
|
/** Called on the client when successfully block/parry an attack */
|
|
simulated function PlayLocalBlockEffects(AKBaseSoundObject Sound, ParticleSystem PSTemplate)
|
|
{
|
|
local vector Loc;
|
|
local rotator Rot;
|
|
local ParticleSystemComponent PSC;
|
|
|
|
if (Sound != None)
|
|
{
|
|
PlaySoundBase(Sound, true);
|
|
}
|
|
|
|
if (PSTemplate != None)
|
|
{
|
|
if (MySkelMesh.GetSocketWorldLocationAndRotation(BlockEffectsSocketName, Loc, Rot))
|
|
{
|
|
PSC = WorldInfo.MyEmitterPool.SpawnEmitter(PSTemplate, Loc, Rot);
|
|
PSC.SetDepthPriorityGroup(SDPG_Foreground);
|
|
}
|
|
else
|
|
{
|
|
`log(self@GetFuncName()@"missing BlockEffects Socket!");
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Returns sound and particle system overrides using index into BlockDamageTypes array */
|
|
simulated function GetBlockEffects(byte BlockDTIndex, out AKBaseSoundObject outSound, out ParticleSystem outParticleSys)
|
|
{
|
|
outSound = BlockSound;
|
|
outParticleSys = BlockParticleSystem;
|
|
|
|
if (BlockDTIndex != 255)
|
|
{
|
|
if (BlockDamageTypes[BlockDTIndex].BlockSound != None)
|
|
{
|
|
outSound = BlockDamageTypes[BlockDTIndex].BlockSound;
|
|
}
|
|
if (BlockDamageTypes[BlockDTIndex].BlockParticleSys != None)
|
|
{
|
|
outParticleSys = BlockDamageTypes[BlockDTIndex].BlockParticleSys;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Should replicate to 3P to show the shield effects
|
|
*/
|
|
simulated function NotifyShieldActive(bool bActive)
|
|
{
|
|
local KFPawn KFP;
|
|
|
|
if (WorldInfo.NetMode != NM_Client)
|
|
{
|
|
KFP = KFPawn(Instigator);
|
|
KFP.OnWeaponSpecialAction(bActive ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
simulated function NotifyShieldBlockActive(bool bActive)
|
|
{
|
|
local KFPawn KFP;
|
|
|
|
if (WorldInfo.NetMode != NM_Client)
|
|
{
|
|
KFP = KFPawn(Instigator);
|
|
KFP.OnWeaponSpecialAction(bActive ? 3 : 2);
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************************
|
|
* 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.
|
|
*********************************************************************************************/
|
|
|
|
simulated state WeaponEquipping
|
|
{
|
|
simulated function BeginState(Name PreviousStateName)
|
|
{
|
|
UpdateShieldFXValue(0.0f);
|
|
FXDelta = 0.0f;
|
|
bShieldActionAvailable = true;
|
|
super.BeginState(PreviousStateName);
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************************
|
|
* State WeaponPuttingDown
|
|
* Putting down weapon in favor of a new one.
|
|
* Weapon is transitioning to the Inactive state.
|
|
*********************************************************************************************/
|
|
|
|
simulated state WeaponPuttingDown
|
|
{
|
|
simulated event EndState(Name NextStateName)
|
|
{
|
|
UpdateShieldFXValue(0.0f);
|
|
|
|
// Reset Values
|
|
bIsShieldActive = false;
|
|
bWasShieldDepleted = false;
|
|
bWasShielDestroyed = false;
|
|
bCanRechargeShield = true;
|
|
bShieldActionAvailable = false;
|
|
bActivatingShield = false;
|
|
bDeactivatingShield = false;
|
|
FXDelta = 0.0f;
|
|
bNetDirty=true;
|
|
|
|
super.EndState(NextStateName);
|
|
}
|
|
}
|
|
|
|
simulated function UpdateShieldBlockVFX(float Value)
|
|
{
|
|
if( WeaponMICs.Length > `BARRIERRIFLE_MIC_SHIELD_INDEX )
|
|
{
|
|
WeaponMICs[`BARRIERRIFLE_MIC_SHIELD_INDEX].SetScalarParameterValue('RedOverlay', Value);
|
|
}
|
|
}
|
|
|
|
function ResetShieldBlockVFX()
|
|
{
|
|
NotifyShieldBlockActive(false);
|
|
}
|
|
|
|
/** Shield doesn't count as ammo for purposes of inventory management (e.g. switching) */
|
|
simulated function bool HasAnyAmmo()
|
|
{
|
|
return AmmoCount[0] > 0 || SpareAmmoCount[0] > 0;
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
// Shooting Animations
|
|
FireSightedAnims[0]=Shoot_Iron
|
|
FireSightedAnims[1]=Shoot_Iron2
|
|
FireSightedAnims[2]=Shoot_Iron3
|
|
|
|
// FOV
|
|
MeshFOV=75
|
|
MeshIronSightFOV=35
|
|
PlayerIronSightFOV=70
|
|
|
|
// Depth of field
|
|
DOF_FG_FocalRadius=85
|
|
DOF_FG_MaxNearBlurSize=2.5
|
|
|
|
// Content
|
|
PackageKey="HRG_BarrierRifle"
|
|
FirstPersonMeshName="WEP_1P_HRG_BarrierRifle_MESH.WEP_1stP_HRG_BarrielRifle_Rig"
|
|
FirstPersonAnimSetNames(0)="WEP_1P_HRG_BarrierRifle_ANIM.Wep_1stP_HRG_BarrierRifle_Anim"
|
|
PickupMeshName="WEP_3P_HRG_BarrierRifle_MESH.Wep_3rdP_HRG_BarrierRifle_Pickup"
|
|
AttachmentArchetypeName="WEP_HRG_BarrierRifle_ARCH.Wep_HRG_BarrierRifle_3P"
|
|
MuzzleFlashTemplateName="WEP_HRG_BarrierRifle_ARCH.Wep_HRG_BarrierRifle_MuzzleFlash"
|
|
|
|
// Zooming/Position
|
|
PlayerViewOffset=(X=4.0,Y=8,Z=-4)
|
|
IronSightPosition=(X=8.5,Y=0,Z=0)
|
|
|
|
// Ammo
|
|
MagazineCapacity[0]=60
|
|
SpareAmmoCapacity[0]=540 //480
|
|
InitialSpareMags[0]=2
|
|
bCanBeReloaded=true
|
|
bReloadFromMagazine=true
|
|
|
|
// Shield "Ammo"
|
|
MagazineCapacity[1]=100
|
|
SpareAmmoCapacity[1]=0
|
|
bCanRefillSecondaryAmmo=false
|
|
|
|
// Recoil
|
|
maxRecoilPitch=110 //120
|
|
minRecoilPitch=70 //70
|
|
maxRecoilYaw=80 //130
|
|
minRecoilYaw=-80 //-130
|
|
RecoilRate=0.045 //0.08
|
|
RecoilMaxYawLimit=500
|
|
RecoilMinYawLimit=65035
|
|
RecoilMaxPitchLimit=900
|
|
RecoilMinPitchLimit=65035
|
|
RecoilISMaxYawLimit=75
|
|
RecoilISMinYawLimit=65460
|
|
RecoilISMaxPitchLimit=375
|
|
RecoilISMinPitchLimit=65460
|
|
RecoilViewRotationScale=0.4 //0.25
|
|
IronSightMeshFOVCompensationScale=2.3
|
|
HippedRecoilModifier=1.5
|
|
//WalkingRecoilModifier=1.1
|
|
//JoggingRecoilModifier=1.2
|
|
|
|
// Inventory / Grouping
|
|
InventorySize=7
|
|
GroupPriority=125
|
|
WeaponSelectTexture=Texture2D'wep_ui_hrg_barrierrifle_tex.UI_WeaponSelect_HRG_BarrierRifle'
|
|
AssociatedPerkClasses(0)=class'KFPerk_SWAT'
|
|
|
|
// DEFAULT_FIREMODE
|
|
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletAuto'
|
|
FiringStatesArray(DEFAULT_FIREMODE)=WeaponFiring
|
|
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_InstantHit
|
|
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_AssaultRifle'
|
|
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_HRG_BarrierRifle'
|
|
FireInterval(DEFAULT_FIREMODE)=+0.066 // 900 RPM
|
|
Spread(DEFAULT_FIREMODE)=0.025 //0.0085
|
|
InstantHitDamage(DEFAULT_FIREMODE)=33.0 //35.0
|
|
FireOffset=(X=30,Y=4.5,Z=-5)
|
|
|
|
// ALT_FIREMODE
|
|
FireModeIconPaths(ALTFIRE_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletAuto'
|
|
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Custom
|
|
AmmoCost(ALTFIRE_FIREMODE)=0
|
|
FireInterval(ALTFIRE_FIREMODE)=0.01f
|
|
SecondaryAmmoTexture=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Electricity'
|
|
|
|
// BASH_FIREMODE
|
|
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_HRG_BarrierRifle'
|
|
InstantHitDamage(BASH_FIREMODE)=26
|
|
|
|
// Fire Effects
|
|
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Stoner.Play_WEP_Stoner_Fire_3P_Loop', FirstPersonCue=AkEvent'WW_WEP_Stoner.Play_WEP_Stoner_Fire_1P_Loop')
|
|
WeaponFireLoopEndSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Stoner.Play_WEP_Stoner_Fire_3P_EndLoop', FirstPersonCue=AkEvent'WW_WEP_Stoner.Play_WEP_Stoner_Fire_1P_EndLoop')
|
|
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_SA_L85A2.Play_WEP_SA_L85A2_Handling_DryFire'
|
|
EjectedShellForegroundDuration=0.8f
|
|
|
|
// Advanced (High RPM) Fire Effects
|
|
bLoopingFireAnim(DEFAULT_FIREMODE)=true
|
|
bLoopingFireSnd(DEFAULT_FIREMODE)=true
|
|
|
|
// Attachments
|
|
bHasIronSights=true
|
|
bHasFlashlight=false
|
|
|
|
// Ammo belt
|
|
AmmoBeltBulletBonePrefix="RW_Bullets"
|
|
NumAmmoBeltBullets=14
|
|
LastAmmoCount=-1
|
|
|
|
bIsShieldActive=false
|
|
bWasShieldDepleted=false
|
|
bWasShielDestroyed=false
|
|
bCanRechargeShield=true
|
|
ShieldRechargeIncrement=0.0f;
|
|
ShieldConsumptionIncrement=0.0f
|
|
|
|
ShieldConsumptionPerSecond=3.0f //10.0f
|
|
ShieldRechargePerSecond=8.0f //10.0f //15.0f
|
|
CooldownAfterShieldDepleted=3.0f //3.0f
|
|
CooldownAfterShieldDestroyed=3.0f //5.0f
|
|
|
|
ShieldActivateSound=(DefaultCue=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_3P_Shield_On', FirstPersonCue=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_On')
|
|
ShieldDeactivateSound=(DefaultCue=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_3P_Shield_Off', FirstPersonCue=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Off')
|
|
ShieldEndSound=(DefaultCue=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_3P_Shield_End', FirstPersonCue=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_End')
|
|
|
|
BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact'
|
|
BlockParticleSystem=ParticleSystem'FX_Impacts_EMIT.FX_Block_melee_01'
|
|
BlockEffectsSocketName=BlockEffect
|
|
|
|
RedOverlayMax=1.0f
|
|
RedOverlayMin=0.0f
|
|
OverlayDelta=0.0f
|
|
ShieldBlockVFXDuration=0.5f
|
|
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_Bludgeon', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact'))
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_Slashing', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact'))
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_Fire_HuskFireball', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact'))
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_Fire_HuskFlamethrower'))
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_BloatPuke'))
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_EvilDAR_Rocket', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact'))
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_EvilDAR_Laser', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact'))
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_DAR_EMPBlast', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact'))
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_Ballistic_PatMinigun', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact'))
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_Explosive_PatMissile', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact'))
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_Ballistic_HansAK12', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact'))
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_EMP_MatriarchTeslaBlast', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact'))
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_EMP_MatriarchPlasmaCannon'))
|
|
BlockDamageTypes.Add((DmgType=class'KFDT_FleshpoundKing_ChestBeam'))
|
|
BlockDamageModifier=0.3f //0.4f
|
|
ShieldDamageAbsorbtionModifier=1.2f //0.8f //0.8 = equal to base damage
|
|
BlockingAngle=180.f // Adjust with visuals.
|
|
bShieldActionAvailable=true
|
|
bActivatingShield=false
|
|
bDeactivatingShield=false
|
|
FXDelta=0.0f
|
|
ShieldFXDuration=0.15f
|
|
bAllowClientAmmoTracking=true
|
|
NumBloodMapMaterials=5
|
|
|
|
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.0f), (Stat=EWUS_Weight, Add=0)))
|
|
}
|