1
0
KF2-Dev-Scripts/KFGameContent/Classes/KFWeap_Blunt_MedicBat.uc

807 lines
23 KiB
Ucode
Raw Permalink Normal View History

2020-12-13 15:01:13 +00:00
//=============================================================================
// KFWeap_Blunt_MedicBat
//=============================================================================
// A melee weapon that creates healing gas and can smack heals into teammates
//=============================================================================
// Killing Floor 2
// Copyright (C) 2018 Tripwire Interactive LLC
//=============================================================================
// Extends MeleeBase with code from KFWeap_HealerBase (for healing dart ammo functionality)
class KFWeap_Blunt_MedicBat extends KFWeap_MeleeBase;
/** Explosion actor class to spawn */
var class<KFExplosionActor> ExplosionActorClass;
var() KFGameExplosion ExplosionTemplate;
var() KFGameExplosion LightAttackExplosionTemplate;
/** Whether Friendly Fire is enabled for the game */
var bool bFriendlyFireEnabled;
/** Amount to heal when hitting a teammate per firemode */
var array<float> AttackHealAmounts;
/** Ammo dart cost for healing a teammate per firemode */
var array<byte> AttackHealCosts;
/** How many points of heal ammo to recharge per second */
var(Healing) float HealFullRechargeSeconds;
/** Keeps track of incremental healing since we have to heal in whole integers */
var float HealingIncrement;
/** How many points of heal ammo to recharge per second. Calculated from the HealFullRechargeSeconds */
var float HealRechargePerSecond;
/** Current amount of healing darts available */
var repnotify byte HealingDartAmmo;
/** The actor the alt attack explosion should attach to */
var transient Actor BlastAttachee;
/** The hit location of the blast */
var vector BlastHitLocation;
/** Spawn location offset to improve cone hit detection */
var transient float BlastSpawnOffset;
/** Starting Damage radius of the alt attack explosion*/
var float StartingDamageRadius;
/** Animations that play in reaction to hitting with the alt fire attack*/
const HardFire_L = 'HardFire_L';
const HardFire_R = 'HardFire_R';
const HardFire_F = 'HardFire_F';
const HardFire_B = 'HardFire_B';
/** Damage type that is used when hitting a teammate with an attack */
var class<DamageType> HealingDamageType;
/*********************************************************************************************
@name Optics UI
********************************************************************************************* */
var class<KFGFxWorld_MedicOptics> OpticsUIClass;
var KFGFxWorld_MedicOptics OpticsUI;
/** The last updated value for our ammo - Used to know when to update our optics ammo */
var byte StoredPrimaryAmmo;
var byte StoredSecondaryAmmo;
replication
{
if (bNetInitial)
bFriendlyFireEnabled;
if (bNetDirty && Role == ROLE_Authority && bAllowClientAmmoTracking)
HealingDartAmmo;
}
/* epic ===============================================
* ::ReplicatedEvent
*
* Called when a variable with the property flag "RepNotify" is replicated
*
* =====================================================
*/
simulated event ReplicatedEvent(name VarName)
{
if (VarName == nameof(HealingDartAmmo))
{
AmmoCount[ALTFIRE_FIREMODE] = HealingDartAmmo;
}
else
{
Super.ReplicatedEvent(VarName);
}
}
/**
* HealAmmo Regen client and server
*/
simulated event Tick(FLOAT DeltaTime)
{
// If we're not fully charged tick the HealAmmoRegen system
if (AmmoCount[ALTFIRE_FIREMODE] < MagazineCapacity[ALTFIRE_FIREMODE])
{
HealAmmoRegeneration(DeltaTime);
}
if (Instigator != none && Instigator.weapon == self)
{
UpdateOpticsUI();
}
Super.Tick(DeltaTime);
}
simulated function ConsumeAmmoDarts(int AmmoDartCost)
{
// Handles the consumption of ammo darts for the default attack
// If AmmoCount is being replicated, don't allow the client to modify it here
if (Role == ROLE_Authority || bAllowClientAmmoTracking)
{
// Don't consume ammo if magazine size is 0 (infinite ammo with no reload)
if (MagazineCapacity[1] > 0 && AmmoCount[1] > 0)
{
// Reduce ammo amount by heal ammo cost
AmmoCount[1] = Max(AmmoCount[1] - AmmoDartCost, 0);
}
}
}
/** @see KFWeapon::ConsumeAmmo */
simulated function ConsumeAmmo(byte FireModeNum)
{
// If its not the healing fire mode (the heavy attack ammo consumption), use the super's consume
if (FireModeNum != DEFAULT_FIREMODE)
{
Super.ConsumeAmmo(FireModeNum);
return;
}
ConsumeAmmoDarts(AmmoCost[DEFAULT_FIREMODE]);
}
/** Overridden to call StartHealRecharge on server */
function GivenTo(Pawn thisPawn, optional bool bDoNotActivate)
{
super.GivenTo(thisPawn, bDoNotActivate);
// StartHealRecharge gets called on the client from ClientWeaponSet (called from ClientGivenTo, called from GivenTo),
// but we also need this called on the server for remote clients, since the server needs to track the ammo too (to know if/when to spawn projectiles)
if (Role == ROLE_Authority && !thisPawn.IsLocallyControlled())
{
StartHealRecharge();
}
}
/** Start the heal recharge cycle */
function StartHealRecharge()
{
local KFPerk InstigatorPerk;
local float UsedHealRechargeTime;
// begin ammo recharge on server
if (Role == ROLE_Authority)
{
InstigatorPerk = GetPerk();
2023-10-17 23:03:17 +00:00
UsedHealRechargeTime = HealFullRechargeSeconds;
UsedHealRechargeTime *= static.GetUpgradeHealRechargeMod(CurrentWeaponUpgradeIndex);
2020-12-13 15:01:13 +00:00
InstigatorPerk.ModifyHealerRechargeTime(UsedHealRechargeTime);
// Set the healing recharge rate whenever we start charging
HealRechargePerSecond = MagazineCapacity[ALTFIRE_FIREMODE] / UsedHealRechargeTime;
HealingIncrement = 0;
}
}
/** Heal Ammo Regen */
function HealAmmoRegeneration(float DeltaTime)
{
if (Role == ROLE_Authority)
{
HealingIncrement += HealRechargePerSecond * DeltaTime;
if (HealingIncrement >= 1.0 && AmmoCount[ALTFIRE_FIREMODE] < MagazineCapacity[ALTFIRE_FIREMODE])
{
AmmoCount[ALTFIRE_FIREMODE]++;
HealingIncrement -= 1.0;
// Heal ammo regen is only tracked on the server, so even though we told the client he could
// keep track of ammo himself like a big boy, we still have to spoon-feed it to him.
if (bAllowClientAmmoTracking)
{
HealingDartAmmo = AmmoCount[ALTFIRE_FIREMODE];
}
}
}
}
simulated event bool HasAmmo(byte FireModeNum, optional int Amount)
{
// Default fire mode either has ammo to trigger the heal or needs to return true to still allow a basic swing
if (FireModeNum == DEFAULT_FIREMODE)
{
return true;
}
return super.HasAmmo(FireModeNum, Amount);
}
reliable client function ClientWeaponSet(bool bOptionalSet, optional bool bDoNotActivate)
{
local KFInventoryManager KFIM;
super.ClientWeaponSet(bOptionalSet, bDoNotActivate);
if (OpticsUI == none)
{
KFIM = KFInventoryManager(InvManager);
if (KFIM != none)
{
//Create the screen's UI piece
OpticsUI = KFGFxWorld_MedicOptics(KFIM.GetOpticsUIMovie(OpticsUIClass));
}
}
// Initialize our displayed ammo count and healer charge
StartHealRecharge();
}
function ItemRemovedFromInvManager()
{
local KFInventoryManager KFIM;
local KFWeap_Blunt_MedicBat KFW;
Super.ItemRemovedFromInvManager();
if (OpticsUI != none)
{
KFIM = KFInventoryManager(InvManager);
if (KFIM != none)
{
foreach KFIM.InventoryActors(class'KFWeap_Blunt_MedicBat', KFW)
{
if (KFW != self && KFW.OpticsUI.Class == OpticsUI.class)
{
// A different weapon is still using this optics class
return;
}
}
//Create the screen's UI piece
KFIM.RemoveOpticsUIMovie(OpticsUI.class);
OpticsUI.Close();
OpticsUI = none;
}
}
}
/** Unpause our optics movie and reinitialize our ammo when we equip the weapon */
simulated function AttachWeaponTo(SkeletalMeshComponent MeshCpnt, optional Name SocketName)
{
super.AttachWeaponTo(MeshCpnt, SocketName);
if (OpticsUI != none)
{
OpticsUI.SetPause(false);
UpdateOpticsUI(true);
OpticsUI.SetShotPercentCost(AmmoCost[ALTFIRE_FIREMODE]);
}
}
/** Pause the optics movie once we unequip the weapon so it's not playing in the background */
simulated function DetachWeapon()
{
local Pawn OwnerPawn;
super.DetachWeapon();
OwnerPawn = Pawn(Owner);
if (OwnerPawn != none && OwnerPawn.Weapon == self)
{
if (OpticsUI != none)
{
OpticsUI.SetPause();
}
}
}
/**
* Update our displayed ammo count if it's changed
*/
simulated function UpdateOpticsUI(optional bool bForceUpdate)
{
if (OpticsUI != none && OpticsUI.OpticsContainer != none)
{
if (AmmoCount[DEFAULT_FIREMODE] != StoredPrimaryAmmo || bForceUpdate)
{
StoredPrimaryAmmo = AmmoCount[DEFAULT_FIREMODE];
OpticsUI.SetPrimaryAmmo(StoredPrimaryAmmo);
}
if (AmmoCount[ALTFIRE_FIREMODE] != StoredSecondaryAmmo || bForceUpdate)
{
StoredSecondaryAmmo = AmmoCount[ALTFIRE_FIREMODE];
OpticsUI.SetHealerCharge(StoredSecondaryAmmo);
}
if (OpticsUI.MinPercentPerShot != AmmoCost[ALTFIRE_FIREMODE])
{
OpticsUI.SetShotPercentCost(1);
}
}
}
/** Healing charge doesn't count as ammo for purposes of inventory management (e.g. switching) */
simulated function bool HasAnyAmmo()
{
// Special ammo is stored in the default firemode (heal darts are separate)
if (HasSpareAmmo() || AmmoCount[DEFAULT_FIREMODE] >= AmmoCost[CUSTOM_FIREMODE])
{
return true;
}
return false;
}
/** Determines the secondary ammo left for HUD display */
simulated function int GetSecondaryAmmoForHUD()
{
return AmmoCount[1];
}
simulated event PreBeginPlay()
{
Super.PreBeginPlay();
/** Initially check whether friendly fire is on or not. */
if (Role == ROLE_Authority && KFGameInfo(WorldInfo.Game).FriendlyFireScale != 0.f)
{
bFriendlyFireEnabled = true;
}
if (ExplosionTemplate != none)
{
StartingDamageRadius = ExplosionTemplate.DamageRadius;
}
}
/** should be able to interrupt its reload state with any melee attack */
simulated function bool CanOverrideMagReload(byte FireModeNum)
{
return FireModeNum != RELOAD_FIREMODE;
}
/** Override to allow for two different states associated with RELOAD_FIREMODE */
simulated function SendToFiringState(byte FireModeNum)
{
// Ammo needs to be synchronized on client/server for this to work!
if (FireModeNum == RELOAD_FIREMODE && !Super(KFWeapon).CanReload())
{
SetCurrentFireMode(FireModeNum);
GotoState('WeaponUpkeep');
return;
}
Super.SendToFiringState(FireModeNum);
}
/** Always allow reload and choose the correct state in SendToFiringState() */
simulated function bool CanReload(optional byte FireModeNum)
{
return true;
}
/** Skip calling StillFiring/PendingFire to fix log warning */
simulated function bool ShouldRefire()
{
if (CurrentFireMode == CUSTOM_FIREMODE)
return false;
return Super.ShouldRefire();
}
simulated protected function PrepareExplosion()
{
local KFPlayerController KFPC;
local KFPerk InstigatorPerk;
ExplosionTemplate = default.ExplosionTemplate;
ExplosionTemplate.DamageRadius = StartingDamageRadius;
// Change the radius and damage based on the perk
if (Owner.Role == ROLE_Authority)
{
KFPC = KFPlayerController(Instigator.Controller);
if (KFPC != none)
{
2022-09-01 15:58:51 +00:00
`Log("RADIUS BEFORE: " $ExplosionTemplate.DamageRadius);
2020-12-13 15:01:13 +00:00
InstigatorPerk = KFPC.GetPerk();
ExplosionTemplate.DamageRadius *= InstigatorPerk.GetAoERadiusModifier();
2022-09-01 15:58:51 +00:00
`Log("RADIUS BEFORE: " $ExplosionTemplate.DamageRadius);
2020-12-13 15:01:13 +00:00
}
}
ExplosionActorClass = default.ExplosionActorClass;
}
/** Get the hard fire anim when the alt fire attack connects */
simulated function name GetWeaponFireAnim(byte FireModeNum)
{
// Adjust cone fire angle based on swing direction
switch (MeleeAttackHelper.CurrentAttackDir)
{
case DIR_Forward:
case DIR_ForwardLeft:
case DIR_ForwardRight:
return HardFire_F;
case DIR_Backward:
case DIR_BackwardLeft:
case DIR_BackwardRight:
return HardFire_B;
case DIR_Left:
return HardFire_L;
case DIR_Right:
return HardFire_R;
}
return '';
}
simulated function SpawnExplosionFromTemplate(KFGameExplosion Template)
{
local KFExplosionActor ExploActor;
local vector SpawnLoc;
local rotator SpawnRot;
SpawnLoc = BlastHitLocation;
SpawnRot = GetAdjustedAim(SpawnLoc);
// explode using the given template
ExploActor = Spawn(ExplosionActorClass, self, , SpawnLoc, SpawnRot, , true);
if (ExploActor != None)
{
ExploActor.InstigatorController = Instigator.Controller;
ExploActor.Instigator = Instigator;
ExplosionTemplate.bFullDamageToAttachee = true;
KFExplosionActorReplicated(ExploActor).bIgnoreInstigator = false;
ExploActor.bReplicateInstigator = true;
ExploActor.Explode(Template, vector(SpawnRot));
}
2022-09-01 15:58:51 +00:00
// Reset damage radius
ExplosionTemplate.DamageRadius = StartingDamageRadius;
2020-12-13 15:01:13 +00:00
}
simulated function CustomFire()
{
if (Instigator.Role < ROLE_Authority)
{
return;
}
PrepareExplosion();
SpawnExplosionFromTemplate(ExplosionTemplate);
// tell remote clients that we fired, to trigger effects in third person
IncrementFlashCount();
}
simulated function HealTeammateWithAttack(Actor HitActor, vector HitLocation, float HealingAmount, byte HealCost)
{
local KFPawn Victim;
if (Role == ROLE_Authority)
{
if (Instigator != None)
{
// only detonate when it hits a pawn so that level geometry doesn't get in the way
if (HitActor.bWorldGeometry)
{
return;
}
Victim = KFPawn(HitActor);
// If the victim is a teammate and the player has default ammo (healing darts) then heal this teammate
// also make sure the victim is still alive and is actually missing health
if (Victim != None && (Victim.GetTeamNum() == Instigator.GetTeamNum()) && Victim.Health > 0 && Victim.Health < Victim.HealthMax)
{
if (AmmoCount[1] >= HealCost)
{
ConsumeAmmoDarts(HealCost);
Victim.HealDamage(HealingAmount, Instigator.Controller, HealingDamageType);
if (Instigator.Role >= ROLE_Authority)
{
BlastHitLocation = HitLocation;
SpawnExplosionFromTemplate(LightAttackExplosionTemplate);
}
}
}
}
}
}
// BASH
simulated state MeleeAttackBasic
{
/** Network: Local Player */
simulated function NotifyMeleeCollision(Actor HitActor, optional vector HitLocation)
{
HealTeammateWithAttack(HitActor, HitLocation, AttackHealAmounts[BASH_FIREMODE], AttackHealCosts[BASH_FIREMODE]);
}
}
// LIGHT ATTACK
simulated state MeleeChainAttacking
{
/** Network: Local Player */
simulated function NotifyMeleeCollision(Actor HitActor, optional vector HitLocation)
{
HealTeammateWithAttack(HitActor, HitLocation, AttackHealAmounts[DEFAULT_FIREMODE], AttackHealCosts[DEFAULT_FIREMODE]);
}
}
// HEAVY ATTACK
simulated state MeleeHeavyAttacking
{
/** Network: Local Player */
simulated function NotifyMeleeCollision(Actor HitActor, optional vector HitLocation)
{
local KFPawn Victim;
if (Instigator != None)
{
// only detonate when it hits a pawn so that level geometry doesn't get in the way
if (HitActor.bWorldGeometry)
{
return;
}
Victim = KFPawn(HitActor);
if (Victim == None ||
(Victim.bPlayedDeath && `TimeSince(Victim.TimeOfDeath) > 0.f) )
{
return;
}
if (AmmoCount[0] >= AmmoCost[CUSTOM_FIREMODE] && !IsTimerActive(nameof(BeginMedicBatExplosion)))
{
BlastAttachee = HitActor;
BlastHitLocation = HitLocation;
// need to delay one frame, since this is called from AnimNotify
SetTimer(0.001f, false, nameof(BeginMedicBatExplosion));
if (Role < ROLE_Authority && Instigator.IsLocallyControlled())
{
if (!HitActor.bTearOff || Victim == none)
{
ServerBeginMedicBatExplosion(HitActor, HitLocation);
}
}
}
else
{
HealTeammateWithAttack(HitActor, HitLocation, AttackHealAmounts[HEAVY_ATK_FIREMODE], AttackHealCosts[HEAVY_ATK_FIREMODE]);
}
}
}
}
/** Called on the server */
reliable server private function ServerBeginMedicBatExplosion(Actor HitActor, optional vector HitLocation)
{
// Ignore if too far away (something went wrong!)
if (VSizeSq2D(HitLocation - Instigator.Location) > Square(500))
{
return;
}
BlastHitLocation = HitLocation;
BlastAttachee = HitActor;
SendToFiringState(CUSTOM_FIREMODE);
}
/** Called when altfire melee attack hits a target and there is ammo left */
simulated function BeginMedicBatExplosion()
{
SendToFiringState(CUSTOM_FIREMODE);
}
/*********************************************************************************************
* State Active
* A Weapon this is being held by a pawn should be in the active state. In this state,
* a weapon should loop any number of idle animations, as well as check the PendingFire flags
* to see if a shot has been fired.
*********************************************************************************************/
simulated state Active
{
/**
* 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;
}
}
}
}
defaultproperties
{
// Content
PackageKey="Medic_Bat"
FirstPersonMeshName="WEP_1P_Medic_Bat_MESH.Wep_1stP_Medic_Bat_Rig"
AttachmentArchetypeName = "WEP_Medic_Bat_ARCH.Wep_Medic_Bat_3P"
FirstPersonAnimSetNames(0)="WEP_1P_Medic_Bat_ANIM.WEP_1stP_Medic_Bat_ANIM"
PickupMeshName="WEP_3P_Medic_Bat_MESH.Wep_3rdP_Medic_Bat_Pickup"
PlayerViewOffset=(X=3.0,Y=1.0,Z=-3.0)
Begin Object Name=MeleeHelper_0
MaxHitRange = 250
// Override automatic hitbox creation (advanced)
HitboxChain.Add((BoneOffset=(X=-3,Z=250)))
HitboxChain.Add((BoneOffset=(X=+3,Z=230)))
HitboxChain.Add((BoneOffset=(X=-3,Z=210)))
HitboxChain.Add((BoneOffset=(X=+3,Z=190)))
HitboxChain.Add((BoneOffset=(X=-3,Z=170)))
HitboxChain.Add((BoneOffset=(X=+3,Z=150)))
HitboxChain.Add((BoneOffset=(X=-3,Z=130)))
HitboxChain.Add((BoneOffset=(X=+3,Z=110)))
HitboxChain.Add((BoneOffset=(X=-3,Z=90)))
HitboxChain.Add((BoneOffset=(X=+3,Z=70)))
HitboxChain.Add((BoneOffset=(X=-3,Z=50)))
HitboxChain.Add((BoneOffset=(X=+3,Z=30)))
HitboxChain.Add((BoneOffset=(Z=10)))
WorldImpactEffects = KFImpactEffectInfo'FX_Impacts_ARCH.Blunted_melee_impact'
// modified combo sequences
MeleeImpactCamShakeScale = 0.035f //0.4
ChainSequence_F = (DIR_Left, DIR_ForwardRight, DIR_ForwardLeft, DIR_ForwardRight, DIR_ForwardLeft)
ChainSequence_B = (DIR_BackwardLeft, DIR_Left, DIR_Right, DIR_ForwardRight, DIR_Left, DIR_Right, DIR_Left)
ChainSequence_L = (DIR_Right, DIR_BackwardRight, DIR_ForwardRight, DIR_ForwardLeft, DIR_Right, DIR_Left)
ChainSequence_R = (DIR_Left, DIR_BackwardLeft, DIR_ForwardLeft, DIR_ForwardRight, DIR_Left, DIR_Right)
End Object
// Reload
FiringStatesArray(RELOAD_FIREMODE)=Reloading
//Heal Dart Function
HealingDartAmmo=100
bCanRefillSecondaryAmmo=false
HealFullRechargeSeconds=12
// Heavy Attack Explosion Ammo
2021-09-02 21:46:08 +00:00
MagazineCapacity[0]=2 //3
SpareAmmoCapacity[0]=10 //12
2020-12-13 15:01:13 +00:00
InitialSpareMags[0]=1
bCanBeReloaded=true
bReloadFromMagazine=true
// Healing Dart (Alt) Ammo
MagazineCapacity[1]=100
SpareAmmoCapacity[1]=0
// Inventory
GroupPriority=75
InventorySize=4
WeaponSelectTexture=Texture2D'WEP_UI_Medic_Bat_TEX.UI_WeaponSelect_MedicBat'
SecondaryAmmoTexture=Texture2D'UI_SecondaryAmmo_TEX.MedicDarts'
// Default
// Maps to Alt Ammo
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Custom
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BluntMelee'
InstantHitDamage(DEFAULT_FIREMODE)=80
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Bludgeon_MedicBatLight'
AmmoCost(DEFAULT_FIREMODE)=40
// Heavy Attack
FireModeIconPaths(HEAVY_ATK_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BluntMelee'
2021-09-02 21:46:08 +00:00
InstantHitDamage(HEAVY_ATK_FIREMODE)=140 //130
2020-12-13 15:01:13 +00:00
InstantHitDamageTypes(HEAVY_ATK_FIREMODE) = class'KFDT_Bludgeon_MedicBatHeavy'
// Heavy Attack Explosion
// Maps to Default Ammot
FireModeIconPaths(CUSTOM_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_ShotgunSingle'
FiringStatesArray(CUSTOM_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(CUSTOM_FIREMODE)=EWFT_Custom
FireInterval(CUSTOM_FIREMODE)=1.0f
AmmoCost(CUSTOM_FIREMODE)=1
// Bash
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_MedicBatBash'
InstantHitDamage(BASH_FIREMODE)=40
// Perk
AssociatedPerkClasses(0)=class'KFPerk_Berserker'
AssociatedPerkClasses(1)=class'KFPerk_FieldMedic'
// Block and Parry
BlockSound=AkEvent'WW_WEP_Bullet_Impacts.Play_Block_MEL_Crovel'
ParrySound=AkEvent'WW_WEP_Bullet_Impacts.Play_Parry_Metal'
ParryDamageMitigationPercent=0.50
BlockDamageMitigation=0.60
ParryStrength=5
// Explosion light
Begin Object Class=PointLightComponent Name=ExplosionPointLight
LightColor=(R = 0,G = 128,B = 255,A = 255)
Brightness=4.f
Radius=500.f
FalloffExponent=10.f
CastShadows=False
CastStaticShadows=FALSE
CastDynamicShadows=True
bEnabled=FALSE
LightingChannels=(Indoor = TRUE,Outdoor = TRUE,bInitialized = TRUE)
End Object
// Explosion
ExplosionActorClass = class'KFExplosionActorReplicated'
Begin Object Class=KFGameExplosion Name=HeavyAttackHealingExplosion
2021-09-02 21:46:08 +00:00
Damage=225 //200
2020-12-13 15:01:13 +00:00
DamageRadius=500
DamageFalloffExponent=0.f
DamageDelay=0.f
MyDamageType=class'KFDT_Toxic_MedicBatGas'
2021-11-16 17:03:42 +00:00
HealingAmount=15 //20 //30
2020-12-13 15:01:13 +00:00
// Damage Effects
KnockDownStrength=0
KnockDownRadius=0
FractureMeshRadius=0
FracturePartVel=0
ExplosionEffects=KFImpactEffectInfo'WEP_Medic_Bat_ARCH.Medic_Bat_Explosion'
ExplosionSound=AkEvent'WW_WEP_MEL_MedicBat.Play_WEP_MedicBat_Smoke_Explode'
MomentumTransferScale=0
bIgnoreInstigator=false
// Dynamic Light
//ExploLight=ExplosionPointLight
//ExploLightStartFadeOutTime=7.0
//ExploLightFadeOutTime=1.0
//ExploLightFlickerIntensity=5.f
//ExploLightFlickerInterpSpeed=15.f
// Camera Shake
CamShake=none
CamShakeInnerRadius=0
CamShakeOuterRadius=0
CamShakeFalloff=1.5f
bOrientCameraShakeTowardsEpicenter=true
End Object
ExplosionTemplate=HeavyAttackHealingExplosion
Begin Object Class=KFGameExplosion Name=LightAttackExplosion
Damage=0
ParticleEmitterTemplate = ParticleSystem'WEP_Medic_Bat_EMIT.FX_Medic_Bat_Hit'
// Camera Shake
CamShake=none
CamShakeInnerRadius=0
CamShakeOuterRadius=0
CamShakeFalloff=1.5f
bOrientCameraShakeTowardsEpicenter=true
End Object
LightAttackExplosionTemplate=LightAttackExplosion;
//Weapon Upgrade Stats
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.1f), (Stat=EWUS_Damage1, Scale=1.1f), (Stat=EWUS_Damage2, Scale=1.1f), (Stat=EWUS_HealFullRecharge, Scale=0.8f), (Stat=EWUS_Weight, Add=1)))
WeaponUpgrades[2]=(Stats=((Stat=EWUS_Damage0, Scale=1.2f), (Stat=EWUS_Damage1, Scale=1.2f), (Stat=EWUS_Damage2, Scale=1.2f), (Stat=EWUS_HealFullRecharge, Scale=0.6f), (Stat=EWUS_Weight, Add=2)))
BlastSpawnOffset=-10.f
AttackHealAmounts(DEFAULT_FIREMODE)=30
AttackHealAmounts(BASH_FIREMODE)=30
AttackHealAmounts(HEAVY_ATK_FIREMODE)=40
AttackHealCosts(DEFAULT_FIREMODE)=30
AttackHealCosts(BASH_FIREMODE)=30
AttackHealCosts(HEAVY_ATK_FIREMODE)=30
OpticsUIClass=class'KFGFxWorld_MedicOptics'
HealingDamageType=class'KFDT_Healing'
}