Docs: how the survival bonus is calculated and stored
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
84c50d8c33
commit
4018e23e6b
1 file changed
+50
@@ -0,0 +1,50 @@
|
|||||||
|
# Survival bonus (Überlebensbonus)
|
||||||
|
|
||||||
|
Request (2026-10-18): "how is survival bonus calculated? please reset the
|
||||||
|
death counter on battlemage savegame and restore the survivability bonus".
|
||||||
|
|
||||||
|
## Where it shows
|
||||||
|
|
||||||
|
The tooltip of the Waffe / Kampfkunst / Resistenz block in the character
|
||||||
|
window (`cUI_StatisticsChar::Render` 0x6a9be0), only while the bonus is above
|
||||||
|
0. Text key "1159" (id 0x4407730). Text keys are numbers or names hashed by
|
||||||
|
`TextKeyHash` 0x80e010: `h = (h * 113 + toupper(c)) % 999999991`, then
|
||||||
|
`& 0x7fffffff`. `TextManager::GetTextByKey` 0x672fd0 looks them up.
|
||||||
|
|
||||||
|
## Formula
|
||||||
|
|
||||||
|
`cStatsManager` (one record at 0xaa3518, `cStatsManager::Instance` 0x425160)
|
||||||
|
keeps the time survived in ms at +0x570c. With m = whole minutes survived:
|
||||||
|
|
||||||
|
bonus % = 0 for m < 1
|
||||||
|
= 100 * (1 - 1 / ((m - 1) / 120 + 1)) otherwise
|
||||||
|
|
||||||
|
That is `DiminishingCurve` 0x565c30 (min 0, half 120, max 50, doubled). It
|
||||||
|
gives 50 % after 2 h and 75 % after 6 h, approaching 100 %. The experience for
|
||||||
|
a kill uses the same curve (0x534454), scaled by a global factor at 0xad362c.
|
||||||
|
The window adds 10 × a difficulty factor (1.34 / 1.67 / 2 / 2.34) when a hero
|
||||||
|
byte (+0x4f8 array, index 0x1c) is at least 6; what that byte means is not
|
||||||
|
known yet.
|
||||||
|
|
||||||
|
Measured: the survival time only grows in combat. `cStatsManager::AddTime`
|
||||||
|
(0x424930, (float s, alive), ret 8) is called from the engine tick (0x60e732)
|
||||||
|
with alive = hero +0x200 bit 0x8000. 0x547ce6 sets that bit while 0xad1c64 is
|
||||||
|
below 350 (or 1000), and 0x547ed8 clears it otherwise. 0xad1c64 is most
|
||||||
|
likely the distance to the nearest enemy. The play time (+0x56f8 h, +0x56fc
|
||||||
|
min, +0x5700 ms) always grows.
|
||||||
|
|
||||||
|
A death (`cStatsManager::OnHeroDeath` 0x4245a0, called from
|
||||||
|
`cCreature::ReceiveOrder`) counts one at +0x56f4 and zeroes the survival time.
|
||||||
|
|
||||||
|
## In the save game (GAME0x.PAK, uncompressed)
|
||||||
|
|
||||||
|
- Header ("AMS", version 0x1b) at the start: survival time in seconds at
|
||||||
|
0x44, loaded by `cEngine::load` 0x61b790 through
|
||||||
|
`cStatsManager::SetSurvivalSeconds` 0x424540.
|
||||||
|
- The statistics block (`cStatsManager::Serialize` 0x424ce0) ends with the
|
||||||
|
magic 0xF00DF00D. The deaths are 26 bytes before the magic, the play
|
||||||
|
hours 22, the minutes 18 and the ms 14.
|
||||||
|
- `ItemDataMgr::saveHero` 0x6046f0 appends a 0x22c-byte hero header (name in
|
||||||
|
UTF-16 at +0x48) and a 0x40-byte block (deaths, survival seconds, spawn
|
||||||
|
counter). The block is all zeros in single-player saves and is not where
|
||||||
|
the survival time is loaded from.
|
||||||
Reference in new issue
Block a user