Skip to content

v1.24.0

Choose a tag to compare

@duysqubix duysqubix released this 26 May 18:36
· 72 commits to master since this release

v1.24.0 — The Arena Has Waves Now

Last release made arena combat hit back. This one makes each fight harder than the last.

In v1.23 every round of a tier felt roughly the same — monsters scaled a little per round but the curve was nearly flat. You'd clear all 10 rounds of the Gauntlet at full HP because rounds 1 and 10 played out the same way. That's not what the user asked for, and the data didn't lie: a L150 prestige-3 Godslayer was clearing the entire 49-round Godslayer's Court at 39% HP, taking 1% of max HP per round on average. The arena's headline tier was a victory lap.

v1.24 introduces wave-based escalation — a step function on enemy HP, accuracy, and crit chance that turns each tier into a deliberate gauntlet where round 10 is something you genuinely flex about clearing.


⚔️ Wave-Based Combat

Every arena round is now mapped to a difficulty wave. The wave determines three independent multipliers that compound:

Wave Rounds HP multiplier Hit cap Enemy crit%
Warmup 1-3 ×1.0 18 (10% land) 0%
Building 4-6 ×1.4 17 (15% land) 3%
Tense 7-9 ×2.0 15 (25% land) 6%
Boss-tier 10-15 ×3.0 14 (30% land) 8%
Brutal 16-25 ×4.5 12 (40% land) 12%
Nightmare 26-40 ×6.5 10 (50% land) 18%
Endgame 41+ ×9.0 8 (65% land) 22%

Each row is a wall. Rounds 1-3 are a warmup so newbies can ease in. Round 4 is the first wall — monster HP nearly doubles. Round 7 is the second wall — monsters now have a 25% land rate against your defense regardless of how high you stacked it, and they have a 6% chance to crit you for double damage. Round 10 is the boss-tier wall — almost no one will clear it on their first run.

For your L26 Warrior with a Rare+4 weapon, the Gauntlet now looks like this in real numbers:

Round Enemy HP Enemy hit% Enemy crit% Realistic swings to kill
1 127 10% 0% 3
5 207 15% 3% 5
7 322 25% 6% 8
10 707 30% 8% 17

The cumulative damage in a single Gauntlet attempt — even when you cash out at round 7 — now eats 30-50% of your HP. Pushing to round 10 means real risk of KO.

💥 Enemy Critical Hits

Late-round enemies can now crit you for double damage with a new message variant:

CRITICAL! The Heap Corruptor crushes your guard for 88 damage! HP: 60/190
CRITICAL! The Page Fault Phantom lands a devastating blow! 76 damage! HP: 14/180
CRITICAL! The Race Condition Reaper eviscerates you for 92 damage! HP: 0/152

Crit chance is 0% in the warmup waves so the early game is unchanged, then ramps up: 3% in wave 2, 6% in wave 3, 8% in boss-tier (wave 4), all the way to 22% in endgame waves. A boss-tier 30-swing fight at 8% crit chance gives you roughly 2.4 expected crit damage events — enough to randomly swing a marginal fight into a KO.

The crit message is distinct (red CRITICAL! prefix, different action verbs) so you can tell when it happens.

🎯 Accuracy Cap Ramps Per Wave

In v1.23 the enemy hit threshold was capped at a fixed 18 across all rounds, giving a permanent 10-15% land rate regardless of how deep you pushed. That's why round 25 of Abyssal felt the same as round 5 — the enemy hit rate was identical.

In v1.24 the cap is per-wave. Warmup cap is 18 (10% land); by Wave 4 (round 10) it's 14 (30%); by Wave 6 (round 26) it's 10 (50%). A defense-stacked tank still benefits from gear, but the cap eats into them progressively as they push deeper into a tier.

🧪 The Black-Mirror Balance Simulator (dev-tool)

The fixes in this release weren't tuned by feel. They came out of a Python harness at dev-tools/balance-sim/ that runs hundreds of compressed shellquest playthroughs in parallel and persists every metric to SQLite. Think of it as the Hang the DJ episode for shellquest: a thousand simulated lives across class × race × strategy combinations, each one driving a real sq binary through tick → equip → enchant → arena cycles, recording every action, every drop, every arena attempt for later analysis.

The simulator validated this release end-to-end. For the v1.24-soft tuning we shipped:

  • Pit (tier 1) — 13/13 Wizards survived, 6/6 Rogues, all clearing 4 rounds. The entry tier still works for newbies. ✓
  • Gauntlet (tier 2) — most attempts end in KO around round 7-9 (~0-30% survival rate). Pushing to round 10 is a real flex. ✓
  • Enemy crits fire on schedule — 0.14-0.50 crits per arena attempt depending on tier depth. ✓
  • No class is broken — all 5 classes reach L40 in 1300-2100 ticks, similar progression curves. ✓

The harness lives outside the shellquest binary — it's a Python tool that calls sq as a subprocess, parses save.json directly, and aggregates 24-run sweeps in ~4 minutes wall clock with --parallel 4. Future balance changes get tested with empirical data instead of intuition.

Usage:

cd dev-tools/balance-sim

# Run a small validation sweep
python3 runner.py --runs 3 --classes Warrior Wizard --strategies greedy balanced \
                  --target-level 40 --max-ticks 2500 --parallel 4 \
                  --tuning-label my-test

# Generate the report
python3 report.py --tuning-label my-test --output reports/my-test.md

See dev-tools/balance-sim/README.md for the full reference.

🧪 Tests

Seven new arena tuning tests pin the wave-based behaviour:

  • enemy_hp_at_round_ten_is_meaningfully_harder_than_round_one — locks in ≥4× HP scaling at round 10.
  • enemy_hp_curve_is_monotonic_non_decreasing_through_round_fifty — guards against accidental wave-table inversions.
  • enemy_hit_cap_grows_stricter_in_later_waves — locks in the per-wave cap ramp.
  • high_defense_player_takes_more_hits_in_late_rounds_than_early — verifies the cap actually changes hit rate end-to-end.
  • enemy_does_not_crit_in_warmup_waves — exhaustive check that rounds 1-3 are crit-free.
  • enemy_can_crit_in_late_waves_but_not_always — confirms the crit roll is probabilistic, not deterministic.
  • enemy_crit_message_contains_critical_marker_and_doubled_damage — locks in the new tournament_enemy_crit message contract.

Total: 361 passing, up from 354.

🩹 Migration & Behaviour

  • No save format changes. Existing characters continue working without touching disk state.
  • Arena combat will feel dramatically different on the next sq arena run, especially past round 4.
  • Newbie Pit experience preserved (rounds 1-3 unchanged from v1.23).
  • The enemy_hit_threshold_cap field in ArenaCombatTuning and the no-round compute_enemy_hit wrapper were removed (the wave function now owns these). External consumers (none in-tree) would need to use compute_enemy_hit_at_round(..., round) and arena_wave(round).hit_threshold_cap.
  • All combat surfaces (arena + boss + overworld tick) still share the crit formula change from v1.23.