1
0
This commit is contained in:
2021-06-02 23:06:18 +03:00
parent 9553ac0b31
commit 90e235396c
96 changed files with 5520 additions and 161 deletions

View File

@ -0,0 +1,52 @@
//=============================================================================
// KFDT_Ballistic_BlastBrawlersShotgun
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Ballistic_BlastBrawlersShotgun extends KFDT_Ballistic_Shotgun
abstract
hidedropdown;
/** Allows the damage type to customize exactly which hit zones it can dismember */
static simulated function bool CanDismemberHitZone( name InHitZoneName )
{
if( super.CanDismemberHitZone( InHitZoneName ) )
{
return true;
}
switch ( InHitZoneName )
{
case 'lupperarm':
case 'rupperarm':
case 'chest':
case 'heart':
return true;
}
return false;
}
defaultproperties
{
BloodSpread=0.4
BloodScale=0.6
KDamageImpulse=900
KDeathUpKick=-500
KDeathVel=350
//KDamageImpulse=350
//KDeathUpKick=120
//KDeathVel=10
StumblePower=12
GunHitPower=12
OverrideImpactEffect=ParticleSystem'WEP_HRG_BlastBrawlers_EMIT.FX_BlastBrawlers_Impact'
WeaponDef=class'KFWeapDef_HRG_BlastBrawlers'
}

View File

@ -0,0 +1,27 @@
//=============================================================================
// KFDT_Ballistic_FAMAS_Rifle
//=============================================================================
// Damage type class for the FAMAS rifle
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Ballistic_FAMAS_Rifle extends KFDT_Ballistic_AssaultRifle
abstract
hidedropdown;
defaultproperties
{
KDamageImpulse=900
KDeathUpKick=-300
KDeathVel=100
StumblePower=12
GunHitPower=0
WeaponDef=class'KFWeapDef_FAMAS'
ModifierPerkList(0)=class'KFPerk_Commando'
ModifierPerkList(1)=class'KFPerk_Support'
}

View File

@ -0,0 +1,47 @@
//=============================================================================
// KFDT_Ballistic_FAMAS_Shotgun
//=============================================================================
// Damage type class for the FAMAS shotgun alt fire
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Ballistic_FAMAS_Shotgun extends KFDT_Ballistic_Shotgun
abstract
hidedropdown;
/** Allows the damage type to customize exactly which hit zones it can dismember */
static simulated function bool CanDismemberHitZone( name InHitZoneName )
{
if( super.CanDismemberHitZone( InHitZoneName ) )
{
return true;
}
switch ( InHitZoneName )
{
case 'lupperarm':
case 'rupperarm':
case 'chest':
case 'heart':
return true;
}
return false;
}
defaultproperties
{
BloodSpread=0.4
BloodScale=0.6
KDamageImpulse=900
KDeathUpKick=500
KDeathVel=350
StumblePower=10
GunHitPower=15
WeaponDef=class'KFWeapDef_FAMAS'
}

View File

@ -0,0 +1,26 @@
//=============================================================================
// KFDT_Ballistic_HRG_BarrierRifle
//=============================================================================
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Ballistic_HRG_BarrierRifle extends KFDT_Ballistic_AssaultRifle
abstract
hidedropdown;
defaultproperties
{
KDamageImpulse=900
KDeathUpKick=-300
KDeathVel=100
StumblePower=20
GunHitPower=20
WeaponDef=class'KFWeapDef_HRG_BarrierRifle'
//Perk
ModifierPerkList(0)=class'KFPerk_SWAT'
}

View File

@ -0,0 +1,55 @@
//=============================================================================
// KFDT_Ballistic_ThermiteBoreImpact
//=============================================================================
// Rocket impact damage type for the Thermite rocket launcher
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Ballistic_ThermiteBoreImpact extends KFDT_Ballistic_Shell
abstract
hidedropdown;
// Damage type to use for the burning damage over time
var class<KFDamageType> BurnDamageType;
static simulated function bool CanDismemberHitZone(name InHitZoneName)
{
return false;
}
static simulated function bool CanDismemberHitZoneWhileAlive(name InHitZoneName)
{
return false;
}
/** Called when damage is dealt to apply additional damage type (e.g. Damage Over Time) */
static function ApplySecondaryDamage( KFPawn Victim, int DamageTaken, optional Controller InstigatedBy )
{
// Overriden to specific a different damage type to do the burn damage over
// time. We do this so we don't get shotgun pellet impact sounds/fx during
// the DOT burning.
if ( default.BurnDamageType.default.DoT_Type != DOT_None )
{
Victim.ApplyDamageOverTime(DamageTaken, InstigatedBy, default.BurnDamageType);
}
}
defaultproperties
{
KDamageImpulse=0
KDeathUpKick=0
KDeathVel=0
BurnPower=50
KnockdownPower=50
StumblePower=350
GunHitPower=300
BurnDamageType=class'KFDT_Fire_ThermiteImpactDoT'
ModifierPerkList(0)=class'KFPerk_FireBug'
WeaponDef=class'KFWeapDef_ThermiteBore'
}

View File

@ -0,0 +1,24 @@
//=============================================================================
// KFDT_Bludgeon_BlastBrawlers
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Bludgeon_BlastBrawlers extends KFDT_Bludgeon
abstract
hidedropdown;
defaultproperties
{
KDamageImpulse=2500
KDeathUpKick=500
KDeathVel=400
MeleeHitPower=100
StunPower=0
StumblePower=0
WeaponDef=class'KFWeapDef_HRG_BlastBrawlers'
ModifierPerkList(0)=class'KFPerk_Support'
}

View File

@ -0,0 +1,25 @@
//=============================================================================
// KFDT_Bludgeon_BlastBrawlersBash
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Bludgeon_BlastBrawlersBash extends KFDT_Bludgeon
abstract
hidedropdown;
defaultproperties
{
KDamageImpulse=3500
KDeathUpKick=800
KDeathVel=575
KnockdownPower=0
StunPower=0
StumblePower=200
MeleeHitPower=100
WeaponDef=class'KFWeapDef_HRG_BlastBrawlers'
ModifierPerkList(0)=class'KFPerk_Support'
}

View File

@ -0,0 +1,28 @@
//=============================================================================
// KFDT_Bludgeon_BlastBrawlersHeavy
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Bludgeon_BlastBrawlersHeavy extends KFDT_Bludgeon
abstract
hidedropdown;
defaultproperties
{
KDamageImpulse=3500
KDeathUpKick=800
KDeathVel=575
KnockdownPower=75
StunPower=0
StumblePower=150
MeleeHitPower=150
EMPPower=0
WeaponDef=class'KFWeapDef_HRG_BlastBrawlers'
ModifierPerkList(0)=class'KFPerk_Support'
//OverrideImpactEffect=ParticleSystem'WEP_HRG_BlastBrawlers_EMIT.FX_Static_Strikers_Impact'
}

View File

@ -0,0 +1,15 @@
//=============================================================================
// KFDT_Bludgeon_FAMAS
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Bludgeon_FAMAS extends KFDT_Bludgeon_RifleButt
abstract
hidedropdown;
DefaultProperties
{
//defaults
WeaponDef=class'KFWeapDef_FAMAS'
}

View File

@ -0,0 +1,15 @@
//=============================================================================
// KFDT_Bludgeon_HRG_BarrierRifle
//=============================================================================
// Killing Floor 2
// Copyright (C) 2016 Tripwire Interactive LLC
//=============================================================================
class KFDT_Bludgeon_HRG_BarrierRifle extends KFDT_Bludgeon_RifleButt
abstract
hidedropdown;
DefaultProperties
{
//defaults
WeaponDef=class'KFWeapDef_HRG_BarrierRifle'
}

View File

@ -0,0 +1,15 @@
//=============================================================================
// KFDT_Bludgeon_ThermiteBore
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Bludgeon_ThermiteBore extends KFDT_Bludgeon_RifleButt
abstract
hidedropdown;
DefaultProperties
{
//defaults
WeaponDef=class'KFWeapDef_ThermiteBore'
}

View File

@ -0,0 +1,49 @@
//=============================================================================
// KFDT_Explosive_Thermite
//=============================================================================
// Explosive damage type for the Seal Squeal
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Explosive_Thermite extends KFDT_Fire
abstract
hidedropdown;
// Damage type to use for the burning damage over time
var class<KFDamageType> BurnDamageType;
/** Called when damage is dealt to apply additional damage type (e.g. Damage Over Time) */
static function ApplySecondaryDamage( KFPawn Victim, int DamageTaken, optional Controller InstigatedBy )
{
// Overriden to specific a different damage type to do the burn damage over
// time. We do this so we don't get shotgun pellet impact sounds/fx during
// the DOT burning.
if ( default.BurnDamageType.default.DoT_Type != DOT_None )
{
Victim.ApplyDamageOverTime(DamageTaken, InstigatedBy, default.BurnDamageType);
}
}
defaultproperties
{
bShouldSpawnPersistentBlood = true
// physics impact
RadialDamageImpulse = 2000
GibImpulseScale = 0.15
KDeathUpKick = 1000
KDeathVel = 300
KnockdownPower = 0
BurnPower = 50
StumblePower = 200
BurnDamageType=class'KFDT_Fire_ThermiteExplosionDoT'
//Perk
ModifierPerkList(0) = class'KFPerk_Firebug'
WeaponDef = class'KFWeapDef_ThermiteBore'
}

View File

@ -0,0 +1,33 @@
//=============================================================================
// KFDT_Fire_Ground_ThermiteBore
//=============================================================================
// Damage type class for the thermite bore ground fire
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Fire_Ground_ThermiteBore extends KFDT_Fire_Ground
abstract;
defaultproperties
{
bShouldSpawnPersistentBlood=false
// physics impact
RadialDamageImpulse=0
KDeathUpKick=0
KDeathVel=0
KnockdownPower=0
StumblePower=100
BurnPower=10
// DOT
DoT_Duration=3.0 //5.0
DoT_Interval=0.5
DoT_DamageScale=0.5 //0.2
bIgnoreSelfInflictedScale=false
WeaponDef=class'KFWeapDef_ThermiteBore'
}

View File

@ -0,0 +1,42 @@
//=============================================================================
// KFDT_Fire_ThermiteExplosionDoT
//=============================================================================
// Damage caused by burning from being hit by a thermite bore explosion
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Fire_ThermiteExplosionDoT extends KFDT_Fire
abstract
hidedropdown;
static function int GetKillerDialogID()
{
return 86;//KILL_Fire
}
static function int GetDamagerDialogID()
{
return 102;//DAMZ_Fire
}
static function int GetDamageeDialogID()
{
return 116;//DAMP_Fire
}
defaultproperties
{
WeaponDef=class'KFWeapDef_ThermiteBore'
DoT_Type=DOT_Fire
DoT_Duration=3.0
DoT_Interval=0.5
DoT_DamageScale=0.2
BurnPower=10
// Explosion DOT does not damage the instigator
bNoInstigatorDamage=true
}

View File

@ -0,0 +1,40 @@
//=============================================================================
// KFDT_Fire_ThermiteImpactDoT
//=============================================================================
// Damage caused by burning from being hit by a thermite bore projectile
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Fire_ThermiteImpactDoT extends KFDT_Fire
abstract
hidedropdown;
static function int GetKillerDialogID()
{
return 86;//KILL_Fire
}
static function int GetDamagerDialogID()
{
return 102;//DAMZ_Fire
}
static function int GetDamageeDialogID()
{
return 116;//DAMP_Fire
}
defaultproperties
{
WeaponDef=class'KFWeapDef_ThermiteBore'
DoT_Type=DOT_Fire
DoT_Duration=3.0
DoT_Interval=0.5
DoT_DamageScale=0.2
BurnPower=10
}

View File

@ -0,0 +1,30 @@
//=============================================================================
// KFExplosion_Thermite
//=============================================================================
// Used by projectiles and kismet to spawn an explosion
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFExplosion_Thermite extends KFExplosionActorLingering;
/** Replacement particles to play when hitting surfaces at different angles */
var() ParticleSystem LoopingParticleEffectCeiling;
var() ParticleSystem LoopingParticleEffectWall;
DefaultProperties
{
Interval=0.5
MaxTime=10
bDoFullDamage=true
LoopingParticleEffect=ParticleSystem'WEP_Thermite_EMIT.FX_Thermite_ground_fire_01'
LoopingParticleEffectCeiling=ParticleSystem'WEP_Thermite_EMIT.FX_Thermite_Spread_Ceiling_01'
LoopingParticleEffectWall=ParticleSystem'WEP_Thermite_EMIT.FX_Thermite_Spread_Wall_01'
LoopStartEvent=AkEvent'WW_WEP_SA_Flamethrower.Play_WEP_SA_Flamethrower_Residual_Fire_Loop'
LoopStopEvent=AkEvent'WW_WEP_SA_Flamethrower.Stop_WEP_SA_Flamethrower_Residual_Fire_Loop'
}

View File

