code wiki / _hdl_build / nx_rpgstats.nx
nx_rpgstats.nx
buildroot/runtime/_hdl_build/nx_rpgstats.nx
about
nx_rpgstats.nx -- the SOVEREIGN CHARACTER PROGRESSION PART. nx_gamebench gap-queue rank 1 after
save-load landed: rpg-stats-progression was PARTIAL and blocks 8 of 12 benchmarked titles
(OpenXcom, Open Diablo II, Cataclysm-DDA, Veloren, NetHack, Crawl, Endless Sky, adventure).
Built as a CERTIFIED COMPOSABLE PART (knowledge/registry/game_parts.tsv doctrine: build once to exceed,
compose forever). Character state is a flat i64 vector BY DESIGN so it drops straight into gs_save/gs_load
from nx_gamesave -- parts composing is the whole point of the recombinator.
THE PROPERTIES THAT MAKE IT SAFE TO COMPOSE (each one is a gate tooth):
1. ORDER-INDEPENDENT MODIFIER STACKING. Real RPGs get this wrong constantly: apply +10 then +20% and you
get a different number than +20% then +10, so buff/debuff application order silently changes outcomes
and desyncs multiplayer. Here additive and multiplicative pools are summed SEPARATELY and applied once
-- commutative BY CONSTRUCTION, not by convention.
2. DATA-DRIVEN CURVES (rule 11). The XP curve, HP formula and skill thresholds are PARAMETERS, never
literals in code. A game tunes progression without touching the part.
3. MONOTONIC + EXACTLY INVERTIBLE XP. level_for_xp is the true inverse of xp_for_level at every boundary,
so a character can never land between levels or oscillate.
4. INTEGER-ONLY, DETERMINISTIC. No float anywhere, so progression replays bit-identically -- the same
determinism exceed the renderer and nx_gamesave carry.
5. CLAMPED BY CONSTRUCTION. Extreme inputs saturate instead of overflowing into negative HP / wrapped
levels (the classic "damage so high it heals you" bug).
LIB ONLY -- no main() by ecosystem convention (cf. nx_swgpu.nx).
license_tier: ORIGINAL expect_exit: 0
dependencies 1 imports · 10 importers
imports: nx_syscalls.nx
imported by: nx_coc_engine.nxnx_drift_engine.nxnx_frontier_engine.nxnx_game_companion.nxnx_m2d_engine.nxnx_rpgstats_gate.nxnx_wire_diablo2_gate.nxnx_wire_endlesssky_gate.nxnx_wire_nethack_gate.nxnx_wire_probe.nx
structs
| none |
consts
| 27 | const RS_MAXLEVEL: i64 = 200 |
| 28 | const RS_SAT: i64 = 0x3FFFFFFFFFFFFFFF // saturation ceiling, far below i64 overflow |
| 29 | const RS_PCT: i64 = 100 |
functions
| 31 | func rs_clamp(v: i64, lo: i64, hi: i64) -> i64 |
| 39 | func rs_sadd(a: i64, b: i64) -> i64 |
| 45 | func rs_smul(a: i64, b: i64) -> i64 |
| 60 | func rs_xp_for_level(level: i64, base: i64, quad: i64) -> i64 |
| 69 | func rs_level_for_xp(xp: i64, base: i64, quad: i64) -> i64 |
| 81 | func rs_derived_hp(con: i64, level: i64, hp_base: i64, hp_per_con: i64, hp_per_lvl: i64) -> i64 called by 12: fe_newfe_tickbrd_to_creaturecomp_powermd_maxhpmd_init+6 calls 3: rs_saddrs_smulrs_clamp |
| 91 | func rs_apply_mods(base: i64, mods: *i64, nmods: i64) -> i64 |
| 112 | func rs_skill_rank(uses: i64, threshold: i64, maxrank: i64) -> i64 |