diff --git a/Content/Data/classes.json b/Content/Data/classes.json index 6797f4e..9bca719 100644 --- a/Content/Data/classes.json +++ b/Content/Data/classes.json @@ -10,7 +10,7 @@ "weapon_proficiencies": ["simple", "martial", "natural"], "tool_proficiencies": [], "skills_choose": 2, - "skill_options": ["athletics", "intimidation", "perception", "survival", "animal_handling"], + "skill_options": ["athletics", "animal_handling", "brawl", "force", "intimidation", "marksmanship", "pain_tolerance", "perception", "survival"], "subclass_ids": ["pack_forged", "lone_fang"], "starting_kit": [ { "item_id": "rend_sword", "qty": 1, "auto_equip": true, "equip_slot": "main_hand" }, @@ -68,7 +68,7 @@ "weapon_proficiencies": ["simple", "martial", "natural"], "tool_proficiencies": [], "skills_choose": 2, - "skill_options": ["athletics", "insight", "intimidation", "medicine", "perception"], + "skill_options": ["athletics", "endurance", "fortitude", "hardiness", "insight", "intimidation", "medicine", "pain_tolerance", "perception"], "subclass_ids": ["herd_wall", "antler_guard"], "starting_kit": [ { "item_id": "hoof_club", "qty": 1, "auto_equip": true, "equip_slot": "main_hand" }, @@ -128,7 +128,7 @@ "weapon_proficiencies": ["simple", "natural"], "tool_proficiencies": [], "skills_choose": 2, - "skill_options": ["athletics", "intimidation", "nature", "perception", "survival"], + "skill_options": ["athletics", "brawl", "endurance", "fortitude", "hardiness", "haulage", "intimidation", "nature", "perception", "survival"], "subclass_ids": ["blood_memory", "stampede_heart"], "starting_kit": [ { "item_id": "paw_axe", "qty": 1, "auto_equip": true, "equip_slot": "main_hand" }, @@ -191,7 +191,7 @@ "weapon_proficiencies": ["simple", "hand_crossbow", "short_sword", "rapier", "natural"], "tool_proficiencies": ["thieves_tools"], "skills_choose": 4, - "skill_options": ["acrobatics", "athletics", "deception", "insight", "intimidation", "investigation", "perception", "persuasion", "sleight_of_hand", "stealth"], + "skill_options": ["acrobatics", "athletics", "build_read", "deception", "driving", "insight", "intimidation", "investigation", "marksmanship", "perception", "persuasion", "sleight_of_hand", "stealth"], "subclass_ids": ["noseblind", "ambush_artist"], "starting_kit": [ { "item_id": "thorn_blade", "qty": 1, "auto_equip": true, "equip_slot": "main_hand" }, @@ -255,7 +255,7 @@ "weapon_proficiencies": ["simple", "natural"], "tool_proficiencies": ["alchemists_supplies", "perfumers_kit"], "skills_choose": 3, - "skill_options": ["deception", "insight", "investigation", "medicine", "perception", "persuasion", "stealth"], + "skill_options": ["build_read", "deception", "insight", "investigation", "lung_craft", "medicine", "perception", "persuasion", "scent_speak", "stealth"], "subclass_ids": ["perfumer", "tracker"], "starting_kit": [ { "item_id": "fang_knife", "qty": 1, "auto_equip": true, "equip_slot": "main_hand" }, @@ -316,7 +316,7 @@ "weapon_proficiencies": ["simple", "martial", "natural"], "tool_proficiencies": [], "skills_choose": 2, - "skill_options": ["athletics", "insight", "intimidation", "medicine", "persuasion", "religion"], + "skill_options": ["athletics", "brawl", "force", "insight", "intimidation", "lung_craft", "medicine", "persuasion", "religion", "scent_speak"], "subclass_ids": ["the_warden", "the_bridge"], "starting_kit": [ { "item_id": "rend_sword", "qty": 1, "auto_equip": true, "equip_slot": "main_hand" }, @@ -377,7 +377,7 @@ "weapon_proficiencies": ["simple", "natural"], "tool_proficiencies": ["musical_instrument", "musical_instrument_2", "musical_instrument_3"], "skills_choose": 3, - "skill_options": ["acrobatics", "animal_handling", "arcana", "athletics", "deception", "history", "insight", "intimidation", "investigation", "medicine", "nature", "perception", "performance", "persuasion", "religion", "sleight_of_hand", "stealth", "survival"], + "skill_options": ["acrobatics", "animal_handling", "arcana", "athletics", "brawl", "build_read", "deception", "driving", "endurance", "force", "fortitude", "hardiness", "haulage", "history", "insight", "intimidation", "investigation", "lung_craft", "marksmanship", "medicine", "nature", "pain_tolerance", "perception", "performance", "persuasion", "religion", "scent_speak", "sleight_of_hand", "stealth", "survival"], "subclass_ids": ["warhorn", "whisperfur"], "starting_kit": [ { "item_id": "fang_knife", "qty": 1, "auto_equip": true, "equip_slot": "main_hand" }, @@ -440,7 +440,7 @@ "weapon_proficiencies": ["simple", "natural", "firearms"], "tool_proficiencies": ["tinkers_tools", "artisans_tools", "artisans_tools_2"], "skills_choose": 3, - "skill_options": ["arcana", "investigation", "medicine", "nature", "perception", "sleight_of_hand"], + "skill_options": ["arcana", "build_read", "driving", "force", "haulage", "investigation", "medicine", "nature", "perception", "sleight_of_hand"], "subclass_ids": ["combat_engineer", "body_wright"], "starting_kit": [ { "item_id": "hoof_club", "qty": 1, "auto_equip": true, "equip_slot": "main_hand" }, diff --git a/Theriapolis.Core/Rules/Character/CharacterBuilder.cs b/Theriapolis.Core/Rules/Character/CharacterBuilder.cs index 8002d52..6852e4c 100644 --- a/Theriapolis.Core/Rules/Character/CharacterBuilder.cs +++ b/Theriapolis.Core/Rules/Character/CharacterBuilder.cs @@ -401,6 +401,19 @@ public sealed class CharacterBuilder SkillId.SleightOfHand => "sleight_of_hand", SkillId.Stealth => "stealth", SkillId.Survival => "survival", + + SkillId.Brawl => "brawl", + SkillId.BuildRead => "build_read", + SkillId.Driving => "driving", + SkillId.Endurance => "endurance", + SkillId.Force => "force", + SkillId.Fortitude => "fortitude", + SkillId.Hardiness => "hardiness", + SkillId.Haulage => "haulage", + SkillId.LungCraft => "lung_craft", + SkillId.Marksmanship => "marksmanship", + SkillId.PainTolerance => "pain_tolerance", + SkillId.ScentSpeak => "scent_speak", _ => s.ToString().ToLowerInvariant(), }; diff --git a/Theriapolis.Core/Rules/Stats/SkillId.cs b/Theriapolis.Core/Rules/Stats/SkillId.cs index affb24e..b43acec 100644 --- a/Theriapolis.Core/Rules/Stats/SkillId.cs +++ b/Theriapolis.Core/Rules/Stats/SkillId.cs @@ -1,8 +1,11 @@ namespace Theriapolis.Core.Rules.Stats; /// -/// Standard d20-adjacent skill list. Each skill is backed by a single -/// ability — see . +/// Skill list used by Theriapolis — extends the d20 baseline with 12 +/// additional skills (M6.18) so each ability has 5 skills tied to it. +/// New skills appended at the end of the byte enum to preserve save-game +/// compatibility with characters created before M6.18. Each skill is +/// backed by a single ability — see . /// public enum SkillId : byte { @@ -24,6 +27,20 @@ public enum SkillId : byte SleightOfHand = 15, Stealth = 16, Survival = 17, + + // M6.18 — Theriapolis-flavored expansions, 5 per ability. + Brawl = 18, // STR + BuildRead = 19, // STR + Driving = 20, // DEX + Endurance = 21, // CON + Force = 22, // STR + Fortitude = 23, // CON + Hardiness = 24, // CON + Haulage = 25, // STR + LungCraft = 26, // CON + Marksmanship = 27, // DEX + PainTolerance = 28, // CON + ScentSpeak = 29, // CHA } public static class SkillIdExtensions @@ -48,6 +65,19 @@ public static class SkillIdExtensions SkillId.SleightOfHand => AbilityId.DEX, SkillId.Stealth => AbilityId.DEX, SkillId.Survival => AbilityId.WIS, + + SkillId.Brawl => AbilityId.STR, + SkillId.BuildRead => AbilityId.STR, + SkillId.Driving => AbilityId.DEX, + SkillId.Endurance => AbilityId.CON, + SkillId.Force => AbilityId.STR, + SkillId.Fortitude => AbilityId.CON, + SkillId.Hardiness => AbilityId.CON, + SkillId.Haulage => AbilityId.STR, + SkillId.LungCraft => AbilityId.CON, + SkillId.Marksmanship => AbilityId.DEX, + SkillId.PainTolerance => AbilityId.CON, + SkillId.ScentSpeak => AbilityId.CHA, _ => throw new ArgumentOutOfRangeException(nameof(s)), }; @@ -72,6 +102,19 @@ public static class SkillIdExtensions "sleight_of_hand" => SkillId.SleightOfHand, "stealth" => SkillId.Stealth, "survival" => SkillId.Survival, + + "brawl" => SkillId.Brawl, + "build_read" => SkillId.BuildRead, + "driving" => SkillId.Driving, + "endurance" => SkillId.Endurance, + "force" => SkillId.Force, + "fortitude" => SkillId.Fortitude, + "hardiness" => SkillId.Hardiness, + "haulage" => SkillId.Haulage, + "lung_craft" => SkillId.LungCraft, + "marksmanship" => SkillId.Marksmanship, + "pain_tolerance" => SkillId.PainTolerance, + "scent_speak" => SkillId.ScentSpeak, _ => throw new ArgumentException($"Unknown skill: '{raw}'"), }; } diff --git a/Theriapolis.Godot/UI/SkillsCatalog.cs b/Theriapolis.Godot/UI/SkillsCatalog.cs index c9e0e91..b6b29bb 100644 --- a/Theriapolis.Godot/UI/SkillsCatalog.cs +++ b/Theriapolis.Godot/UI/SkillsCatalog.cs @@ -1,15 +1,15 @@ namespace Theriapolis.GodotHost.UI; /// -/// All 18 skills with display labels, governing ability, and codex +/// All 30 skills with display labels, governing ability, and codex /// flavor descriptions. Entries are keyed by their snake_case JSON id — /// the same string that appears in class.skill_options and /// background.skill_proficiencies in Content/Data. /// -/// Labels and ability mapping mirror Theriapolis.Core.Rules.Stats.SkillId; -/// descriptions are ported verbatim from src/data.jsx's -/// SKILL_DESC table in the React prototype. If the JSON schema -/// gains a description field later, swap to a data-driven lookup. +/// Labels and ability mapping mirror Theriapolis.Core.Rules.Stats.SkillId. +/// The 18 d20-baseline descriptions are ported from the React prototype's +/// SKILL_DESC table; the 12 M6.18 expansions (5 per ability total) +/// are Theriapolis-specific and authored against the design canon. /// public static class SkillsCatalog { @@ -25,8 +25,24 @@ public static class SkillsCatalog "Knowledge of the older magics: scent-sorcery, blood-sigil, the half-forgotten rites that pre-date the Covenant of Claws."), new("athletics", "Athletics", "STR", "Raw physical effort. Climbing scaffold, swimming the foul canal, hauling a packmate from the pit, breaking a hold."), + new("brawl", "Brawl", "STR", + "Bare-fanged unarmed violence — claws, teeth, horns, hooves. The coliseum tradition and the back-alley one. Distinct from Athletics (the running body) and Intimidation (the threat unspoken) — this is the application of natural-weapon force."), + new("build_read", "Build-Read", "STR", + "Sizing up another creature's physical capabilities at a glance. Cross-clade body diversity makes this nontrivial — a Mustelid's frame lies about its strength, a Cervid's stillness lies about its speed. The dockside boxer's eye for who can fight."), new("deception", "Deception", "CHA", "Speaking convincingly past your scent. The art of the false posture, the planted rumor, the answer that is technically true."), + new("driving", "Driving", "DEX", + "Vehicle and mount control under pressure. Caravan-work, Hare-courier carts, riding a clademorphic beast over broken ground, navigating a contested street at speed."), + new("endurance", "Endurance", "CON", + "Sustained applied effort. The act of doing hard work for a long time — forced marches, all-night hauls, rowing the canal-shift, the long chase. What you put out, hour after hour."), + new("force", "Force", "STR", + "Applied violence on objects. Doors, chains, shutters, locked chests, walls that shouldn't be there anymore. The Bulwark's quiet talent and the Claw-Wright's last resort."), + new("fortitude", "Fortitude", "CON", + "Resisting what you swallow. Ingested poison and contagion, spoiled rations, foreign cuisine, the Goat-Folk welcome of rotted cheese, the dockside whiskey flight, the ritual draught you cannot politely refuse."), + new("hardiness", "Hardiness", "CON", + "Withstanding external conditions. Temperature extremes, smoke and dust, thin mountain air, the slow attrition of weather. The Polar Bear-Folk's cold tolerance, the Coyote-Folk's heat-of-the-day shift, the herd-wall holding under blizzard."), + new("haulage", "Haulage", "STR", + "Bearing weight under distance. Porter discipline, stretcher-craft, shouldering an unconscious packmate up a switchback. The Bovid wagon-train's daily reality and the battlefield medic's quiet requirement."), new("history", "History", "INT", "The long memory of Theriapolis — the Imperium's fall, the Compact's ratification, which clade owes which other a centuries-old debt."), new("insight", "Insight", "WIS", @@ -35,10 +51,16 @@ public static class SkillsCatalog "Bared-teeth diplomacy. The threat made plain enough that violence is not required to extract compliance."), new("investigation", "Investigation", "INT", "Methodical search and inference: scene-reading, document-sifting, the patient accumulation of small facts into a verdict."), + new("lung_craft", "Lung-Craft", "CON", + "Sustained vocalization and breath-control. The physical basis of Muzzle-Speaker oratory, the diver's stillness underwater, the smoke-tolerant veteran's projection across a coliseum without shredding the throat."), + new("marksmanship", "Marksmanship", "DEX", + "Accurate ranged weapon use — bow, crossbow, sling, javelin, thrown blade. The skill that lets prey-clade militias hold a wall against predator charge, and the Shadow-Pelt's clean answer at distance."), new("medicine", "Medicine", "WIS", "Field surgery, poultice-craft, knowing which clade tolerates which tincture. Stabilizing the dying without finishing them."), new("nature", "Nature", "INT", "Knowledge of the wild outside the city wall — terrain, weather, plant-lore, and the unsigned beasts that observe no Covenant."), + new("pain_tolerance", "Pain Tolerance", "CON", + "Function while wounded. Holding the line bleeding, finishing the sentence with a knife in your shoulder, performing surgery on yourself. The hybrid medical-mistrust skill — the one you use when the doctor isn't an option."), new("perception", "Perception", "WIS", "Awareness through every sense your clade gives you: ear-cock, scent-prickle, the half-glimpsed shape at the edge of vision."), new("performance", "Performance", "CHA", @@ -47,6 +69,8 @@ public static class SkillsCatalog "Open-handed argument. The case made on its merits, the appeal to mutual benefit, the patient construction of agreement."), new("religion", "Religion", "INT", "The hymn-cycles of the Cervid liturgy, the Compact's sacred clauses, the small household rites your clade keeps without thinking."), + new("scent_speak", "Scent-Speak", "CHA", + "Deliberate pheromone communication — the unspoken half of every Theriapolis conversation. Broadcasting calm, threat, deference, lineage, trust. The Scent-Broker's craft, the passer's nightmare, the perfumer's living. Distinct from Insight (which reads the scent) — this is the active emission."), new("sleight_of_hand", "Sleight of Hand", "DEX", "Quiet fingers — pickpocketing, palmed coins, the swap performed under another's nose. Useful in markets and courtrooms alike."), new("stealth", "Stealth", "DEX",