@ -170,7 +170,7 @@ function bool TrySetNextWaveSpecial()
function WaveEnded(EWaveEndCondition WinCondition)
{
if(!bWaveStarted)
if(!bWaveStarted && !MyKFGRI.bTraderIsOpen && WinCondition != WEC_TeamWipedOut)
{
return;
}

View File

@ -937,16 +937,19 @@ function ResetAllPickups()
/** Overridden to scale the number of active pickups by wave */
function ResetPickups( array<KFPickupFactory> PickupList, int NumPickups )
{
if(NumPickups != 0)
NumPickups *= (float(WaveNum) / float(WaveMax));
// make sure to have at least 1 ammo pickup in the level, and if it's wave 2 or later make sure there's
// at least one weapon pickup. Also, we need to ensure if OverrideItemPickupModifier is set to 0 we really
// don't want any item pickups.
if( NumPickups == 0 && PickupList.Length > 0
&& (WaveNum > 1
|| KFPickupFactory_Ammo(PickupList[0]) != none
|| (KFPickupFactory_Item(PickupList[0]) != none && (OutbreakEvent == none || OutbreakEvent.ActiveEvent.OverrideItemPickupModifier != 0))
)
)
{
NumPickups *= (float(WaveNum) / float(WaveMax));
// make sure to have at least 1 ammo pickup in the level, and if it's wave 2 or later make sure there's
// at least one weapon pickup
if( NumPickups == 0 && PickupList.Length > 0 && (WaveNum > 1 || KFPickupFactory_Ammo(PickupList[0]) != none) )
{
NumPickups = 1;
}
NumPickups = 1;
}
super.ResetPickups( PickupList, NumPickups );
}
@ -1117,8 +1120,10 @@ function WaveEnded(EWaveEndCondition WinCondition)
local int i;
local KFPlayerController KFPC;
if(!bWaveStarted && !MyKFGRI.bTraderIsOpen)
if(!bWaveStarted && !MyKFGRI.bTraderIsOpen && WinCondition != WEC_TeamWipedOut)
{
return;
}
if (WorldInfo.NetMode == NM_DedicatedServer)
{

View File

@ -65,6 +65,11 @@ event PreBeginPlay()
super.PreBeginPlay();
OutbreakEvent.UpdateGRI();
if (Role == Role_Authority && MyKFGRI != none && OutbreakEvent.ActiveEvent.bUnlimitedWeaponPickups)
{
MyKFGRI.NotifyBrokenTrader();
}
}
function CreateOutbreakEvent()
@ -136,6 +141,7 @@ function SetPickupItemList()
ItemFactory.ItemPickups.Remove(0, ItemFactory.ItemPickups.Length);
continue;
}
foreach OutbreakEvent.ActiveEvent.TraderWeaponList.SaleItems(TraderItem)
{
for (Idx = ItemFactory.ItemPickups.Length - 1; Idx >= 0; --Idx)
@ -241,14 +247,18 @@ protected function ScoreMonsterKill( Controller Killer, Controller Monster, KFPa
function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer)
{
local int i;
local int j;
local KFPlayerController KFPC;
local KFPlayerReplicationInfo DamagerKFPRI;
local array<DamageInfo> DamageHistory;
local array<KFPlayerController> Attackers;
local KFPawn_Human PawnHuman;
local KFGameInfo KFGI;
DamageHistory = MonsterPawn.DamageHistory;
KFGI = KFGameInfo(WorldInfo.Game);
for ( i = 0; i < DamageHistory.Length; i++ )
{
if( DamageHistory[i].DamagerController != none
@ -266,9 +276,30 @@ function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer)
{
PawnHuman = KFPawn_Human(KFPC.Pawn);
Attackers.AddItem(KFPC);
/*
Weekly event Aracnophobia (10):
2 kind of heales: one for killing and another for killing by jumping on enemies.
HealByAssistance is used for the latest, no need to add extra variables.
*/
if( KFPC == Killer && KFGI != none && KFGI.OutbreakEvent.ActiveEvent.bGoompaJumpEnabled )
{
for (j = 0; j < DamageHistory[i].DamageTypes.Length; j++)
{
if (DamageHistory[i].DamageTypes[j] == class 'KFDT_GoompaStomp')
{
PawnHuman.HealDamageForce(MonsterPawn.HealByAssistance, KFPC, class'KFDT_Healing', false, false );
return;
}
}
PawnHuman.HealDamageForce(MonsterPawn.HealByKill, KFPC, class'KFDT_Healing', false, false );
return;
}
//
if( KFPC == Killer )
{
`Log("Heal by Kill: "$MonsterPawn.HealByKill);
PawnHuman.HealDamageForce(MonsterPawn.HealByKill, KFPC, class'KFDT_Healing', false, false );
if( KFPawn_ZedFleshpound(MonsterPawn) != none || KFPawn_ZedScrake(MonsterPawn) != none )
@ -278,7 +309,6 @@ function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer)
}
else
{
`Log("Heal by Assistance: "$MonsterPawn.HealByAssistance);
PawnHuman.HealDamageForce(MonsterPawn.HealByAssistance, KFPC, class'KFDT_Healing', false, false );
}
}
@ -286,7 +316,6 @@ function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer)
}
}
}
}
@ -482,6 +511,34 @@ function StartWave()
SetTimer(OutbreakEvent.ActiveEvent.AdditionalBossWaveStartDelay, true, nameof(SpawnBossWave));
}
if (OutbreakEvent.ActiveEvent.bUnlimitedWeaponPickups)
{
OverridePickupList();
}
}
function bool OverridePickupList()
{
local KFPickupFactory PickupFactory;
local KFPickupFactory_Item ItemFactory;
local KFGameReplicationInfo_WeeklySurvival KFGRI_WS;
KFGRI_WS=KFGameReplicationInfo_WeeklySurvival(MyKFGRI);
if (KFGRI_WS == none)
return false;
foreach ItemPickups(PickupFactory)
{
ItemFactory = KFPickupFactory_Item(PickupFactory);
if (ItemFactory == none)
continue;
KFGRI_WS.OverrideWeaponPickups(ItemFactory);
ItemFactory.OverridePickup();
}
return true;
}
function EnableGlobalDamage()
@ -614,8 +671,6 @@ function InitAllPickups()
{
NumWeaponPickups = ItemPickups.Length * (OutbreakEvent.ActiveEvent.OverrideItemPickupModifier >= 0.f ? OutbreakEvent.ActiveEvent.OverrideItemPickupModifier : DifficultyInfo.GetItemPickupModifier());
NumAmmoPickups = AmmoPickups.Length * (OutbreakEvent.ActiveEvent.OverrideAmmoPickupModifier >= 0.f ? OutbreakEvent.ActiveEvent.OverrideAmmoPickupModifier : DifficultyInfo.GetAmmoPickupModifier());
`log("OutbreakEvent.ActiveEvent.OverrideItemPickupModifier"@OutbreakEvent.ActiveEvent.OverrideItemPickupModifier);
`log("NumWeaponPickups"@NumWeaponPickups);
`if(`__TW_SDK_)
if( BaseMutator != none )
@ -696,6 +751,7 @@ function class<KFPawn_Monster> GetAISpawnType(EAIType AIType)
function bool AllowPrimaryWeapon(string ClassPath)
{
local STraderItem Item;
if (OutbreakEvent.ActiveEvent.SpawnWeaponList != none)
{
foreach OutbreakEvent.ActiveEvent.SpawnWeaponList.SaleItems(Item)
@ -704,8 +760,8 @@ function bool AllowPrimaryWeapon(string ClassPath)
{
return true;
}
}
return false;
}
return true;
}
return true;
}
@ -788,6 +844,42 @@ function DoDeathExplosion(Pawn DeadPawn, KFGameExplosion ExplosionTemplate, clas
}
}
simulated function AddWeaponsFromSpawnList(KFPawn P)
{
local STraderItem Item;
if (OutbreakEvent.ActiveEvent.SpawnWeaponList != none || OutbreakEvent.ActiveEvent.bAddSpawnListToLoadout)
{
foreach OutbreakEvent.ActiveEvent.SpawnWeaponList.SaleItems(Item)
{
P.DefaultInventory.AddItem(class<Weapon>(DynamicLoadObject(Item.WeaponDef.default.WeaponClassPath, class'Class')));
}
}
}
simulated function OverrideHumanDefaults(KFPawn_Human P)
{
if (OutbreakEvent.ActiveEvent.JumpZ >= 0.0f)
{
P.JumpZ = OutbreakEvent.ActiveEvent.JumpZ;
}
}
simulated function ModifyDamageGiven(out int InDamage, optional Actor DamageCauser, optional KFPawn_Monster MyKFPM, optional KFPlayerController DamageInstigator, optional class<KFDamageType> DamageType, optional int HitZoneIdx )
{
local KFPlayerController_WeeklySurvival KFPC;
local int Streak;
if (OutbreakEvent.ActiveEvent.bGoompaJumpEnabled)
{
KFPC = KFPlayerController_WeeklySurvival(DamageInstigator);
if (KFPC != none)
{
Streak = KFPC.GoompaStreakBonus < KFPC.MaxGoompaStreak ? KFPC.GoompaStreakBonus : KFPC.MaxGoompaStreak;
InDamage *= (1 + OutbreakEvent.ActiveEvent.GoompaStreakDamage * Streak);
}
}
}
defaultproperties
{

View File

@ -9,6 +9,14 @@
class KFGameReplicationInfo_WeeklySurvival extends KFGameReplicationInfo;
struct SBrokeTraderPickupItem
{
/** Weapons available for spawning */
var() array<class<KFWeaponDefinition> > WeaponClasses;
};
var() array<SBrokeTraderPickupItem> BrokenTraderItemPickups;
simulated function array<int> GetKFSeqEventLevelLoadedIndices()
{
local array<int> ActivateIndices;
@ -16,4 +24,262 @@ simulated function array<int> GetKFSeqEventLevelLoadedIndices()
ActivateIndices[0] = 7;
return ActivateIndices;
}
}
simulated function OverrideWeaponPickups(out KFPickupFactory_Item ItemFactory)
{
local int Idx;
local ItemPickup Pickup;
if (ItemFactory == none)
return;
if ( BrokenTraderItemPickups.Length == 0 || WaveNum > BrokenTraderItemPickups.Length )
return;
ItemFactory.ItemPickups.Remove(0, ItemFactory.ItemPickups.Length);
for(Idx = 0; Idx < BrokenTraderItemPickups[WaveNum-1].WeaponClasses.Length; Idx++)
{
Pickup.ItemClass = class<KFWeapon> (DynamicLoadObject(BrokenTraderItemPickups[WaveNum-1].WeaponClasses[Idx].default.WeaponClassPath, class'Class'));
ItemFactory.ItemPickups.AddItem(Pickup);
}
}
simulated function NotifyWaveStart()
{
local KFPickupFactory_Item ItemFactory;
if (WorldInfo.NetMode == NM_Client && bIsBrokenTrader)
{
foreach AllActors(class'KFPickupFactory_Item', ItemFactory)
{
OverrideWeaponPickups(ItemFactory);
ItemFactory.SetPickupMesh();
}
}
super.NotifyWaveStart();
}
DefaultProperties
{
BrokenTraderItemPickups={(
(WeaponClasses={(
class'KFGame.KFWeapDef_9mmDual',
class'KFGame.KFWeapDef_Crovel',
class'KFGame.KFWeapDef_MB500',
class'KFGame.KFWeapDef_MedicPistol',
class'KFGame.KFWeapDef_HX25',
class'KFGame.KFWeapDef_CaulkBurn',
class'KFGame.KFWeapDef_Remington1858Dual',
class'KFGame.KFWeapDef_Winchester1894',
class'KFGame.KFWeapDef_MP7',
class'KFGame.KFWeapDef_AR15'
)}),
(WeaponClasses={(
class'KFGame.KFWeapDef_Nailgun',
class'KFGame.KFWeapDef_Katana',
class'KFGame.KFWeapDef_ChainBat',
class'KFGame.KFWeapDef_FireAxe',
class'KFGame.KFWeapDef_Bullpup',
class'KFGame.KFWeapDef_Thompson',
class'KFGame.KFWeapDef_DoubleBarrel',
class'KFGame.KFWeapDef_HZ12',
class'KFGame.KFWeapDef_DragonsBreath',
class'KFGame.KFWeapDef_MedicSMG',
class'KFGame.KFWeapDef_Healthrower_HRG',
class'KFGame.KFWeapDef_M79',
class'KFGame.KFWeapDef_FlareGunDual',
class'KFGame.KFWeapDef_Mac10',
class'KFGame.KFWeapDef_HRGScorcher',
class'KFGame.KFWeapDef_Colt1911Dual',
class'KFGame.KFWeapDef_HRGWinterbite',
class'KFGame.KFWeapDef_CenterfireMB464',
class'KFGame.KFWeapDef_Crossbow',
class'KFGame.KFWeapDef_MP5RAS'
)}),
(WeaponClasses={(
class'KFGame.KFWeapDef_Nailgun',
class'KFGame.KFWeapDef_Katana',
class'KFGame.KFWeapDef_ChainBat',
class'KFGame.KFWeapDef_FireAxe',
class'KFGame.KFWeapDef_Bullpup',
class'KFGame.KFWeapDef_Thompson',
class'KFGame.KFWeapDef_DoubleBarrel',
class'KFGame.KFWeapDef_HZ12',
class'KFGame.KFWeapDef_DragonsBreath',
class'KFGame.KFWeapDef_MedicSMG',
class'KFGame.KFWeapDef_Healthrower_HRG',
class'KFGame.KFWeapDef_M79',
class'KFGame.KFWeapDef_FlareGunDual',
class'KFGame.KFWeapDef_Mac10',
class'KFGame.KFWeapDef_HRGScorcher',
class'KFGame.KFWeapDef_Colt1911Dual',
class'KFGame.KFWeapDef_HRGWinterbite',
class'KFGame.KFWeapDef_CenterfireMB464',
class'KFGame.KFWeapDef_Crossbow',
class'KFGame.KFWeapDef_MP5RAS'
)}),
(WeaponClasses={(
class'KFGame.KFWeapDef_MedicBat',
class'KFGame.KFWeapDef_Pulverizer',
class'KFGame.KFWeapDef_Rifle_FrostShotgunAxe',
class'KFGame.KFWeapDef_AK12',
class'KFGame.KFWeapDef_MKB42',
class'KFGame.KFWeapDef_M16M203',
class'KFGame.KFWeapDef_M4',
class'KFGame.KFWeapDef_SW500Dual_HRG',
class'KFGame.KFWeapDef_MedicShotgun',
class'KFGame.KFWeapDef_Hemogoblin',
class'KFGame.KFWeapDef_Mine_Reconstructor',
class'KFGame.KFWeapDef_SealSqueal',
class'KFGame.KFWeapDef_FlameThrower',
class'KFGame.KFWeapDef_HRGIncendiaryRifle',
class'KFGame.KFWeapDef_ChiappaRhinoDual',
class'KFGame.KFWeapDef_DeagleDual',
class'KFGame.KFWeapDef_M14EBR',
class'KFGame.KFWeapDef_HRG_SonicGun',
class'KFGame.KFWeapDef_MosinNagant',
class'KFGame.KFWeapDef_P90',
class'KFGame.KFWeapDef_Nailgun_HRG',
class'KFGame.KFWeapDef_HK_UMP',
class'KFGame.KFWeapDef_FreezeThrower',
class'KFGame.KFWeapDef_HRG_Kaboomstick',
class'KFGame.KFWeapDef_FAMAS'
)}),
(WeaponClasses={(
class'KFGame.KFWeapDef_MedicBat',
class'KFGame.KFWeapDef_Rifle_FrostShotgunAxe',
class'KFGame.KFWeapDef_M16M203',
class'KFGame.KFWeapDef_M4',
class'KFGame.KFWeapDef_MedicShotgun',
class'KFGame.KFWeapDef_FlameThrower',
class'KFGame.KFWeapDef_HRGIncendiaryRifle',
class'KFGame.KFWeapDef_DeagleDual',
class'KFGame.KFWeapDef_HRG_SonicGun',
class'KFGame.KFWeapDef_MosinNagant',
class'KFGame.KFWeapDef_HK_UMP',
class'KFGame.KFWeapDef_FreezeThrower',
class'KFGame.KFWeapDef_HRG_Kaboomstick',
class'KFGame.KFWeapDef_FAMAS',
class'KFGame.KFWeapDef_Eviscerator',
class'KFGame.KFWeapDef_FNFal',
class'KFGame.KFWeapDef_MedicRifle',
class'KFGame.KFWeapDef_ElephantGun',
class'KFGame.KFWeapDef_Seeker6',
class'KFGame.KFWeapDef_HuskCannon',
class'KFGame.KFWeapDef_SW500Dual',
class'KFGame.KFWeapDef_Kriss',
class'KFGame.KFWeapDef_HRG_EMP_ArcGenerator'
)}),
(WeaponClasses={(
class'KFGame.KFWeapDef_HRGTeslauncher',
class'KFGame.KFWeapDef_Eviscerator',
class'KFGame.KFWeapDef_MaceAndShield',
class'KFGame.KFWeapDef_PowerGloves',
class'KFGame.KFWeapDef_SCAR',
class'KFGame.KFWeapDef_Stoner63A',
class'KFGame.KFWeapDef_MedicRifle',
class'KFGame.KFWeapDef_FNFal',
class'KFGame.KFWeapDef_AA12',
class'KFGame.KFWeapDef_ElephantGun',
class'KFGame.KFWeapDef_Blunderbuss',
class'KFGame.KFWeapDef_HRGIncision',
class'KFGame.KFWeapDef_HRG_Vampire',
class'KFGame.KFWeapDef_RPG7',
class'KFGame.KFWeapDef_Seeker6',
class'KFGame.KFWeapDef_HuskCannon',
class'KFGame.KFWeapDef_MicrowaveGun',
class'KFGame.KFWeapDef_SW500Dual',
class'KFGame.KFWeapDef_AF2011Dual',
class'KFGame.KFWeapDef_Pistol_DualG18',
class'KFGame.KFWeapDef_RailGun',
class'KFGame.KFWeapDef_G18',
class'KFGame.KFWeapDef_Kriss',
class'KFGame.KFWeapDef_HRG_EMP_ArcGenerator',
class'KFGame.KFWeapDef_AbominationAxe',
class'KFGame.KFWeapDef_Minigun',
class'KFGame.KFWeapDef_MedicRifleGrenadeLauncher',
class'KFGame.KFWeapDef_MicrowaveRifle',
class'KFGame.KFWeapDef_CompoundBow',
class'KFGame.KFWeapDef_M99',
class'KFGame.KFWeapDef_LazerCutter',
class'KFGame.KFWeapDef_HRG_BlastBrawlers',
class'KFGame.KFWeapDef_ThermiteBore',
class'KFGame.KFWeapDef_HRG_BarrierRifle'
)}),
(WeaponClasses={(
class'KFGame.KFWeapDef_HRGTeslauncher',
class'KFGame.KFWeapDef_Eviscerator',
class'KFGame.KFWeapDef_MaceAndShield',
class'KFGame.KFWeapDef_PowerGloves',
class'KFGame.KFWeapDef_SCAR',
class'KFGame.KFWeapDef_Stoner63A',
class'KFGame.KFWeapDef_MedicRifle',
class'KFGame.KFWeapDef_FNFal',
class'KFGame.KFWeapDef_AA12',
class'KFGame.KFWeapDef_ElephantGun',
class'KFGame.KFWeapDef_Blunderbuss',
class'KFGame.KFWeapDef_HRGIncision',
class'KFGame.KFWeapDef_HRG_Vampire',
class'KFGame.KFWeapDef_RPG7',
class'KFGame.KFWeapDef_Seeker6',
class'KFGame.KFWeapDef_HuskCannon',
class'KFGame.KFWeapDef_MicrowaveGun',
class'KFGame.KFWeapDef_SW500Dual',
class'KFGame.KFWeapDef_AF2011Dual',
class'KFGame.KFWeapDef_Pistol_DualG18',
class'KFGame.KFWeapDef_RailGun',
class'KFGame.KFWeapDef_G18',
class'KFGame.KFWeapDef_Kriss',
class'KFGame.KFWeapDef_HRG_EMP_ArcGenerator',
class'KFGame.KFWeapDef_AbominationAxe',
class'KFGame.KFWeapDef_Minigun',
class'KFGame.KFWeapDef_MedicRifleGrenadeLauncher',
class'KFGame.KFWeapDef_MicrowaveRifle',
class'KFGame.KFWeapDef_CompoundBow',
class'KFGame.KFWeapDef_M99',
class'KFGame.KFWeapDef_LazerCutter',
class'KFGame.KFWeapDef_HRG_BlastBrawlers',
class'KFGame.KFWeapDef_ThermiteBore',
class'KFGame.KFWeapDef_HRG_BarrierRifle'
)}),
(WeaponClasses={(
class'KFGame.KFWeapDef_HRGTeslauncher',
class'KFGame.KFWeapDef_Eviscerator',
class'KFGame.KFWeapDef_MaceAndShield',
class'KFGame.KFWeapDef_PowerGloves',
class'KFGame.KFWeapDef_SCAR',
class'KFGame.KFWeapDef_Stoner63A',
class'KFGame.KFWeapDef_MedicRifle',
class'KFGame.KFWeapDef_FNFal',
class'KFGame.KFWeapDef_AA12',
class'KFGame.KFWeapDef_ElephantGun',
class'KFGame.KFWeapDef_Blunderbuss',
class'KFGame.KFWeapDef_HRGIncision',
class'KFGame.KFWeapDef_HRG_Vampire',
class'KFGame.KFWeapDef_RPG7',
class'KFGame.KFWeapDef_Seeker6',
class'KFGame.KFWeapDef_HuskCannon',
class'KFGame.KFWeapDef_MicrowaveGun',
class'KFGame.KFWeapDef_SW500Dual',
class'KFGame.KFWeapDef_AF2011Dual',
class'KFGame.KFWeapDef_Pistol_DualG18',
class'KFGame.KFWeapDef_RailGun',
class'KFGame.KFWeapDef_G18',
class'KFGame.KFWeapDef_Kriss',
class'KFGame.KFWeapDef_HRG_EMP_ArcGenerator',
class'KFGame.KFWeapDef_AbominationAxe',
class'KFGame.KFWeapDef_Minigun',
class'KFGame.KFWeapDef_MedicRifleGrenadeLauncher',
class'KFGame.KFWeapDef_MicrowaveRifle',
class'KFGame.KFWeapDef_CompoundBow',
class'KFGame.KFWeapDef_M99',
class'KFGame.KFWeapDef_LazerCutter',
class'KFGame.KFWeapDef_HRG_BlastBrawlers',
class'KFGame.KFWeapDef_ThermiteBore',
class'KFGame.KFWeapDef_HRG_BarrierRifle'
)})
)}
}

