Code/k/PityCounter.cs
using System;
namespace Sandbox.k;
/// <summary>
/// A pity counter is a system that increases the probability
/// of a rare event occurring after a series of failures.
/// </summary>
public class PityCounter
{
private int _failures;
private readonly int _maxFailures; // The guaranteed success threshold
private readonly float _baseChance; // Base probability of success
private readonly float _pityIncrease; // How much chance increases per failure
public int Failures => _failures;
/// <summary>
/// How It Works:
/// 1) Each failed attempt increments the pity counter.
/// 2) The chance to get a rare outcome increases slightly after each failure.
/// 3) If a guaranteed threshold (e.g., 10 fails) is reached, the next attempt must succeed.
/// 4) If a success happens before the pity limit, the counter resets to 0.
/// </summary>
/// <param name="baseChance">The initial probability of success (before pity increases). Value from 0 to 1</param>
/// <param name="pityIncrease">The amount by which the success chance increases after each failure.</param>
/// <param name="maxFailures">The number of consecutive failures required to guarantee success.</param>
public PityCounter(float baseChance, float pityIncrease, int maxFailures)
{
_baseChance = baseChance;
_pityIncrease = pityIncrease;
_maxFailures = maxFailures;
_failures = 0;
}
public bool TryTrigger(float luckMultiplier = 1f)
{
float currentChance = (_baseChance * luckMultiplier) + (_failures * _pityIncrease);
// If max failures reached, guarantee success
if (_failures >= _maxFailures || Random.Shared.Float() < currentChance)
{
_failures = 0; // Reset pity counter
return true;
}
_failures++; // Increase pity counter on failure
return false;
}
public void Reset() => _failures = 0;
}