//============================================================================= // KFWeap_Flame_HuskCannon //============================================================================= // Husk Cannon weapon code //============================================================================= // Killing Floor 2 // Copyright (C) 2017 Tripwire Interactive LLC //============================================================================= class KFWeap_HuskCannon extends KFWeapon; //Props related to charging the weapon var float MaxChargeTime; var float ValueIncreaseTime; var float DmgIncreasePerCharge; var float AOEIncreasePerCharge; var float IncapIncreasePerCharge; var int AmmoIncreasePerCharge; var transient float ChargeTime; var transient float ConsumeAmmoTime; var transient float MaxChargeLevel; var ParticleSystem ChargingEffect; var ParticleSystem ChargedEffect; var const ParticleSystem MuzzleFlashEffectL1; var const ParticleSystem MuzzleFlashEffectL2; var const ParticleSystem MuzzleFlashEffectL3; var transient ParticleSystemComponent ChargingPSC; var transient bool bIsFullyCharged; var const WeaponFireSndInfo FullyChargedSound; var float SelfDamageReductionValue; var float FullChargedTimerInterval; static simulated event EFilterTypeUI GetTraderFilter() { return FT_Flame; } static simulated function float CalculateTraderWeaponStatDamage() { local float CalculatedDamage; local class DamageType; local GameExplosion ExplosionInstance; ExplosionInstance = class(default.WeaponProjectiles[DEFAULT_FIREMODE]).default.ExplosionTemplate; CalculatedDamage = default.InstantHitDamage[DEFAULT_FIREMODE] + ExplosionInstance.Damage; DamageType = class(ExplosionInstance.MyDamageType); if (DamageType != none && DamageType.default.DoT_Type != DOT_None) { CalculatedDamage += (DamageType.default.DoT_Duration / DamageType.default.DoT_Interval) * (CalculatedDamage * DamageType.default.DoT_DamageScale); } return CalculatedDamage; } /** * @see Weapon::ConsumeAmmo */ simulated function ConsumeAmmo(byte FireModeNum) { local KFPerk InstigatorPerk; `if(`notdefined(ShippingPC)) if (bInfiniteAmmo) { return; } `endif InstigatorPerk = GetPerk(); if (InstigatorPerk != none && InstigatorPerk.GetIsUberAmmoActive(self)) //check for pyro maniac { return; } // If AmmoCount is being replicated, don't allow the client to modify it here if (Role == ROLE_Authority || bAllowClientAmmoTracking) { super.ConsumeAmmo(FireModeNum); } } simulated function StartFire(byte FiremodeNum) { if (IsTimerActive('RefireCheckTimer')) { return; } super.StartFire(FiremodeNum); } simulated function OnStartFire() { local KFPawn PawnInst; PawnInst = KFPawn(Instigator); if (PawnInst != none) { PawnInst.OnStartFire(); } } simulated function FireAmmunition() { // Let the accuracy tracking system know that we fired HandleWeaponShotTaken(CurrentFireMode); // Handle the different fire types switch (WeaponFireTypes[CurrentFireMode]) { case EWFT_InstantHit: // Launch a projectile if we are in zed time, and this weapon has a projectile to launch for this mode if (`IsInZedTime(self) && WeaponProjectiles[CurrentFireMode] != none ) { ProjectileFire(); } else { InstantFireClient(); } break; case EWFT_Projectile: ProjectileFire(); break; case EWFT_Custom: CustomFire(); break; } // If we're firing without charging, still consume one ammo if (GetChargeLevel() < 1) { ConsumeAmmo(CurrentFireMode); } NotifyWeaponFired(CurrentFireMode); // Play fire effects now (don't wait for WeaponFired to replicate) PlayFireEffects(CurrentFireMode, vect(0, 0, 0)); } simulated state HuskCannonCharge extends WeaponFiring { //For minimal code purposes, I'll directly call global.FireAmmunition after charging is released simulated function FireAmmunition() {} //Store start fire time so we don't have to timer this simulated event BeginState(Name PreviousStateName) { super.BeginState(PreviousStateName); ChargeTime = 0; ConsumeAmmoTime = 0; MaxChargeLevel = int(MaxChargeTime / ValueIncreaseTime); if (ChargingPSC == none) { ChargingPSC = new(self) class'ParticleSystemComponent'; if(MySkelMesh != none) { MySkelMesh.AttachComponentToSocket(ChargingPSC, 'MuzzleFlash'); } else { AttachComponent(ChargingPSC); } } else { ChargingPSC.ActivateSystem(); } bIsFullyCharged = false; global.OnStartFire(); if(ChargingPSC != none) { ChargingPSC.SetTemplate(ChargingEffect); } } simulated function bool ShouldRefire() { // ignore how much ammo is left (super/global counts ammo) return StillFiring(CurrentFireMode); } simulated event Tick(float DeltaTime) { local float ChargeRTPC; global.Tick(DeltaTime); // Don't charge unless we're holding down the button if (PendingFire(CurrentFireMode)) { ConsumeAmmoTime += DeltaTime; } if (bIsFullyCharged) { if (ConsumeAmmoTime >= FullChargedTimerInterval) { //ConsumeAmmo(DEFAULT_FIREMODE); ConsumeAmmoTime -= FullChargedTimerInterval; } return; } // Don't charge unless we're holding down the button if (PendingFire(CurrentFireMode)) { ChargeTime += DeltaTime; } ChargeRTPC = FMin(ChargeTime / MaxChargeTime, 1.f); KFPawn(Instigator).SetWeaponComponentRTPCValue("Weapon_Charge", ChargeRTPC); //For looping component Instigator.SetRTPCValue('Weapon_Charge', ChargeRTPC); //For one-shot sounds if (ConsumeAmmoTime >= ValueIncreaseTime) { ConsumeAmmo(DEFAULT_FIREMODE); ConsumeAmmoTime -= ValueIncreaseTime; } if (ChargeTime >= MaxChargeTime || !HasAmmo(DEFAULT_FIREMODE)) { bIsFullyCharged = true; ChargingPSC.SetTemplate(ChargedEffect); KFPawn(Instigator).SetWeaponAmbientSound(FullyChargedSound.DefaultCue, FullyChargedSound.FirstPersonCue); } } //Now that we're done charging, directly call FireAmmunition. This will handle the actual projectile fire and scaling. simulated event EndState(Name NextStateName) { ClearZedTimeResist(); ClearPendingFire(CurrentFireMode); ClearTimer(nameof(RefireCheckTimer)); KFPawn(Instigator).bHasStartedFire = false; KFPawn(Instigator).bNetDirty = true; if (ChargingPSC != none) { ChargingPSC.DeactivateSystem(); } KFPawn(Instigator).SetWeaponAmbientSound(none); } simulated function HandleFinishedFiring() { global.FireAmmunition(); if (bPlayingLoopingFireAnim) { StopLoopingFireEffects(CurrentFireMode); } if (MuzzleFlash != none) { SetTimer(MuzzleFlash.MuzzleFlash.Duration, false, 'Timer_StopFireEffects'); } else { SetTimer(0.3f, false, 'Timer_StopFireEffects'); } NotifyWeaponFinishedFiring(CurrentFireMode); super.HandleFinishedFiring(); } } // Placing the actual Weapon Firing end state here since we need it to happen at the end of the actual firing loop. simulated function Timer_StopFireEffects() { // Simulate weapon firing effects on the local client if (WorldInfo.NetMode == NM_Client) { Instigator.WeaponStoppedFiring(self, false); } ClearFlashCount(); ClearFlashLocation(); } simulated function KFProjectile SpawnProjectile(class KFProjClass, vector RealStartLoc, vector AimDir) { local KFProj_HuskCannon_Fireball HuskBall; local int Charges; HuskBall = KFProj_HuskCannon_Fireball(super.SpawnProjectile(KFProjClass, RealStartLoc, AimDir)); //Calc and set scaling values if (HuskBall != none) { Charges = GetChargeLevel(); HuskBall.DamageScale = 1.f + DmgIncreasePerCharge * Charges; HuskBall.AOEScale = 1.f + AOEIncreasePerCharge * Charges; HuskBall.IncapScale = 1.f + IncapIncreasePerCharge * Charges; return HuskBall; } return none; } simulated function CauseMuzzleFlash(byte FireModeNum) { if (MuzzleFlash == None) { AttachMuzzleFlash(); } if (MuzzleFlash != none) { switch (GetChargeFXLevel()) { case 1: MuzzleFlash.MuzzleFlash.ParticleSystemTemplate = MuzzleFlashEffectL1; MuzzleFlash.MuzzleFlash.PSC.SetTemplate(MuzzleFlashEffectL1); break; case 2: MuzzleFlash.MuzzleFlash.ParticleSystemTemplate = MuzzleFlashEffectL2; MuzzleFlash.MuzzleFlash.PSC.SetTemplate(MuzzleFlashEffectL2); break; case 3: MuzzleFlash.MuzzleFlash.ParticleSystemTemplate = MuzzleFlashEffectL3; MuzzleFlash.MuzzleFlash.PSC.SetTemplate(MuzzleFlashEffectL3); break; } } super.CauseMuzzleFlash(FireModeNum); } simulated function int GetChargeLevel() { return Min(ChargeTime / ValueIncreaseTime, MaxChargeLevel); } // Should generally match up with KFWeapAttach_HuskCannon::GetChargeFXLevel simulated function int GetChargeFXLevel() { local int ChargeLevel; ChargeLevel = GetChargeLevel(); if (ChargeLevel < 1) { return 1; } else if (ChargeLevel < MaxChargeLevel) { return 2; } else { return 3; } } function AdjustDamage(out int InDamage, class DamageType, Actor DamageCauser) { super.AdjustDamage(InDamage, DamageType, DamageCauser); if (Instigator != none && DamageCauser != none && DamageCauser.Instigator == Instigator ) //self { InDamage *= SelfDamageReductionValue; } } // increase the instant hit damage based on the charge level simulated function int GetModifiedDamage(byte FireModeNum, optional vector RayDir) { local int ModifiedDamage; ModifiedDamage = super.GetModifiedDamage(FireModeNum, RayDir); if (FireModeNum == DEFAULT_FIREMODE) { ModifiedDamage = ModifiedDamage * (1.f + DmgIncreasePerCharge * GetChargeLevel()); } return ModifiedDamage; } defaultproperties { SelfDamageReductionValue=0.1f //Gameplay Props MaxChargeTime=1.0 ValueIncreaseTime=0.2 DmgIncreasePerCharge=0.8 AOEIncreasePerCharge=0.6 IncapIncreasePerCharge=0.22 AmmoIncreasePerCharge=1 // Shooting Animations FireSightedAnims[0]=Shoot FireSightedAnims[1]=Shoot_Heavy_Iron FireLoopSightedAnim=ShootLoop_Iron FireLoopEndAnim=ShootLoop_End FireLoopEndSightedAnim=ShootLoop_Iron_End // FOV Meshfov=80 MeshIronSightFOV=65 //52 PlayerIronSightFOV=50 //80 // Depth of field DOF_FG_FocalRadius=150 DOF_FG_MaxNearBlurSize=1 // Content PackageKey="HuskCannon" FirstPersonMeshName="WEP_1P_HuskCannon_MESH.Wep_1stP_HuskCannon_Rig" FirstPersonAnimSetNames(0)="WEP_1P_HuskCannon_ANIM.Wep_1stP_HuskCannon_Anim" PickupMeshName="wep_3p_huskcannon_mesh.Wep_3rdP_HuskCannon_Pickup" AttachmentArchetypeName="WEP_HuskCannon_ARCH.Wep_HuskCannon_3P" MuzzleFlashTemplateName="WEP_HuskCannon_ARCH.Wep_HuskCannon_MuzzleFlash" // Zooming/Position PlayerViewOffset=(X=20.0,Y=12,Z=-1) IronSightPosition=(X=0,Y=0,Z=-0.18) // Ammo MagazineCapacity[0]=30 SpareAmmoCapacity[0]=150 InitialSpareMags[0]=1 AmmoPickupScale[0]=0.75 bCanBeReloaded=true bReloadFromMagazine=true // Recoil maxRecoilPitch=150 minRecoilPitch=115 maxRecoilYaw=115 minRecoilYaw=-115 RecoilRate=0.085 RecoilMaxYawLimit=500 RecoilMinYawLimit=65035 RecoilMaxPitchLimit=900 RecoilMinPitchLimit=65035 RecoilISMaxYawLimit=75 RecoilISMinYawLimit=65460 RecoilISMaxPitchLimit=375 RecoilISMinPitchLimit=65460 RecoilViewRotationScale=0.25 IronSightMeshFOVCompensationScale=1.5 HippedRecoilModifier=1.5 // Inventory InventorySize=8 GroupPriority=75 WeaponSelectTexture=Texture2D'WEP_UI_HuskCannon_TEX.UI_WeaponSelect_HuskCannon' //@TODO: Replace me // DEFAULT_FIREMODE FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Grenade' //@TODO: Replace me FiringStatesArray(DEFAULT_FIREMODE)=HuskCannonCharge WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile Spread(DEFAULT_FIREMODE) = 0.0085 WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_HuskCannon_Fireball' FireInterval(DEFAULT_FIREMODE)=+0.223 //269 RPMs InstantHitDamage(DEFAULT_FIREMODE)=40 InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Explosive_HuskCannonImpact' FireOffset=(X=30,Y=4.5,Z=-5) WeaponFireTypes(ALTFIRE_FIREMODE) = EWFT_None // BASH_FIREMODE InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_HuskCannon' InstantHitDamage(BASH_FIREMODE)=28 // Fire Effects WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Husk_Cannon.Play_WEP_Husk_Cannon_3P_Start', FirstPersonCue=AkEvent'WW_WEP_Husk_Cannon.Play_WEP_Husk_Cannon_1P_Start') WeaponFireLoopEndSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Husk_Cannon.Play_WEP_Husk_Cannon_3P_Fire', FirstPersonCue=AkEvent'WW_WEP_Husk_Cannon.Play_WEP_Husk_Cannon_1P_Fire') FullyChargedSound=(DefaultCue = AkEvent'WW_WEP_Husk_Cannon.Play_WEP_Husk_Cannon_Charged_3P', FirstPersonCue=AkEvent'WW_WEP_Husk_Cannon.Play_WEP_Husk_Cannon_Charged') WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_SA_Flamethrower.Play_WEP_SA_Flamethrower_Handling_DryFire' //@TODO: Replace me WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_SA_Flamethrower.Play_WEP_SA_Flamethrower_Handling_DryFire' //@TODO: Replace me // Advanced (High RPM) Fire Effects bLoopingFireAnim(DEFAULT_FIREMODE)=true bLoopingFireSnd(DEFAULT_FIREMODE)=true SingleFireSoundIndex=FIREMODE_NONE bLoopingFireAnim(ALTFIRE_FIREMODE)=false bLoopingFireSnd(ALTFIRE_FIREMODE)=false Spread(ALTFIRE_FIREMODE) = 0.0085 // Attachments bHasIronSights=true bHasFlashlight=false AssociatedPerkClasses(0)= class'KFPerk_Firebug' AssociatedPerkClasses(1)= class'KFPerk_Demolitionist' WeaponFireWaveForm=ForceFeedbackWaveform'FX_ForceFeedback_ARCH.Gunfire.Weak_Recoil' ChargingEffect=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Charging_01' ChargedEffect=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Charged_01' MuzzleFlashEffectL1=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_MuzzleFlash_L1_1P' MuzzleFlashEffectL2=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_MuzzleFlash_L2_1P' MuzzleFlashEffectL3=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_MuzzleFlash_L3_1P' FullChargedTimerInterval=2.0f // Weapon Upgrade stat boosts //WeaponUpgrades[1]=(IncrementDamage=1.1f,IncrementWeight=1) WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.1f), (Stat=EWUS_Weight, Add=1))) }