diff --git a/sources/Weapons/BaseWeaponClasses/Melee/NiceMeleeFire.uc b/sources/Weapons/BaseWeaponClasses/Melee/NiceMeleeFire.uc index 23195ed..f4cfd8c 100644 --- a/sources/Weapons/BaseWeaponClasses/Melee/NiceMeleeFire.uc +++ b/sources/Weapons/BaseWeaponClasses/Melee/NiceMeleeFire.uc @@ -272,19 +272,19 @@ simulated function HandleRecoil(float Rec){} defaultproperties { - weaponRange=70.000000 - damageDelay=0.300000 - ImpactShakeRotMag=(X=50.000000,Y=50.000000,Z=50.000000) - ImpactShakeRotRate=(X=10000.000000,Y=10000.000000,Z=10000.000000) - ImpactShakeRotTime=2.000000 - ImpactShakeOffsetMag=(X=10.000000,Y=10.000000,Z=10.000000) - ImpactShakeOffsetRate=(X=1000.000000,Y=1000.000000,Z=1000.000000) - ImpactShakeOffsetTime=2.000000 - MeleeHitVolume=1.000000 - HitEffectClass=Class'KFMod.KFMeleeHitEffect' - WideDamageMinHitAngle=1.000000 - bFiringDoesntAffectMovement=True - FireEndAnim= - FireForce="ShockRifleFire" - aimerror=100.000000 + weaponRange=70.000000 + damageDelay=0.300000 + ImpactShakeRotMag=(X=50.000000,Y=50.000000,Z=50.000000) + ImpactShakeRotRate=(X=10000.000000,Y=10000.000000,Z=10000.000000) + ImpactShakeRotTime=2.000000 + ImpactShakeOffsetMag=(X=10.000000,Y=10.000000,Z=10.000000) + ImpactShakeOffsetRate=(X=1000.000000,Y=1000.000000,Z=1000.000000) + ImpactShakeOffsetTime=2.000000 + MeleeHitVolume=1.000000 + HitEffectClass=Class'KFMod.KFMeleeHitEffect' + WideDamageMinHitAngle=1.000000 + bFiringDoesntAffectMovement=True + FireEndAnim= + FireForce="ShockRifleFire" + aimerror=100.000000 } diff --git a/sources/Weapons/Playable/Tools/NiceSyringe.uc b/sources/Weapons/Playable/Tools/NiceSyringe.uc new file mode 100644 index 0000000..56ac0d6 --- /dev/null +++ b/sources/Weapons/Playable/Tools/NiceSyringe.uc @@ -0,0 +1,108 @@ +class NiceSyringe extends NiceMeleeWeapon; + +var () int HealBoostAmount; +var float RegenTimer; +var localized string SuccessfulHealMessage; + +replication +{ + reliable if( Role == ROLE_Authority ) + ClientSuccessfulHeal; + +} + +simulated function PostBeginPlay() +{ + // Weapon will handle FireMode instantiation + Super.PostBeginPlay(); + + if( Role == ROLE_Authority ) { + HealBoostAmount = default.HealBoostAmount; + } +} + +// The server lets the client know they successfully healed someone +simulated function ClientSuccessfulHeal(String HealedName) +{ + if( PlayerController(Instigator.Controller) != none ) + { + PlayerController(Instigator.controller).ClientMessage(SuccessfulHealMessage$HealedName, 'CriticalEvent'); + } +} + +simulated function Timer() +{ + Super.Timer(); + if( KFPawn(Instigator)!=None && KFPawn(Instigator).bIsQuickHealing>0 && ClientState==WS_ReadyToFire ) + { + if( KFPawn(Instigator).bIsQuickHealing==1 ) + { + if( !HackClientStartFire() ) + { + if( Instigator.Health>=Instigator.HealthMax || ChargeBar()<0.75 ) + KFPawn(Instigator).bIsQuickHealing = 2; // Was healed by someone else or some other error occurred. + SetTimer(0.2,False); + return; + } + KFPawn(Instigator).bIsQuickHealing = 2; + SetTimer(FireMode[1].FireRate+0.5,False); + } + else + { + Instigator.SwitchToLastWeapon(); + KFPawn(Instigator).bIsQuickHealing = 0; + } + } + else if( ClientState==WS_Hidden && KFPawn(Instigator)!=None ) + KFPawn(Instigator).bIsQuickHealing = 0; // Weapon was changed, ensure to reset this. +} + +simulated function bool HackClientStartFire() +{ + if( StartFire(1) ) + { + if( Role 1 && KFPlayerController(Instigator.Controller) != none && + KFSteamStatsAndAchievements(KFPlayerController(Instigator.Controller).SteamStatsAndAchievements) != none ) + { + KFSteamStatsAndAchievements(KFPlayerController(Instigator.Controller).SteamStatsAndAchievements).AddSelfHeal(); + } +} + +function Timer() +{ + local float HealSum, HealPotency; + local KFPlayerReplicationInfo KFPRI; + + KFPRI = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo); + + HealSum = NiceSyringe(Weapon).HealBoostAmount; + + HealPotency = 1.0; + + if ( KFPRI != none && KFPRI.ClientVeteranSkill != none ) + HealPotency = KFPRI.ClientVeteranSkill.Static.GetHealPotency(KFPRI); + HealSum *= HealPotency; + + Load = 1; + ReduceAmmoClient(); + if ( NiceHumanPawn(Instigator) != none ) + NiceHumanPawn(Instigator).TakeHealing(NiceHumanPawn(Instigator), HealSum, HealPotency, KFWeapon(Instigator.Weapon)); + else + KFPawn(Instigator).GiveHealth(HealSum, Instigator.HealthMax); +} + +function bool AllowFire() +{ + if (Instigator.Health >= Instigator.HealthMax) + return false; + + return Weapon.AmmoAmount(ThisModeNum) >= AmmoPerFire; +} + +event ModeDoFire() +{ + Load = 1; + Super.ModeDoFire(); +} + +function PlayFiring() +{ + if ( Weapon.Mesh != None ) + { + if ( FireCount > 0 ) + { + if ( Weapon.HasAnim(FireLoopAnim) ) + { + Weapon.PlayAnim(FireLoopAnim, FireLoopAnimRate, 0.0); + } + else + { + Weapon.PlayAnim(FireAnim, FireAnimRate, 0.0); + } + } + else + { + Weapon.PlayAnim(FireAnim, FireAnimRate, 0.0); + } + } + Weapon.PlayOwnedSound(FireSound,SLOT_Interact,TransientSoundVolume,,TransientSoundRadius,Default.FireAnimRate/FireAnimRate,false); + ClientPlayForceFeedback(FireForce); // jdf + + FireCount++; +} + +defaultproperties { + AmmoClass=class'NiceSyringeAmmo' + AmmoPerFire=1 + TweenTime=0.1 + TransientSoundVolume=1.8 + FireAnim="AltFire" + FireRate=3.60000 + bModeExclusive=true + InjectDelay=0.1 + HealeeRange=70.000000 +} diff --git a/sources/Weapons/Playable/Tools/NiceSyringeAmmo.uc b/sources/Weapons/Playable/Tools/NiceSyringeAmmo.uc new file mode 100644 index 0000000..dc7731f --- /dev/null +++ b/sources/Weapons/Playable/Tools/NiceSyringeAmmo.uc @@ -0,0 +1,12 @@ +class NiceSyringeAmmo extends NiceAmmo; + +defaultproperties { + WeaponPickupClass=class'NiceSyringePickup' + AmmoPickupAmount=0 + MaxAmmo=4 + InitialAmount=1 + PickupClass=class'NiceSyringeAmmoPickup' + IconMaterial=Texture'KillingFloorHUD.Generic.HUD' + IconCoords=(X1=336,Y1=82,X2=382,Y2=125) + ItemName="Healing juice" +} diff --git a/sources/Weapons/Playable/Tools/NiceSyringeAmmoPickup.uc b/sources/Weapons/Playable/Tools/NiceSyringeAmmoPickup.uc new file mode 100644 index 0000000..600369e --- /dev/null +++ b/sources/Weapons/Playable/Tools/NiceSyringeAmmoPickup.uc @@ -0,0 +1,8 @@ +class NiceSyringeAmmoPickup extends NiceAmmoPickup; + +defaultproperties { + AmmoAmount=1 + InventoryType=class'NiceSyringe' + PickupMessage="Healing juice" + StaticMesh=StaticMesh'KillingFloorStatics.L85Ammo' +} diff --git a/sources/Weapons/Playable/Tools/NiceSyringeFire.uc b/sources/Weapons/Playable/Tools/NiceSyringeFire.uc new file mode 100644 index 0000000..287a10a --- /dev/null +++ b/sources/Weapons/Playable/Tools/NiceSyringeFire.uc @@ -0,0 +1,208 @@ +class NiceSyringeFire extends NiceMeleeFire; + +var float LastHealAttempt; +var float HealAttemptDelay; +var float LastHealMessageTime; +var float HealMessageDelay; +var localized string NoHealTargetMessage; +var KFHumanPawn CachedHealee; +var transient float PendingHealTime; + +simulated function DestroyEffects() +{ + super.DestroyEffects(); + + if (CachedHealee != None) + CachedHealee = none; +} + +simulated function bool AllowFire() { + local KFHumanPawn Healtarget; + local string healeeName; + if (!super.AllowFire()) { + return false; + } + if (CanFindHealee()) { + if( CachedHealee.PlayerReplicationInfo != none && + CachedHealee.PlayerReplicationInfo.PlayerName != "") + { + HealeeName = CachedHealee.PlayerReplicationInfo.PlayerName; + } + else { + HealeeName = CachedHealee.MenuName; + } + NiceSyringe(Weapon).ClientSuccessfulHeal(HealeeName); + // Give the messages if we missed our heal, can't find a target, etc + if ( KFPlayerController(Instigator.Controller) != none ) + { + if ( LastHealAttempt + HealAttemptDelay < Level.TimeSeconds) + { + PlayerController(Instigator.controller).ClientMessage(NoHealTargetMessage, 'CriticalEvent'); + LastHealAttempt = Level.TimeSeconds; + } + + if ( Level.TimeSeconds - LastHealMessageTime > HealMessageDelay ) + { + // if there's a Player within 2 meters who needs healing, say that we're trying to heal them + foreach Instigator.VisibleCollidingActors(class'KFHumanPawn', Healtarget, 100) + { + if ( Healtarget != Instigator && Healtarget.Health < Healtarget.HealthMax ) + { + PlayerController(Instigator.Controller).Speech('AUTO', 5, ""); + LastHealMessageTime = Level.TimeSeconds; + + break; + } + } + } + } + return true; + } + return false; +} + +function Timer() +{ + local KFPlayerReplicationInfo PRI; + local int MedicReward; + local KFHumanPawn Healed; + local float HealSum, HealPotency; // for modifying based on perks + + PRI = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo); + Healed = CachedHealee; + HealPotency = 1.0; + CachedHealee = none; + if ( Healed != none && Healed.Health > 0 && Healed != Instigator ) + { + Load = 1; + ReduceAmmoClient(); + + if ( PRI != none && PRI.ClientVeteranSkill != none ) + HealPotency = PRI.ClientVeteranSkill.Static.GetHealPotency(PRI); + + HealSum = NiceSyringe(Weapon).HealBoostAmount; + + HealSum *= HealPotency; + MedicReward = HealSum; + + if ( (Healed.Health + Healed.healthToGive + MedicReward) > Healed.HealthMax ) + { + MedicReward = Healed.HealthMax - (Healed.Health + Healed.healthToGive); + if ( MedicReward < 0 ) + { + MedicReward = 0; + } + } + + if ( NiceHumanPawn(Healed) != none ) + NiceHumanPawn(Healed).TakeHealing(NiceHumanPawn(Instigator), HealSum, HealPotency, KFWeapon(Instigator.Weapon)); + else + Healed.GiveHealth(HealSum, Healed.HealthMax); + + // Tell them we're healing them + PlayerController(Instigator.Controller).Speech('AUTO', 5, ""); + LastHealMessageTime = Level.TimeSeconds; + + if ( PRI != None ) + { + if ( MedicReward > 0 && KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements) != none ) + { + KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements).AddDamageHealed(MedicReward); + } + + // Give the medic reward money as a percentage of how much of the person's health they healed + MedicReward = int((FMin(float(MedicReward),Healed.HealthMax)/Healed.HealthMax) * 60); // Increased to 80 in Balance Round 6, reduced to 60 in Round 7 + + if ( class'ScrnBalance'.default.Mut.bMedicRewardFromTeam && Healed.PlayerReplicationInfo != none && Healed.PlayerReplicationInfo.Team != none ) { + // give money from team wallet + if ( Healed.PlayerReplicationInfo.Team.Score >= MedicReward ) { + Healed.PlayerReplicationInfo.Team.Score -= MedicReward; + PRI.Score += MedicReward; + } + } + else + PRI.Score += MedicReward; + + if ( KFHumanPawn(Instigator) != none ) + { + KFHumanPawn(Instigator).AlphaAmount = 255; + } + } + } +} + +function KFHumanPawn GetHealee() +{ + local KFHumanPawn KFHP, BestKFHP; + local vector Dir; + local float TempDot, BestDot; + + Dir = vector(Instigator.GetViewRotation()); + + foreach Instigator.VisibleCollidingActors(class'KFHumanPawn', KFHP, 80.0) + { + if ( KFHP.Health < KFHP.HealthMax && KFHP.Health > 0 ) + { + TempDot = Dir dot (KFHP.Location - Instigator.Location); + if ( TempDot > 0.7 && TempDot > BestDot ) + { + BestKFHP = KFHP; + BestDot = TempDot; + } + } + } + + return BestKFHP; +} + +// Can we find someone to heal +function bool CanFindHealee() +{ + local KFHumanPawn Healtarget; + + Healtarget = GetHealee(); + CachedHealee = Healtarget; + + // Can't use syringe if we can't find a target + if ( Healtarget == none ) + { + if ( KFPlayerController(Instigator.Controller) != none ) + { + KFPlayerController(Instigator.Controller).CheckForHint(53); + } + + return false; + } + + // Can't use syringe if our target is already being healed to full health. + if ( (Healtarget.Health == Healtarget.Healthmax) || ((Healtarget.healthToGive + Healtarget.Health) >= Healtarget.Healthmax) ) + { + return false; + } + + return true; +} + +function float GetFireSpeed() +{ + if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none ) + { + return KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.GetFireSpeedMod(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), Weapon); + } + + return 1; +} + +defaultproperties { + AmmoClass=class'NiceSyringeAmmo' + ammoPerFire=1 + + FireAnims(0)="Fire" + FireRate=2.800000 + damageDelay=0.36 + + HealAttemptDelay=0.5 + HealMessageDelay=10.0 + NoHealTargetMessage="You must be near another player to heal them!" + bWaitForRelease=true +} diff --git a/sources/Weapons/Playable/Tools/NiceSyringePickup.uc b/sources/Weapons/Playable/Tools/NiceSyringePickup.uc new file mode 100644 index 0000000..424c4e4 --- /dev/null +++ b/sources/Weapons/Playable/Tools/NiceSyringePickup.uc @@ -0,0 +1,19 @@ +class NiceSyringePickup extends NiceWeaponPickup; + +defaultproperties { + ItemName="Med-Syringe" + InventoryType=Class'NicePack.NiceSyringe' + Weight=0.000000 + cost=100 + AmmoCost=40 + BuyClipSize=1 + PickupMessage="You got the Med-Syringe." + PickupSound=Sound'Inf_Weapons_Foley.AmmoPickup' + PickupForce="AssaultRiflePickup" + StaticMesh=StaticMesh'KF_pickups_Trip.Syringe_pickup' + CollisionHeight=5.000000 + EquipmentCategoryID=0 + ItemShortName="Syringe" + AmmoItemName="Healing juice" + Description="Basic equipment, necessary for survival." +}