A unique curse perk that damages the player when they touch the arena bounds (the fence). It checks the player's 2D position each update and, if outside expanded bounds, applies damage, knockback, visual highlight and plays a nearby sound.
using Sandbox;
using System;
using System.Numerics;
[Perk( Rarity.Unique, curse: true, alwaysOfferDebug: false, IncludedCategories = new[] { PerkCategory.SelfDmg })]
public class CurseArenaBoundsHurt : Perk
{
private enum Mod { Dmg };
private TimeSince _timeSinceDmg;
static CurseArenaBoundsHurt()
{
Register<CurseArenaBoundsHurt>(
name: "Sharp Fence",
imagePath: "textures/icons/vector/curse_arena_bounds_hurt.png",
description: level => $"-{GetValue( level, Mod.Dmg )} hp when you\ntouch the fence"
);
}
public override void Start()
{
base.Start();
ShouldUpdate = true;
}
public override void Refresh()
{
base.Refresh();
}
public override void Update( float dt )
{
base.Update( dt );
float cooldown = GetValue( Level, Mod.Dmg );
if ( _timeSinceDmg > 0.5f && !Player.IsInTheAir )
{
var pos = Player.Position2D;
var amount = 1.05f;
var minX = Manager.Instance.BOUNDS_MIN.x - Player.BoundsExpand + Player.Radius * amount;
var maxX = Manager.Instance.BOUNDS_MAX.x + Player.BoundsExpand - Player.Radius * amount;
var minY = Manager.Instance.BOUNDS_MIN.y - Player.BoundsExpand + Player.Radius * amount;
var maxY = Manager.Instance.BOUNDS_MAX.y + Player.BoundsExpand - Player.Radius * amount;
if ( pos.x > maxX && pos.y > maxY ) GetHurt( new Vector2( -1f, -1f ) );
else if ( pos.x > maxX && pos.y < minY ) GetHurt( new Vector2( -1f, 1f ) );
else if ( pos.x < minX && pos.y > maxY ) GetHurt( new Vector2( 1f, -1f ) );
else if ( pos.x < minX && pos.y < minY ) GetHurt( new Vector2( 1f, -1f ) );
else if ( pos.x > maxX ) GetHurt( new Vector2( -1f, 0f ) );
else if ( pos.x < minX ) GetHurt( new Vector2( 1f, 0f ) );
else if ( pos.y > maxY ) GetHurt( new Vector2( 0f, -1f ) );
else if ( pos.y < minY ) GetHurt( new Vector2( 0f, 1f ) );
}
}
private static float GetValue( int level, Mod mod, bool isPercent = false )
{
switch ( mod )
{
case Mod.Dmg:
default:
return 20f;
}
}
void GetHurt( Vector2 dir )
{
Player.Damage( GetValue( Level, Mod.Dmg), DamageType.Self, Player.Position2D, dir, upwardAmount: 0f, force: 0f, ragdollForce: 1f, enemySource: null, enemyType: EnemyType.None );
Player.Velocity += dir.Normal * Game.Random.Float( 600f, 800f );
_timeSinceDmg = 0f;
HighlightColor = new Color( 0.85f, 0.2f, 1f );
HighlightDuration = 0.5f;
HighlightOpacity = 4f;
Highlight();
Manager.Instance.PlaySfxNearbyRpc( "fence.hurt", Player.Position2D, pitch: Game.Random.Float( 0.9f, 1.1f ), volume: 2f, maxDist: 400f );
IconScale = Game.Random.Float( 1.2f, 1.3f );
IconAngleOffset = Game.Random.Float( 10f, 20f ) * (Game.Random.Int( 0, 1 ) == 0 ? -1f : 1f);
}
}