This repository has been archived on 2026-10-05. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
dnd-manager/docs/GAME_RULES_REFERENCE.md
2026-09-22 16:27:53 +02:00

5.0 KiB
Raw Permalink Blame History

D&D 5e Rules Reference — Implementation Spec

This is the canonical math the backend must implement. Build it as a single shared calculation module (e.g. backend/src/game/calculations.ts) that is the only place these formulas live — every API route and the character builder call into it rather than re-deriving numbers. This mirrors the logic already built and verified in the "DnD Character Sheet Calculator.xlsx" workbook delivered earlier in this project; treat that workbook as the reference implementation if anything below is ambiguous.

All rules are 5e (2014 core rules).

Ability Modifier

modifier = floor((score - 10) / 2)

Use Math.floor, not integer truncation — they differ for negative results (e.g. score 7 → (7-10)/2 = -1.5 → floor = -2, not -1).

Proficiency Bonus

proficiencyBonus = 2 + floor((level - 1) / 4)

Level 1–4 → +2, 5–8 → +3, 9–12 → +4, 13–16 → +5, 17–20 → +6.

Final Ability Score

finalScore = rolledScore + speciesBonus(ability, species)

speciesBonus comes from the Species Ability Score Increase table below. See seed-data/species.json.

Saving Throws

saveBonus = abilityModifier + (proficient ? proficiencyBonus : 0)

Proficiency per ability comes from the Class Quick Facts table (seed-data/classes.json).

Skills

skillBonus = governingAbilityModifier + (proficient ? proficiencyBonus : 0)

Governing ability per skill is fixed — see seed-data/skills.json. Proficiency is a per-character, per-skill boolean the player/DM sets during character building (CharacterSkillProficiency in the Prisma schema).

Passive Perception:

passivePerception = 10 + perceptionSkillBonus

Armor Class

armorClass = 10 + dexModifier + armorBonus

armorBonus is a flat number the player enters representing whatever armor/shield they have equipped (this matches the workbook's "Armor Bonus (from armor worn)" input cell). Do not try to model armor types as a lookup table unless you want to extend scope later — a plain integer field on Character is enough for v1.

Initiative

initiative = dexModifier

Speed

Comes from the species table (30 ft standard; 25 ft for Gnome, Dwarf, Halfling). Store as speed on the species seed data; characters may override it (speedOverride on Character) for future feature support (e.g. barbarian speed boosts) without a schema change.

Hit Points

Hit Die size comes from class (seed-data/classes.json).

hpMax(level) =
  if level === 1:
    hitDieMax + conModifier
  else:
    hitDieMax + conModifier
    + (level - 1) * (floor(hitDieSize / 2) + 1 + conModifier)

Important: level 1 always uses the maximum possible roll of the Hit Die, not the average. Every level after 1 uses the fixed "average" value floor(hitDieSize / 2) + 1 (e.g. d10 → 6, d6 → 4, d12 → 7) plus the CON modifier again. This was a bug caught and fixed while building the Excel calculator — do not regress it.

hitDice available to spend on a short rest = character level (one die of the class's Hit Die size per level).

Spellcasting (only for classes with a Spellcasting Ability ≠ "None")

spellSaveDC = 8 + proficiencyBonus + spellcastingAbilityModifier
spellAttackBonus = proficiencyBonus + spellcastingAbilityModifier

Spellcasting ability per class is in seed-data/classes.json (Intelligence, Wisdom, or Charisma). Classes with "None" have no spellcasting stats — the UI should hide those fields entirely rather than show them as zero/blank.

Species Ability Score Increases & Speed

See seed-data/species.json for the full table (10 species). Note: Half-Elf gets +2 Charisma fixed, plus +1 to two other abilities of the player's choice — the seed data defaults that flexible pair to STR/INT, but the character builder UI must let the player pick which two abilities get the +1 during Half-Elf character creation (don't hardcode the default in the UI).

Class Quick Facts

See seed-data/classes.json for the full table (12 classes): Hit Die, Primary Ability, the two Saving Throw proficiencies, and Spellcasting Ability.

Skill → Governing Ability

See seed-data/skills.json (18 skills).

"Quick Stats" View (combat-context panel)

When the frontend shows the contextual quick-stats panel during an attack action, surface exactly these derived values (all computed via the module above, never stored redundantly):

  • Attack bonus for the equipped/selected weapon: proficiencyBonus (if proficient) + relevantAbilityModifier (STR normally, DEX for finesse/ranged weapons — see seed-data/weapons.json's attackAbility field, which is "STR", "DEX", or "FINESSE" meaning "use whichever of STR/DEX is higher")
  • Damage: weapon's damage dice + relevant ability modifier
  • Current HP / Max HP / Temp HP
  • AC
  • Any special abilities/features flagged on the character (free-text list is fine for v1 — a specialAbilities text/JSON field on Character or a simple related table)

This is a read view assembled from existing data — it does not need its own schema table.