A perk component that gives the player a health pack after being hit by melee damage a set number of times. It counts melee hits, spawns a flying health pack and plays a sound, and updates HUD display values and highlight visuals.
using Sandbox;
[Perk( Rarity.Epic, locked: true, alwaysOfferDebug: false )]
public class PerkHurtMeleeHealthPack : Perk
{
private int _meleeHitCount;
private enum Mod { HitsRequired }
static PerkHurtMeleeHealthPack()
{
Register<PerkHurtMeleeHealthPack>(
name: "Pain Relief",
imagePath: "textures/icons/vector/hurt_melee_health_pack.png",
description: level => $"+1 healthpack every {(int)GetValue( level, Mod.HitsRequired )} times\nyou're hit by melee dmg",
upgradeDescription: level => $"+1 healthpack every {(int)GetValue( level - 1, Mod.HitsRequired )}→{(int)GetValue( level, Mod.HitsRequired )} times\nyou're hit by melee dmg"
);
}
public override void Start()
{
base.Start();
HighlightColor = new Color( 0.3f, 1f, 0.5f );
HighlightDuration = 1f;
HighlightOpacity = 2.5f;
DisplayCooldownColor = new Color( 0.3f, 1f, 0.5f, 0.5f );
_meleeHitCount = 0;
RefreshDisplay();
}
public override void Refresh()
{
base.Refresh();
RefreshDisplay();
}
public override void OnHit( float amount, DamageType damageType, bool isSelfInflicted, Vector2 dir, float force, Enemy enemySource, EnemyType enemyType, float previousHealth )
{
base.OnHit( amount, damageType, isSelfInflicted, dir, force, enemySource, enemyType, previousHealth );
if ( !Player.IsDamageTypeMelee( damageType ) )
return;
if ( !(amount > 0f) )
return;
_meleeHitCount++;
Check();
}
void Check()
{
int hitsRequired = (int)GetValue( Level, Mod.HitsRequired );
if ( _meleeHitCount >= hitsRequired )
{
SpawnHealthPack();
_meleeHitCount -= hitsRequired;
Highlight();
IconScale = 1.4f;
IconAngleOffset = 20f;
}
RefreshDisplay();
}
void SpawnHealthPack()
{
var targetPos = Player.Position2D;
int tries = 0;
while ( targetPos.Distance( Player.Position2D ) < 300f )
{
var dir = Utils.GetRandomVector();
var dist = Game.Random.Float( 300f, 1000f );
targetPos = Manager.Instance.ClampPosToBounds( Player.Position2D + dir * dist );
tries++;
if ( tries > 20 )
break;
}
Manager.Instance.SpawnItemFlyToRpc( "health_pack", Player.Position2D, targetPos, time: Game.Random.Float( 1.4f, 1.8f ), height: Game.Random.Float( 220f, 250f ) );
Manager.Instance.PlaySfxNearbyRpc( "scuffle", Player.Position2D, pitch: Game.Random.Float( 0.95f, 1.05f ), volume: 1.3f, maxDist: 300f );
}
void RefreshDisplay()
{
int hitsRequired = (int)GetValue( Level, Mod.HitsRequired );
DisplayText = $"{hitsRequired - _meleeHitCount}";
DisplayCooldown = (float)_meleeHitCount / hitsRequired;
}
private static float GetValue( int level, Mod mod, bool isPercent = false )
{
switch ( mod )
{
case Mod.HitsRequired:
default:
switch( level )
{
case 1: default: return 13;
case 2: return 11;
case 3: return 9;
case 4: return 7;
}
}
}
}