A unique perk class 'CurseHurtHover' that damages the local player when their mouse is hovering over their own player model. It tracks hover time and periodically applies self-damage, plays a highlight effect and randomizes icon visuals.
using System;
using Sandbox;
[Perk( Rarity.Unique, curse: true, controlMode: ControlMode.MouseAndKeyboard, alwaysOfferDebug: false, IncludedCategories = new[] { PerkCategory.SelfDmg })]
public class CurseHurtHover : Perk
{
private enum Mod { HpLoss };
// Track player rotation over time
private float _accumulatedTime;
private TimeSince _timeSinceHurt;
static CurseHurtHover()
{
Register<CurseHurtHover>(
name: "Sharp Cursor",
imagePath: "textures/icons/vector/curse_hurt_hover.png",
description: level => $"-{(int)GetValue( level, Mod.HpLoss )} hp when pointing at yourself"
);
}
public override void Start()
{
base.Start();
ShouldUpdate = true;
HighlightColor = new Color( 1f, 0.3f, 0.6f );
HighlightDuration = 0.75f;
HighlightOpacity = 6f;
}
public override void Refresh()
{
base.Refresh();
}
public override void Update( float dt )
{
base.Update( dt );
if( IsHoveringSelf() )
{
_accumulatedTime += dt;
var timeReq = 0.05f;
if( _accumulatedTime > timeReq && _timeSinceHurt > 0.5f )
{
Player.Damage( GetValue( Level, Mod.HpLoss ), DamageType.Self, Player.Position2D, Utils.GetRandomVector(), upwardAmount: Game.Random.Float(0f, 0.2f), force: 0f, ragdollForce: 1f, enemySource: null, enemyType: EnemyType.None);
Highlight();
IconScale = Game.Random.Float( 1.2f, 1.3f );
IconAngleOffset = Game.Random.Float( 10f, 20f ) * (Game.Random.Int( 0, 1 ) == 0 ? -1f : 1f);
_accumulatedTime -= timeReq;
_timeSinceHurt = 0f;
}
}
else
{
_accumulatedTime *= (1f - Time.Delta * 4f);
}
}
bool IsHoveringSelf()
{
var tr = Player.Scene.Trace.Sphere( 3f, Player.Scene.Camera.ScreenPixelToRay( Mouse.Position ), 2500f ).HitTriggersOnly().WithAllTags( "player" ).Run();
if ( tr.Hit )
{
var player = tr.GameObject?.GetComponent<Player>();
return player == Player;
}
return false;
}
private static float GetValue( int level, Mod mod, bool isPercent = false )
{
switch ( mod )
{
case Mod.HpLoss:
default:
return 11f;
//switch( level )
//{
// case 1: default: return 10;
// case 2: return 30;
// case 3: return 95;
//}
}
}
}