using PkmnLib.Dynamic.Libraries; namespace PkmnLib.Plugin.Gen7.Libraries.Battling; public class Gen7CaptureLibrary : ICaptureLibrary { private readonly Gen7PluginConfiguration _configuration; public Gen7CaptureLibrary(Gen7PluginConfiguration configuration) { _configuration = configuration; } /// public CaptureResult TryCapture(IPokemon target, IItem captureItem, IBattleRandom random) { var maxHealth = target.BoostedStats.Hp; var currentHealth = target.CurrentHealth; var catchRate = target.Species.CaptureRate; byte bonusBall = 1; if (target.Library.ScriptResolver.TryResolveBattleItemScript(captureItem, out var script) && script is PokeballScript pokeballScript) { bonusBall = pokeballScript.GetCatchRate(target); } byte bonusStatus = 1; target.RunScriptHook(x => x.ChangeCatchRateBonus(target, captureItem, ref bonusStatus)); var modifiedCatchRate = (3.0f * maxHealth - 2.0f * currentHealth) * catchRate * bonusBall / (3.0f * maxHealth); modifiedCatchRate *= bonusStatus; var shakeProbability = 65536 / Math.Pow(255 / modifiedCatchRate, 0.1875f); byte shakes = 0; if (modifiedCatchRate >= 255) { shakes = 4; } else { var timesCaught = _configuration.TimesSpeciesCaught(target.Species); if (timesCaught > 30) { var criticalCaptureModifier = timesCaught switch { > 600 => 2.5f, > 450 => 2.0f, > 300 => 1.5f, > 150 => 1.0f, > 30 => 0.5f, // Default arm, should be heuristically unreachable (due to the timesCaught > 30 check above) _ => throw new ArgumentOutOfRangeException(), }; var criticalCaptureChance = (int)(modifiedCatchRate * criticalCaptureModifier / 6); if (random.GetInt(0, 256) < criticalCaptureChance) { return new CaptureResult(true, 1, true); } } for (var i = 0; i < 4; i++) { if (random.GetInt(0, 65536) < shakeProbability) { shakes++; } } } var success = shakes >= 3; return new CaptureResult(success, shakes, false); } }