A multiplayer-only Epic perk that modifies healthpack behavior. It increases the player's extra HP from healthpacks and when the player gains a healthpack it spawns a visual ring and either heals nearby allies or damages them depending on a stat, using RPC calls to apply HealRpc/DamageRpc to nearby players.
using Sandbox;
using System;
[Perk( Rarity.Epic, multiplayerMode: MultiplayerMode.OnlyMultiplayer, locked: true, alwaysOfferDebug: false, IncludedCategories = new[] { PerkCategory.Aoe })]
public class PerkHealthPackHealAllies : Perk
{
private enum Mod { Percent };
public const float HEAL_RADIUS = 120f;
static PerkHealthPackHealAllies()
{
Register<PerkHealthPackHealAllies>(
name: "Shared Needles",
imagePath: "textures/icons/vector/health_pack_heal_allies.png",
description: level => $"Nearby players get\n+{(int)GetValue( level, Mod.Percent, true )}% hp from healthpacks you get",
upgradeDescription: level => $"Nearby players get\n+{(int)GetValue( level - 1, Mod.Percent, true )}%→+{(int)GetValue( level, Mod.Percent, true )}% hp\nfrom healthpacks you get"
);
}
public override void Start()
{
base.Start();
HighlightColor = new Color( 0f, 1f, 0f );
HighlightDuration = 0.75f;
HighlightOpacity = 2f;
}
public override void Refresh()
{
base.Refresh();
Player.Modify( this, PlayerStat.HealthPackExtraHp, GetValue( Level, Mod.Percent ), ModifierType.Add );
}
public override void OnGainHealthpack( float amount )
{
base.OnGainHealthpack( amount );
Vector2 pos = Player.Position2D;
float radius = HEAL_RADIUS * Player.Stats[PlayerStat.RadiusMultiplier];
//if ( Player.Stats[PlayerStat.HealthpackXpPercent] > 0f )
//{
// Manager.Instance.SpawnRingRpc( Player.Position2D, radius, new Color( 0.3f, 0.35f, 1f, 0.5f ), lifetime: 0.45f, path: "ring2" );
// var xpAmount = amount * Player.Stats[PlayerStat.HealthpackXpPercent];
// foreach ( Player player in Manager.Instance.AlivePlayers )
// {
// if ( player == Player )
// continue;
// if ( (player.Position2D - pos).LengthSquared < MathF.Pow( radius, 2f ) )
// player.AddXpRpc( xpAmount, XpSource.Healthpack );
// }
// HighlightColor = new Color( 0.3f, 0.3f, 1f );
// Highlight();
//}
if( Player.Stats[PlayerStat.HealthPacksHurt] > 0f )
{
Manager.Instance.SpawnRingRpc( Player.Position2D, radius, new Color(1f, 0.25f, 0.3f, 0.6f ), lifetime: 0.45f, path: "ring_spiky_2" );
var hurtAmount = amount * GetValue( Level, Mod.Percent );
foreach ( Player player in Manager.Instance.AlivePlayers )
{
if ( player == Player )
continue;
if ( (player.Position2D - pos).LengthSquared < MathF.Pow( radius, 2f ) )
{
var dir = (player.Position2D - Player.Position2D).Normal;
var hitPos = player.Position2D - dir * player.Radius;
player.DamageRpc( hurtAmount, DamageType.Aoe, hitPos, dir, upwardAmount: 0f, force: hurtAmount * 5f, ragdollForce: hurtAmount * 0.1f, enemySource: null, enemyType: EnemyType.None );
}
}
HighlightColor = new Color( 1f, 0f, 0f );
Highlight();
}
else
{
Manager.Instance.SpawnRingRpc( Player.Position2D, radius, new Color( 0.3f, 1f, 0.35f, 0.5f ), lifetime: 0.45f, path: "ring2" );
var healAmount = amount * GetValue( Level, Mod.Percent );
foreach ( Player player in Manager.Instance.AlivePlayers )
{
if ( player == Player )
continue;
if ( (player.Position2D - pos).LengthSquared < MathF.Pow( radius, 2f ) && player.Health < player.GetSyncStat( PlayerStat.MaxHp ) )
player.HealRpc( healAmount, playSfx: true, Player );
}
HighlightColor = new Color( 0f, 1f, 0f );
Highlight();
}
//var healthpackMaxHpLevel = Player.GetPerkLevel( TypeLibrary.GetType( typeof( PerkHealthPackMaxHp ) ) );
//if ( healthpackMaxHpLevel > 0 && !(Player.Health < Player.Stats[PlayerStat.MaxHp]) )
//{
//}
}
private static float GetValue( int level, Mod mod, bool isPercent = false )
{
switch ( mod )
{
case Mod.Percent:
default:
return isPercent
? 40f + 40f * level
: 0.40f + 0.40f * level;
}
}
}