Files
code_of_conquest_dnd/client/scripts/rules/races.gd
Phillip Tarrant 78e18107b2 feat(rules): the race, calling, skill and attribute tables
Mechanics are rules and live in code, beside Luck and Currency. The skill pools
are new — the races/classes spec said only 'the stat-appropriate slice' and never
enumerated them; each pool is larger than its pick count so the choice is real.

The dwarf's +2 vs poison is exposed separately from save() rather than folded
into it: baking a conditional into a flat number is how a sheet starts lying.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYa9u7Kdxv5gX4AnwWexy8
2026-07-12 20:14:44 -05:00

61 lines
1.9 KiB
GDScript

class_name Races
extends RefCounted
## The 4 races (races-and-classes spec §3). FEATURES ONLY — no race touches an
## attribute score, which is what keeps the roll + spend pure.
##
## nightsight / claws / keen_scent are FLAGS, not numbers. Combat (M5) and the DM's
## exploration checks consume them; creation only stores them.
##
## The dwarf's +2 is SITUATIONAL (vs poison and the affliction track), so it is NOT
## a flat save bonus — baking a conditional into a flat number is how a sheet starts
## lying. It is exposed separately as poison_save_bonus().
const IDS := ["human", "elf", "dwarf", "beastfolk"]
const TABLE := {
"human": {
"save_bonus": 1, "granted_skills": [], "bonus_skill_choice": true,
"poison_save_bonus": 0,
"flags": {"nightsight": false, "claws": false, "keen_scent": false},
},
"elf": {
"save_bonus": 0, "granted_skills": ["perception"], "bonus_skill_choice": false,
"poison_save_bonus": 0,
"flags": {"nightsight": true, "claws": false, "keen_scent": false},
},
"dwarf": {
"save_bonus": 0, "granted_skills": [], "bonus_skill_choice": false,
"poison_save_bonus": 2,
"flags": {"nightsight": true, "claws": false, "keen_scent": false},
},
"beastfolk": {
"save_bonus": 0, "granted_skills": [], "bonus_skill_choice": false,
"poison_save_bonus": 0,
"flags": {"nightsight": false, "claws": true, "keen_scent": true},
},
}
static func exists(id: String) -> bool:
return TABLE.has(id)
static func save_bonus(id: String) -> int:
return int(TABLE.get(id, {}).get("save_bonus", 0))
static func granted_skills(id: String) -> Array:
return TABLE.get(id, {}).get("granted_skills", [])
static func wants_bonus_skill(id: String) -> bool:
return bool(TABLE.get(id, {}).get("bonus_skill_choice", false))
static func poison_save_bonus(id: String) -> int:
return int(TABLE.get(id, {}).get("poison_save_bonus", 0))
static func flag(id: String, name: String) -> bool:
return bool(TABLE.get(id, {}).get("flags", {}).get(name, false))