View File

@ -0,0 +1,34 @@
//=============================================================================
// KFMeleeHelperWeaponBlastBrawlers
//=============================================================================
// Manages melee attack related functionality for 1st person weapons
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFMeleeHelperWeaponBlastBrawlers extends KFMeleeHelperWeapon
config(Game);
event InitWorldTraceForHitboxCollision()
{
local KFWeap_HRG_BlastBrawlers BlastBrawlers;
BlastBrawlers = KFWeap_HRG_BlastBrawlers(Instigator.Weapon);
if (BlastBrawlers != none)
{
BlastBrawlers.Shoot();
}
super.InitWorldTraceForHitboxCollision();
}
simulated function InitAttackSequence(EPawnOctant NewAtkDir, EMeleeAttackType NewAtkType)
{
super.InitAttackSequence(NewAtkDir, NewAtkType);
NextAttackType = NewAtkType;
}
defaultproperties
{
}

View File

@ -407,6 +407,115 @@ defaultproperties
)}
// Aracnophobia
SetEvents[10]={(
EventDifficulty=2, //1,
GameLength=GL_Normal,
SpawnRateMultiplier=0.75, //5.0,
bHealAfterKill = true,
bGoompaJumpEnabled = true,
GoompaJumpDamage = 550, //300,
GoompaStreakDamage = 0.1, //0.2,
GoompaJumpImpulse = 600, //1000,
GoompaStreakMax = 5,
GoompaBonusDuration=8.0f, //10.0f,
DoshOnKillGlobalModifier=1.0,
SpawnWeaponList=KFGFxObject_TraderItems'GP_Trader_ARCH.AracnophobiaWeeklySpawnList',
bAddSpawnListToLoadout=true,
WaveAICountScale=(0.6, 0.6, 0.6, 0.6, 0.6, 0.6),
JumpZ=700.f, // 650.0 by default; -1 used for not overriding.
/** HealByKill = Normal kill. HealByAssistance = Goomba stomping */
ZedsToAdjust={(
(ClassToAdjust=class'KFGameContent.KFPawn_ZedCrawler',HealthScale=10.0, HeadHealthScale=20.0, DamageDealtScale=0.7, InitialGroundSpeedModifierScale=0.7, HealByAssistance=10),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedCrawlerKing',HealthScale=10.0,HeadHealthScale=20.0, DamageDealtScale=0.7, InitialGroundSpeedModifierScale=0.7, HealByAssistance=20)
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Cyst',HealByAssistance=5),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Alpha',HealByAssistance=5),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_AlphaKing',HealByAssistance=5),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Slasher',HealByAssistance=5),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedSiren',HealByAssistance=5),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedStalker',HealByAssistance=5),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedGorefast',HealByAssistance=5),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedGorefastDualBlade',HealByAssistance=5),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloat',HealByAssistance=5),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedHusk',HealByAssistance=5),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_EMP',HealByAssistance=5),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_Laser',HealByAssistance=5),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_Rocket',HealByAssistance=5),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedScrake',HealByAssistance=15),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpound',HealByAssistance=15),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpoundMini',HealByAssistance=15),
//(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloatKingSubspawn',HealByAssistance=5)
)},
SpawnReplacementList={(
(SpawnEntry=AT_Clot,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6),
(SpawnEntry=AT_AlphaClot,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6),
(SpawnEntry=AT_SlasherClot,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6),
(SpawnEntry=AT_Stalker,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6),
(SpawnEntry=AT_Bloat,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6),
(SpawnEntry=AT_Siren,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6),
(SpawnEntry=AT_Husk,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6),
(SpawnEntry=AT_GoreFast,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6),
//(SpawnEntry=AT_Scrake,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.7),
//(SpawnEntry=AT_FleshPound,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.7),
//(SpawnEntry=AT_FleshpoundMini,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.7),
(SpawnEntry=AT_EliteClot,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6),
(SpawnEntry=AT_EliteGoreFast,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6),
(SpawnEntry=AT_EDAR_EMP,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6),
(SpawnEntry=AT_EDAR_Laser,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6),
(SpawnEntry=AT_EDAR_Rocket,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6),
(SpawnEntry=AT_Crawler,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=1.0)
)}
)}
// Broken Trader
SetEvents[11]={(
EventDifficulty=1,
GameLength=GL_Normal,
bSpawnWeaponListAffectsSecondaryWeapons=true,
TraderWeaponList=KFGFxObject_TraderItems'GP_Trader_ARCH.BrokenTraderWeeklyTraderList',
PickupResetTime=PRS_Wave,
bDisableTraders=false,
DroppedItemLifespan=10.0f, // 300 default
DoshOnKillGlobalModifier=0.2,
//Pickup Notes for when you're modifying:
// NumPickups = Actors * OverridePickupModifer * WavePickupModifier
// Ex: 16 item pickups in the world
// * 0.9 Pickup Modifier = 14
// * 0.5 Current wave modifier = 7 expected to spawn
//
// Ex: 16 ammo pickups in the world
// * 0.1 pickup modifier = 2
// * 0.5 current wave modifier = 1 expected to spawn
bUnlimitedWeaponPickups=true,
OverrideItemPickupModifier=2.0,
OverrideAmmoPickupModifier=0.8, //0.5,
WaveItemPickupModifiers={(
1.0, 1.0, 1.0, 1.0, 1.0
)},
WaveAmmoPickupModifiers={(
0.5, 0.6, 0.7, 0.8, 0.9
)},
bUseOverrideAmmoRespawnTime=true,
OverrideAmmoRespawnTime={(
PlayersMod[0]=20.000000,
PlayersMod[1]=20.000000,
PlayersMod[2]=10.000000,
PlayersMod[3]=10.000000,
PlayersMod[4]=5.000000,
PlayersMod[5]=5.000000,
ModCap=1.000000
)},
bUseOverrideItemRespawnTime=true,
OverrideItemRespawnTime={(
PlayersMod[0]=10.000000,
PlayersMod[1]=10.000000,
PlayersMod[2]=5.000000,
PlayersMod[3]=5.000000,
PlayersMod[4]=2.000000,
PlayersMod[5]=2.000000,
ModCap=1.000000
)}
)}
//Test events from here down. These don't end up in the regular rotation.

View File

