mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-24 04:01:52 +00:00
Rebalance Doomsday Clock: late-game stalemate-breaker (10min grace + wave squeeze), slower troop drain, gentler-but-steeper warship attrition (#4518)
Resolves #<add your approved & assigned issue number> ## Description: Rebalances the Doomsday Clock so it acts as a **late-game stalemate-breaker** rather than an early-game culler, softens how fast it removes troops and warships, and makes the HUD countdown clearer. **Clock schedule (all presets):** - A flat **10-minute grace** at 0% required share — the early game is decided by combat, not the clock. - Then a 6-wave squeeze at accelerating levels (4 / 9 / 16 / 26 / 40 / 55%) with short pauses, reaching the final 55% at each preset's cap: **45 / 35 / 25 / 15 min** for slow / normal / fast / veryfast. - `WaveSchedule` `rampSeconds`/`pauseSeconds` are now **per-wave arrays**, so the curve can be shaped (gentle early, steeper late) instead of one uniform ramp. `requiredBasisPoints` and the HUD companion `doomsdayClockWaveState` walk the per-wave segments in lockstep. **Troop drain:** warn window `10s → 30s`, drain eased (`2%→5%` over `90s`), so a caught side takes ~2 minutes to wipe instead of ~1. **Warship attrition:** warships get their own gentler start plus a **convex** decay curve — a ship caught when its side is first doomed lasts about as long as troops, but the rate ramps up steeply so a side at full attrition still loses its fleet in ~2s. Adds a `curveExponent` argument to `doomsdayClockDrain` (1 = linear, used for troops; higher = convex, used for ships). **Determinism:** the drain curve is **integer-only** (fixed-point power, no floats), so the floored per-tick loss is bit-identical on every client in the lockstep sim. The linear troop path keeps its exact existing integer form; only the convex warship path is reshaped. **HUD countdown clarity:** the clock readout now shows a live countdown in both states — `Will reach 16% in M:SS` while the bar is actively climbing, and `Starts rising to 26% in M:SS` during a pause (previously `Next 26% in …`, which read as if it jumped there instantly). Backed by a new `secondsToTarget` field on the shared wave state so the sim and HUD stay in agreement. All display text goes through `translateText()` / `en.json`. <img width="278" height="116" alt="image" src="https://github.com/user-attachments/assets/e0be3d2c-bb88-46be-b344-34d63e4859bd" /> <img width="304" height="171" alt="image" src="https://github.com/user-attachments/assets/da74bd05-0b9a-4aec-bbf5-e7380fbda88e" /> **Danger skull:** while a side is below the bar in the warn window, its on-map skull now blinks progressively faster as the countdown runs out (accelerating to the moment the drain begins), then holds steady once it is actually draining — a clearer "you are about to be hit" cue. Rationale: the previous schedule removed players heavily in the first half of a match and could leave a drawn-out endgame. Holding the clock at 0% early keeps the opening about fighting, and concentrating its pressure in the back half reserves it for actually breaking stalemates. Values are tuning starting points and easy to adjust in `DoomsdayClock.ts` / the config defaults. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory ## Please put your Discord username so you can be contacted if a bug or regression is found: <add your Discord username>
This commit is contained in:
@@ -85,19 +85,23 @@ export const SAM_CONSTRUCTION_TICKS = 30 * 10;
|
||||
// Times in seconds. The required map share rises in waves (levels + times in
|
||||
// DoomsdayClock.ts, chosen by `speed`). A side caught below the bar gets a
|
||||
// warnSeconds cooldown ("Danger, decay in Xs"), then troops bleed to zero: the
|
||||
// warn (10s) + the linear drain (~55s from full troops, sooner with fewer troops
|
||||
// or a shrinking territory) make ~1 minute from caught to wiped out.
|
||||
// warn (30s) + the linear drain (~90s from full troops, sooner with fewer troops
|
||||
// or a shrinking territory) make ~2 minutes from caught to wiped out.
|
||||
const DOOMSDAY_CLOCK_DEFAULTS = {
|
||||
enabled: false,
|
||||
speed: "normal" as DoomsdayClockSpeed,
|
||||
warnSeconds: 10, // cooldown before decay after the bar catches you
|
||||
warnSeconds: 30, // cooldown (the flashing danger cue) before decay begins
|
||||
drainStartPercent: 2, // starts bleeding at once (already beats troop income)
|
||||
drainMaxPercent: 6,
|
||||
drainRampSeconds: 50, // ramps LINEARLY to the max over this long
|
||||
// Warships bleed on the same start + ramp but to a much higher ceiling than
|
||||
// troops, so a fleet at full attrition sinks in ~2s (50% of a ship's max
|
||||
// health per second) instead of riding out the gentle troop rate. Ships only.
|
||||
drainMaxPercent: 5,
|
||||
drainRampSeconds: 90, // ramps LINEARLY to the max over this long (~1:30 to zero)
|
||||
// Warships bleed on their OWN gentler start + a STEEP (convex) ramp to a much
|
||||
// higher ceiling. A ship caught when its side is first doomed lasts about as
|
||||
// long as troops (the low start + no income ≈ the troop net rate), but the rate
|
||||
// curves up sharply (warshipDrainCurveExponent), so once a side has been under
|
||||
// the clock the full ramp, ships sink in ~2s (50%/s). Ships only.
|
||||
warshipDrainStartPercent: 1,
|
||||
warshipDrainMaxPercent: 50,
|
||||
warshipDrainCurveExponent: 8, // >1 = convex: stays gentle early, then spikes
|
||||
};
|
||||
|
||||
export class Config {
|
||||
@@ -134,7 +138,9 @@ export class Config {
|
||||
drainStartPercent: d.drainStartPercent,
|
||||
drainMaxPercent: d.drainMaxPercent,
|
||||
drainRampSeconds: d.drainRampSeconds,
|
||||
warshipDrainStartPercent: d.warshipDrainStartPercent,
|
||||
warshipDrainMaxPercent: d.warshipDrainMaxPercent,
|
||||
warshipDrainCurveExponent: d.warshipDrainCurveExponent,
|
||||
};
|
||||
}
|
||||
spawnImmunityDuration(): Tick {
|
||||
|
||||
Reference in New Issue
Block a user