1
0
KF2-Dev-Scripts/KFGameContent/Classes/KFWeap_HRG_WarthogWeapon.uc
2023-05-25 23:42:10 +03:00

495 lines
14 KiB
Ucode

//=============================================================================
// KFWeap_HRG_WarthogWeapon
//=============================================================================
// An HRG Warthog Grenade Launcher
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFWeap_HRG_WarthogWeapon extends KFWeap_GrenadeLauncher_Base;
var KFPawn_HRG_Warthog InstigatorDrone;
// Used to calculate parabola when spawn projectile
var KFPawn_Monster CurrentTarget;
// Used to force distance when throwing projectiles when the pawn dies
var float CurrentDistanceProjectile;
var float DistanceParabolicLaunch;
var transient float FireLookAheadSeconds;
simulated event PreBeginPlay()
{
super.PreBeginPlay();
StartLoadWeaponContent();
}
simulated state WeaponFiring
{
simulated function EndState(Name NextStateName)
{
local Pawn OriginalInstigator;
// The Instigator for this weapon is the Player owning the weapon (for Perk, damage, etc,. calculations)
// But for Weapon Firing end state logic we need to point to the real Drone Pawn so we don't mess
// With whichever weapon the Player had equipped at that point
OriginalInstigator = Instigator;
Instigator = InstigatorDrone;
super.EndState(NextStateName);
Instigator = OriginalInstigator;
}
}
simulated function FireAmmunition()
{
CurrentFireMode = DEFAULT_FIREMODE;
super.FireAmmunition();
}
simulated function GetMuzzleLocAndRot(out vector MuzzleLoc, out rotator MuzzleRot)
{
if (KFSkeletalMeshComponent(Mesh).GetSocketWorldLocationAndRotation('MuzzleFlash', MuzzleLoc, MuzzleRot) == false)
{
`Log("MuzzleFlash not found!");
}
}
simulated function Projectile ProjectileFire()
{
local vector RealStartLoc, AimDir, TargetLocation;
local rotator AimRot;
local class<KFProjectile> MyProjectileClass;
// tell remote clients that we fired, to trigger effects
if ( ShouldIncrementFlashCountOnFire() )
{
IncrementFlashCount();
}
MyProjectileClass = GetKFProjectileClass();
if( Role == ROLE_Authority || (MyProjectileClass.default.bUseClientSideHitDetection
&& MyProjectileClass.default.bNoReplicationToInstigator && Instigator != none
&& Instigator.IsLocallyControlled()) )
{
GetMuzzleLocAndRot(RealStartLoc, AimRot);
if (CurrentTarget != none)
{
TargetLocation = CurrentTarget.Location;
TargetLocation.Z += CurrentTarget.GetCollisionHeight() * 0.5f; // Add an offset on the location, so it matches correctly
AimDir = Normal(TargetLocation - RealStartLoc);
}
else
{
AimDir = Vector(Owner.Rotation);
}
return SpawnAllProjectiles(MyProjectileClass, RealStartLoc, AimDir);
}
return None;
}
simulated function KFProjectile SpawnProjectile( class<KFProjectile> KFProjClass, vector RealStartLoc, vector AimDir )
{
local KFProjectile SpawnedProjectile;
local int ProjDamage;
local Pawn OriginalInstigator;
local vector TargetLocation, Distance;
local float HorizontalDistance, TermA, TermB, TermC, InitialSpeed;
/*
* Instigator issues here. The instigator of the weapon here is the PlayerController which needs to replicate the projectile.
* We spawn it with that instigator, then we change to be able to be able to apply perk effects.
*/
// Spawn projectile
OriginalInstigator = Instigator;
Instigator = InstigatorDrone;
SpawnedProjectile = Spawn( KFProjClass, self,, RealStartLoc);
if( SpawnedProjectile != none && !SpawnedProjectile.bDeleteMe )
{
if (CurrentTarget != none) // This is used for regular shooting
{
//TargetLocation = CurrentTarget.Mesh.GetBoneLocation('Spine1');
TargetLocation = CurrentTarget.Location;
TargetLocation.Z += CurrentTarget.GetCollisionHeight() * 0.5f; // Add an offset on the location, so it matches correctly
// Apply look ahead
TargetLocation += CurrentTarget.Velocity * FireLookAheadSeconds;
}
else if (CurrentDistanceProjectile > 0.f) // This is used for the explosion when drone dies
{
TargetLocation = RealStartLoc + AimDir * CurrentDistanceProjectile;
TargetLocation.Z -= InstigatorDrone.DeployHeight; // We target more or less the ground
}
//CurrentTarget.DrawDebugSphere(TargetLocation, 100, 10, 0, 255, 0, true);
Distance = TargetLocation - RealStartLoc;
Distance.Z = 0.f;
HorizontalDistance = VSize(Distance); // 2D
// If bigger than minimal horizontal distance, and drone is higher than target..
if (HorizontalDistance > DistanceParabolicLaunch
&& RealStartLoc.Z > TargetLocation.Z)
{
// Parabolic launch calculation
// Tweak speed so it can fall on the TargetLocation, use parabolic launch, we assume an Angle = 0
// We transform from 3D to 2D, assume horizontal start is 0, and horizontal distance is the modulus of the vector distance to target
// Angle = 0 -> sin(0) -> 0 so no need to apply any initial Y velocity
// ( ( Y - Y0 ) / ( 0.5 * gravity ) )
TermA = (TargetLocation.Z - RealStartLoc.Z) / (-11.5f * 0.5f * 100.f); // gravity to cm/s
// ( X - X0 )^2 / V^2 -> assume XO is 0
TermB = HorizontalDistance * HorizontalDistance;
TermC = TermB / TermA;
InitialSpeed = Sqrt(TermC);
AimDir = Normal(Distance);
AimDir.Z = 0.f;
}
else
{
// No parabollic, so we force Speed
if (RealStartLoc.Z < TargetLocation.Z)
{
InitialSpeed = 3000.f;
}
else
{
InitialSpeed = 1000.f;
}
}
SpawnedProjectile.Speed = InitialSpeed;
SpawnedProjectile.MaxSpeed = 0;
SpawnedProjectile.TerminalVelocity = InitialSpeed * 2.f;
SpawnedProjectile.TossZ = 0.f;
// Mirror damage and damage type from weapon. This is set on the server only and
// these properties are replicated via TakeHitInfo
if ( InstantHitDamage.Length > CurrentFireMode && InstantHitDamageTypes.Length > CurrentFireMode )
{
ProjDamage = GetModifiedDamage(CurrentFireMode);
SpawnedProjectile.Damage = ProjDamage;
SpawnedProjectile.MyDamageType = InstantHitDamageTypes[CurrentFireMode];
}
SpawnedProjectile.UpgradeDamageMod = GetUpgradeDamageMod();
SpawnedProjectile.Init( AimDir );
}
Instigator = OriginalInstigator;
return SpawnedProjectile;
}
simulated function IncrementFlashCount()
{
local KFPawn P;
P = KFPawn(Owner);
if( P != None )
{
P.IncrementFlashCount( Self, CurrentFireMode );
}
}
simulated function Fire()
{
if (IsInState('WeaponFiring'))
{
return;
}
if (HasAmmo(DEFAULT_FIREMODE))
{
SendToFiringState(DEFAULT_FIREMODE);
}
}
simulated function StopFire(byte FireModeNum)
{
super.StopFire(FireModeNum);
GoToState('Inactive');
}
simulated function bool ShouldRefire()
{
return false;
}
simulated function ForceExplosionReplicateKill(Vector HitLocation, KFProj_HighExplosive_HRG_Warthog Proj)
{
HandleClientProjectileExplosion(HitLocation, Proj);
Proj.Shutdown(); // cleanup/destroy projectile
}
simulated function ForceExplosionReplicate(Actor Other, Vector HitLocation, Vector HitNormal, KFProj_HighExplosive_HRG_Warthog Proj)
{
HandleClientProjectileExplosion(HitLocation, Proj);
if (Proj.ExplosionTemplate != None)
{
Proj.TriggerExplosion(HitLocation, HitNormal, Other);
}
Proj.Shutdown(); // cleanup/destroy projectile
}
/**
* Starts playing looping FireSnd only (used for switching sounds in Zedtime)
*/
simulated function StartLoopingFireSound(byte FireModeNum)
{
if ( FireModeNum < bLoopingFireSnd.Length && bLoopingFireSnd[FireModeNum] && !ShouldForceSingleFireSound() )
{
bPlayingLoopingFireSnd = true;
KFPawn(Owner).SetWeaponAmbientSound(WeaponFireSnd[FireModeNum].DefaultCue, WeaponFireSnd[FireModeNum].FirstPersonCue);
}
}
/**
* Stops playing looping FireSnd only (used for switching sounds in Zedtime)
*/
simulated function StopLoopingFireSound(byte FireModeNum)
{
if ( bPlayingLoopingFireSnd )
{
KFPawn(Owner).SetWeaponAmbientSound(None);
if ( FireModeNum < WeaponFireLoopEndSnd.Length )
{
WeaponPlayFireSound(WeaponFireLoopEndSnd[FireModeNum].DefaultCue, WeaponFireLoopEndSnd[FireModeNum].FirstPersonCue);
}
bPlayingLoopingFireSnd = false;
}
}
simulated function PlayFireEffects( byte FireModeNum, optional vector HitLocation )
{
local name WeaponFireAnimName;
local KFPerk CurrentPerk;
local float TempTweenTime, AdjustedAnimLength;
local KFPawn KFPO;
// 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);
KFPO = KFPawn(Owner);
if( KFPO != none )
{
// Tell our pawn about any changes in animation speed
UpdateWeaponAttachmentAnimRate( GetThirdPersonAnimRate() );
if( KFPO.IsLocallyControlled() )
{
if( KFPO.IsFirstPerson() )
{
if ( !bPlayingLoopingFireAnim )
{
WeaponFireAnimName = GetWeaponFireAnim(FireModeNum);
if ( WeaponFireAnimName != '' )
{
AdjustedAnimLength = MySkelMesh.GetAnimLength(WeaponFireAnimName);
TempTweenTime = FireTweenTime;
CurrentPerk = GetPerk();
if( CurrentPerk != none )
{
CurrentPerk.ModifyRateOfFire( AdjustedAnimLength, self );
// We need to unlock the slide if we fire from zero ammo while uber ammo is active
if( EmptyMagBlendNode != none
&& BonesToLockOnEmpty.Length > 0
&& AmmoCount[GetAmmoType(FireModeNum)] == 0
&& CurrentPerk.GetIsUberAmmoActive(self) )
{
EmptyMagBlendNode.SetBlendTarget( 0, 0 );
TempTweenTime = 0.f;
}
}
PlayAnimation(WeaponFireAnimName, AdjustedAnimLength,, TempTweenTime);
}
}
// Start muzzle flash effect
CauseMuzzleFlash(FireModeNum);
}
HandleRecoil();
ShakeView();
if (AmmoCount[0] == 0 && ForceReloadTimeOnEmpty > 0)
{
SetTimer(ForceReloadTimeOnEmpty, false, nameof(ForceReload));
}
}
}
}
simulated function WeaponPlayFireSound(AkBaseSoundObject DefaultSound, AkBaseSoundObject FirstPersonSound)
{
// ReplicateSound needs an "out" vector
local vector SoundLocation;
if( Owner != None && !bSuppressSounds )
{
SoundLocation = KFPawn(Owner).GetPawnViewLocation();
if ( DefaultSound != None )
{
Owner.PlaySoundBase( DefaultSound, false, false, false, SoundLocation );
}
}
}
/** True if we want to override the looping fire sounds with fire sounds from another firemode */
simulated function bool ShouldForceSingleFireSound()
{
// If this weapon has a single-shot firemode, disable looping fire sounds during zedtime
if ( `IsInZedTime(Instigator) && SingleFireSoundIndex != 255 )
{
return true;
}
return false;
}
simulated function bool HasAlwaysOnZedTimeResist()
{
return true;
}
defaultproperties
{
// Inventory / Grouping
InventorySize=5
GroupPriority=25
WeaponSelectTexture=Texture2D'WEP_UI_AutoTurret_TEX.UI_WeaponSelect_AutoTurret'
// FOV
MeshIronSightFOV=52
PlayerIronSightFOV=70
// Depth of field
DOF_FG_FocalRadius=75
DOF_FG_MaxNearBlurSize=3.5
// Zooming/Position
PlayerViewOffset=(X=9.0,Y=10,Z=-4)
// Content
PackageKey="HRG_WarthogWeapon"
FirstPersonMeshName="Wep_1P_HRG_WarthogWeapon_MESH.Wep_1stP_HRG_WarthogWeapon_Rig"
FirstPersonAnimSetNames(0)="Wep_1P_HRG_WarthogWeapon_ANIM.Wep_1stP_HRG_WarthogWeapon_Anim"
PickupMeshName="WEP_3P_HRG_WarthogWeapon_MESH.Wep_HRG_Warthog_Pickup"
AttachmentArchetypeName="WEP_HRG_WarthogWeapon_ARCH.HRG_WarthogWeaponAttachment"
MuzzleFlashTemplateName="WEP_HRG_WarthogWeapon_ARCH.HRG_WarthogWeapon_MuzzleFlash"
// Zooming/Position
IronSightPosition=(X=0,Y=0,Z=0)
// Ammo
MagazineCapacity[0]=35
SpareAmmoCapacity[0]=0
InitialSpareMags[0]=0
bCanBeReloaded=false
bReloadFromMagazine=false
// Recoil
maxRecoilPitch=225
minRecoilPitch=150
maxRecoilYaw=150
minRecoilYaw=-150
RecoilRate=0.085
RecoilMaxYawLimit=500
RecoilMinYawLimit=65035
RecoilMaxPitchLimit=900
RecoilMinPitchLimit=65035
RecoilISMaxYawLimit=75
RecoilISMinYawLimit=65460
RecoilISMaxPitchLimit=195
RecoilISMinPitchLimit=65460
RecoilViewRotationScale=0.25
IronSightMeshFOVCompensationScale=1.5
// DEFAULT_FIREMODE
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Grenade'
FiringStatesArray(DEFAULT_FIREMODE)=WeaponFiring
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_HighExplosive_HRG_Warthog'
FireInterval(DEFAULT_FIREMODE)=+0.7
InstantHitDamage(DEFAULT_FIREMODE)=10.0
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_HRG_Warthog'
Spread(DEFAULT_FIREMODE)=0.0
FireOffset=(X=30,Y=4.5,Z=-4)
// ALT_FIREMODE
FiringStatesArray(ALTFIRE_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_None
// BASH_FIREMODE
WeaponFireTypes(BASH_FIREMODE)=EWFT_None
// Fire Effects
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_HRG_Warthog.Play_WEP_HRG_Warthog_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_HRG_Warthog.Play_WEP_HRG_Warthog_Fire_1P')
//@todo: add akevent when we have it
WeaponDryFireSnd(DEFAULT_FIREMODE)=none
// Attachments
bHasIronSights=false
bHasFlashlight=false
AssociatedPerkClasses(0)=class'KFPerk_Demolitionist'
WeaponFireWaveForm=ForceFeedbackWaveform'FX_ForceFeedback_ARCH.Gunfire.Heavy_Recoil_SingleShot'
// Weapon Upgrade stat boosts
//WeaponUpgrades[1]=(IncrementDamage=1.12f,IncrementWeight=1)
//WeaponUpgrades[2]=(IncrementDamage=1.3f,IncrementWeight=2)
//WeaponUpgrades[3]=(IncrementDamage=1.55f,IncrementWeight=3)
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.12f), (Stat=EWUS_Weight, Add=1)))
WeaponUpgrades[2]=(Stats=((Stat=EWUS_Damage0, Scale=1.3f), (Stat=EWUS_Weight, Add=2)))
WeaponUpgrades[3]=(Stats=((Stat=EWUS_Damage0, Scale=1.55f), (Stat=EWUS_Weight, Add=3)))
InstigatorDrone=none
CurrentTarget=none
CurrentDistanceProjectile=-1.f
DistanceParabolicLaunch=150.f //cm
FireLookAheadSeconds=0.2f
}