Author: A human being.
Co-author: An artificial intelligence.
Proofreader: A human being.
Formatter: A human being.
Documentation for: Volume 02: Halls of Torment — Script for Unified Multiplier
Halls of Torment — Volume Two Scripts: Usage Guide
Version 1.7 (2026-08-05) · Released under CC0 1.0 Universal (public domain)
This guide accompanies Halls-Of-Torment-Vol2-Scripts-(Version_1.7).CT. An annotated edition of the table and standalone commented script files are published alongside it for readers who want to study the internals.
How to Use
Before you start (requirements)
| Requirement | Detail |
| Game | Halls of Torment (Steam). Single-player only — there is no anti-cheat and no online play to disrupt. |
| Tested against | Steam build 22764619 ("HoT Fixes" update, 2026-04-14) — the public build current as of 2026-08-05. Later builds may work but are unverified; a game update can break the table (see "If something goes wrong"). Check your build against the game's build history on SteamDB — this table's build is 22764619. |
| Cheat Engine | Version 7.5. Other versions are untested. |
| Character scope | Built and validated on the Swordsman with the Zweihänder equipped. Defensive and miscellaneous stats are shared player stats and should work on any character, but only the Swordsman is validated. The weapon block affects the Zweihänder only. |
| Coverage | 14 stats: Max Health, Health Regen, Block Strength, Defense, Movement Speed, Experience Gain, and 8 Zweihänder stats (Damage, Range, Cone Angle, Attack Speed, Crit Chance, Crit Bonus, Multistrike, Knockback). |
Step-by-step
- Launch the game first, then open the
.CT file. Cheat Engine starts and offers to attach to HallsOfTorment.exe — accept. If it doesn't ask, click the computer icon (top-left) and select the process manually.
- Expand the table: click "Click Here to access Volume Two Scripts", then open the Main Content section (green).
- Activate the script: tick the checkbox on
>>> Unified Multiplier Script (Vol2) <<<.
- No dialog appears = success. The script verified all four hook signatures and installed cleanly.
- A dialog naming a hook site means the game version doesn't match — nothing was written to memory, and the table needs an update.
- Start a run. Multiplier values resolve once your character exists in a level; in menus they may show
?? or 0 — that is normal.
- Set multipliers under Simplified View:
- Whole category at once: use the dropdown on a category header (Defensive Values / Miscellaneous / Swordsman - Main Weapon - Zweihänder). Presets run 1× to 1000×; every stat in the category takes the value.
- Single stat: edit any row's value directly, or use its own dropdown.
[ DEFAULT = 1 ] means "no change".
- Deactivate by unticking the script's checkbox. A confirmation dialog reports a clean teardown: original game code is restored, all memory is freed, and stats return to normal on their next refresh.
Things worth knowing
- Changes apply on stat refresh events — level-up, trait pick, weapon swap, level load — not always instantly. Health Regen refreshes constantly, so it reacts first.
- Multipliers scale the game's own computed total (base + all in-game bonuses). They don't edit base values or upgrade math, which is why everything returns to normal when the script is off.
- Floors and ceilings: every stat has a floor (its base-stat default) and a ceiling. Scaled results are clamped into that window. Both are editable per stat under Detailed View.
- Detailed View also shows each stat's "Original Total" readout — the raw value the game computed before your multiplier — useful for checking what the game thinks your build is worth.
- Range and Movement Speed look 18× too big in raw form: the game stores them in internal units where raw = displayed × 18.
- Debug Central (magenta "Advanced Users Section") is diagnostics only — safe to ignore during normal play.
- The Expand/Collapse entry at the top of the table only hides Cheat Engine's scanner panels for a cleaner window. It never touches the game.
If something goes wrong
| Symptom | Meaning | Fix |
| "…hook signature not found" dialog on activation | The game was updated and a hook site moved. Nothing was modified. | Wait for / request an updated table. |
Values show ?? | Script inactive, or CE not attached to the game. | Attach to HallsOfTorment.exe, activate the script. |
| Multiplied stat didn't change | No refresh event has fired yet. | Level up, swap weapons, or reload a level. |
| A stat ignores an extreme value | The sanity window or ceiling clamped it. | Raise the ceiling in Detailed View; sanity windows protect against corrupt writes. |
What This Script Actually Does
Plain-language version
Halls of Torment recalculates each of your stats whenever something about your build changes — you level up, pick a trait, swap a weapon. At the end of each recalculation, the game stores the finished number (your base stat plus every bonus) into that stat's slot in memory.
This script places a small detour at the exact moments those stores happen — four locations in the game's code cover all 14 stats. When the game is about to store a stat the table covers, the detour:
- checks the number is plausible (a corrupted value is let through untouched and counted, never scaled);
- records the original number so the table can show it to you;
- multiplies it by your chosen multiplier;
- clamps the result between a floor and a ceiling so it can't go absurd or negative;
- hands the result back to the game's own store instruction.
The game then carries on, believing this was the number it computed. Because the change happens at the moment of storage — not by overwriting memory afterwards — it survives every recalculation, and turning the script off restores the game's code exactly as it was.
One safety system deserves mention: the script must know which memory belongs to your character's stats, and that memory moves around (each run, each level, sometimes mid-play). A background task re-locates all 14 stat containers twice per second and hands fresh addresses to the detours. If a container temporarily doesn't exist — main menu, death screen, loading — the address is set to zero and the detours simply do nothing. Stale memory is never touched, which is what makes the script stable across restarts and long sessions.
Technical version
Injection. Four AOB signatures are located with aobscanmodule against HallsOfTorment.exe — three integer store sites and one float store site, each ending at a mov [rdi+168],eax / movss [rdi+168],xmm0 that commits a finished stat total into a Godot stat-container object. Each site is hooked with a 5-byte jmp into an allocated code cave (alloc near the target), with stolen bytes (22/15/15/17) re-executed at the top of the cave and preserved via readmem into an allocated backup buffer for byte-exact restoration on disable.
Preflight. Before any patching, a {$lua} block runs all four signature scans with AOBScan. Any miss aborts activation with a message naming the failed site (error() unwinds the [ENABLE] section), guaranteeing all-or-nothing installation.
Dispatch. All 14 stats share the four hooks. Parameters live in two allocated tables (integer: 5 records; float: 9 records), one 0x30-byte record per stat: multiplier (float), floor, ceiling, sanity min/max, intended-value readout, per-site reject counters, and an 8-byte container-pointer cache. Each hook walks its table comparing rdi (the container being written) against each record's cached pointer — a match identifies which stat is being stored right now; no match means the write belongs to a stat we don't cover and passes through untouched.
Scaling path (integer sites). Sanity-check eax against the record's window → store raw total to the readout field → cvtsi2ss / mulss by the multiplier / cvttss2si back → clamp to floor and ceiling via compare-and-move → fall through to the original store. The float site does the same in SSE registers directly (ucomiss checks, mulss, maxss/minss clamps).
Pointer cache. A single CE createTimer (500 ms) resolves all 14 pointer chains from the static root HallsOfTorment.exe+396BD00 using readPointer hops. A nil/0 at any hop poisons that chain's cache with 0 for the tick, so hooks compare against 0 and never dereference stale memory — game code never walks pointer chains itself. The timer self-destructs if it detects the script's symbols are gone, and destroys any legacy timers from older table versions on startup.
Teardown. [DISABLE] restores all four sites' original bytes from the backups, unregisters all 127 symbols, deallocates every buffer, destroys the timer, and confirms with a dialog. Because hooks scale values only in flight, no persistent memory edit outlives deactivation; stats revert on their next natural refresh.
Diagnostics. Sanity-window rejections increment per-site counters exposed as table rows under Debug Central, alongside cached-container address rows — enough to distinguish "signature broke" from "chain broke" from "value out of window" when triaging a report.
For the fully commented source, see:
Halls-of-Torment-CheatScript-Unified-Multiplier-Annotated.txt
Halls-of-Torment-CheatScript-Compact-View-Toggle-Annotated.txt
Halls-Of-Torment-Vol2-Scripts-(Version_1.7-Annotated).CT — the same table with commentary embedded in the script bodies
License: https://creativecommons.org/publicdomain/zero/1.0/