//============================================================================= // KFWeap_AssaultRifle_LazerCutter //============================================================================= // Killing Floor 2 // Copyright (C) 2017 Tripwire Interactive LLC //============================================================================= class KFWeap_AssaultRifle_LazerCutter extends KFWeap_FlameBase; /** The amount of time it takes to reach the next charge level */ var float ChargeTimePerLevel; /** How often ammo is consumed once the weapon is fully charged*/ var float OverchargeConsumeTime; /** How often ammo is consumed if the weapon is charging*/ var float ChargeConsumeTime; /** Total time spent during this weapon charged */ var float TotalChargeTime; /** Total time spent charing in this charge level*/ var float CurrentChargeTime; /** How often to signal 3p fire effects*/ var float FlashInterval; /** Timer for keeping track of when to deal damage to targets in the beam*/ var float DamageTime; /** Timer keeping track of how long remains in the beam duration*/ var float FiringTime; /** Timer keeping track of when to flash next*/ var float FlashTime; /** Movement and rotation limits when charging*/ var float ChargingRotationSpeedLimit; var float ChargingMovementSpeedModifier; /** Movement and rotation limits when firing*/ var array FiringRotationSpeedLimit; var float FiringMovementSpeedModifier; /** Base size of the beam*/ var float BaseScale; /** Amount to increase the size of the beam per charge level*/ var float ScalePerChargeLevel; /** Amount of damage to deal per tick per charge level (added to InstantHitDamage)*/ var float DamagePerChargeLevel; /** Firing duration at no charge level*/ var float BaseDuration; /** Firing duration added per charge level*/ var float DurationPerChargeLevel; /** Highest charge level of the beam*/ var int MaxChargeLevel; /** Charge in animation */ var(Animations) const editconst name AltFireLoopStartAnim; /** Charge animations per level */ var(Animations) const editconst name AltFireBeamInAnimL1; var(Animations) const editconst name AltFireBeamInAnimL2; var(Animations) const editconst name AltFireBeamInAnimL3; /** Animations to loop if stuck at a charge level*/ var(Animations) const editconst name AltFireLoopAnimL1; var(Animations) const editconst name AltFireLoopAnimL2; var(Animations) const editconst name AltFireLoopAnimL3; /** Firing animations per level */ var(Animations) const editconst name CustomFireLoopAnimL1; var(Animations) const editconst name CustomFireLoopAnimL2; var(Animations) const editconst name CustomFireLoopAnimL3; /** Firing end animations */ var(Animations) const editconst name CustomFireLoopEndLastAnim; var(Animations) const editconst name CustomFireLoopEndAnim; /** Muzzle flash effects per level */ var const ParticleSystem MuzzleFlashEffectL1; var const ParticleSystem MuzzleFlashEffectL2; var const ParticleSystem MuzzleFlashEffectL3; /** Looping sound event for when the beam is firing */ var array FireLoopSounds; /** Sound event to kill the looping firing beam when it ends*/ var WeaponFireSndInfo FireLoopStop; /** Looping sound event for when the beam is charing */ var array ChargeSounds; /** Kill all sounds events on the weapon*/ var WeaponFireSndInfo InterruptSoundEvent; /** Sound info for the full auto mode when in zed time*/ var WeaponFireSndInfo SingleShotFireSnd; /** Color for the weapon center when charging/firing*/ var LinearColor DefaultFireModeColor; var LinearColor EnergyColorL0; var LinearColor EnergyColorL1; var LinearColor EnergyColorL2; var LinearColor EnergyColorL3; /** Effect that happens while charging up the beam*/ var transient ParticleSystemComponent ChargingPSC; var const ParticleSystem ChargingEffect; /** Amount of time over which to reduce the rotation speed limit back to normal*/ var float MaxRotationAdjustmentTime; /** Curve used for determining how much to reduce the rotation speed to*/ var InterpCurveFloat RotationAdjustmentCurve; /** Used to gate the beam firing muzzle flash to only play once after the beam starts */ var bool bPlayMuzzleFlash; simulated function Activate() { super.Activate(); SetBeamColor(0); // set the initial beam color } 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 CustomFire() { // tell remote clients that we fired, to trigger effects if (CurrentFireMode == CUSTOM_FIREMODE) { IncrementFlashCount(); } super.CustomFire(); } simulated function AltFireMode() { super.AltFireMode(); // different beam colors for different fire modes SetBeamColor(GetChargeLevel()); } simulated function int GetChargeLevel() { return Min(TotalChargeTime / ChargeTimePerLevel, MaxChargeLevel); } 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 (CurrentFireMode == DEFAULT_FIREMODE) { ConsumeAmmo(CurrentFireMode); } NotifyWeaponFired(CurrentFireMode); // Play fire effects now (don't wait for WeaponFired to replicate) PlayFireEffects(CurrentFireMode, vect(0, 0, 0)); } simulated function name GetLoopStartFireAnim(byte FireModeNum) { if (FireModeNum == ALTFIRE_FIREMODE) { return AltFireLoopStartAnim; } else if (FireModeNum == CUSTOM_FIREMODE) { return ''; } return super.GetLoopStartFireAnim(FireModeNum); } simulated function name GetLoopEndFireAnim(byte FireModeNum) { local bool bPlayFireLast; if (FireModeNum == ALTFIRE_FIREMODE) { return ''; } else if (FireModeNum == CUSTOM_FIREMODE) { bPlayFireLast = ShouldPlayFireLast(FireModeNum); if (bPlayFireLast && CustomFireLoopEndLastAnim != '') { return CustomFireLoopEndLastAnim; } else { return CustomFireLoopEndAnim; } } return super.GetLoopEndFireAnim(FireModeNum); } simulated function name GetLoopingFireAnim(byte FireModeNum) { if (FireModeNum == ALTFIRE_FIREMODE) { return AltFireLoopStartAnim; } else if (FireModeNum == CUSTOM_FIREMODE) { switch (GetChargeLevel()) { case 3: return CustomFireLoopAnimL3; case 2: return CustomFireLoopAnimL2; case 1: case 0: return CustomFireLoopAnimL1; } } return super.GetLoopingFireAnim(FireModeNum); } simulated function CauseMuzzleFlash(byte FireModeNum) { if (MuzzleFlash == None) { AttachMuzzleFlash(); } // swap the muzzle flash per charge level (this should do nothing for full-auto) if (MuzzleFlash != none) { if (FireModeNum == CUSTOM_FIREMODE) { if (bPlayMuzzleFlash) { switch (GetChargeLevel()) { case 0: 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; } bPlayMuzzleFlash = false; // setting to 0 so that the muzzle flash doesn't get turned off based on a timer MuzzleFlash.MuzzleFlash.Duration = 0.0f; super.CauseMuzzleFlash(FireModeNum); } } // otherwise use the default else { MuzzleFlash.MuzzleFlash.ParticleSystemTemplate = MuzzleFlashTemplate.MuzzleFlash.ParticleSystemTemplate; MuzzleFlash.MuzzleFlash.PSC.SetTemplate(MuzzleFlashTemplate.MuzzleFlash.ParticleSystemTemplate); MuzzleFlash.MuzzleFlash.Duration = MuzzleFlashTemplate.MuzzleFlash.Duration; super.CauseMuzzleFlash(FireModeNum); } } } simulated function SetBeamColor(int ChargeLevel) { local LinearColor BeamColor; local int i; if (bUseAltFireMode) { switch (ChargeLevel) { case 3: BeamColor = EnergyColorL3; break; case 2: BeamColor = EnergyColorL2; break; case 1: BeamColor = EnergyColorL1; break; default: BeamColor = EnergyColorL0; break; } } else { BeamColor = DefaultFireModeColor; } if (WorldInfo.NetMode != NM_DedicatedServer) { for (i = 0; i < WeaponMICs.Length; ++i) { if (WeaponMICs[i] != none) { WeaponMICs[i].SetVectorParameterValue('Energy_Color', BeamColor); } } } } /** True if we want to override the looping fire sounds with fire sounds from another firemode * Overrides the KFWeapon functionality because the LaserCutter doesn't have a SingleFireSoundIndex but still has a single fire sound */ simulated function bool ShouldForceSingleFireSound() { // If this weapon has a single-shot firemode, disable looping fire sounds during zedtime return `IsInZedTime(self); } /** * Tells the weapon to play a firing sound (uses CurrentFireMode) * Overrides the base KFWeapon functionality because the LazerCutter has a different way of finding the single shot sound */ simulated function PlayFiringSound(byte FireModeNum) { local bool bUseSingleFireSound; MakeNoise(1.0, 'PlayerFiring'); // AI if (!bPlayingLoopingFireSnd) { // Use the single fire sound if we're in zed time and want to play single fire sounds if (FireModeNum < bLoopingFireSnd.Length && bLoopingFireSnd[FireModeNum] && ShouldForceSingleFireSound()) { bUseSingleFireSound = true; } if (bUseSingleFireSound) { WeaponPlayFireSound(SingleShotFireSnd.DefaultCue, SingleShotFireSnd.FirstPersonCue); } else if (FireModeNum < WeaponFireSnd.Length) { WeaponPlayFireSound(WeaponFireSnd[FireModeNum].DefaultCue, WeaponFireSnd[FireModeNum].FirstPersonCue); } } } // which category this shows up under in the trader // FlameBase defaults to Flame, so this needs to override static simulated event EFilterTypeUI GetTraderFilter() { return FT_Electric; } static simulated event EFilterTypeUI GetAltTraderFilter() { return FT_Assault; } // the FlameBase CalculateTraderWeaponStatDamage uses spray damage // LazerCutter will just show the full auto damage like a normal KFWeapon static simulated function float CalculateTraderWeaponStatDamage() { local float CalculatedDamage; CalculatedDamage = default.InstantHitDamage[DEFAULT_FIREMODE]; return CalculatedDamage; } simulated state LazerCharge extends WeaponFiring { simulated function FireAmmunition(){} simulated function bool AllowIronSights() { return false; } // can't switch fire modes when charging or firing the beam simulated function AltFireMode() {} simulated function AltFireModeRelease() {} simulated event OnAnimEnd(AnimNodeSequence SeqNode, float PlayedTime, float ExcessTime) { local name WeaponFireAnimName; if (WorldInfo.NetMode != NM_DedicatedServer) { if (AmmoCount[DEFAULT_FIREMODE] == 0) { // get the next looping animation we have and play that instead // this will happen when a player gets stuck at a level by running out of ammo switch (GetChargeLevel()) { case 3: case 2: WeaponFireAnimName = AltFireLoopAnimL3; break; case 1: WeaponFireAnimName = AltFireLoopAnimL2; break; case 0: WeaponFireAnimName = AltFireLoopAnimL1; break; } } else { // if an animation has ended early and the player still has ammo // continue onto the next beam in animation switch (GetChargeLevel()) { case 3: // once it hits the max level it just loops WeaponFireAnimName = AltFireLoopAnimL3; break; case 2: WeaponFireAnimName = AltFireBeamInAnimL2; break; case 1: WeaponFireAnimName = AltFireBeamInAnimL1; break; } } if (WeaponFireAnimName != '' && WeaponAnimSeqNode.AnimSeq.SequenceName != WeaponFireAnimName) { PlayAnimation(WeaponFireAnimName, MySkelMesh.GetAnimLength(WeaponFireAnimName), AmmoCount[DEFAULT_FIREMODE] == 0, FireTweenTime); } } } simulated event BeginState(Name PreviousStateName) { local KFPawn_Human OwnerHuman; local KFPlayerController OwnerController; OwnerHuman = KFPawn_Human(Instigator); super.BeginState(PreviousStateName); // reset charging variables TotalChargeTime = 0; CurrentChargeTime = 0; DamageTime = 0; FiringTime = 0; FlashTime = 0; // slow down the player's movement and rotation when charging MovementSpeedMod = ChargingMovementSpeedModifier; if (OwnerHuman != None) { OwnerController = KFPlayerController(OwnerHuman.Controller); if (OwnerController != none) { OwnerController.RotationSpeedLimit = ChargingRotationSpeedLimit; } OwnerHuman.UpdateGroundSpeed(); } // kick the player out of ironsights (no ironsights when shooting the beam) if (bUsingSights) { SetIronSights(false); } // setup the charging particle effect // setup the charging particle effect if (ChargingPSC == none) { ChargingPSC = new(self) class'ParticleSystemComponent'; if (MySkelMesh != none) { MySkelMesh.AttachComponentToSocket(ChargingPSC, 'MuzzleFlash'); } else { AttachComponent(ChargingPSC); } } else { ChargingPSC.ActivateSystem(); } if (ChargingPSC != none) { ChargingPSC.SetTemplate(ChargingEffect); } global.OnStartFire(); } simulated function bool ShouldRefire() { // ignore how much ammo is left (super/global counts ammo) return StillFiring(CurrentFireMode); } simulated event Tick(float DeltaTime) { local float ConsumeTime, ChargeRTPC; local name WeaponFireAnimName; local int StartChargeLevel, EndChargeLevel; global.Tick(DeltaTime); StartChargeLevel = GetChargeLevel(); FlashTime += DeltaTime; ConsumeTime = GetChargeLevel() >= MaxChargeLevel ? OverchargeConsumeTime : ChargeConsumeTime; // Don't charge unless we're holding down the button and still have ammo if (PendingFire(CurrentFireMode) && AmmoCount[DEFAULT_FIREMODE] > 0) { TotalChargeTime += DeltaTime; CurrentChargeTime += DeltaTime; } if (ConsumeTime > 0) { // consume ammo whenever the charge level goes up while (CurrentChargeTime >= ConsumeTime) { CurrentChargeTime -= ConsumeTime; ConsumeAmmo(ALTFIRE_FIREMODE); } } // triggers 3p visual effects/anims while (FlashTime >= FlashInterval) { FlashTime -= FlashInterval; IncrementFlashCount(); } EndChargeLevel = GetChargeLevel(); // whenever the charge level increases, check to play a new shoot loop animation if (EndChargeLevel != StartChargeLevel) { // play a sound event for the new charge level if (EndChargeLevel >= 0 && EndChargeLevel < ChargeSounds.Length) { StartLoopingFireSound(CurrentFireMode); } // play the animation for the next charge level, these will loop if sitting in this state if (bPlayingLoopingFireAnim) { switch (GetChargeLevel()) { case 3: // once it hits the max level it just loops WeaponFireAnimName = AltFireLoopAnimL3; break; case 2: WeaponFireAnimName = AltFireBeamInAnimL2; break; case 1: WeaponFireAnimName = AltFireBeamInAnimL1; break; } if (WeaponFireAnimName != '' && WeaponAnimSeqNode.AnimSeq.SequenceName != WeaponFireAnimName) { PlayAnimation(WeaponFireAnimName, MySkelMesh.GetAnimLength(WeaponFireAnimName), GetChargeLevel() == 3, FireTweenTime); } } } // set the beam color based on the current charge level SetBeamColor(GetChargeLevel()); // set an RTPC for charging sounds ChargeRTPC = FMin(TotalChargeTime / (MaxChargeLevel * ChargeTimePerLevel), 1.f); KFPawn(Instigator).SetWeaponComponentRTPCValue("Weapon_Charge", ChargeRTPC); //For looping component Instigator.SetRTPCValue('Weapon_Charge', ChargeRTPC); //For one-shot sounds } //Now that we're done charging, directly call FireAmmunition. This will handle the actual projectile fire and scaling. simulated function EndState(Name NextStateName) { local KFPawn_Human OwnerHuman; local KFPlayerController OwnerController; OwnerHuman = KFPawn_Human(Instigator); // reset the player's movement and rotation speed MovementSpeedMod = 1.f; if (OwnerHuman != None) { OwnerController = KFPlayerController(OwnerHuman.Controller); if (OwnerController != none) { OwnerController.RotationSpeedLimit = -1.f; } OwnerHuman.UpdateGroundSpeed(); } ClearZedTimeResist(); ClearPendingFire(CurrentFireMode); ClearTimer(nameof(RefireCheckTimer)); NotifyWeaponFinishedFiring(CurrentFireMode); KFPawn(Instigator).bHasStartedFire = false; KFPawn(Instigator).bNetDirty = true; super.EndState(NextStateName); } function DropFrom(vector StartLocation, vector StartVelocity) { global.DropFrom(StartLocation, StartVelocity); if (Instigator == none) { // weapon was actually dropped WeaponAnimSeqNode.StopAnim(); } } simulated function PutDownWeapon() { TotalChargeTime = 0; CurrentChargeTime = 0; global.PutDownWeapon(); } simulated function HandleFinishedFiring() { SendToFiringState(CUSTOM_FIREMODE); } } simulated state SprayingFireLazer extends SprayingFire { simulated function bool AllowIronSights() { return false; } // can't switch fire modes when charging or firing the beam simulated function AltFireMode(){} simulated function AltFireModeRelease(){} simulated function BeginState(Name PreviousStateName) { local KFPawn_Human OwnerHuman; local KFPlayerController OwnerController; local float ChargeLevel; OwnerHuman = KFPawn_Human(Instigator); ChargeLevel = GetChargeLevel(); // play the muzzle flash once (it will then stick around until firing is over) bPlayMuzzleFlash = true; // reset firing variables FlashTime = 0; // If we're firing without charging, still consume one ammo if (TotalChargeTime < ChargeConsumeTime) { ConsumeAmmo(CurrentFireMode); } // slow down the player's movement and rotation when firing MovementSpeedMod = FiringMovementSpeedModifier; if (OwnerHuman != None) { OwnerController = KFPlayerController(OwnerHuman.Controller); if (OwnerController != none) { if (ChargeLevel >= 0 && ChargeLevel < FiringRotationSpeedLimit.Length) { OwnerController.RotationSpeedLimit = FiringRotationSpeedLimit[ChargeLevel]; } } OwnerHuman.UpdateGroundSpeed(); } // the firing time will be used to determine how long the firing portion will last // scale this based on the charge level FiringTime = BaseDuration + ChargeLevel * DurationPerChargeLevel; // kick the player out of ironsights (no ironsights when shooting the beam) if (bUsingSights) { SetIronSights(false); } // stop the charging particle system if (ChargingPSC != none) { ChargingPSC.DeactivateSystem(); } super.BeginState(PreviousStateName); } // show debug boxes around the bones used for tracing collisions simulated function DebugRenderBones() { local Vector BoneLoc; local string BoneString; local int x, y; local vector BoxExtent; for (x = 0; x < ArrayCount(FlamePool); x++) { for (y = 1; y <= 15; y++) { BoxExtent.X = BaseScale + ScalePerChargeLevel * (GetChargeLevel() - 1); BoxExtent.Y = BaseScale + ScalePerChargeLevel * (GetChargeLevel() - 1); BoxExtent.Z = 1; BoneString = "Bone"; if (y < 10) { BoneString $= "0"; } BoneString $= string(y); BoneLoc = FlamePool[x].SkeletalSprayMesh.GetBoneLocation(name(BoneString)); DrawDebugBox(BoneLoc, BoxExtent, 255, 255, 0, TRUE); } } } simulated function DamageActorsCheck() { local KFPawn HitPawn; local vector BeamExtent, SmallBeamExtent; local int FlamePoolCounter, BoneCounter; local string BoneString; local vector BoneLoc, PrevBoneLoc; local KFPawn OwnerPawn; local int CurrentCollisions; local array AlreadyHitActors; local array HitDamageActors; local array HitBeamActors; local array DamageHitLocations; local array BeamHitLocations; local vector HitLocation; local int i; // scale the size of the damage collision volume based on the charge level BeamExtent.X = BaseScale + ScalePerChargeLevel * (GetChargeLevel() - 1); BeamExtent.Y = BaseScale + ScalePerChargeLevel * (GetChargeLevel() - 1); BeamExtent.Z = 1; // matching the extent size of the spray actor SmallBeamExtent.X = 8.f; SmallBeamExtent.Y = 8.f; SmallBeamExtent.Z = 8.f; CurrentCollisions = 0; OwnerPawn = KFPawn(Owner); for (FlamePoolCounter = 0; FlamePoolCounter < ArrayCount(FlamePool); FlamePoolCounter++) { // assumes 15 bones used in the laser mesh for (BoneCounter = 1; BoneCounter < 15; BoneCounter++) { BoneString = "Bone"; if (BoneCounter < 10) { BoneString $= "0"; } BoneString $= string(BoneCounter); BoneLoc = FlamePool[FlamePoolCounter].SkeletalSprayMesh.GetBoneLocation(name(BoneString)); if (BoneCounter != 1) { if(CurrentCollisions < FlamePool[FlamePoolCounter].MaxSprayMeshesCollided) { // large damage collision radius HitDamageActors = BeamLineCheck(PrevBoneLoc, BoneLoc, BeamExtent, DamageHitLocations); // smaller box for the beam itself HitBeamActors = BeamLineCheck(PrevBoneLoc, BoneLoc, SmallBeamExtent, BeamHitLocations); // stop the beam if the actual laser (small extent) looks like it would collide with something // but until then still do damage in the larger area based on charge level // this will mean that the beam can hit people around small corners at high charge levels // but it won't be stuck as easily on when super charged for(i = 0; i < HitDamageActors.Length; i++) { if (CurrentCollisions < FlamePool[FlamePoolCounter].MaxSprayMeshesCollided) { HitPawn = KFPawn(HitDamageActors[i]); // hit another pawn in the world if (HitPawn != none && HitPawn.Base != Owner && HitPawn != Owner && HitPawn.bBlockActors && AlreadyHitActors.Find(HitPawn) == INDEX_NONE) { CurrentCollisions++; // keep track of which actors were hit so fat actors don't get caught multiple times AlreadyHitActors.AddItem(HitPawn); HitLocation = vect(0, 0, 0); if (DamageHitLocations.Length > i) { HitLocation = DamageHitLocations[i]; } // scale the damage based on charge level, using the InstantHitDamage as the base HitPawn.TakeDamage(InstantHitDamage[ALTFIRE_FIREMODE] + GetChargeLevel() * DamagePerChargeLevel, OwnerPawn.Controller, HitLocation, vect(0, 0, 0), InstantHitDamageTypes[ALTFIRE_FIREMODE],,self); } // hit world geometry (with small extent), set to max collisions to stop the beam else if (HitDamageActors[i] != none && HitDamageActors[i].Base != Owner && HitDamageActors[i] != Owner && HitDamageActors[i].bBlockActors && HitDamageActors[i].bWorldGeometry && HitBeamActors.Find(HitDamageActors[i]) != INDEX_NONE) { CurrentCollisions = FlamePool[FlamePoolCounter].MaxSprayMeshesCollided; } } } } } PrevBoneLoc = BoneLoc; } } } simulated event Tick(float DeltaTime) { global.Tick(DeltaTime); if (FiringTime > 0.0f) { FiringTime -= DeltaTime; DamageTime += DeltaTime; FlashTime += DeltaTime; // check for damaging actors after a set interval while (DamageTime >= FireInterval[ALTFIRE_FIREMODE]) { DamageTime -= FireInterval[ALTFIRE_FIREMODE]; DamageActorsCheck(); } // triggers 3p visual effects/anims while (FlashTime >= FlashInterval) { FlashTime -= FlashInterval; IncrementFlashCount(); } } else { // when the charge/firing time is over, exit this state GotoState('Active'); } } simulated function EndState(Name NextStateName) { local int FlamePoolCounter; local KFPawn_Human OwnerHuman; local KFPlayerController OwnerController; OwnerHuman = KFPawn_Human(Instigator); // reset the player's movement and rotation speed modifiers MovementSpeedMod = 1.f; if (OwnerHuman != None) { OwnerController = KFPlayerController(OwnerHuman.Controller); if (OwnerController != none) { // set the starting point for the rotation curve to line up with the current speed limit if(RotationAdjustmentCurve.Points.Length > 0) { RotationAdjustmentCurve.Points[0].OutVal = OwnerController.RotationSpeedLimit; } OwnerController.StartRotationAdjustment(RotationAdjustmentCurve, MaxRotationAdjustmentTime); } OwnerHuman.UpdateGroundSpeed(); } // reset the mesh size for (FlamePoolCounter = 0; FlamePoolCounter < ArrayCount(FlamePool); FlamePoolCounter++) { FlamePool[FlamePoolCounter].SkeletalSprayMesh.SetScale(1.f); } // manually turn off the muzzle flash since these won't kill themselves if (MuzzleFlash.MuzzleFlash.PSC != none) { MuzzleFlash.MuzzleFlash.PSC.DeactivateSystem(); } // return the beam color back to the default SetBeamColor(0); // reset charging variables TotalChargeTime = 0; CurrentChargeTime = 0; DamageTime = 0; FiringTime = 0; FlashTime = 0; ClearFlashLocation(); ClearTimer('RefireCheckTimer'); ClearPendingFire(0); super.EndState(NextStateName); } simulated function bool ShouldRefire() { return FiringTime > 0.0f; } simulated function bool IsFiring() { return FiringTime > 0.0f; } simulated function bool TryPutDown() { // can't put down when firing return false; } }; simulated function StartLoopingFireSound(byte FireModeNum) { local float ChargeLevel; switch (FireModeNum) { case ALTFIRE_FIREMODE: ChargeLevel = GetChargeLevel(); WeaponFireSnd[FireModeNum] = FireLoopSounds[ChargeLevel]; break; case CUSTOM_FIREMODE: ChargeLevel = GetChargeLevel(); WeaponFireSnd[FireModeNum] = ChargeSounds[ChargeLevel]; break; } super.StartLoopingFireSound(FireModeNum); } defaultproperties { FlameSprayArchetype = SprayActor_Flame'WEP_Laser_Cutter_ARCH.WEP_Laser_Cutter_Flame' ChargeTimePerLevel = 1.0f; ChargeConsumeTime = 0.12f; //Consumes 25 on full charge OverchargeConsumeTime = 0; //Setting to 0 or below deactivates ammo consumption while holding a charge // Shooting Animations FireSightedAnims[0]=Shoot_Iron FireSightedAnims[1]=Shoot_Iron2 FireSightedAnims[2]=Shoot_Iron3 // FOV MeshIronSightFOV=52 PlayerIronSightFOV=70 // Depth of field DOF_FG_FocalRadius=85 DOF_FG_MaxNearBlurSize=2.5 // Content PackageKey="Laser_Cutter" FirstPersonMeshName="wep_1p_laser_cutter_mesh.Wep_1stP_Laser_Cutter_Rig" FirstPersonAnimSetNames(0)="wep_1p_laser_cutter_anim.wep_1p_laser_cutter_anim" PickupMeshName="WEP_3P_Laser_Cutter_Mesh.Wep_3rdP_Laser_Cutter_Pickup" AttachmentArchetypeName="WEP_Laser_Cutter_ARCH.Wep_Laser_Cutter_3P" MuzzleFlashTemplateName="WEP_Laser_Cutter_ARCH.Wep_Laser_Cutter_MuzzleFlash_1P" // Zooming/Position PlayerViewOffset = (X = 3.0, Y = 10, Z = -1) IronSightPosition = (X = 0, Y = 0, Z = 0) // Ammo MagazineCapacity[0] = 50 SpareAmmoCapacity[0] = 300 InitialSpareMags[0] = 1 bCanBeReloaded = true bReloadFromMagazine = true // Recoil maxRecoilPitch = 100 minRecoilPitch = 70 maxRecoilYaw = 100 minRecoilYaw = -100 RecoilRate = 0.063 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 / Grouping InventorySize = 8 GroupPriority = 125 WeaponSelectTexture=Texture2D'WEP_UI_Laser_Cutter_TEX.UI_WeaponSelect_Laser_Cutter' AssociatedPerkClasses(0) = class'KFPerk_Survivalist' // 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_LazerCutter' InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_LazerCutter' FireInterval(DEFAULT_FIREMODE)=+0.0857 // 700 RPM Spread(DEFAULT_FIREMODE)=0.015 InstantHitDamage(DEFAULT_FIREMODE)=50.0 FireOffset=(X=30,Y=4.5,Z=-5) AmmoCost(DEFAULT_FIREMODE)=1 // ALT_FIREMODE FireModeIconPaths(ALTFIRE_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Electricity' WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_InstantHit WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_Bullet_LazerCutter' InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_LazerCutter_Beam' FireInterval(ALTFIRE_FIREMODE)=+0.07 // 857 RPM Spread(ALTFIRE_FIREMODE)=0.0085 InstantHitDamage(ALTFIRE_FIREMODE)=40.0 FiringStatesArray(ALTFIRE_FIREMODE)=LazerCharge AmmoCost(ALTFIRE_FIREMODE)=1 // BASH_FIREMODE InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_LazerCutter' InstantHitDamage(BASH_FIREMODE)=26 // Fire Effects WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue = AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_FullAuto_LP_3P', FirstPersonCue = AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_FullAuto_LP_1P') WeaponFireLoopEndSnd(DEFAULT_FIREMODE)=(DefaultCue = AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_FullAuto_LP_End_3P', FirstPersonCue = AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_FullAuto_LP_End_1P') WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LaserCutter_DryFire' SingleShotFireSnd=(DefaultCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_Single_3P', FirstPersonCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_Single_1P') WeaponFireSnd(ALTFIRE_FIREMODE)={( DefaultCue = AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_Beam_Shoot_LP_Level_0_3P', FirstPersonCue = AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_Beam_Shoot_LP_Level_0_1P' )} WeaponFireLoopEndSnd(ALTFIRE_FIREMODE)={( DefaultCue = AkEvent'WW_WEP_Lazer_Cutter.Stop_WEP_LazerCutter_Beam_Shoot_Loop_3P', FirstPersonCue = AkEvent'WW_WEP_Lazer_Cutter.Stop_WEP_LazerCutter_Beam_Shoot_LP_1P' )} WeaponFireSnd(CUSTOM_FIREMODE)={( DefaultCue = AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LaserCutter_Beam_Charged_LP_Level_0_3P', FirstPersonCue = AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LaserCutter_Beam_Charged_LP_Level_0_1P' )} WeaponFireLoopEndSnd(CUSTOM_FIREMODE)={( DefaultCue = AkEvent'WW_WEP_Lazer_Cutter.Stop_WEP_LazerCutter_Interrupt_3P', FirstPersonCue = AkEvent'WW_WEP_Lazer_Cutter.Stop_WEP_LazerCutter_Interrupt_1P' )} // Advanced (High RPM) Fire Effects bLoopingFireAnim(DEFAULT_FIREMODE)=true bLoopingFireSnd(DEFAULT_FIREMODE)=true bLoopingFireAnim(ALTFIRE_FIREMODE)=true bLoopingFireSnd(ALTFIRE_FIREMODE)=true bLoopingFireAnim(CUSTOM_FIREMODE)=true bLoopingFireSnd(CUSTOM_FIREMODE)=true // Attachments bHasIronSights = true bHasFlashlight = false FireModeIconPaths(CUSTOM_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Electricity' FiringStatesArray(CUSTOM_FIREMODE)=SprayingFireLazer WeaponFireTypes(CUSTOM_FIREMODE)=EWFT_Custom FireInterval(CUSTOM_FIREMODE)=+0.07 // 857 RPM AmmoCost(CUSTOM_FIREMODE)=1 BaseScale=40.f; ScalePerChargeLevel=10.f; DamagePerChargeLevel=5.f; FlashInterval = 0.15f; BaseDuration=0.25f; DurationPerChargeLevel=0.75f; MaxChargeLevel=3; ChargingRotationSpeedLimit = 0.f; ChargingMovementSpeedModifier = 1.f; FiringRotationSpeedLimit(0)=420.f; FiringRotationSpeedLimit(1)=240.f; FiringRotationSpeedLimit(2)=180.f; FiringRotationSpeedLimit(3)=120.f; FiringMovementSpeedModifier=0.75f; MaxRotationAdjustmentTime = 0.25f; RotationAdjustmentCurve = { (Points = ((InVal = 0.000000,OutVal = 120.0f), (InVal = 1.000000,OutVal = 2000.0f,InterpMode = CIM_CurveAuto))) } AltFireLoopStartAnim=Beam_Charge_In_lvl1; AltFireBeamInAnimL1=Beam_Charge_In_lvl2; AltFireBeamInAnimL2=Beam_Charge_In_lvl3; AltFireLoopAnimL1=Beam_Charge_Loop_lvl1; AltFireLoopAnimL2=Beam_Charge_Loop_lvl2; AltFireLoopAnimL3=Beam_Charge_Loop_lvl3; CustomFireLoopAnimL1=Beam_Shoot_Loop_lvl1; CustomFireLoopAnimL2=Beam_Shoot_Loop_lvl2; CustomFireLoopAnimL3=Beam_Shoot_Loop_lvl3; CustomFireLoopEndLastAnim=Beam_Shoot_End_Last; CustomFireLoopEndAnim=Beam_Shoot_End; bHasFireLastAnims=true 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))) MuzzleFlashEffectL1=ParticleSystem'WEP_Laser_Cutter_EMIT.FX_Laser_Cutter_Beam_Muzzleflash_01' MuzzleFlashEffectL2=ParticleSystem'WEP_Laser_Cutter_EMIT.FX_Laser_Cutter_Beam_Muzzleflash_02' MuzzleFlashEffectL3=ParticleSystem'WEP_Laser_Cutter_EMIT.FX_Laser_Cutter_Beam_Muzzleflash_03' ChargingEffect=ParticleSystem'WEP_Laser_Cutter_EMIT.FX_Laser_Cutter_Beam_Charge_00' FireLoopSounds(0)={( DefaultCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_Beam_Shoot_LP_Level_0_3P', FirstPersonCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_Beam_Shoot_LP_Level_0_1P')} FireLoopSounds(1)={( DefaultCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_Beam_Shoot_LP_Level_1_3P', FirstPersonCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_Beam_Shoot_LP_Level_1_1P')} FireLoopSounds(2)={( DefaultCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_Beam_Shoot_LP_Level_2_3P', FirstPersonCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_Beam_Shoot_LP_Level_2_1P')} FireLoopSounds(3)={( DefaultCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_Beam_Shoot_LP_Level_3_3P', FirstPersonCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_Beam_Shoot_LP_Level_3_1P')} FireLoopStop={( DefaultCue=AkEvent'WW_WEP_Lazer_Cutter.Stop_WEP_LazerCutter_Beam_Shoot_Loop_3P', FirstPersonCue=AkEvent'WW_WEP_Lazer_Cutter.Stop_WEP_LazerCutter_Beam_Shoot_LP_1P')} ChargeSounds(0)={( DefaultCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LaserCutter_Beam_Charged_LP_Level_0_3P', FirstPersonCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LaserCutter_Beam_Charged_LP_Level_0_1P')} ChargeSounds(1)={( DefaultCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LaserCutter_Beam_Charged_LP_Level_1_3P', FirstPersonCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LaserCutter_Beam_Charged_LP_Level_1_1P')} ChargeSounds(2)={( DefaultCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LaserCutter_Beam_Charged_LP_Level_2_3P', FirstPersonCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LaserCutter_Beam_Charged_LP_Level_2_1P')} ChargeSounds(3)={( DefaultCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LaserCutter_Beam_Charged_LP_Level_3_3P', FirstPersonCue=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LaserCutter_Beam_Charged_LP_Level_3_1P')} InterruptSoundEvent={( DefaultCue=AkEvent'WW_WEP_Lazer_Cutter.Stop_WEP_LazerCutter_Interrupt_3P', FirstPersonCue=AkEvent'WW_WEP_Lazer_Cutter.Stop_WEP_LazerCutter_Interrupt_1P')} PilotLightPlayEvent=AkEvent'WW_WEP_Lazer_Cutter.Play_WEP_LazerCutter_Idle_LP' PilotLightStopEvent=AkEvent'WW_WEP_Lazer_Cutter.Stop_WEP_LazerCutter_Idle_LP' DefaultFireModeColor=(R=5.f,G=1.f,B=20.f) EnergyColorL0=(R=5.f,G=1.f,B=20.f) EnergyColorL1=(R=20.f,G=5.f,B=200.f) EnergyColorL2=(R=5.f,G=25.f,B=200.f) EnergyColorL3=(R=20.f,G=50.f,B=200.f) NumBloodMapMaterials=5 }