//============================================================================= // SeekerSixRocketLauncher //============================================================================= // Weapon class for the SeekerSix mini rocket launcher //============================================================================= // Killing Floor Source // Copyright (C) 2013 Tripwire Interactive LLC // - John "Ramm-Jaeger" Gibson //============================================================================= class SeekerSixRocketLauncher extends KFWeapon; var() Material Counter0; var() Material Counter1; var() Material Counter2; var() Material Counter3; var() Material Counter4; var() Material Counter5; var() Material Counter6; // Site reticles var() Material SiteReticle; var() Material SiteReticleLocked; // References to site reticles var string SiteReticleRef; var string SiteReticleLockedRef; var Pawn SeekTarget; var float LockTime, UnLockTime, SeekCheckTime; var bool bLockedOn, bBreakLock, bOldLockedOn; var bool bTightSpread; var(Seeking) float SeekCheckFreq, SeekRange; var(Seeking) float LockRequiredTime, UnLockRequiredTime; var(Seeking) float LockAim; var sound LockOnSound; // Locked on sound var sound LockLostSound; // Lost lock on sound var string LockOnSoundRef; var string LockLostSoundRef; replication { reliable if (Role == ROLE_Authority && bNetOwner) bLockedOn; } static function PreloadAssets(Inventory Inv, optional bool bSkipRefCount) { default.Counter0 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter0_Shader", class'Material', true)); default.Counter1 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter1_Shader", class'Material', true)); default.Counter2 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter2_Shader", class'Material', true)); default.Counter3 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter3_Shader", class'Material', true)); default.Counter4 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter4_Shader", class'Material', true)); default.Counter5 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter5_Shader", class'Material', true)); default.Counter6 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter6_Shader", class'Material', true)); default.SiteReticle = Material(DynamicLoadObject(default.SiteReticleRef, class'Material', true)); default.SiteReticleLocked = Material(DynamicLoadObject(default.SiteReticleLockedRef, class'Material', true)); if ( default.LockOnSoundRef != "" ) { default.LockOnSound = sound(DynamicLoadObject(default.LockOnSoundRef, class'Sound', true)); } if ( default.LockLostSoundRef != "" ) { default.LockLostSound = sound(DynamicLoadObject(default.LockLostSoundRef, class'Sound', true)); } if ( SeekerSixRocketLauncher(Inv) != none ) { SeekerSixRocketLauncher(Inv).Counter0 = default.Counter0; SeekerSixRocketLauncher(Inv).Counter1 = default.Counter1; SeekerSixRocketLauncher(Inv).Counter2 = default.Counter2; SeekerSixRocketLauncher(Inv).Counter3 = default.Counter3; SeekerSixRocketLauncher(Inv).Counter4 = default.Counter4; SeekerSixRocketLauncher(Inv).Counter5 = default.Counter5; SeekerSixRocketLauncher(Inv).Counter6 = default.Counter6; SeekerSixRocketLauncher(Inv).SiteReticle = default.SiteReticle; SeekerSixRocketLauncher(Inv).SiteReticleLocked = default.SiteReticleLocked; SeekerSixRocketLauncher(Inv).LockOnSound = default.LockOnSound; SeekerSixRocketLauncher(Inv).LockLostSound = default.LockLostSound; } super.PreloadAssets(Inv, bSkipRefCount); } static function bool UnloadAssets() { if ( super.UnloadAssets() ) { default.Counter0 = none; default.Counter1 = none; default.Counter2 = none; default.Counter3 = none; default.Counter4 = none; default.Counter5 = none; default.Counter6 = none; default.LockOnSound = none; default.LockLostSound = none; default.SiteReticle = none; default.SiteReticleLocked = none; return true; } return false; } simulated function WeaponTick(float dt) { super.WeaponTick(dt); if ( Level.NetMode!=NM_DedicatedServer) { if ((MagAmmoRemaining ) == 1) Skins[2] = Counter1; if ((MagAmmoRemaining ) == 2) Skins[2] = Counter2; if ((MagAmmoRemaining ) == 3) Skins[2] = Counter3; if ((MagAmmoRemaining ) == 4) Skins[2] = Counter4; if ((MagAmmoRemaining ) == 5) Skins[2] = Counter5; if ((MagAmmoRemaining ) == 6) Skins[2] = Counter6; if ((MagAmmoRemaining ) == 0) Skins[2] = Counter0; // Swap the site reticle if you are locked on if( bOldLockedOn != bLockedOn ) { bOldLockedOn = bLockedOn; if( bLockedOn ) { Skins[1] = SiteReticleLocked; } else { Skins[1] = SiteReticle; } } } } // Handle locking on function Tick(float dt) { local Pawn Other; local Vector StartTrace; local Rotator Aim; local float BestDist, BestAim; if (Instigator == None || Instigator.Weapon != self) return; if ( Role < ROLE_Authority ) return; if ( !Instigator.IsHumanControlled() ) return; if (Level.TimeSeconds > SeekCheckTime) { // if( !bAimingRifle ) // { // return; // } if( MagAmmoRemaining < 1 || bIsReloading ) { bLockedOn = false; SeekTarget = None; return; } if (bBreakLock) { bBreakLock = false; bLockedOn = false; SeekTarget = None; } StartTrace = Instigator.Location + Instigator.EyePosition(); Aim = Instigator.GetViewRotation(); BestAim = LockAim; Other = Instigator.Controller.PickTarget(BestAim, BestDist, Vector(Aim), StartTrace, SeekRange); if ( CanLockOnTo(Other) ) { if (Other == SeekTarget) { LockTime += SeekCheckFreq; if (!bLockedOn && LockTime >= LockRequiredTime) { bLockedOn = true; PlaySound(LockOnSound,SLOT_None,2.0); } } else { SeekTarget = Other; LockTime = 0.0; } UnLockTime = 0.0; } else { if (SeekTarget != None) { UnLockTime += SeekCheckFreq; if (UnLockTime >= UnLockRequiredTime) { SeekTarget = None; if (bLockedOn) { bLockedOn = false; PlaySound(LockLostSound,SLOT_None,2.0); } } } else bLockedOn = false; } SeekCheckTime = Level.TimeSeconds + SeekCheckFreq; } } // See if this weapon can lock on to the actor function bool CanLockOnTo(Actor Other) { local Pawn P; P = Pawn(Other); if (P == None || P == Instigator || !P.bProjTarget) return false; if (!Level.Game.bTeamGame) return true; if ( (Instigator.Controller != None) && Instigator.Controller.SameTeamAs(P.Controller) ) return false; return ( (P.PlayerReplicationInfo == None) || (P.PlayerReplicationInfo.Team != Instigator.PlayerReplicationInfo.Team) ); } //============================================================================= // Functions //============================================================================= function Projectile SpawnProjectile(Vector Start, Rotator Dir) { local SeekerSixRocketProjectile Rocket; local SeekerSixSeekingRocketProjectile SeekingRocket; bBreakLock = true; if (bLockedOn && SeekTarget != None) { SeekingRocket = Spawn(class'SeekerSixSeekingRocketProjectile',,, Start, Dir); SeekingRocket.Seeking = SeekTarget; return SeekingRocket; } else { Rocket = Spawn(class'SeekerSixRocketProjectile',,, Start, Dir); return Rocket; } } // Allow this weapon to auto reload on alt fire simulated function AltFire(float F) { if( MagAmmoRemaining < 1 && !bIsReloading && FireMode[1].NextFireTime <= Level.TimeSeconds ) { // We're dry, ask the server to autoreload ServerRequestAutoReload(); PlayOwnedSound(FireMode[1].NoAmmoSound,SLOT_None,2.0,,,,false); } super.AltFire(F); } simulated function bool ConsumeAmmo( int Mode, float Load, optional bool bAmountNeededIsMax ) { local Inventory Inv; local bool bOutOfAmmo; local KFWeapon KFWeap; if ( Super(Weapon).ConsumeAmmo(Mode, Load, bAmountNeededIsMax) ) { if ( Load > 0 && (Mode == 0 || bReduceMagAmmoOnSecondaryFire) ) MagAmmoRemaining -= Load; NetUpdateTime = Level.TimeSeconds - 1; if ( FireMode[Mode].AmmoPerFire > 0 && InventoryGroup > 0 && !bMeleeWeapon && bConsumesPhysicalAmmo && (Ammo[0] == none || FireMode[0] == none || FireMode[0].AmmoPerFire <= 0 || Ammo[0].AmmoAmount < FireMode[0].AmmoPerFire) && (Ammo[1] == none || FireMode[1] == none || FireMode[1].AmmoPerFire <= 0 || Ammo[1].AmmoAmount < FireMode[1].AmmoPerFire) ) { bOutOfAmmo = true; for ( Inv = Instigator.Inventory; Inv != none; Inv = Inv.Inventory ) { KFWeap = KFWeapon(Inv); if ( Inv.InventoryGroup > 0 && KFWeap != none && !KFWeap.bMeleeWeapon && KFWeap.bConsumesPhysicalAmmo && ((KFWeap.Ammo[0] != none && KFWeap.FireMode[0] != none && KFWeap.FireMode[0].AmmoPerFire > 0 &&KFWeap.Ammo[0].AmmoAmount >= KFWeap.FireMode[0].AmmoPerFire) || (KFWeap.Ammo[1] != none && KFWeap.FireMode[1] != none && KFWeap.FireMode[1].AmmoPerFire > 0 && KFWeap.Ammo[1].AmmoAmount >= KFWeap.FireMode[1].AmmoPerFire)) ) { bOutOfAmmo = false; break; } } if ( bOutOfAmmo ) { PlayerController(Instigator.Controller).Speech('AUTO', 3, ""); } } return true; } return false; } function float GetAIRating() { local AIController B; B = AIController(Instigator.Controller); if ( (B == None) || (B.Enemy == None) ) return AIRating; return (AIRating + 0.0003 * FClamp(1500 - VSize(B.Enemy.Location - Instigator.Location),0,1000)); } function byte BestMode() { return 0; } function bool RecommendRangedAttack() { return true; } //TODO: long ranged? function bool RecommendLongRangedAttack() { return true; } function float SuggestAttackStyle() { return -1.0; } simulated function AddReloadedAmmo() { UpdateMagCapacity(Instigator.PlayerReplicationInfo); if(AmmoAmount(0) >= MagCapacity) MagAmmoRemaining = MagCapacity; else MagAmmoRemaining = AmmoAmount(0) ; // Don't do this on a "Hold to reload" weapon, as it can update too quick actually and cause issues maybe - Ramm if( !bHoldToReload ) { ClientForceKFAmmoUpdate(MagAmmoRemaining,AmmoAmount(0)); } } defaultproperties { WeaponReloadAnim=Reload_IJC_SeekerSix IdleAimAnim=Idle_Iron SkinRefs(0)="KF_IJC_Halloween_Weapons2.SeekerSix.Seeker_Six_cmb" SkinRefs(1)="KF_IJC_Halloween_Weapons2.SeekerSix.Seeker_Sight_Shader" SleeveNum=3 SiteReticleRef="KF_IJC_Halloween_Weapons2.SeekerSix.Seeker_Sight_Shader" SiteReticleLockedRef="KF_IJC_Halloween_Weapons2.SeekerSix.Seeker_Sight_Lock_Shader" Weight=7.000000 MagCapacity=6 ReloadRate=3.13 ReloadAnim="Reload" ReloadAnimRate=1.0 FireModeClass(0)=Class'KFMod.SeekerSixFire' FireModeClass(1)=Class'KFMod.SeekerSixMultiFire' PutDownAnim="PutDown" SelectSoundRef="KF_FY_SeekerSixSND.WEP_SeekerSix_Foley_Select" SelectForce="SwitchToAssaultRifle" bModeZeroCanDryFire=True AIRating=0.650000 CurrentRating=0.650000 Description="An advanced Horzine mini missile launcher. Fire one, or all six, lock on and let 'em rip!" Priority=182 InventoryGroup=4 GroupOffset=16 PickupClass=Class'KFMod.SeekerSixPickup' PlayerViewOffset=(X=35.000000,Y=20.000000,Z=-5.000000) BobDamping=6.000000 AttachmentClass=Class'KFMod.SeekerSixAttachment' IconCoords=(X1=253,Y1=146,X2=333,Y2=181) ItemName="SeekerSix Rocket Launcher" LightType=LT_None LightBrightness=0.000000 LightRadius=0.000000 MeshRef="KF_IJC_Halloween_Weps_2.SeekerSix" DrawScale=1.000000 AmbientGlow=0 ZoomTime=0.25 FastZoomOutTime=0.2 ZoomInRotation=(Pitch=-910,Yaw=0,Roll=2910) bHasAimingMode=true DisplayFOV=65.000000 StandardDisplayFOV=65.0 PlayerIronSightFOV=70 ZoomedDisplayFOV=60 HudImageRef="KF_IJC_HUD.WeaponSelect.SeekerSix_unselected" SelectedHudImageRef="KF_IJC_HUD.WeaponSelect.SeekerSix" TraderInfoTexture=texture'KF_IJC_HUD.Trader_Weapon_Icons.Trader_SeekerSix' // Achievement Helpers bIsTier3Weapon=true SeekCheckFreq=0.25 SeekRange=25000 LockRequiredTime=0.75 UnLockRequiredTime=0.5 LockAim=0.95 LockOnSoundRef="KF_FY_SeekerSixSND.WEP_Seeker_LockOn_M" LockLostSoundRef="KF_FY_SeekerSixSND.WEP_Seeker_LockOnLost_M" AppID=258751 }