Stats Contract - xopherdeep/do-it-for-the-xp GitHub Wiki

Stats Contract (2026-10-10)

What the fifteen special stats on the profile sheet do. Owner's rule: every line on the stats screen must be true. The code is src/lib/services/stats/StatEffects.ts (the table of multipliers), laid over the class table in ClassPassives.ts by heroPassive(hero) (multiply, never replace). The copy lives in one place, src/constants/PILLARS.ts; the profile sheet (UserProfileModal.vue) and the old profile page read it. Spec: tests/unit/StatEffects.spec.ts.

Points trained, not the badge

The badge on the sheet shows the class's starting number (5 for a hero without a class) plus the points the hero has trained: earned at level-ups through the class's statBoosts and kept on stats.special. Every effect counts trained points only. The class's starting numbers are already folded into its base HP/MP, growth and passive (a Thief does not get 8 % off for the 8 charisma it was born with; it gets the +25 % GP passive instead). This is how calculateMaxHp / calculateMaxMp have always read endurance, intelligence and wisdom, so no existing profile changes. Under each stat the sheet prints the live effect: "Trained 4: strikes land 4 % softer".

The table

Stat Pillar What the screen said What the code did What it does now (per point trained, cap)
Defense Body Increases Maximum HP capacity nothing +1 max HP (calculateMaxHp)
Strength Body Decreases HP loss when taking damage nothing (read into hero.stats.strength, unused) every beast strike lands 1 % softer, up to 25 % (strikeFactor in strikeDamage)
Endurance Body Boosts HP recovery and restoration +HP ร— class enduranceMultiplier (Warrior 3, Mage 1 โ€ฆ) unchanged; the copy now says so
Perception Mind Increases Maximum MP capacity nothing +2 % chance to find GP when searching a temple room, up to +30 % (hunt)
Intelligence Mind Decreases MP cost for active abilities +MP ร— class intelligenceMultiplier unchanged, and 1 % off every MP cost, up to 25 %, compounding with the Mage/Sage discount (heroMpBill: BattleItems, ItemUse)
Wisdom Mind Boosts MP recovery and meditation rate +MP ร— class wisdomMultiplier unchanged; the copy now says so
Agility Spirit Gain more AP when completing tasks 8+ (special) leaps clear of temple traps; read as battle speed, unused +1 % chance to dodge the parting strike when you run (up to +25 %, and never past 50 % in all) and +1 s per chore on the battle clock (up to 120 s); traps as before
Focus Spirit Influence chances of receiving bonus AP points nothing flavour for now (AP is paid by the chore, not rolled)
Flow Spirit Reduces AP cost for active abilities nothing (abilities have no AP cost) flavour for now
Awareness Heart Influences the amount of GP awarded nothing +1 % GP from temple chests, searches and the gate, up to +25 %, multiplied with the Thief/Ninja +25 % (heroGold in earnGold)
Presence Heart Influences GP to $ conversion and trade rates nothing (there is no exchange rate) flavour for now
Charisma Heart Reduces the GP cost of items in shops nothing shop prices โˆ’1 %, up to 20 %, shown and charged: the town Accessory Shop shelf (shopPrice, with a "N % off" sign) and the temple shop room (shopWares); wallet upgrades are not wares and keep their price
Guts Legend Influences the amount of XP awarded +0.5 max HP unchanged, and Defend blocks 1 % more (brace factor ร— (1 โˆ’ 0.01ยทguts), up to 25 %; a Warrior's quarter with 10 guts is 0.225)
Luck Legend Influence chances of receiving bonus XP points nothing the top of a temple gold range grows 2 %, up to +50 %, rounded up (luckyTop: searches, the hidden chest; the hidden chest's fixed 20 becomes a 20..24 roll at 10 luck)
Mastery Legend Reduces the XP threshold required to reach the next Level nothing (getXpForLevel is one curve for everyone) flavour for now

Class multipliers checked and found true: JOB_CLASS_BASE_STATS.{endurance,intelligence,wisdom}Multiplier feed calculateMaxHp / calculateMaxMp; CLASS_LEVEL_BONUSES add per class level; JOB_CLASS_OPTIONS.statBoosts are handed out per level in calculateLevelUp and land on stats.special. The four tier-1 class blurbs in JOB_CLASS_OPTIONS were reworded to name what the class trains and its passive, instead of promising AP/XP mechanics that did not exist.

Where the multipliers land

  • Battle engine (BattleService): BattlePassive gained strikeFactor and runChanceBonus; BattleField.ts hands the engine heroPassive(hero). strikeDamage(maxHp, attack, braced, roll, braceFactor, strikeFactor): the strike share first, then the brace, each floored, never below 1. Run Away always works and costs one parting strike (QR8): a Thief's or Ninja's slip softens it through the brace factor, and agility (runChanceBonus) is the chance to dodge it outright, capped at 50 % (PARTING_DODGE_CEILING). Clock: the Monk's minute + agility's seconds per chore.
  • MP bill: heroMpBill(cost, hero) = floor(cost ร— (1 โˆ’ class) ร— (1 โˆ’ intelligence)); 0 stays 0.
  • Temple gold (RoomInteractions): earnGold โ†’ heroGold; hunt adds perception to the chance and luck to the top of the range; the secret chest rolls its gold up to luckyTop.
  • Shops: shopPrice(price, hero) on the shelf before display, so the badge, the "need N more" line and the charge (PurchaseService charges item.price) agree.
  • Not wired, by design: battle and quest-board rewards keep the class-only rewardsWithPassive / bonusGp (those files were under another task when this landed). If guts/awareness should also touch XP/GP there, wire heroPassive into useBattleOutcome.rewardsForHero and QuestCompletionService.paidQuestRewards and update the Awareness line.

Rates in one place

STAT_RATES in StatEffects.ts: strike 1 %/25 %, brace 1 %/25 %, MP 1 %/25 %, run 1 %/25 %, clock 1 s/120 s, find 2 %/30 %, gold 1 %/25 %, luck 2 %/50 %, shop 1 %/20 %, HP: defense 1, guts 0.5. Change a rate there and the sheet's "Trained N" line follows; change a description in PILLARS.ts only if the code keeps the promise.