@ -36,7 +36,13 @@ simulated function PlayHeadAsplode()
/** Set our gib flag on the server, replicate it with bTearOff */
function bool Died(Controller Killer, class<DamageType> DamageType, vector HitLocation)
{
if( !bPlayedDeath && DamageType != class'KFSM_PlayerCrawler_Suicide'.default.SuicideDamageType )
local KFGameInfo_WeeklySurvival KFGI_WS;
// Not exploding if we are in arachnophobia weekly.
KFGI_WS = KFGameInfo_WeeklySurvival(WorldInfo.Game);
if( !bPlayedDeath && DamageType != class'KFSM_PlayerCrawler_Suicide'.default.SuicideDamageType &&
(KFGI_WS == none|| !KFGI_WS.OutbreakEvent.ActiveEvent.bGoompaJumpEnabled))
{
bShouldExplode = true;
}

View File

@ -440,7 +440,7 @@ function AdjustDamage(out int InDamage, out vector Momentum, Controller Instigat
}
}
function HandleAfflictionsOnHit(Controller DamageInstigator, vector HitDir, class<KFDamageType> DamageType, Actor DamageCauser)
function HandleAfflictionsOnHit(Controller DamageInstigator, vector HitDir, class<DamageType> DamageType, Actor DamageCauser)
{
if (ShieldHealthPctByte == 0)
{

View File

@ -0,0 +1,51 @@
//=============================================================================
// KFPhysicsDamageByPawnVolume
//=============================================================================
// PhysicsVolume are, by default, used for traps on all maps. This KFPhysicsDamageByPawnVolume
// gives the ability to make different damage values for Humans and Monsters.
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
// Roberto Moreno
//=============================================================================
class KFPhysicsDamageByPawnVolume extends PhysicsVolume
placeable;
var() float DamagePerSecMultiplierForHuman;
var() float DamagePerSecMultiplierForMonster;
function CausePainTo(Actor Other)
{
local float DamagePerSecModified;
DamagePerSecModified = DamagePerSec;
if (KFPawn_Human(Other) != None)
{
DamagePerSecModified *= DamagePerSecMultiplierForHuman;
}
else if (KFPawn_Monster(Other) != None)
{
DamagePerSecModified *= DamagePerSecMultiplierForMonster;
}
if (DamagePerSecModified > 0)
{
if ( WorldInfo.bSoftKillZ && (Other.Physics != PHYS_Walking) )
return;
if ( (DamageType == None) || (DamageType == class'DamageType') )
`log("No valid damagetype ("$DamageType$") specified for "$PathName(self));
Other.TakeDamage(DamagePerSecModified*PainInterval, DamageInstigator, Location, vect(0,0,1), DamageType,, self);
}
else
{
Other.HealDamage(-DamagePerSecModified * PainInterval, DamageInstigator, DamageType);
}
}
DefaultProperties
{
DamagePerSecMultiplierForHuman=1.0
DamagePerSecMultiplierForMonster=1.0
}

View File

@ -234,9 +234,9 @@ defaultproperties
// Ice explosion
Begin Object Class=KFGameExplosion Name=ExploTemplate0
Damage=25
DamageRadius=200
DamageFalloffExponent=1.f
Damage=75 //25
DamageRadius=250 //200
DamageFalloffExponent=0.5f //1.f
DamageDelay=0.f
bIgnoreInstigator=false

View File

@ -0,0 +1,29 @@
//=============================================================================
// KFProj_Bullet_BlastBrawlers
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFProj_Bullet_BlastBrawlers extends KFProj_Bullet_Pellet
hidedropdown;
defaultproperties
{
MaxSpeed=7000.0
Speed=7000.0
bWarnAIWhenFired=true
DamageRadius=0
ImpactEffects = KFImpactEffectInfo'WEP_HRG_BlastBrawlers_ARCH.HRG_BlastBrawler_Projectile_Impacts'
ProjFlightTemplate=ParticleSystem'WEP_HRG_BlastBrawlers_EMIT.FX_BlastBrawlers_Tracer_Instant'
ProjFlightTemplateZedTime=ParticleSystem'WEP_HRG_BlastBrawlers_EMIT.FX_BlastBrawlers_Tracer_Instant'
//ProjFlightTemplate=ParticleSystem'WEP_HRG_BlastBrawlers_EMIT.FX_BlastBrawlers_Projectile'
//ProjFlightTemplateZedTime=ParticleSystem'WEP_HRG_BlastBrawlers_EMIT.FX_BlastBrawlers_Projectile'
AmbientSoundPlayEvent=none
AmbientSoundStopEvent=none
}

View File

@ -11,13 +11,10 @@ class KFProj_Grenade_GravityImploder extends KFProj_BallisticExplosive
/* Ensure it detonates */
var float DetonationTime;
var float VortexDuration;
var float VortexRadius;
var float VortexImpulseStrength;
var protected transient bool bVortexActive;
var protected RB_RadialImpulseComponent RadialImpulseComponent;
simulated state GrenadeState
{
simulated event BeginState(Name PrevStateName)
@ -49,18 +46,25 @@ simulated state VortexState
simulated event Tick(float DeltaTime)
{
local float ImpulseModifier;
local Actor Victim;
local TraceHitInfo HitInfo;
local FracturedStaticMeshActor FracActor;
if(bVortexActive && (WorldInfo.NetMode == NM_Client || WorldInfo.NetMode == NM_Standalone))
{
// ImpulseModifier = (bReduceGibImpulseOnTick) ? (1.0f - AccumulatedTime / Lifetime) : 1.0f;
ImpulseModifier = 1.0f;
RadialImpulseComponent.ImpulseRadius = VortexRadius;
RadialImpulseComponent.ImpulseStrength = VortexImpulseStrength * ImpulseModifier;
RadialImpulseComponent.bVelChange = true;
RadialImpulseComponent.ImpulseFalloff = RIF_Constant;
RadialImpulseComponent.FireImpulse(Location);
foreach CollidingActors(class'Actor', Victim, VortexRadius, Location, true,, HitInfo)
{
if (KFPawn_Human(Victim) == none && Victim.CollisionComponent != none && !Victim.bWorldGeometry)
{
Victim.CollisionComponent.AddRadialImpulse(Location, VortexRadius, VortexImpulseStrength, RIF_Constant, true);
}
FracActor = FracturedStaticMeshActor(Victim);
if (FracActor != none)
{
FracActor.BreakOffPartsInRadius(Location, VortexRadius, VortexImpulseStrength, true);
}
}
}
}
}
@ -123,9 +127,9 @@ defaultproperties
ProjFlightTemplate=ParticleSystem'WEP_Gravity_Imploder_EMIT.FX_Yellow_Projectile'
ProjFlightTemplateZedTime=ParticleSystem'WEP_Gravity_Imploder_EMIT.FX_Yellow_Projectile_ZEDTIME'
GrenadeBounceEffectInfo=KFImpactEffectInfo'FX_Impacts_ARCH.DefaultGrenadeImpacts'
//GrenadeBounceEffectInfo=KFImpactEffectInfo'FX_Impacts_ARCH.DefaultGrenadeImpacts'
ProjDisintegrateTemplate=ParticleSystem'ZED_Siren_EMIT.FX_Siren_grenade_disable_01'
AltExploEffects=KFImpactEffectInfo'WEP_Gravity_Imploder_ARCH.Yellow_Explosion_Concussive_Force'
//AltExploEffects=KFImpactEffectInfo'WEP_Gravity_Imploder_ARCH.Yellow_Explosion_Concussive_Force'
// Grenade explosion light
Begin Object Class=PointLightComponent Name=ExplosionPointLight
@ -179,10 +183,4 @@ defaultproperties
VortexImpulseStrength=-100
VortexDuration=0.5f
bVortexActive=false
Begin Object Class=RB_RadialImpulseComponent Name=ImpulseComponent0
End Object
RadialImpulseComponent=ImpulseComponent0
Components.Add(ImpulseComponent0)
}

View File

@ -0,0 +1,368 @@
//=============================================================================
// KFProj_Rocket_ThermiteBore
//=============================================================================
// Thermite Bore Rifle rocket launcher harpoon
//=============================================================================
// Killing Floor 2
// Copyright (C) 2012 Tripwire Interactive LLC
//=============================================================================
class KFProj_Rocket_ThermiteBore extends KFProjectile;
var float FuseTime;
/** This is the effect indicator that is played for the current user **/
var(Projectile) ParticleSystem ProjIndicatorTemplate;
var ParticleSystemComponent ProjIndicatorEffects;
var bool IndicatorActive;
/**
Fire effects
*/
var class<KFProjectile> ResidualFlameProjClass;
var int NumResidualFlames;
/** Cone Angle to determine residual flame directions */
var float ResidualFlameHalfConeAngle;
/** Impulse modiffier apply to residual forces*/
var float ResidualFlameForceMultiplier;
simulated function TryActivateIndicator()
{
if(!IndicatorActive && Instigator != None)
{
IndicatorActive = true;
if(WorldInfo.NetMode == NM_Standalone || Instigator.Role == Role_AutonomousProxy ||
(Instigator.Role == ROLE_Authority && WorldInfo.NetMode == NM_ListenServer && Instigator.IsLocallyControlled() ))
{
if( ProjIndicatorTemplate != None )
{
ProjIndicatorEffects = WorldInfo.MyEmitterPool.SpawnEmitterCustomLifetime(ProjIndicatorTemplate);
}
if(ProjIndicatorEffects != None)
{
ProjIndicatorEffects.SetAbsolute(false, false, false);
ProjIndicatorEffects.SetLODLevel(WorldInfo.bDropDetail ? 1 : 0);
ProjIndicatorEffects.bUpdateComponentInTick = true;
AttachComponent(ProjIndicatorEffects);
}
}
}
}
/**
* Set the initial velocity and cook time
*/
simulated event PostBeginPlay()
{
Super.PostBeginPlay();
if (Role == ROLE_Authority)
{
SetTimer(FuseTime, false, 'Timer_Detonate');
}
AdjustCanDisintigrate();
}
/**
* Explode after a certain amount of time
*/
function Timer_Detonate()
{
Detonate();
}
/** Called when the owning instigator controller has left a game */
simulated function OnInstigatorControllerLeft()
{
if( WorldInfo.NetMode != NM_Client )
{
SetTimer( 1.f + Rand(5) + fRand(), false, nameOf(Timer_Detonate) );
}
}
/**
* Trace down and get the location to spawn the explosion effects and decal
*/
simulated function GetExplodeEffectLocation(out vector HitLocation, out vector HitRotation, out Actor HitActor)
{
local vector EffectStartTrace, EffectEndTrace;
local TraceHitInfo HitInfo;
EffectStartTrace = Location + vect(0,0,1) * 4.f;
EffectEndTrace = EffectStartTrace - vect(0,0,1) * 32.f;
// Find where to put the decal
HitActor = Trace(HitLocation, HitRotation, EffectEndTrace, EffectStartTrace, false,, HitInfo, TRACEFLAG_Bullet);
// If the locations are zero (probably because this exploded in the air) set defaults
if (IsZero(HitLocation))
{
HitLocation = Location;
}
if (IsZero(HitRotation))
{
HitRotation = vect(0,0,1);
}
}
/** Used to check current status of StuckTo actor (to figure out if we should fall) */
simulated event Tick(float DeltaTime)
{
super.Tick(DeltaTime);
StickHelper.Tick(DeltaTime);
if (!IsZero(Velocity))
{
SetRelativeRotation(rotator(Velocity));
}
TryActivateIndicator();
}
/** Causes charge to explode */
function Detonate()
{
local KFWeap_RocketLauncher_ThermiteBore WeaponOwner;
local vector ExplosionNormal;
if (Role == ROLE_Authority)
{
WeaponOwner = KFWeap_RocketLauncher_ThermiteBore(Owner);
if (WeaponOwner != none)
{
WeaponOwner.RemoveDeployedHarpoon(, self);
}
}
ExplosionNormal = vect(0,0,1) >> Rotation;
Explode(Location, ExplosionNormal);
}
simulated function Explode(vector HitLocation, vector HitNormal)
{
local vector HitVelocity;
HitVelocity = Velocity;
StickHelper.UnPin();
super.Explode(HitLocation, HitNormal);
// Spawn fire projectiles
if(Role < Role_Authority)
{
return;
}
SpawnResidualFlames(HitLocation, HitNormal, HitVelocity);
SpawnResidualFlame(ResidualFlameProjClass, Location, HitVelocity);
}
simulated function Disintegrate( rotator InDisintegrateEffectRotation )
{
local KFWeap_RocketLauncher_ThermiteBore WeaponOwner;
if (Role == ROLE_Authority)
{
WeaponOwner = KFWeap_RocketLauncher_ThermiteBore(Owner);
if (WeaponOwner != none)
{
WeaponOwner.RemoveDeployedHarpoon(, self);
}
}
super.Disintegrate(InDisintegrateEffectRotation);
}
// for nukes && concussive force
simulated protected function PrepareExplosionTemplate()
{
class'KFPerk_Demolitionist'.static.PrepareExplosive(Instigator, self);
super.PrepareExplosionTemplate();
}
simulated function SyncOriginalLocation()
{
// IMPORTANT NOTE: We aren't actually syncing to the original location (or calling the super).
// We just want to receive the original location so we can do a trace between that location and
// our current location to determine if we hit any zeds between those two locations.
// KFII-45464
local Actor HitActor;
local vector HitLocation, HitNormal;
local TraceHitInfo HitInfo;
if (Role < ROLE_Authority && Instigator != none && Instigator.IsLocallyControlled())
{
HitActor = Trace(HitLocation, HitNormal, OriginalLocation, Location,,, HitInfo, TRACEFLAG_Bullet);
if (HitActor != none)
{
StickHelper.TryStick(HitNormal, HitLocation, HitActor);
}
}
}
simulated protected function StopSimulating()
{
super.StopSimulating();
if (ProjIndicatorEffects!=None)
{
ProjIndicatorEffects.DeactivateSystem();
}
}
/** Spawn several projectiles that explode and linger on impact */
function SpawnResidualFlames( vector HitLocation, vector HitNormal, vector HitVelocity )
{
local int i;
local vector HitVelDir;
local float HitVelMag;
local vector SpawnLoc, SpawnVel;
HitVelMag = VSize( HitVelocity );
HitVelDir = Normal( HitVelocity );
SpawnLoc = HitLocation + (HitNormal * 10.f);
// spawn random lingering fires (rather, projectiles that cause little fires)
for( i = 0; i < NumResidualFlames; ++i )
{
SpawnVel = CalculateResidualFlameVelocity( HitNormal, HitVelDir, HitVelMag );
SpawnResidualFlame( ResidualFlameProjClass, SpawnLoc, SpawnVel );
}
}
function vector CalculateResidualFlameVelocity( vector HitNormal, vector HitVelDir, float HitVelMag )
{
local vector SpawnDir;
// apply some spread
SpawnDir = VRandCone( HitNormal, ResidualFlameHalfConeAngle * DegToRad );
/*
// make HitVelDir parallel to contact surface by subtracting component parallel to HitNormal
SpawnDir = SpawnDir + (-(SpawnDir dot HitNormal) * HitNormal);
// apply some more spread to get some of the flames to stick to the wall and others the ground beneath the wall
// (makes it looks kind of smeared down the wall, like a real molotov)
SpawnDir = VRandCone( SpawnDir, PI/4 );
*/
return SpawnDir * ResidualFlameForceMultiplier;
}
defaultproperties
{
ProjFlightTemplate=ParticleSystem'WEP_Thermite_EMIT.FX_Harpoon_Projectile'
ProjIndicatorTemplate=ParticleSystem'WEP_Thermite_EMIT.FX_Harpoon_Projectile_Indicator'
bWarnAIWhenFired=true
MaxSpeed=5000.0 //4000.0
Speed=5000.0 //4000.0
TerminalVelocity=5000 //4000
Physics=PHYS_Falling
TossZ=0 //150
GravityScale=0.36 //0.5//0.7
GlassShatterType=FMGS_ShatterAll
bCollideComplex=true
bIgnoreFoliageTouch=true
bBlockedByInstigator=false
bAlwaysReplicateExplosion=true
FuseTime=4.0
bNetTemporary=false
NetPriority=5
NetUpdateFrequency=200
bNoReplicationToInstigator=false
bUseClientSideHitDetection=true
bUpdateSimulatedPosition=true
bSyncToOriginalLocation=true
bSyncToThirdPersonMuzzleLocation=true
PinBoneIdx=INDEX_None
bCanBeDamaged=true
bCanDisintegrate=true
Begin Object Name=CollisionCylinder
BlockNonZeroExtent=false
// for siren scream
CollideActors=true
End Object
// explosion light
Begin Object Class=PointLightComponent Name=ExplosionPointLight
LightColor=(R=252,G=218,B=171,A=255)
Brightness=4.f
Radius=2000.f
FalloffExponent=10.f
CastShadows=False
CastStaticShadows=FALSE
CastDynamicShadows=False
bCastPerObjectShadows=false
bEnabled=FALSE
LightingChannels=(Indoor=TRUE,Outdoor=TRUE,bInitialized=TRUE)
End Object
// explosion
Begin Object Class=KFGameExplosion Name=ExploTemplate0 // @todo: change me
Damage=150 //250
DamageRadius=500 //600
DamageFalloffExponent=1.f
DamageDelay=0.f
// Damage Effects
MyDamageType=class'KFDT_Explosive_Thermite'
KnockDownStrength=0
FractureMeshRadius=200.0
FracturePartVel=500.0
ExplosionEffects=KFImpactEffectInfo'WEP_Thermite_ARCH.ThermiteHarpoon_Explosion'
ExplosionSound=AkEvent'WW_WEP_SealSqueal.Play_WEP_SealSqueal_Shoot_Explode'
// Dynamic Light
ExploLight=ExplosionPointLight
ExploLightStartFadeOutTime=0.0
ExploLightFadeOutTime=0.2
// Camera Shake
CamShake=CameraShake'FX_CameraShake_Arch.Misc_Explosions.Light_Explosion_Rumble'
CamShakeInnerRadius=200
CamShakeOuterRadius=900
CamShakeFalloff=1.5f
bOrientCameraShakeTowardsEpicenter=true
End Object
ExplosionTemplate=ExploTemplate0
ExplosionActorClass=class'KFExplosionActor'
bCanStick=true
bCanPin=true
Begin Object Class=KFProjectileStickHelper Name=StickHelper0
End Object
StickHelper=StickHelper0
ProjDisintegrateTemplate=ParticleSystem'ZED_Siren_EMIT.FX_Siren_grenade_disable_01'
ResidualFlameProjClass=class'KFProj_ThermiteSplash'
NumResidualFlames=4 //it always spawn 1 more than this parameter, so 5
ResidualFlameHalfConeAngle=72
ResidualFlameForceMultiplier=700f; //1000f;
}

View File

@ -0,0 +1,110 @@
//=============================================================================
// KFProj_ThermiteSplash
//=============================================================================
// Projectile class for the thermite rocket launchers
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFProj_ThermiteSplash extends KFProj_MolotovSplash;
/*
simulated function Tick(float Delta)
{
super.Tick(Delta);
if (WorldInfo.NetMode != NM_Client && WorldInfo.NetMode != NM_Standalone)
{
return;
}
// Rotate towards velocity:
if (VSizeSq(Velocity) > 0)
{
SetRotation(rotator(Normal(Velocity)));
}
}
*/
defaultproperties
{
Physics=PHYS_Falling
bCollideComplex=TRUE // Ignore simple collision on StaticMeshes, and collide per poly
// network
bNetTemporary=False
bAlwaysReplicateExplosion=true
AlwaysRelevantDistanceSquared=6250000 // 25m
// gameplay
bBlockedByInstigator=false
GlassShatterType=FMGS_ShatterNone
// audio
bStopAmbientSoundOnExplode=false
bAutoStartAmbientSound=true
bAmbientSoundZedTimeOnly=false
AmbientSoundPlayEvent=AkEvent'WW_WEP_SA_Flamethrower.Play_WEP_SA_Flamethrower_Residual_Fire_Loop'
AmbientSoundStopEvent=AkEvent'WW_WEP_SA_Flamethrower.Stop_WEP_SA_Flamethrower_Residual_Fire_Loop'
Begin Object name=AmbientAkSoundComponent
bStopWhenOwnerDestroyed=true
bForceOcclusionUpdateInterval=true
OcclusionUpdateInterval=0.25;
End Object
AmbientComponent=AmbientAkSoundComponent
Components.Add(AmbientAkSoundComponent)
// light
Begin Object Name=FlamePointLight
LightColor=(R=245,G=190,B=140,A=255)
Brightness=2.f
Radius=300.f
FalloffExponent=10.f
CastShadows=False
CastStaticShadows=FALSE
CastDynamicShadows=FALSE
bCastPerObjectShadows=false
bEnabled=FALSE
LightingChannels=(Indoor=TRUE,Outdoor=TRUE,bInitialized=TRUE)
End Object
// explosion
Begin Object Name=ExploTemplate0
Damage=10
DamageRadius=150
DamageFalloffExponent=1.f
DamageDelay=0.f
// Don't burn the guy that tossed it, it's just too much damage with multiple fires, its almost guaranteed to kill the guy that tossed it
bIgnoreInstigator=true
MomentumTransferScale=1
// Damage Effects
MyDamageType=class'KFDT_Fire_Ground_ThermiteBore'
KnockDownStrength=0
FractureMeshRadius=0
ExplosionEffects=KFImpactEffectInfo'wep_thermite_arch.Thermite_GroundFire'
bDirectionalExplosion=true
// Camera Shake
CamShake=none
// Dynamic Light
ExploLight=FlamePointLight
ExploLightStartFadeOutTime=4.2
ExploLightFadeOutTime=0.3
End Object
ExplosionTemplate=ExploTemplate0
ProjFlightTemplate=ParticleSystem'WEP_Thermite_EMIT.FX_Thermite_Spread_01'
ExplosionActorClass=class'KFExplosion_Thermite'
AssociatedPerkClass=class'KFPerk_Firebug'
// Ground Fire Perk Skill Alternative FX
AltExploEffects=KFImpactEffectInfo'WEP_Thermite_ARCH.GroundFire_Splash_Impacts'
}

View File

@ -0,0 +1,137 @@
//=============================================================================
// KFSeasonalEventStats_Summer2021
//=============================================================================
// Tracks event-specific challenges/accomplishments for Summer 2021
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFSeasonalEventStats_Summer2021 extends KFSeasonalEventStats;
var transient private const int ZedsStompRequired, LaserKillsRequired, JumpKillsRequired, EndlessWaveRequired;
private event Initialize(string MapName)
{
local string CapsMapName;
CapsMapName = Caps(MapName);
bObjectiveIsValidForMap[0] = 1; // Stomp on 50 Zeds
bObjectiveIsValidForMap[1] = 0; // Complete the Weekly on Moonbase
bObjectiveIsValidForMap[2] = 0; // Use the laser trap to kill 20 Zeds on Moonbase
bObjectiveIsValidForMap[3] = 0; // Kill 300 Zeds while jumping in the air on Moonbase
bObjectiveIsValidForMap[4] = 0; // Complete wave 15 on Endless Hard or higher difficulty on Moonbase
if (CapsMapName == "KF-MOONBASE")
{
bObjectiveIsValidForMap[1] = 1;
bObjectiveIsValidForMap[2] = 1;
bObjectiveIsValidForMap[3] = 1;
bObjectiveIsValidForMap[4] = 1;
}
SetSeasonalEventStatsMax(ZedsStompRequired, 0, LaserKillsRequired, JumpKillsRequired, 0);
}
private event GrantEventItems()
{
if (Outer.IsEventObjectiveComplete(0) &&
Outer.IsEventObjectiveComplete(1) &&
Outer.IsEventObjectiveComplete(2) &&
Outer.IsEventObjectiveComplete(3) &&
Outer.IsEventObjectiveComplete(4))
{
// @TODO: Set Proper Reward ID
//
GrantEventItem(8844);
}
}
simulated event OnGameWon(class<GameInfo> GameClass, int Difficulty, int GameLength, bool bCoOp)
{
// Moonbase weekly
if (bObjectiveIsValidForMap[1] != 0)
{
if (GameClass == class'KFGameInfo_WeeklySurvival')
{
FinishedObjective(SEI_Summer, 1);
}
}
}
simulated function OnZedKilled(class<KFPawn_Monster> MonsterClass, int Difficulty, class<DamageType> DT)
{
local int ObjIdx;
local KFPlayerController KFPC;
local KFPawn_Human KFP;
// Laser Kills
ObjIdx = 2;
if (bObjectiveIsValidForMap[ObjIdx] != 0)
{
if (ClassIsChildOf(DT, class'KFDT_EMPTrap'))
{
IncrementSeasonalEventStat(ObjIdx, 1);
if (Outer.GetSeasonalEventStatValue(ObjIdx) >= LaserKillsRequired)
{
FinishedObjective(SEI_SUMMER, ObjIdx);
}
}
}
ObjIdx = 3;
if (bObjectiveIsValidForMap[ObjIdx] != 0)
{
KFPC = Outer.MyKFPC;
if (KFPC != none)
{
KFP = KFPawn_Human(KFPC.Pawn);
if (KFP != none && KFP.Physics == PHYS_Falling)
{
IncrementSeasonalEventStat(ObjIdx, 1);
if (Outer.GetSeasonalEventStatValue(ObjIdx) >= JumpKillsRequired)
{
FinishedObjective(SEI_SUMMER, ObjIdx);
}
}
}
}
}
simulated function OnHitGiven(class<DamageType> DT)
{
local int ObjIdx;
ObjIdx = 0;
// Stomps
if (ClassIsChildOf(DT, class'DmgType_Crushed'))
{
IncrementSeasonalEventStat(ObjIdx, 1);
if (Outer.GetSeasonalEventStatValue(ObjIdx) >= ZedsStompRequired)
{
FinishedObjective(SEI_SUMMER, ObjIdx);
}
}
}
simulated event OnWaveCompleted(class<GameInfo> GameClass, int Difficulty, int WaveNum)
{
local int ObjIdx;
// Waves in Endless hard
ObjIdx = 4;
if (bObjectiveIsValidForMap[ObjIdx] != 0)
{
if (WaveNum >= EndlessWaveRequired && GameClass == class'KFGameInfo_Endless' && Difficulty >= `DIFFICULTY_HARD)
{
FinishedObjective(SEI_Summer, ObjIdx);
}
}
}
defaultproperties
{
ZedsStompRequired=50
LaserKillsRequired=20
JumpKillsRequired=300
EndlessWaveRequired=15
}

View File

@ -0,0 +1,231 @@
//=============================================================================
// KFWeapAttach_FAMAS
//=============================================================================
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeapAttach_FAMAS extends KFWeaponAttachment;
const SecondaryFireAnim = 'Shoot_Secondary';
const SecondaryFireIronAnim = 'Shoot_Secondary_Iron';
const SecondaryFireAnimLast = 'Shoot_Secondary_Last';
const SecondaryFireIronAnimLast = 'Shoot_Secondary_Iron_Last';
const SecondaryFireBodyAnim = 'ADD_Shoot_Secondary';
const SecondaryFireBodyAnimCH = 'ADD_Shoot_Secondary_CH';
const SecondaryFireBodyAnimIron = 'ADD_Shoot_Secondary_Iron';
const SecondaryReloadAnimEmpty = 'Reload_Secondary_Empty';
const SecondaryReloadAnimHalf = 'Reload_Secondary_Half';
const SecondaryReloadAnimEliteEmpty = 'Reload_Secondary_Elite_Empty';
const SecondaryReloadAnimEliteHalf = 'Reload_Secondary_Elite_Half';
const ShotgunMuzzleSocket = 'ShotgunMuzzleFlash';
var protected transient KFMuzzleFlash ShotgunMuzzleFlash;
/** Play a 3rd person reload animation */
simulated function PlayReloadMagazineAnim(EWeaponState NewWeaponState, KFPawn P)
{
local name AnimName;
if(NewWeaponState == WEP_ReloadSecondary || NewWeaponState == WEP_ReloadSecondary_Elite)
{
switch (NewWeaponState)
{
case WEP_ReloadSecondary:
AnimName = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryReloadAnimEmpty : SecondaryReloadAnimHalf;
break;
case WEP_ReloadSecondary_Elite:
AnimName = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryReloadAnimEliteEmpty : SecondaryReloadAnimEliteHalf;
break;
}
PlayCharacterMeshAnim(P, AnimName, true);
}
else
{
Super.PlayReloadMagazineAnim(NewWeaponState, P);
}
}
simulated function CauseMuzzleFlash(byte FiringMode)
{
if ( FiringMode == 1 ) // AltFire
{
if (ShotgunMuzzleFlash == None)
{
AttachMuzzleFlash();
}
if (ShotgunMuzzleFlash != None )
{
ShotgunMuzzleFlash.CauseMuzzleFlash(FiringMode);
if ( ShotgunMuzzleFlash.bAutoActivateShellEject )
{
ShotgunMuzzleFlash.CauseShellEject();
}
}
}
else
{
Super.CauseMuzzleFlash(FiringMode);
}
}
/** Added second weapon */
simulated function AttachMuzzleFlash()
{
Super.AttachMuzzleFlash();
if ( WeapMesh != none && ShotgunMuzzleFlash == None )
{
ShotgunMuzzleFlash = new(self) Class'KFMuzzleFlash'(class'KFWeap_AssaultRifle_FAMAS'.default.ShotgunMuzzleFlashTemplate);
ShotgunMuzzleFlash.AttachMuzzleFlash(WeapMesh, ShotgunMuzzleSocket,);
}
}
/** Plays fire animation on weapon mesh */
simulated function PlayFireAnim(KFPawn P)
{
local float Duration;
local name Anim;
local KFPawn OwnerPawn;
OwnerPawn = KFPawn(Owner);
if ( Instigator.bIsWalking ) // IronSight anims
{
if (OwnerPawn.FiringMode == 0) // DEFAULT FIRE MODE (Rifle)
{
Anim = WeaponIronFireAnim;
}
else if (OwnerPawn.FiringMode == 1) // ALT FIRE MODE (Shotgun)
{
// Anim = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryFireIronAnimLast : SecondaryFireIronAnim;
Anim = SecondaryFireIronAnim;
}
}
else // Normal anims
{
if (Pawn(Owner).FiringMode == 0) // DEFAULT FIRE MODE (Rifle)
{
Anim = WeaponFireAnim;
}
else if (Pawn(Owner).FiringMode == 1) // ALT FIRE MODE (Shotgun)
{
// Anim = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryFireAnimLast : SecondaryFireAnim;
Anim = SecondaryFireAnim;
}
}
Duration = WeapMesh.GetAnimLength( Anim );
WeapMesh.PlayAnim( Anim, Duration / ThirdPersonAnimRate,, true );
}
simulated function bool ThirdPersonFireEffects( vector HitLocation, KFPawn P, byte ThirdPersonAnimRateByte )
{
local EAnimSlotStance AnimType;
if (P.FiringMode == 1) // AltFire
{
SpawnTracer(GetAltMuzzleLocation(), HitLocation);
}
else
{
SpawnTracer(GetMuzzleLocation(), HitLocation);
}
// Effects below this point are culled based on visibility and distance
if ( !ActorEffectIsRelevant(P, false, MaxFireEffectDistance) )
{
return false;
}
DecodeThirdPersonAnimRate( ThirdPersonAnimRateByte );
// Weapon shoot anims
if( !bWeapMeshIsPawnMesh )
{
PlayFireAnim(P);
}
if( P.IsDoingSpecialMove() && P.SpecialMoves[P.SpecialMove].bAllowFireAnims )
{
AnimType = EAS_Additive;
}
else
{
AnimType = EAS_FullBody;
}
// Character shoot anims
if ( !P.IsDoingSpecialMove() || AnimType == EAS_Additive )
{
PlayPawnFireAnim( P, AnimType );
// interrupt other weapon action anims (e.g. Reload)
if( !P.IsDoingSpecialMove() )
{
P.StopBodyAnim(P.bIsCrouched ? EAS_CH_UpperBody : EAS_UpperBody, 0.1f);
}
if ( OnWeaponStateChanged != None )
{
OnWeaponStateChanged(true);
}
}
CauseMuzzleFlash(P.FiringMode);
return true;
}
/** Plays fire animation on pawn */
simulated function PlayPawnFireAnim( KFPawn P, EAnimSlotStance AnimType )
{
if (P.FiringMode == 0)
{
super.PlayPawnFireAnim(P, AnimType);
}
else if (P.FiringMode == 1)
{
if ( P.bIsCrouched )
{
P.PlayBodyAnim(SecondaryFireBodyAnimCH, AnimType, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime);
}
else if ( P.bIsWalking )
{
P.PlayBodyAnim(SecondaryFireBodyAnimIron, AnimType, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime);
}
else
{
P.PlayBodyAnim(SecondaryFireBodyAnim, AnimType, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime);
}
}
}
simulated function vector GetAltMuzzleLocation(optional byte MuzzleID)
{
local vector SocketLocation;
if (ShotgunMuzzleFlash == None && MuzzleFlashTemplate != None)
{
AttachMuzzleFlash();
}
if( ShotgunMuzzleFlash != none )
{
WeapMesh.GetSocketWorldLocationAndRotation(ShotgunMuzzleFlash.GetSocketName(), SocketLocation);
return SocketLocation;
}
return Super.GetMuzzleLocation(MuzzleID);
}
defaultproperties
{
}

View File

@ -0,0 +1,102 @@
//=============================================================================
// KFWeapAttach_HRG_BarrierRifle
//=============================================================================
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeapAttach_HRG_BarrierRifle extends KFWeaponAttachment;
`define BARRIERRIFLE_MIC_SHIELD_INDEX 0
/** Indicates wheter we are activating/deactivating the shield fx */
var protected transient bool bActivatingShield;
var protected transient float FXDelta;
var protected transient float ShieldFXDuration;
var protected transient float OverlayDelta;
var protected transient float OverlayMax;
var protected transient float OverlayMin;
var protected transient float ShieldBlockVFXDuration;
simulated event PreBeginPlay()
{
Super.PreBeginPlay();
if ( WorldInfo.NetMode == NM_DedicatedServer )
{
return;
}
ShieldFXDuration = class'KFWeap_HRG_BarrierRifle'.default.ShieldFXDuration;
OverlayMax = class'KFWeap_HRG_BarrierRifle'.default.RedOverlayMax;
OverlayMin = class'KFWeap_HRG_BarrierRifle'.default.RedOverlayMin;
ShieldBlockVFXDuration = class'KFWeap_HRG_BarrierRifle'.default.ShieldBlockVFXDuration;
UpdateShieldFXValue(0.0f);
}
simulated function UpdateShieldFXValue(float Value)
{
if ( WeaponMIC == None && WeapMesh != None )
{
WeaponMIC = WeapMesh.CreateAndSetMaterialInstanceConstant(`BARRIERRIFLE_MIC_SHIELD_INDEX);
}
WeaponMIC.SetScalarParameterValue('Opacity', Value);
}
unreliable client function SetShieldActive(bool bActive)
{
bActivatingShield = bActive;
}
/** Special event added for weap attachments. Free for use */
function OnSpecialEvent(int Arg)
{
if (Arg < 2)
{
SetShieldActive(Arg == 1 ? True : False);
}
else if (Arg == 3)
{
UpdateShieldBlockVFX(OverlayMax);
OverlayDelta = OverlayMax;
}
}
simulated function UpdateShieldBlockVFX(float Value)
{
if ( WeaponMIC == None && WeapMesh != None )
{
WeaponMIC = WeapMesh.CreateAndSetMaterialInstanceConstant(`BARRIERRIFLE_MIC_SHIELD_INDEX);
}
WeaponMIC.SetScalarParameterValue('RedOverlay', Value);
}
simulated event Tick(float DeltaTime)
{
// Update Shield visuals
if (bActivatingShield && FXDelta < class'KFWeap_HRG_BarrierRifle'.default.ShieldFXDuration)
{
FXDelta = FMin(FXDelta + DeltaTime, ShieldFXDuration);
UpdateShieldFXValue(FXDelta / ShieldFXDuration);
}
else if (!bActivatingShield && FXDelta > 0.0f)
{
FXDelta = FMax(FXDelta - DeltaTime, 0.0f);
UpdateShieldFXValue(FXDelta / ShieldFXDuration);
}
if (OverlayDelta > 0.0f)
{
OverlayDelta = FMax(OverlayDelta - DeltaTime, OverlayMin);
UpdateShieldBlockVFX(OverlayMax * (OverlayDelta / ShieldBlockVFXDuration));
}
}
defaultproperties
{
OverlayDelta=0.0f
}

View File

@ -0,0 +1,142 @@
//=============================================================================
// KFWeapAttach_HRG_BlastBrawlers
//=============================================================================
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeapAttach_HRG_BlastBrawlers extends KFWeapAttach_DualBase;
var protected transient bool bUsingLeftWeapon;
var protected transient name ReloadAnimName;
var protected transient float ReloadAnimRateMod;
/** Overrides to prevent weapon animation */
simulated function PlayWeaponFireAnim();
/** Caching reload anim name */
simulated event PreBeginPlay()
{
Super.PreBeginPlay();
ReloadAnimName = class'KFWeap_HRG_BlastBrawlers'.default.ReloadAnimation;
ReloadAnimRateMod = class'KFWeap_HRG_BlastBrawlers'.default.ReloadAnimRateModifier;
}
/** Overriding to avoid interrupting meleen anims with fire anims */
simulated function bool ThirdPersonFireEffects( vector HitLocation, KFPawn P, byte ThirdPersonAnimRateByte )
{
SpawnTracer(GetMuzzleLocation(), HitLocation);
// Effects below this point are culled based on visibility and distance
if ( !ActorEffectIsRelevant(P, false, MaxFireEffectDistance) )
{
return false;
}
CauseMuzzleFlash(P.FiringMode);
P.LastWeaponFireTime = -1.f;
return true;
}
simulated function vector GetMuzzleLocation(optional byte MuzzleID)
{
local vector SocketLocation;
if ( bUsingLeftWeapon)
{
if (LeftMuzzleFlash == None && MuzzleFlashTemplate != None)
{
AttachMuzzleFlash();
}
if( LeftMuzzleFlash != none )
{
LeftWeapMesh.GetSocketWorldLocationAndRotation(LeftMuzzleFlash.GetSocketName(), SocketLocation);
return SocketLocation;
}
}
return Super.GetMuzzleLocation(MuzzleID);
}
/** Added second weapon */
simulated function CauseMuzzleFlash(byte FiringMode)
{
if ( bUsingLeftWeapon )
{
if (LeftMuzzleFlash == None && MuzzleFlashTemplate != None)
{
AttachMuzzleFlash();
}
if (LeftMuzzleFlash != None )
{
LeftMuzzleFlash.CauseMuzzleFlash(FiringMode);
if ( LeftMuzzleFlash.bAutoActivateShellEject )
{
LeftMuzzleFlash.CauseShellEject();
}
}
}
else
{
Super.CauseMuzzleFlash(FiringMode);
bUsingLeftWeapon = true;
}
}
simulated function UpdateThirdPersonWeaponAction(EWeaponState NewWeaponState, KFPawn P, byte ThirdPersonAnimRateByte )
{
// Reset
bUsingLeftWeapon=false;
super.UpdateThirdPersonWeaponAction(NewWeaponState, P, ThirdPersonAnimRateByte);
}
simulated function PlayReloadMagazineAnim(EWeaponState NewWeaponState, KFPawn P)
{
PlayCharacterMeshAnim(P, ReloadAnimNAme, true);
}
simulated function PlayWeaponMeshAnim(name AnimName, AnimNodeSlot SyncNode, bool bLoop)
{
local float Duration;
/** Only reload animation could be played */
if ( !IsAnimationValid(AnimName) )
return;
// Weapon shoot anims
if( !bWeapMeshIsPawnMesh )
{
Duration = WeapMesh.GetAnimLength(AnimName);
if (AnimName == ReloadAnimName)
{
Duration *= ReloadAnimRateMod;
}
WeapMesh.PlayAnim(AnimName, Duration / ThirdPersonAnimRate, bLoop);
// syncronize this with the character anim
if ( SyncNode != None )
{
bSynchronizeWeaponAnim = true;
SyncPawnNode = SyncNode;
SyncAnimName = AnimName;
bSyncAnimCheckRelevance = false;
}
}
}
simulated function bool IsAnimationValid(name AnimName)
{
return AnimName == ReloadAnimName;
}
defaultproperties
{
bUsingLeftWeapon=false
}

View File

@ -0,0 +1,682 @@
//=============================================================================
// KFWeap_AssaultRifle_FAMAS
//=============================================================================
// FAMAS assault rifle with an extra of shotgun. Better than in MGS!
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeap_AssaultRifle_FAMAS extends KFWeap_ScopedBase;
var (Positioning) vector SecondaryFireOffset;
const SecondaryFireAnim = 'Shoot_Secondary';
const SecondaryFireIronAnim = 'Shoot_Secondary_Iron';
const SecondaryFireAnimLast = 'Shoot_Secondary_Last';
const SecondaryFireIronAnimLast = 'Shoot_Secondary_Iron_Last';
const SecondaryReloadAnimEmpty = 'Reload_Secondary_Empty';
const SecondaryReloadAnimHalf = 'Reload_Secondary_Half';
const SecondaryReloadAnimEliteEmpty = 'Reload_Secondary_Elite_Empty';
const SecondaryReloadAnimEliteHalf = 'Reload_Secondary_Elite_Half';
const ShotgunMuzzleSocket = 'ShotgunMuzzleFlash';
/** Animation to play when the weapon is fired in burst mode with 2 rounds left */
var(Animations) const editconst name BurstFire2RdAnim;
var(Animations) const editconst name BurstFire2RdSightedAnim;
/** Animation to play when the weapon is fired in burst fire mode for 3 rounds*/
var(Animations) const editconst name BurstFire3RdAnim;
var(Animations) const editconst name BurstFire3RdSightedAnim;
var transient KFMuzzleFlash ShotgunMuzzleFlash;
var() KFMuzzleFlash ShotgunMuzzleFlashTemplate;
// Used on the server to keep track of grenades
var int ServerTotalAltAmmo;
var transient bool bCanceledAltAutoReload;
var transient int BurstAmountBegin;
var protected const float AltFireRecoilScale;
static simulated event EFilterTypeUI GetTraderFilter()
{
return FT_Assault;
}
static simulated event EFilterTypeUI GetAltTraderFilter()
{
return FT_Explosive;
}
/** Instead of switch fire mode use as immediate alt fire */
simulated function AltFireMode()
{
if ( !Instigator.IsLocallyControlled() )
{
return;
}
if (bCanceledAltAutoReload)
{
bCanceledAltAutoReload = false;
TryToAltReload(true);
return;
}
// StartFire - StopFire called from KFPlayerInput
StartFire(ALTFIRE_FIREMODE);
}
simulated function BeginFire( Byte FireModeNum )
{
local bool bStoredAutoReload;
// We are trying to reload the weapon but the primary ammo in already at full capacity
if ( FireModeNum == RELOAD_FIREMODE && !CanReload() )
{
// Store the current state of bCanceledAltAutoReload in case its not possible to do the reload
bStoredAutoReload = bCanceledAltAutoReload;
bCanceledAltAutoReload = false;
if(CanAltAutoReload(false))
{
TryToAltReload(false);
return;
}
bCanceledAltAutoReload = bStoredAutoReload;
}
super.BeginFire( FireModeNum );
}
/**
* Initializes ammo counts, when weapon is spawned.
*/
function InitializeAmmo()
{
Super.InitializeAmmo();
// Add Secondary ammo to our secondary spare ammo count both of these are important, in order to allow dropping the weapon to function properly.
SpareAmmoCount[1] = Min(SpareAmmoCount[1] + InitialSpareMags[1] * default.MagazineCapacity[1], GetMaxAmmoAmount(1) - AmmoCount[1]);
ServerTotalAltAmmo += SpareAmmoCount[1];
// Make sure the server doesn't get extra shots on listen servers.
if(Role == ROLE_Authority && !Instigator.IsLocallyControlled())
{
ServerTotalAltAmmo += AmmoCount[1];
}
}
/**
* @see Weapon::ConsumeAmmo
*/
simulated function ConsumeAmmo( byte FireModeNum )
{
local byte AmmoType;
local bool bNoInfiniteAmmo;
local int OldAmmoCount;
if(UsesSecondaryAmmo() && FireModeNum == ALTFIRE_FIREMODE && Role == ROLE_Authority && !Instigator.IsLocallyControlled())
{
AmmoType = GetAmmoType(FireModeNum);
OldAmmoCount = AmmoCount[AmmoType];
Super.ConsumeAmmo(FireModeNum);
bNoInfiniteAmmo = (OldAmmoCount - AmmoCount[AmmoType]) > 0 || AmmoCount[AmmoType] == 0;
if ( bNoInfiniteAmmo )
{
ServerTotalAltAmmo--;
}
}
else
{
Super.ConsumeAmmo(FireModeNum);
}
}
/** Make sure user can't fire infinitely if they cheat to get infinite ammo locally. */
simulated event bool HasAmmo( byte FireModeNum, optional int Amount=1 )
{
local byte AmmoType;
AmmoType = GetAmmoType(FireModeNum);
if(AmmoType == 1 && Role == ROLE_Authority && UsesSecondaryAmmo() && !Instigator.IsLocallyControlled())
{
if(ServerTotalAltAmmo <= 0)
{
return false;
}
}
return Super.HasAmmo(FireModeNum, Amount );
}
/**
* Overridden so any grenades added will go to the spare ammo and no the clip.
*/
function int AddSecondaryAmmo(int Amount)
{
local int OldAmmo;
// If we can't accept spare ammo, then abort
if( !CanRefillSecondaryAmmo() )
{
return 0;
}
if(Role == ROLE_Authority && !Instigator.IsLocallyControlled())
{
OldAmmo = ServerTotalAltAmmo;
ServerTotalAltAmmo = Min(ServerTotalAltAmmo + Amount, GetMaxAmmoAmount(1));
ClientGiveSecondaryAmmo(Amount);
return ServerTotalAltAmmo - OldAmmo;
}
else
{
OldAmmo = SpareAmmoCount[1];
ClientGiveSecondaryAmmo(Amount);
return SpareAmmoCount[1] - OldAmmo;
}
}
/** Give client specified amount of ammo (used player picks up ammo on the server) */
reliable client function ClientGiveSecondaryAmmo(byte Amount)
{
SpareAmmoCount[1] = Min(SpareAmmoCount[1] + Amount, GetMaxAmmoAmount(1) - AmmoCount[1]);
TryToAltReload(true);
}
function SetOriginalValuesFromPickup( KFWeapon PickedUpWeapon )
{
local KFWeap_AssaultRifle_FAMAS Weap;
Super.SetOriginalValuesFromPickup(PickedUpWeapon);
if(Role == ROLE_Authority && !Instigator.IsLocallyControlled())
{
Weap = KFWeap_AssaultRifle_FAMAS(PickedUpWeapon);
ServerTotalAltAmmo = Weap.ServerTotalAltAmmo;
SpareAmmoCount[1] = ServerTotalAltAmmo - AmmoCount[1];
}
else
{
// If we're locally controlled, don't bother using ServerTotalAltAmmo.
SpareAmmoCount[1] = PickedUpWeapon.SpareAmmoCount[1];
}
}
simulated state WeaponBurstFiring
{
simulated event BeginState(Name PreviousStateName)
{
BurstAmountBegin = GetBurstAmount();
Super.BeginState(PreviousStateName);
}
simulated function name GetWeaponFireAnim(byte FireModeNum)
{
// only do one burst animation instead of a burst animation per shot
// since burst amount gets reduced after each shot, this will only play the one animation based on the number of shots in the burst fire
if (BurstAmount == BurstAmountBegin)
{
if (BurstAmount == 3)
{
if (bUsingSights)
{
return BurstFire3RdSightedAnim;
}
return BurstFire3RdAnim;
}
else if (BurstAmount == 2)
{
if (bUsingSights)
{
return BurstFire2RdSightedAnim;
}
return BurstFire2RdAnim;
}
else
{
return super.GetWeaponFireAnim(FireModeNum);
}
}
// will not play any animation
return '';
}
}
simulated state FiringSecondaryState extends WeaponFiring
{
// Overriden to not call FireAmmunition right at the start of the state
simulated event BeginState( Name PreviousStateName )
{
Super.BeginState(PreviousStateName);
NotifyBeginState();
}
simulated function EndState(Name NextStateName)
{
Super.EndState(NextStateName);
NotifyEndState();
}
/**
* This function returns the world location for spawning the visual effects
* Overridden to use a special offset for using the shotgun
*/
simulated event vector GetMuzzleLoc()
{
local vector MuzzleLocation;
// swap fireoffset temporarily
FireOffset = SecondaryFireOffset;
MuzzleLocation = Global.GetMuzzleLoc();
FireOffset = default.FireOffset;
return MuzzleLocation;
}
/** Get whether we should play the reload anim as well or not */
simulated function name GetWeaponFireAnim(byte FireModeNum)
{
if (AmmoCount[FireModeNum] > 0)
{
return bUsingSights ? SecondaryFireIronAnim : SecondaryFireAnim;
}
return bUsingSights ? SecondaryFireIronAnimLast : SecondaryFireAnimLast;
}
}
/**
* Don't allow secondary fire to make a primary fire shell particle come out of the gun.
*/
simulated function CauseMuzzleFlash(byte FireModeNum)
{
if(FireModeNum == ALTFIRE_FIREMODE)
{
if (ShotgunMuzzleFlash == None)
{
AttachMuzzleFlash();
}
if (ShotgunMuzzleFlash != none)
{
ShotgunMuzzleFlash.CauseMuzzleFlash(FireModeNum);
}
if ( ShotgunMuzzleFlash.bAutoActivateShellEject )
{
ShotgunMuzzleFlash.CauseShellEject();
SetShellEjectsToForeground();
}
}
else
{
Super.CauseMuzzleFlash(FireModeNum);
}
}
simulated function AttachMuzzleFlash()
{
super.AttachMuzzleFlash();
if ( MySkelMesh != none )
{
if (ShotgunMuzzleFlashTemplate != None)
{
ShotgunMuzzleFlash = new(self) Class'KFMuzzleFlash'(ShotgunMuzzleFlashTemplate);
ShotgunMuzzleFlash.AttachMuzzleFlash(MySkelMesh, ShotgunMuzzleSocket,);
}
}
}
/*********************************************************************************************
* State Reloading
* This is the default Reloading State. It's performed on both the client and the server.
*********************************************************************************************/
/** Do not allow alternate fire to tell the weapon to reload. Alt reload occurs in a separate codepath */
simulated function bool ShouldAutoReload(byte FireModeNum)
{
if(FireModeNum == ALTFIRE_FIREMODE)
{
return false;
}
return Super.ShouldAutoReload(FireModeNum);
}
/** Called on local player when reload starts and replicated to server */
simulated function SendToAltReload()
{
ReloadAmountLeft = MagazineCapacity[1] - AmmoCount[1];
GotoState('AltReloading');
if ( Role < ROLE_Authority )
{
ServerSendToAltReload();
}
}
/** Called from client when reload starts */
reliable server function ServerSendToAltReload()
{
ReloadAmountLeft = MagazineCapacity[1] - AmmoCount[1];
GotoState('AltReloading');
}
/**
* State Reloading
* State the weapon is in when it is being reloaded (current magazine replaced with a new one, related animations and effects played).
*/
simulated state AltReloading extends Reloading
{
ignores ForceReload, ShouldAutoReload, AllowSprinting;
simulated function byte GetWeaponStateId()
{
local KFPerk Perk;
local bool bTacticalReload;
Perk = GetPerk();
bTacticalReload = (Perk != None && Perk.GetUsingTactialReload(self));
return (bTacticalReload ? WEP_ReloadSecondary_Elite : WEP_ReloadSecondary);
}
simulated event BeginState(Name PreviousStateName)
{
super.BeginState(PreviousStateName);
bCanceledAltAutoReload = true;
}
// Overridding super so we don't call functions we don't want to call.
simulated function EndState(Name NextStateName)
{
ClearZedTimeResist();
ClearTimer(nameof(ReloadStatusTimer));
ClearTimer(nameof(ReloadAmmoTimer));
CheckBoltLockPostReload();
NotifyEndState();
`DialogManager.PlayAmmoDialog( KFPawn(Instigator), float(SpareAmmoCount[1]) / float(GetMaxAmmoAmount(1)) );
}
// Overridding super so when this reload is called directly after normal reload state there
// are not complications resulting from back to back reloads.
simulated event ReplicatedEvent(name VarName)
{
Global.ReplicatedEvent(Varname);
}
/** Make sure we can inturrupt secondary reload with anything. */
simulated function bool CanOverrideMagReload(byte FireModeNum)
{
return false;
}
/** Returns animation to play based on reload type and status */
simulated function name GetReloadAnimName( bool bTacticalReload )
{
// magazine relaod
if ( AmmoCount[1] > 0 )
{
return (bTacticalReload) ? SecondaryReloadAnimEliteHalf : SecondaryReloadAnimHalf;
}
else
{
return (bTacticalReload) ? SecondaryReloadAnimEliteEmpty : SecondaryReloadAnimEmpty;
}
}
simulated function PerformReload(optional byte FireModeNum)
{
Global.PerformReload(ALTFIRE_FIREMODE);
if(Instigator.IsLocallyControlled() && Role < ROLE_Authority)
{
ServerSetAltAmmoCount(AmmoCount[1]);
}
bCanceledAltAutoReload = false;
}
simulated function EReloadStatus GetNextReloadStatus(optional byte FireModeNum)
{
return Global.GetNextReloadStatus(ALTFIRE_FIREMODE);
}
}
reliable server function ServerSetAltAmmoCount(byte Amount)
{
AmmoCount[1] = Amount;
}
/** Allow reloads for primary weapon to be interupted by firing secondary weapon. */
simulated function bool CanOverrideMagReload(byte FireModeNum)
{
if(FireModeNum == ALTFIRE_FIREMODE)
{
return true;
}
return Super.CanOverrideMagReload(FireModeNum);
}
/*********************************************************************************************
* State Active
* Try to get weapon to automatically reload secondary fire types when it can.
*********************************************************************************************/
simulated state Active
{
/** Initialize the weapon as being active and ready to go. */
simulated event BeginState(Name PreviousStateName)
{
// do this last so the above code happens before any state changes
Super.BeginState(PreviousStateName);
// If nothing happened, try to reload
TryToAltReload(true);
}
}
/** Network: Local Player */
simulated function bool CanAltAutoReload(bool bIsAuto)
{
if ( !Instigator.IsLocallyControlled() )
{
return false;
}
if(!UsesSecondaryAmmo())
{
return false;
}
// If the weapon wants to fire its primary weapon, and it can fire, do not allow weapon to automatically alt reload
if(PendingFire(DEFAULT_FIREMODE) && HasAmmo(DEFAULT_FIREMODE))
{
return false;
}
if(!CanReload(ALTFIRE_FIREMODE))
{
return false;
}
if (bIsAuto && AmmoCount[1] > 0)
{
return false;
}
if (bCanceledAltAutoReload)
{
return false;
}
return true;
}
simulated function TryToAltReload(bool bIsAuto)
{
if ((IsInState('Active') || IsInState('WeaponSprinting')) && CanAltAutoReload(bIsAuto))
{
SendToAltReload();
}
}
simulated function int GetSecondaryAmmoForHUD()
{
return AmmoCount[1];
}
simulated function int GetSecondarySpareAmmoForHUD()
{
return SpareAmmoCount[1];
}
simulated function ModifyRecoil( out float CurrentRecoilModifier )
{
if( CurrentFireMode == ALTFIRE_FIREMODE )
{
CurrentRecoilModifier *= AltFireRecoilScale;
}
super.ModifyRecoil( CurrentRecoilModifier );
}
defaultproperties
{
bCanRefillSecondaryAmmo = true;
// Content
PackageKey="Famas"
FirstPersonMeshName="wep_1p_famas_mesh.Wep_1stP_Famas_Rig"
FirstPersonAnimSetNames(0)="wep_1p_famas_anim.Wep_1stP_Famas_Anim"
PickupMeshName="WEP_3P_Famas_MESH.WEP_Famas_Pickup"
AttachmentArchetypeName="Wep_Famas_ARCH.Wep_Famas_3P"
MuzzleFlashTemplateName="wep_famas_arch.Wep_Famas_MuzzleFlash"
ShotgunMuzzleFlashTemplate=KFMuzzleFlash'wep_famas_arch.Wep_Famas_Shotgun_MuzzleFlash'
// Scope Render
// 2D scene capture
Begin Object Name=SceneCapture2DComponent0
TextureTarget=TextureRenderTarget2D'Wep_Mat_Lib.WEP_ScopeLense_Target'
FieldOfView=12.5 // "2.0X" = 25.0(our real world FOV determinant)/2.0
End Object
ScopedSensitivityMod = 8.0
ScopeLenseMICTemplate = MaterialInstanceConstant'WEP_1P_FNFAL_MAT.WEP_1P_FNFAL_Scope_MAT'
ScopeMICIndex = 2
// FOV
MeshFov=65
MeshIronSightFOV=60 //45
PlayerIronSightFOV=70
// Depth of field
DOF_BlendInSpeed=3.0
DOF_FG_FocalRadius=0
DOF_FG_MaxNearBlurSize=3.5
// Zooming/Position
PlayerViewOffset=(X=22.0,Y=9.f,Z=-2.f)
IronSightPosition=(X=0,Y=0,Z=0)
// Ammo
MagazineCapacity[0]=24
SpareAmmoCapacity[0]=240
InitialSpareMags[0]=3
bCanBeReloaded=true
bReloadFromMagazine=true
// Shotgun Ammo
MagazineCapacity[1]=6
SpareAmmoCapacity[1]=36 //42
InitialSpareMags[1]=1
// Recoil
maxRecoilPitch=100 //125 //200 //120
minRecoilPitch=75 //100 //150 //70
maxRecoilYaw=40 //80
minRecoilYaw=-40 //-80
RecoilRate=0.085
RecoilMaxYawLimit=500
RecoilMinYawLimit=65035
RecoilMaxPitchLimit=900
RecoilMinPitchLimit=65035
RecoilISMaxYawLimit=75
RecoilISMinYawLimit=65460
RecoilISMaxPitchLimit=375
RecoilISMinPitchLimit=65460
RecoilViewRotationScale=0.25
IronSightMeshFOVCompensationScale=1.7
HippedRecoilModifier=2.0 //1.5
// Inventory / Grouping
InventorySize=6
GroupPriority=80 //75
WeaponSelectTexture=Texture2D'WEP_UI_Famas_TEX.UI_WeaponSelect_Famas'
// DEFAULT_FIREMODE
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletBurst'
FiringStatesArray(DEFAULT_FIREMODE)=WeaponBurstFiring
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_InstantHit
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_AssaultRifle'
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_FAMAS_Rifle'
FireInterval(DEFAULT_FIREMODE)=+0.0667 // 900 RPM
InstantHitDamage(DEFAULT_FIREMODE)=35.0
Spread(DEFAULT_FIREMODE)=0.005 //0.0085
BurstAmount=3
BurstFire2RdAnim=Shoot_Burst2
BurstFire3RdAnim=Shoot_Burst
BurstFire2RdSightedAnim=Shoot_Burst2_Iron
BurstFire3RdSightedAnim=Shoot_Burst_Iron
FireOffset=(X=30,Y=4.5,Z=-5)
SecondaryFireOffset=(X=20.f,Y=4.5,Z=-7.f)
// ALT_FIREMODE
FireModeIconPaths(ALTFIRE_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_ShotgunSingle'
FiringStatesArray(ALTFIRE_FIREMODE)=FiringSecondaryState
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Projectile
WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_Bullet_Pellet'
InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Ballistic_FAMAS_Shotgun'
InstantHitDamage(ALTFIRE_FIREMODE)=25.0
PenetrationPower(DEFAULT_FIREMODE)=2.0
FireInterval(ALTFIRE_FIREMODE)=+1.2 //0.5 //0.7 //85 RPM
NumPellets(ALTFIRE_FIREMODE)=6
Spread(ALTFIRE_FIREMODE)=0.12 //0.07
SecondaryAmmoTexture=Texture2D'ui_firemodes_tex.UI_FireModeSelect_ShotgunSingle'
// BASH_FIREMODE
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_FAMAS'
InstantHitDamage(BASH_FIREMODE)=26
// Fire Effects
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_SA_AR15.Play_WEP_SA_AR15_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_SA_AR15.Play_WEP_SA_AR15_Fire_1P')
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_SA_AR15.Play_WEP_SA_AR15_Handling_DryFire'
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_SA_AA12.Play_WEP_SA_AA12_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_SA_AA12.Play_WEP_SA_AA12_Fire_1P')
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_SA_AA12.Play_WEP_SA_AA12_Handling_DryFire'
// Attachments
bHasIronSights=true
bHasFlashlight=false
AssociatedPerkClasses(0)=class'KFPerk_Commando'
AssociatedPerkClasses(1)=class'KFPerk_Support'
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.125f), (Stat=EWUS_Damage1, Scale=1.125f), (Stat=EWUS_Weight, Add=1)))
WeaponUpgrades[2]=(Stats=((Stat=EWUS_Damage0, Scale=1.25f), (Stat=EWUS_Damage1, Scale=1.25f), (Stat=EWUS_Weight, Add=2)))
bUsesSecondaryAmmoAltHUD=true
AltFireRecoilScale = 4.5 //4.0 //2.5
}

