Escalation in 1.4.4
Escalations are the multi-stage behemoth runs of Dauntless (Shock, Blaze, Umbral and Terra in 1.4.4). Each has a season track of its own: an Escalation level that rises with play, talent points to spend on the season’s talents, and rewards unlocked at certain levels. This page describes how the 1.4.4 game saves that track, and the real saves the metagame now offers.
Status (23 September 2026): built and tested without the game, off by default (ESCALATION_MODE=stub). By default every player still gets upstream’s fake maximum and nothing is saved, exactly as before. With ESCALATION_MODE=real, players in real progression mode keep their own Escalation level, talents and rewards. Switching it on is the owner’s decision after an in-game test, because every player then starts again from level 0 (see Switching it on).
The season registry, the save rules and their tests come from Harmonic’s Dauntless 1.4.4 fork (github.com/Harmonicrain/Undaunted, commit 895f7c7). We adapted them to our audit log and made the less certain rules warn instead of refuse; details on The Harmonic port.
Contents
Evidence and confidence
| Label | Source |
|---|---|
| B | The 1.4.4 executable (Dauntless-Win64-Shipping.exe): disassembly. Addresses are virtual addresses with image base 0x140000000. |
| K | The endpoint table in UndauntedInternalServer/dllmain.cpp, and the client’s own data tables. |
| S | Strong inference: one link in the chain was not traced. |
| G | A design decision of ours, where nothing in the client decides it. |
| C | Our own code and tests. |
How the game saves Escalation
Two endpoint keys, both on the same path (K dllmain.cpp):
| Key | Request | Caller |
|---|---|---|
GetSeasonalEscalationEndpoint | GET /escalation/<season id>/<account id> | the client and the game servers, when they load a player |
UpdateSeasonalEscalationEndpoint | POST /escalation/<season id>/<account id> | the game server, with the whole season as the body |
Both replies are read through the Phoenix envelope {"code", "message", "payload"} (B 0x140aae300). The payload, and the body of a save, is one season:
{
"escalation_level": 3,
"next_level_xp": 140,
"talents_progress": [ { "rank": 1, "talent_id": "ESC_TALENT_S1_TIER1_UPGRADEONE" } ],
"unlock_progress": [ { "collected": true, "reward_id": "ESC_Reward_5" } ],
"update_version": 7
}
escalation_levelis the level reached (0 to 25), andnext_level_xpthe XP gathered towards the next one.- The game server does the arithmetic (S, Harmonic’s reading of the native code): it adds the XP, raises the level, lets the player spend points and hands out the rewards itself, then posts the whole season. The backend only keeps the last good snapshot and refuses one that no real play could produce, or that would erase newer progress.
update_versionis a counter the game raises before every save, starting from the value it loaded (S), so a real save is at least version 1.- The 2.1.1 client asks for
ESC_SEASON_1toESC_SEASON_6at every city load (Backend contract); which ones 1.4.4 asks for is seen in the request log.
The season registry
UndauntedMetagame/src/vendor/escalation/seasons.json lists every season the 1.4.4 client has, exported read-only from the client’s own Escalation progression table and the talent table each season names (by Harmonic, from build CL239827). The metagame checks the file when it starts, and a malformed one stops the start.
| Season | Name | Saved |
|---|---|---|
ESC_SEASON_1 | Shock Escalation | yes |
ESC_SEASON_2 | Blaze Escalation | yes |
ESC_SEASON_3 | Umbral Escalation | yes |
ESC_SEASON_4 | Terra Escalation | yes |
ESC_SEASON_5 | Frost Escalation, marked “do not translate” in the client (unfinished) | no: disabled, every save gets 409 |
Each season has:
- 25 levels. Level 1 costs 500 XP and level 25 costs 10,000; all 25 add up to 109,000 XP. A new player is at level 0.
- 18 talents in 6 tiers of three. A tier opens once 0, 4, 8, 12, 16 or 20 points have been spent in the tiers below it, and each rank of a talent costs points (one point is earned per level). The cost of a rank is the sum of the talent’s first rank costs, as the game’s own
GetSpentTalentPointscounts it (B0x1414ae2a0), and a rank-up is refused while the tier gate is not met (SharedUpgradeTalent, B0x1414c0600). - 6 rewards, at levels 5, 8, 10, 15, 20 and 25: stat boosts, a patrol chest bonus, an extra relic choice and an item grant at level 25.
These values are used only to check a save. They are never used to work out a player’s progress, which stays the game server’s job. The level table agrees with our own earlier reading of the client (C).
The rules a save must pass
Every save is checked in one database transaction. Hard rules are always enforced:
| Rule | Answer when broken |
|---|---|
| The account exists | 404 |
| The season is in the registry | 404 |
| The season is not disabled (Frost) | 409 |
escalation_level is a whole number from 0 to 25, next_level_xp a whole number from 0, update_version from 1, all within 32 bits | 400 |
Every talent and reward id belongs to that season, none twice; a talent’s rank is at most its number of ranks; collected is true or false | 400 |
| Version order: the stored version with the stored content is a retry and gets the stored state back, with nothing written; the stored version with other content, or an older version, is refused | 200 (retry), 409 |
| Nothing goes down: a lower level, or less XP at the same level | 409 |
| A collected reward stays collected | 409 |
The stub guard: a save may not be level 25 with 99,999 XP or more unless the stored season is already at level 25: not a player’s first save, and not a jump from a lower stored level. That is what a game server holds when it loaded the old stub, and it must never become a player’s real progress. Such a game server keeps counting its version while its saves get 404 in stub mode, so after a switch back to real its version can be newer than the stored one; the guard refuses it over a stored season too. Only a player already stored at level 25 builds up that much XP. | 409 |
Talent ranks may go down: a talent reset is a normal game action, so the stored talents are replaced by what the save lists.
Soft rules depend on how we modelled the talent tiers, the level costs and the reward levels. A wrongly modelled rule would refuse every later save of a player, so by default they only warn:
| Soft rule | Default (ESCALATION_STRICT off) | ESCALATION_STRICT=1 |
|---|---|---|
next_level_xp is below the cost of the next level | stored, with a warning line and a note in the audit row | 409 |
| The talents spend no more points than the level has earned | the same | 409 |
| A talent is held only when its tier’s gate is covered by points spent in lower tiers | the same | 409 |
| A reward is collected only at or above its level | the same | 409 |
The stored state is canonical: talents and rewards in the season’s own order, talents at rank 0 left out, only collected rewards kept. The same state therefore always reads back the same way.
Every save is audited. Each POST in real mode, accepted, repeated or refused, is a row in progression_events (the same append-only log as the Hunt Pass and mastery), with the caller, the body, the reply and a note: season <id>, then replay of version N, nothing changed, accepted although ... (ESCALATION_STRICT=0) or the reason for a refusal.
Who may save. Only a game server (its key, from this machine): a player’s own client gets 403, so nobody can write their own Escalation. When a game server’s request carries the token of another player than the one in the URL, the save is kept for the URL’s account and a warning is logged; it is never refused, because a refusal could lose a save in a two-player hunt (G). A player may read only their own seasons; a game server reads any.
Stub and real
ESCALATION_MODE=stub (default) | ESCALATION_MODE=real | |
|---|---|---|
GET | Everyone: {"code": null, "message": "OK", "payload": {"escalation_level": 99999, "next_level_xp": 99999, "talents_progress": [], "unlock_progress": [], "update_version": 1}}. The game shows the last level. | Accounts in real progression mode: their stored season, or level 0 with version 0 when nothing is stored yet (reading creates no row). Accounts in stub progression mode keep the stub. An unknown season: 404. |
POST | 404, as always: nothing is saved. | Saved under the rules above. |
A player’s stored seasons stay in their tables when the mode goes back to stub, and come back when it is real again. Restart the game servers together with the metagame at every switch, in either direction (step 3 below).
Switching it on
What players see: every player in real progression mode drops from the fake maximum (level 25 and 25 talent points) to level 0, and then levels up for real. Tell them before.
- Take a backup (the kit takes one at every start).
- Set
ESCALATION_MODE=realin the metagame’s settings. - Restart the game servers together with the metagame, when nobody is playing, so that no game server still holds the stub’s values and writes them back. The stub guard refuses such a save anyway, also over a stored season, but then that player’s Escalation progress in the session is refused with it until the game server loads the season again. The same restart is needed when the mode goes back to
stub, or an account leavesPROGRESSION_REAL_ACCOUNTS, and later returns. - The in-game test (roadmap 2.16): play an Escalation run, relog, spend a talent point. The level rises and survives the relog, the right number of points shows, and the log has no 409 and no “breaks a soft rule” line.
- Once the logs stay clean for a while,
ESCALATION_STRICT=1turns the soft rules into refusals.
When the test has passed, the plan is for an unset ESCALATION_MODE to follow PROGRESSION_MODE.
The log lines are on Troubleshooting, the switches on Configuration, the routes on HTTP API, the three tables on Files and data and the registry file on Game settings.
Tests
UndauntedMetagame/test/escalation.test.ts holds 27 cases: Harmonic’s 17 (the registry, reads, the version rules, the hard and soft rules, the stub guard), adapted to our answers (a foreign read is 403, a replay is an audited 200, a relayed token of another account is logged and accepted, the soft rules answer 409 only with ESCALATION_STRICT=1, the strict XP case reaches level 25 before its XP grows), a warn-only twin of each soft-rule case, the stub guard over a stored season, stub mode for everyone, stub-mode accounts with ESCALATION_MODE=real, a player’s own save (403, nothing stored), an unknown account, and the audit row.
Still open
| Open point | Label | How it is settled |
|---|---|---|
| The game server does all the Escalation arithmetic and posts the whole season | S | The in-game test: the saves arrive and nothing is refused. |
Which season ids 1.4.4 asks for (2.1.1 asks up to ESC_SEASON_6, which the registry does not have) | unknown | The request log of one city load in real mode. |
| The soft rules match the game | S for the tier gate and the point count (B), G for the rest | No “breaks a soft rule” line in the test. |
| When to switch it on | the owner’s decision | After the test and an announcement. |