A Perk class 'PerkMoreRerollsLoseHp' that triggers on player level-up. It reduces the player's HP to 1, and if the HP lost meets a threshold it grants a reroll item (or directly increments rerolls), an armor item, and permanently increases player max HP by 1 (tracked via a modifier). It also spawns visual/sound effects and floater text.
using Sandbox;
using System;
using System.Numerics;
[Perk( Rarity.Legendary, locked: true, minUnlocksReq: 3, alwaysOfferDebug: false, IncludedCategories = new[] { PerkCategory.SelfDmg, PerkCategory.OneHpLeft })]
public class PerkMoreRerollsLoseHp : Perk
{
private enum Mod { HpRequired };
private int _maxHpAdded;
// todo: make ">30" a richtext, so it doesn't render like "> 30"
static PerkMoreRerollsLoseHp()
{
Register<PerkMoreRerollsLoseHp>(
name: "Blood Donation",
imagePath: "textures/icons/vector/more_rerolls_lose_hp.png",
description: level => $"Lose all but 1 hp on level-up\nIf you lose at least {(int)GetValue( level, Mod.HpRequired )} hp,\nget +1 reroll-item +10 armor-item and +1 max hp",
upgradeDescription: level => $"Lose all but 1 hp on level-up\nIf you lose at least {(int)GetValue( level - 1, Mod.HpRequired )}→{(int)GetValue( level, Mod.HpRequired )} hp,\nget +1 reroll-item +10 armor-item and +1 max hp"
);
}
public override void Start()
{
base.Start();
HighlightColor = new Color( 1f, 0.25f, 0.4f );
HighlightDuration = 0.5f;
HighlightOpacity = 3f;
}
public override void Refresh()
{
base.Refresh();
}
public override void OnPlayerLevelUp()
{
base.OnPlayerLevelUp();
float hpToLose = Player.Health - 1f;
if ( hpToLose > 0f )
{
// todo: better sfx? can't hear it
Player.Damage( hpToLose, damageType: DamageType.Self, Player.Position2D, Utils.GetRandomVector(), upwardAmount: 0f, 0f, ragdollForce: 0.1f, enemySource: null, enemyType: EnemyType.None, cantKill: true );
if( hpToLose >= GetValue(Level, Mod.HpRequired ) )
{
if ( Manager.Instance.IsUnpausedChoosing )
{
var rerollPos = Player.Position2D + Utils.GetRandomVector() * Game.Random.Float( 1f, 5f );
Manager.Instance.SpawnItemRpc( "reroll_item", rerollPos, Utils.GetRandomVectorInCone(-Player.FacingDir ) );
Player.DodgeDuckRpc( dir: Utils.GetRandomVectorInCone( -Player.FacingDir ), time: Game.Random.Float( 0.1f, 0.125f ) );
}
else
{
Player.AddRerolls( 1 );
}
var armorPos = Player.Position2D + Utils.GetRandomVector() * Game.Random.Float( 1f, 5f );
Manager.Instance.SpawnItemRpc( "armor_item", armorPos, Utils.GetRandomVectorInCone( -Player.FacingDir ) );
_maxHpAdded += 1;
Player.Modify( this, PlayerStat.MaxHp, _maxHpAdded, ModifierType.Add );
Manager.Instance.SpawnFloaterTextRpc( Player.WorldPosition.WithZ( 20f ), $"+1 MAX HP!", new Color( 0f, 0.8f, 0f ), size: 1.2f, FloaterType.PositiveMessage );
}
}
Highlight();
}
private static float GetValue( int level, Mod mod, bool isPercent = false )
{
switch ( mod )
{
case Mod.HpRequired:
default:
return 30f - 10f * level;
}
}
}