View File

@ -1142,7 +1142,7 @@ defaultproperties
BonesToLockOnEmpty=(RW_Magazine1, RW_BatteryContactLeft, RW_BatteryContactRight)
// Weapon Upgrade stat boosts
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.2f), (Stat=EWUS_Damage1, Scale=1.2f), (Stat=EWUS_Weight, Add=1)))
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.0f), (Stat=EWUS_Damage1, Scale=1.0f), (Stat=EWUS_Weight, Add=0)))
MuzzleFlashEffectL1=ParticleSystem'WEP_Laser_Cutter_EMIT.FX_Laser_Cutter_Beam_Muzzleflash_01'
MuzzleFlashEffectL2=ParticleSystem'WEP_Laser_Cutter_EMIT.FX_Laser_Cutter_Beam_Muzzleflash_02'

View File

@ -727,9 +727,9 @@ defaultproperties
// Ammo
MagazineCapacity[0]=1
SpareAmmoCapacity[0]=30
InitialSpareMags[0]=10
AmmoPickupScale[0]=3.0 // 3 arrows
SpareAmmoCapacity[0]=35 //30
InitialSpareMags[0]=11 //10
AmmoPickupScale[0]=4.0 //3.0
// Recoil
maxRecoilPitch=200

View File

@ -0,0 +1,731 @@
//=============================================================================
// 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 (Shield) AkBaseSoundObject 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()
{
PlaySoundBase(ShieldActivateSound.FirstPersonCue);
bActivatingShield = true;
bDeactivatingShield = false;
bNetDirty = true;
NotifyShieldActive(true);
SetTimer(FireInterval[ALTFIRE_FIREMODE], false, nameof(ShieldActivationCompleted));
}
simulated function DeactivateShield()
{
PlaySoundBase(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);
PlaySoundBase(ShieldEndSound);
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);
PlaySoundBase(ShieldEndSound);
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)
{
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_1P_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_1P_Shield_Off', FirstPersonCue=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Off')
ShieldEndSound=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)))
}

