Files
healer-man/scripts/runewaker-pipeline/RUNEWAKER_FORMULA_AND_LOOT.md
T
2026-09-08 10:40:26 -04:00

46 lines
3.2 KiB
Markdown

# RuneWaker combat formula and loot fidelity
## Combat damage
Imported RuneWaker damage mechanics now carry a `runewakerFormula` descriptor from `magicobject.db` into the generated enemy attack. The descriptor keeps the source spell/component ids, spell level, damage power, fixed value, damage-over-time base, calculation family, and source-code provenance.
The preserved implementation is in `SourceCodeVS2019/Server/NetGameServer/MainProc/MagicProc/MagicProcess.cpp`:
- `CalPhyDamage` begins at line 3366.
- `CalMagicDamage` begins at line 3651.
- Both use the source ATK/DEF or MATK/MDEF ratio `max(0.2, 1 + ((attack + 100) - (defense + 200)) / max(attack + 100, defense + 200))`.
- Both also depend on native weapon or magic damage, level-difference tables, resistance processing, critical power, fixed-attribute lookup, and global NPC/PvP/AoE/target rates.
HealerMan does not have equivalent RuneWaker ATK, MATK, DEF, MDEF, `FixType`, native weapon/magic damage, level-rate tables, or global rate arrays. The adapter therefore does not label its live result as exact RuneWaker damage:
- Negative `Atk.DmgPower` values with magnitude at most 4 are treated as source ratios against HealerMan's level-scaled enemy damage budget; the native 0.2 minimum is retained.
- Point-valued source powers use the explicit `runtimeBaselineMultiplier` balancing adapter stored with the formula.
- HealerMan's existing hit table, armor, resistance, critical, aura, and absorb pipeline runs afterward and remains identified as HealerMan/WotLK-shaped mitigation.
- Unclassified formula records return zero from the adapter rather than executing guessed damage.
`resolveRunewakerNativeResolvedPower` exposes the source-shaped tail for later use. It requires every native-only input as an argument and supplies no silent one-valued defaults.
## Loot
`export-loot-catalog.mjs` reads each source-classified boss's 15 independent `NPCObjectDB.DropItem` slots. It preserves the original rate denominator of 100,000 and recursively expands `TreasureObjectDB`'s weighted, mutually exclusive outcomes and fixed `DropCount` quantities.
Runtime rules are intentionally bounded:
- Recognized leaves come only from `itemobject.db`, `armorobject.db`, `weaponobject.db`, `cardobject.db`, `runeobject.db`, `recipeobject.db`, and `keyitemobject.db`.
- Treasure recursion stops at 12 levels and cycles fail closed.
- Unknown object ids fail closed.
- Treasure tables with a Lua predicate fail closed because executing arbitrary preserved server Lua is outside the browser runtime.
- `NeedDLv` requirements are preserved and evaluated from the caller-provided source level delta.
- Source names are retained, but source stats, quality, and equipment slots are not inferred. Portable drops enter inventory as common, non-equipable `misc` items with zero stats.
The detailed status for every boss is generated in `RUNEWAKER_LOOT_IMPORT_REPORT.md`. The full probability graph is available in `public/data/runewaker-loot-catalog.json` and the runtime snapshot.
## Refresh and verification
```powershell
npm run runewaker:spells:refresh
npm run runewaker:loot:refresh
node --test scripts/runewaker-pipeline/runewaker-loot-import.test.mjs
vitest run src/game/runewakerCombatFormula.test.ts src/game/runewakerLootCatalog.test.ts
```