A gameplay perk class 'PerkMarkEnemy' that marks an enemy when the player touches them. It applies periodic damage to the marked enemy, manages visual highlight properties, enforces a short cooldown between marks, and unmarks previous targets when replaced or when the perk is removed.
using System;
using Sandbox;
[Perk( Rarity.Epic, locked: true, minUnlocksReq: 2, alwaysOfferDebug: false )]
public class PerkMarkEnemy : Perk
{
private const float COOLDOWN = 0.1f;
private Enemy _markedEnemy;
private TimeSince _timeSinceMark;
static PerkMarkEnemy()
{
Register<PerkMarkEnemy>(
name: "Mark of Doom",
imagePath: "textures/icons/vector/mark_enemy.png",
description: level => $"Touching an enemy marks them\nThe marked enemy takes {GetDamage( level )} dmg/s",
upgradeDescription: level => $"Touching an enemy marks them\nThe marked enemy\ntakes {GetDamage( level - 1 )}→{GetDamage( level )} dmg/s"
);
}
private static float GetDamage( int level ) => 3f * level;
public override void Start()
{
base.Start();
ShouldUpdate = true;
_timeSinceMark = COOLDOWN;
HighlightColor = new Color( 0.75f, 0.4f, 1f );
HighlightDuration = 0.2f;
HighlightOpacity = 3f;
}
public override void Update( float dt )
{
base.Update( dt );
DisplayCooldown = _timeSinceMark < COOLDOWN ? Utils.Map( _timeSinceMark, 0f, COOLDOWN, 1f, 0f ) : 0f;
}
public override void Refresh()
{
base.Refresh();
if ( _markedEnemy.IsValid() )
{
var status = _markedEnemy.GetUnitStatus<UnitStatusMarked>();
if ( status != null )
status.Damage = GetDamage( Level );
}
}
public override void Colliding( Thing other, float percent, float dt )
{
base.Colliding( other, percent, dt );
if ( other is Enemy enemy && !enemy.IsDying && !enemy.IsMarked && enemy != _markedEnemy && _timeSinceMark > COOLDOWN )
{
if ( _markedEnemy.IsValid() )
_markedEnemy.UnMark();
_markedEnemy = enemy;
_timeSinceMark = 0f;
enemy.Mark( Player, GetDamage( Level ) );
Highlight();
IconScale = 1.35f;
IconAngleOffset = Game.Random.Float( 12f, 18f ) * (Game.Random.Int( 0, 1 ) == 0 ? -1f : 1f);
}
}
public override void Remove( bool restart = false )
{
base.Remove( restart );
if ( _markedEnemy.IsValid() )
_markedEnemy.UnMark();
}
}