View File

@ -0,0 +1,482 @@
//=============================================================================
// KFWeap_HRG_BlastBrawlers
//=============================================================================
// Power gloves and shotgun, all in one.
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeap_HRG_BlastBrawlers extends KFWeap_Blunt_PowerGloves;
var name ReloadAnimation;
var float ReloadAnimRateModifier;
var float ReloadAnimRateModifierElite;
var protected transient bool bWaitingForSecondShot;
var protected transient int NumAttacks;
/** A muzzle flash instance for left weapon */
var KFMuzzleFlash LeftMuzzleFlash;
simulated event PreBeginPlay()
{
super.PreBeginPlay();
}
simulated function Shoot()
{
// LocalPlayer Only
if ( !Instigator.IsLocallyControlled() )
{
return;
}
if( Role < Role_Authority )
{
// if we're a client, synchronize server
ServerShoot();
}
ProcessShoot();
}
/**
Each attack shoots twice, once with the right and left fists.
Ammo is decremented after the second shot.
*/
reliable server function bool ServerShoot()
{
return ProcessShoot();
}
simulated function bool ProcessShoot()
{
// Shooting only happens when default firing
if(CurrentFireMode != DEFAULT_FIREMODE)
return false;
CustomFire();
if (!bWaitingForSecondShot)
{
// AmmoCount[DEFAULT_FIREMODE] = Max(AmmoCount[DEFAULT_FIREMODE] - 1, 0);
DecrementAmmo();
}
bWaitingForSecondShot = !bWaitingForSecondShot;
return true;
}
simulated function DecrementAmmo()
{
AmmoCount[DEFAULT_FIREMODE] = Max(AmmoCount[DEFAULT_FIREMODE] - 1, 0);
}
simulated state Active
{
/**
* Called from Weapon:Active.BeginState when HasAnyAmmo (which is overridden above) returns false.
*/
simulated function WeaponEmpty()
{
local int i;
// Copied from Weapon:Active.BeginState where HasAnyAmmo returns true.
// Basically, pretend the weapon isn't empty in this case.
for (i=0; i<GetPendingFireLength(); i++)
{
if (PendingFire(i))
{
BeginFire(i);
break;
}
}
}
}
static simulated event bool UsesAmmo()
{
return true;
}
simulated function CustomFire()
{
local byte CachedFireMode;
CachedFireMode = CurrentFireMode;
CurrentFireMode = CUSTOM_FIREMODE;
ProjectileFire();
// Let the accuracy tracking system know that we fired
HandleWeaponShotTaken(CurrentFireMode);
NotifyWeaponFired(CurrentFireMode);
// Play fire effects now (don't wait for WeaponFired to replicate)
PlayFireEffects(CurrentFireMode, vect(0, 0, 0));
CurrentFireMode = CachedFireMode;
}
/** Overriden for the Tight Choke perk */
simulated function KFProjectile SpawnAllProjectiles(class<KFProjectile> KFProjClass, vector RealStartLoc, vector AimDir)
{
local KFPerk InstigatorPerk;
if (CurrentFireMode == CUSTOM_FIREMODE)
{
InstigatorPerk = GetPerk();
if (InstigatorPerk != none)
{
Spread[CurrentFireMode] = default.Spread[CurrentFireMode] * InstigatorPerk.GetTightChokeModifier();
}
}
return super.SpawnAllProjectiles(KFProjClass, RealStartLoc, AimDir);
}
/** Override for not playing animations (even if noanimation is set it interrupts the melee ones.) */
simulated function PlayFireEffects( byte FireModeNum, optional vector HitLocation )
{
// If we have stopped the looping fire sound to play single fire sounds for zed time
// start the looping sound back up again when the time is back above zed time speed
if( FireModeNum < bLoopingFireSnd.Length && bLoopingFireSnd[FireModeNum] && !bPlayingLoopingFireSnd )
{
StartLoopingFireSound(FireModeNum);
}
PlayFiringSound(CurrentFireMode);
if( Instigator != none )
{
if( Instigator.IsLocallyControlled() )
{
if( Instigator.IsFirstPerson() )
{
// Start muzzle flash effect
CauseMuzzleFlash(FireModeNum);
}
ShakeView();
}
}
}
/**
* @see Weapon::StartFire
*/
simulated function StartFire(byte FireModeNum)
{
// can't start fire because it's in an uninterruptible state
if (StartFireDisabled)
{
return;
}
if (FireModeNum == DEFAULT_FIREMODE)
{
if(AmmoCount[DEFAULT_FIREMODE] > 0)
{
StartMeleeFire(FireModeNum, DIR_FORWARD, ATK_Normal);
}
else
{
super.StartFire(RELOAD_FIREMODE);
// If not cleared, it will loop the animation.
ClearPendingFire(RELOAD_FIREMODE);
}
return;
}
super.StartFire(FireModeNum);
}
/** Avoiding reload anim to interrupt combo */
simulated state MeleeChainAttacking
{
simulated function BeginState(Name PrevStateName)
{
local KFPerk InstigatorPerk;
if( CurrentFireMode == DEFAULT_FIREMODE )
{
StartFireDisabled = true;
bWaitingForSecondShot = false;
NumAttacks = 0;
}
InstigatorPerk = GetPerk();
if (InstigatorPerk != none)
{
SetZedTimeResist( InstigatorPerk.GetZedTimeModifier(self) );
}
super.BeginState( PrevStateName );
}
simulated function EndState(Name NextStateName)
{
super.EndState(NextStateName);
if( CurrentFireMode == DEFAULT_FIREMODE )
{
StartFireDisabled = false;
}
ClearZedTimeResist();
}
simulated function bool ShouldContinueMelee(optional int ChainCount)
{
if ( CurrentFireMode == DEFAULT_FIREMODE )
{
return false;
}
return super.ShouldContinueMelee(ChainCount);
}
}
/**
* 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');
}
}
}
/**
* 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( bWaitingForSecondShot )
{
if (MuzzleFlash != None )
{
// Not ejecting shells for this weapon.
MuzzleFlash.CauseMuzzleFlash(FireModeNum);
}
}
else
{
if( LeftMuzzleFlash != None )
{
// Not ejecting shells for this weapon.
LeftMuzzleFlash.CauseMuzzleFlash(FireModeNum);
}
}
}
/**
* 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 true if weapon can potentially be reloaded */
simulated function bool CanReload(optional byte FireModeNum)
{
if ( FiringStatesArray[RELOAD_FIREMODE] == 'WeaponUpkeep' )
{
return true;
}
if ( FireModeNum == CUSTOM_FIREMODE)
{
FireModeNum = DEFAULT_FIREMODE;
}
return Super.CanReload(FireModeNum);
}
simulated function name GetReloadAnimName( bool bTacticalReload )
{
return ReloadAnimation;
}
/** No diferent states */
simulated function EReloadStatus GetNextReloadStatus(optional byte FireModeNum)
{
switch ( ReloadStatus )
{
case RS_None: //drop
case RS_Reloading:
if ( HasSpareAmmo(FiremodeNum) && ReloadAmountLeft > 0 )
{
return RS_Reloading;
}
}
return RS_Complete;
}
/** Returns an anim rate scale for reloading */
simulated function float GetReloadRateScale()
{
local float Modifier;
Modifier = UseTacticalReload() ? ReloadAnimRateModifierElite : ReloadAnimRateModifier;
return super.GetReloadRateScale() * Modifier;
}
simulated function bool HasAnyAmmo()
{
return AmmoCount[0] != 0 && SpareAmmoCount[0] != 0;
}
defaultproperties
{
// Content
PackageKey="HRG_BlastBrawlers"
FirstPersonMeshName="WEP_1P_HRG_BlastBrawlers_MESH.WEP_1stP_HRG_Blast_Brawlers_Rig"
FirstPersonAnimSetNames(0)="WEP_1P_HRG_BlastBrawlers_ANIM.WEP_1P_HRG_BlastBrawlers_ANIM"
PickupMeshName="WEP_3P_HRG_BlastBrawlers_MESH.Wep_HRG_Blast_Brawlers_Pickup"
AttachmentArchetypeName="WEP_HRG_BlastBrawlers_ARCH.Wep_HRG_BlastBrawlers_3P"
MuzzleFlashTemplateName="WEP_HRG_BlastBrawlers_ARCH.Wep_HRG_BlastBrawler_MuzzleFlash"
Begin Object Class=KFMeleeHelperWeaponBlastBrawlers Name=MeleeHelper_0
MaxHitRange=230 //150 //190
// Override automatic hitbox creation (advanced)
HitboxChain.Add((BoneOffset=(Y=+3,Z=150)))
HitboxChain.Add((BoneOffset=(Y=-3,Z=130)))
HitboxChain.Add((BoneOffset=(Y=+3,Z=110)))
HitboxChain.Add((BoneOffset=(Y=-3,Z=90)))
HitboxChain.Add((BoneOffset=(Y=+3,Z=70)))
HitboxChain.Add((BoneOffset=(Y=-3,Z=50)))
HitboxChain.Add((BoneOffset=(Y=+3,Z=30)))
HitboxChain.Add((BoneOffset=(Z=10)))
HitboxChain.Add((BoneOffset=(Z=-10)))
WorldImpactEffects=KFImpactEffectInfo'FX_Impacts_ARCH.Blunted_melee_impact'
// modified combo sequences
bAllowMeleeToFracture=false
bUseDirectionalMelee=true
bHasChainAttacks=false
MeleeImpactCamShakeScale=0.035f //0.4
ChainSequence_F=()
ChainSequence_B=()
ChainSequence_L=()
ChainSequence_R=()
End Object
MeleeAttackHelper=MeleeHelper_0
// FOV
//MeshFOV=95
// Shotgun Ammo
MagazineCapacity[0]=4 //3
SpareAmmoCapacity[0]=36 //28
InitialSpareMags[0]=2
AmmoPickupScale[0]=1.5 //2.0
bCanBeReloaded=true
bReloadFromMagazine=true
bNoMagazine=false
// Zooming/Position
PlayerViewOffset=(X=20,Y=0,Z=0)
// Inventory
GroupPriority=110
InventorySize=9 //7
WeaponSelectTexture=Texture2D'WEP_UI_HRG_BlastBrawlers_TEX.UI_WeaponSelect_HRG_BlastBrawlers'
FireModeIconPaths(CUSTOM_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_ShotgunSingle'
FiringStatesArray(CUSTOM_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(CUSTOM_FIREMODE)=EWFT_Projectile
WeaponProjectiles(CUSTOM_FIREMODE)=class'KFProj_Bullet_BlastBrawlers'
FireInterval(CUSTOM_FIREMODE)=0.1f
InstantHitDamageTypes(CUSTOM_FIREMODE)=class'KFDT_Ballistic_BlastBrawlersShotgun'
InstantHitDamage(CUSTOM_FIREMODE)=36.0 //30.0
AmmoCost(CUSTOM_FIREMODE)=0
NumPellets(CUSTOM_FIREMODE)=5
Spread(CUSTOM_FIREMODE)=0.1 //0.15
WeaponFireSnd(CUSTOM_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_HRG_BlastBrawlers.Play_WEP_HRG_BlastBrawlers_Shoot_3P', FirstPersonCue=AkEvent'WW_WEP_HRG_BlastBrawlers.Play_WEP_HRG_BlastBrawlers_Shoot_1P')
InstantHitMomentum(CUSTOM_FIREMODE)=1.0
PenetrationDamageReductionCurve(CUSTOM_FIREMODE)=(Points=((InVal=0.f,OutVal=0.f),(InVal=1.f, OutVal=1.f)))
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_ShotgunSingle'
InstantHitDamage(DEFAULT_FIREMODE)=50
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Bludgeon_BlastBrawlers'
FireModeIconPaths(HEAVY_ATK_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BluntMelee'
InstantHitDamage(HEAVY_ATK_FIREMODE)=200 //175
InstantHitDamageTypes(HEAVY_ATK_FIREMODE)=class'KFDT_Bludgeon_BlastBrawlersHeavy'
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_BlastBrawlersBash'
InstantHitDamage(BASH_FIREMODE)=100
FiringStatesArray(RELOAD_FIREMODE)=Reloading
AssociatedPerkClasses(0)=class'KFPerk_Support'
// Block Sounds
BlockSound=AkEvent'WW_WEP_Bullet_Impacts.Play_Block_MEL_Crovel'
ParrySound=AkEvent'WW_WEP_Bullet_Impacts.Play_Parry_Metal'
ParryStrength=5
ParryDamageMitigationPercent=0.40
BlockDamageMitigation=0.40
bWaitingForSecondShot = false
NumAttacks = 0
bAllowClientAmmoTracking=false
ReloadAnimation = "Atk_B"
ReloadAnimRateModifier = 1.6f
ReloadAnimRateModifierElite = 1.0f; //0.5f;
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.125f), (Stat=EWUS_Damage1, Scale=1.125f), (Stat=EWUS_Damage2, Scale=1.125f), (Stat=EWUS_Weight, Add=1)))
}

View File

@ -42,7 +42,7 @@ simulated function ProcessInstantHitEx(byte FiringMode, ImpactInfo Impact, optio
defaultproperties
{
//Healing
HealAmount=20
HealAmount=25 //20
HealFullRechargeSeconds=10
// Inventory / Grouping
@ -84,7 +84,7 @@ defaultproperties
// Ammo
MagazineCapacity[0]=7
SpareAmmoCapacity[0]=98
SpareAmmoCapacity[0]=112 //98
InitialSpareMags[0]=4
bCanBeReloaded=true
bReloadFromMagazine=true
@ -119,7 +119,7 @@ defaultproperties
FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_InstantHit
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_Hemogoblin'
InstantHitDamage(DEFAULT_FIREMODE)=100.0
InstantHitDamage(DEFAULT_FIREMODE)=120.0 //100.0
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_Hemogoblin'
FireInterval(DEFAULT_FIREMODE)=0.25
PenetrationPower(DEFAULT_FIREMODE)=0.0 //2.0

View File

@ -0,0 +1,324 @@
//=============================================================================
// KFWeap_RocketLauncher_ThermiteBore
//=============================================================================
// Impale, burn, repeat
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeap_RocketLauncher_ThermiteBore extends KFWeap_GrenadeLauncher_Base;
/** List of spawned harpoons (will be detonated oldest to youngest) */
var array<KFProj_Rocket_ThermiteBore> DeployedHarpoons;
/** Same as DeployedHarpoons.Length, but replicated because harpoons are only tracked on server */
var int NumDeployedHarpoons;
/** Reduction for the amount of damage dealt to the weapon owner (including damage by the explosion) */
var float SelfDamageReductionValue;
var(Animations) const editconst name DetonateAnim;
var(Animations) const editconst name DetonateAnimLast;
var(Animations) const editconst name DetonateAnimIron;
var(Animations) const editconst name DetonateAnimIronLast;
replication
{
if( bNetDirty )
NumDeployedHarpoons;
}
/**
* Toggle between DEFAULT and ALTFIRE
*/
simulated function AltFireMode()
{
// skip super
if (!Instigator.IsLocallyControlled())
{
return;
}
StartFire(ALTFIRE_FIREMODE);
}
/** Overridded to add spawned charge to list of spawned charges */
simulated function Projectile ProjectileFire()
{
local Projectile P;
local KFProj_Rocket_ThermiteBore Harpoon;
P = super.ProjectileFire();
Harpoon = KFProj_Rocket_ThermiteBore(P);
if (Harpoon != none)
{
DeployedHarpoons.AddItem(Harpoon);
NumDeployedHarpoons = DeployedHarpoons.Length;
bForceNetUpdate = true;
}
return P;
}
/** Returns animation to play based on reload type and status */
simulated function name GetReloadAnimName(bool bTacticalReload)
{
// magazine relaod
if (AmmoCount[0] > 0)
{
return (bTacticalReload) ? ReloadNonEmptyMagEliteAnim : ReloadNonEmptyMagAnim;
}
else
{
return (bTacticalReload) ? ReloadEmptyMagEliteAnim : ReloadEmptyMagAnim;
}
}
function AdjustDamage(out int InDamage, class<DamageType> DamageType, Actor DamageCauser)
{
super.AdjustDamage(InDamage, DamageType, DamageCauser);
if (Instigator != none && DamageCauser != none && DamageCauser.Instigator == Instigator)
{
InDamage *= SelfDamageReductionValue;
}
}
/*********************************************************************************************
* State WeaponDetonating
* The weapon is in this state while detonating a charge
*********************************************************************************************/
simulated function GotoActiveState();
simulated state WeaponDetonating
{
ignores AllowSprinting;
simulated event BeginState( name PreviousStateName )
{
PrepareAndDetonate();
}
simulated function GotoActiveState()
{
GotoState('Active');
}
}
// GrenadeLaunchers determine ShouldPlayFireLast based on the spare ammo
// overriding to use the base KFWeapon version since that uses the current ammo in the mag
simulated function bool ShouldPlayFireLast(byte FireModeNum)
{
return Super(KFWeapon).ShouldPlayFireLast(FireModeNum);
}
simulated function PrepareAndDetonate()
{
local name SelectedAnim;
local float AnimDuration;
local bool bInSprintState;
// choose the detonate animation based on whether it is in ironsights and whether it is the last harpoon
if (bUsingSights)
{
SelectedAnim = ShouldPlayFireLast(DEFAULT_FIREMODE) ? DetonateAnimIronLast : DetonateAnimIron;
}
else
{
SelectedAnim = ShouldPlayFireLast(DEFAULT_FIREMODE) ? DetonateAnimLast : DetonateAnim;
}
AnimDuration = MySkelMesh.GetAnimLength(SelectedAnim);
bInSprintState = IsInState('WeaponSprinting');
if (WorldInfo.NetMode != NM_DedicatedServer)
{
if (bInSprintState)
{
AnimDuration *= 0.25f;
PlayAnimation(SelectedAnim, AnimDuration);
}
else
{
PlayAnimation(SelectedAnim);
}
}
if (Role == ROLE_Authority)
{
Detonate();
}
//AnimDuration value here representes the ALTFIRE FireInterval
AnimDuration = 0.75f; //1.f;
if (bInSprintState)
{
SetTimer(AnimDuration * 0.8f, false, nameof(PlaySprintStart));
}
else
{
SetTimer(AnimDuration * 0.5f, false, nameof(GotoActiveState));
}
}
/** Detonates all the harpoons */
simulated function Detonate()
{
local int i;
// auto switch weapon when out of ammo and after detonating the last deployed charge
if (Role == ROLE_Authority)
{
for (i = DeployedHarpoons.Length - 1; i >= 0; i--)
{
DeployedHarpoons[i].Detonate();
}
if (!HasAnyAmmo() && NumDeployedHarpoons == 0)
{
if (CanSwitchWeapons())
{
Instigator.Controller.ClientSwitchToBestWeapon(false);
}
}
}
}
/** Removes a charge from the list using either an index or an actor and updates NumDeployedHarpoons */
function RemoveDeployedHarpoon(optional int HarpoonIndex = INDEX_NONE, optional Actor HarpoonActor)
{
if (HarpoonIndex == INDEX_NONE)
{
if (HarpoonActor != none)
{
HarpoonIndex = DeployedHarpoons.Find(HarpoonActor);
}
}
if (HarpoonIndex != INDEX_NONE)
{
DeployedHarpoons.Remove(HarpoonIndex, 1);
NumDeployedHarpoons = DeployedHarpoons.Length;
bForceNetUpdate = true;
}
}
/** Allow reloads for primary weapon to be interupted by firing secondary weapon. */
simulated function bool CanOverrideMagReload(byte FireModeNum)
{
if(FireModeNum == ALTFIRE_FIREMODE)
{
return true;
}
return Super.CanOverrideMagReload(FireModeNum);
}
defaultproperties
{
// Content
PackageKey="Thermite"
FirstPersonMeshName="wep_1p_thermite_mesh.WEP_1stP_Thermite_Rig"
FirstPersonAnimSetNames(0)="wep_1p_thermite_anim.WEP_1stP_Thermite_Anim"
PickupMeshName="WEP_3P_Thermite_MESH.WEP_Thermite_Pickup" //@TODO: Replace me
AttachmentArchetypeName="wep_thermite_arch.Wep_Thermite_3P"
MuzzleFlashTemplateName="wep_thermite_arch.Wep_Thermite_MuzzleFlash" //@TODO: Replace me
// Inventory / Grouping
InventorySize=7
GroupPriority=100
WeaponSelectTexture=Texture2D'WEP_UI_Thermite_TEX.UI_WeaponSelect_Thermite'
AssociatedPerkClasses(0)=class'KFPerk_Firebug'
// FOV
MeshFOV=75
MeshIronSightFOV=40
PlayerIronSightFOV=65
// Depth of field
DOF_FG_FocalRadius=50
DOF_FG_MaxNearBlurSize=3.5
// Ammo
MagazineCapacity[0]=6
SpareAmmoCapacity[0]=36 //42
InitialSpareMags[0]=1
bCanBeReloaded=true
bReloadFromMagazine=true
// Zooming/Position
PlayerViewOffset=(X=11.0,Y=8,Z=-2)
IronSightPosition=(X=10,Y=0,Z=0)
// AI warning system
bWarnAIWhenAiming=true
AimWarningDelay=(X=0.4f, Y=0.8f)
AimWarningCooldown=0.0f
// Recoil
maxRecoilPitch=500
minRecoilPitch=400
maxRecoilYaw=150
minRecoilYaw=-150
RecoilRate=0.08
RecoilMaxYawLimit=500
RecoilMinYawLimit=65035
RecoilMaxPitchLimit=1250
RecoilMinPitchLimit=64785
RecoilISMaxYawLimit=50
RecoilISMinYawLimit=65485
RecoilISMaxPitchLimit=500
RecoilISMinPitchLimit=65485
RecoilViewRotationScale=0.6
IronSightMeshFOVCompensationScale=1.5
// DEFAULT_FIREMODE
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletSingle'
FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Rocket_ThermiteBore'
InstantHitDamage(DEFAULT_FIREMODE)=150
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_ThermiteBoreImpact'
FireInterval(DEFAULT_FIREMODE)=0.8 //100 RPM
Spread(DEFAULT_FIREMODE)=0
PenetrationPower(DEFAULT_FIREMODE)=0
FireOffset=(X=25,Y=3.0,Z=-2.5)
// ALTFIRE_FIREMODE (remote detonate)
FiringStatesArray(ALTFIRE_FIREMODE)=WeaponDetonating
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Custom
AmmoCost(ALTFIRE_FIREMODE)=0
// BASH_FIREMODE
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_ThermiteBore'
InstantHitDamage(BASH_FIREMODE)=26
// Custom animations
FireSightedAnims=(Shoot_Iron)
BonesToLockOnEmpty=(RW_Exhaust, RW_BoltAssembly1, RW_BoltAssembly2, RW_BoltAssembly3)
bHasFireLastAnims=true
// Fire Effects
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Thermite.Play_WEP_Thermite_Thermite_Shoot_3P', FirstPersonCue=AkEvent'WW_WEP_Thermite.Play_WEP_Thermite_Thermite_Shoot_1P')
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_Thermite.Play_WEP_Thermite_Dry_Fire'
EjectedShellForegroundDuration=1.5f
// Attachments
bHasIronSights=true
bHasFlashlight=false
WeaponFireWaveForm=ForceFeedbackWaveform'FX_ForceFeedback_ARCH.Gunfire.Medium_Recoil'
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.125f), (Stat=EWUS_Weight, Add=1)))
SelfDamageReductionValue=0.05f //0.25f
DetonateAnim=Alt_Fire
DetonateAnimLast=Alt_Fire_Last
DetonateAnimIron=Alt_Fire_Iron
DetonateAnimIronLast=Alt_Fire_Iron_Last
}