48 lines
2.8 KiB
C#
48 lines
2.8 KiB
C#
using Outnumbered.Config;
|
|
|
|
namespace Outnumbered.Domain;
|
|
|
|
// Pure survival run-economy + escalation curves. The wave state machine + run banking stay engine-side; this owns the
|
|
// numbers they read.
|
|
public static class SurvivalEconomy
|
|
{
|
|
// Bots ALIVE at once this wave (simultaneous pressure), ramping from AliveBase to AliveCap.
|
|
public static int AliveForWave(int wave, SurvivalConfig c) =>
|
|
Math.Clamp(c.AliveBase + c.AlivePerWave * (wave - 1), 1, c.AliveCap);
|
|
|
|
// Total kills to clear a wave.
|
|
public static int WaveBudget(int wave, int aliveHumans, SurvivalConfig c) =>
|
|
Math.Max(1, c.BudgetBase + c.BudgetPerWave * (wave - 1) + c.BudgetPerPlayer * aliveHumans);
|
|
|
|
// Monotonic escalate-only handicap floor in t-space; -1 = no floor (idle / between runs).
|
|
public static double HandicapFloor(int wave, SurvivalConfig c) =>
|
|
// wave>=1 and Max(1,MaxNerfWave)>=1 => quotient>=0, so the lower clamp can never bind; Min(1,x) == Clamp(x,0,1) here.
|
|
wave <= 0 ? -1.0 : Math.Min(1.0, wave / (double)Math.Max(1, c.MaxNerfWave));
|
|
|
|
// Per-wave XP multiplier: ramps exponentially from x1 (wave 1) to xWinMult (the final wave). WinMult is the single
|
|
// knob (the FINAL-wave / "win" multiplier). Back-loaded by design so early waves pay ~nothing and the last few pay big.
|
|
// waveMult(w) = WinMult ^ ((w-1)/(WaveCount-1))
|
|
public static double WaveMult(int wave, SurvivalConfig c) =>
|
|
Math.Pow(c.WinMult, (wave - 1) / (double)Math.Max(1, c.WaveCount - 1));
|
|
|
|
// XP granted at the END of ONE cleared wave: raw wave XP (HP-damage + HS/crit, already xp_mult-card-scaled when banked)
|
|
// x prestige x the wave multiplier. NO per-run cap, NO XpBoost stat, NO handicap mult here — depth is the gate (you must
|
|
// survive + contribute to reach the big back-wave multipliers), and the handicap mult stays excluded so run XP can't
|
|
// re-couple to gameable K/D. 0 for a non-positive wave.
|
|
public static long WaveXpLump(double rawWaveXp, int wave, int prestige, SurvivalConfig c, ProgressionConfig p)
|
|
{
|
|
if (rawWaveXp <= 0) return 0;
|
|
double lump = rawWaveXp * ProgressionModel.PrestigeXpMultiplier(prestige, p) * WaveMult(wave, c);
|
|
return (long)Math.Floor(lump);
|
|
}
|
|
|
|
// Raw combat XP banked into the CURRENT wave's accumulator, scaled by the xp_mult card (so it compounds with the
|
|
// per-wave prestige x waveMult chain applied at grant time).
|
|
public static double AccrueWaveXp(double amount, double xpMultCardPct) =>
|
|
amount * (1.0 + xpMultCardPct / 100.0);
|
|
|
|
// Team-card squad multiplier (compounding): global_deal increases, global_take decreases.
|
|
public static double TeamMult(int level, double perPickPct, bool increase) =>
|
|
increase ? Math.Pow(1.0 + perPickPct / 100.0, level)
|
|
: Math.Pow(Math.Max(0.0, 1.0 - perPickPct / 100.0), level);
|
|
}
|