initial commit
This commit is contained in:
commit
d701598350
67 changed files with 9351 additions and 0 deletions
41
Outnumbered/Domain/StatResolver.cs
Normal file
41
Outnumbered/Domain/StatResolver.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
using System.Collections.Frozen;
|
||||
using Outnumbered.Config;
|
||||
|
||||
namespace Outnumbered.Domain;
|
||||
|
||||
// Resolves a player's effective stat values from their invested levels + run-card bonuses. Takes a stat-def lookup
|
||||
// (key -> StatDef) rather than the named-field config, so it's already shaped for the stat registry — the engine builds
|
||||
// the dictionary once and passes it. `Eff` = permanent only; `EffRun` = permanent + survival card; `CardMag` = the
|
||||
// effect-card magnitude (a non-stat key, cards only).
|
||||
public static class StatResolver
|
||||
{
|
||||
private static readonly StatDef Zero = new(0, 0);
|
||||
|
||||
private static int LevelOf(in PlayerSnapshot s, string key) =>
|
||||
s.Upgrades is not null && s.Upgrades.TryGetValue(key, out var l) ? l : 0;
|
||||
|
||||
public static double Eff(in PlayerSnapshot s, string key, FrozenDictionary<string, StatDef> defs)
|
||||
{
|
||||
var d = defs.TryGetValue(key, out var def) ? def : Zero;
|
||||
return d.Base + LevelOf(s, key) * d.PerLevel;
|
||||
}
|
||||
|
||||
public static double EffRun(in PlayerSnapshot s, string key, FrozenDictionary<string, StatDef> defs) =>
|
||||
Eff(s, key, defs) + (s.Cards?.Bonus(key) ?? 0.0);
|
||||
|
||||
public static double CardMag(in PlayerSnapshot s, string key) => s.Cards?.Bonus(key) ?? 0.0;
|
||||
|
||||
public static int MaxHp(in PlayerSnapshot s, FrozenDictionary<string, StatDef> defs, int baseMax) =>
|
||||
baseMax + (int)EffRun(s, StatKeys.MaxHp, defs);
|
||||
|
||||
public static int MaxArmor(in PlayerSnapshot s, FrozenDictionary<string, StatDef> defs, int baseMax) =>
|
||||
baseMax + (int)EffRun(s, StatKeys.MaxArmor, defs);
|
||||
|
||||
// 0 at full HP, 1 near death — drives Berserk (ability + passive card). Health<=0 (a snapshot built with no live
|
||||
// pawn, or a downed pawn) yields 0, NOT 1: missing-HP scaling only applies to a live attacker, so "no pawn" must
|
||||
// mean "no bonus", not "max bonus" (guards the pd-less Snapshot path where Health defaults to 0).
|
||||
public static double MissingHpFraction(in PlayerSnapshot s, int maxHp) =>
|
||||
// Health>=1 (guarded) and maxHp>=1 => 1 - Health/maxHp < 1, so the upper clamp can't bind; only the lower
|
||||
// (overheal -> negative) is live. Math.Max(0, x) is bit-identical to Math.Clamp(x, 0, 1) here.
|
||||
maxHp <= 0 || s.Health <= 0 ? 0.0 : Math.Max(0.0, 1.0 - s.Health / (double)maxHp);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue