Add minor data model improvements from rulebook audit (16 items)

CharacterData additions:
- Senses (darksight, blindsight, tremorsense, elvenEyes, witchsight, sixthSense)
- Languages array (default: ["Common"])
- Rest tracking (lastRest, breathersTaken, restBonuses)
- Travel tracking (milesThisDay, pace, canForage, shiftsElapsed)
- Crafting projects (activeProjects with materials, shifts, bonuses)
- Combat tracking (isFlanked, flankingAllies, ignoresFlankingPenalty,
  currentZone, isDualWielding, mainHandWeapon, offHandWeapon)
- Casting tracking (equippedTrinket, canCastThroughWeapon/Instrument)
- Downtime activities with type and shifts
- Quest tracking (active, completed, lastQuestCompleted)
- Death state (isDead, deathCause, canBeRevived, luminaryRevivifyUsed)
- Summoned creatures (active array with type, HD, HP, command method)
- Size mechanical effects (unitsOccupied, allowsMovementThrough)
- Being type choices (humanlike, fae, cryptid, etc.)
- preferredZone for class-based positioning

NPCData additions:
- Morale status tracking (checkedThisCombat, lastTrigger, lastResult, broken)
- Senses (darksight, blindsight, tremorsense)

ArmorData additions:
- Medium armor type, hindersDodge, preventsRage flags

WeaponData additions:
- Damage type choices (blunt/piercing/slashing + elemental)
- equippedHand for dual-wielding (main/off/both)

EquipmentData additions:
- isTrinket and canCastThrough for spell component tracking

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Cal Corum 2025-12-12 16:02:23 -06:00
parent 466581efd5
commit c06192f90f
5 changed files with 243 additions and 6 deletions

View File

@ -339,8 +339,29 @@ export default class CharacterData extends VagabondActorBase {
// Character details // Character details
details: new fields.SchemaField({ details: new fields.SchemaField({
size: new fields.StringField({ initial: "medium" }), // Size category with mechanical effects
beingType: new fields.StringField({ initial: "humanlike" }), size: new fields.StringField({
initial: "medium",
choices: ["small", "medium", "large", "huge", "giant", "colossal"],
}),
// Units occupied on grid (derived from size)
unitsOccupied: new fields.NumberField({ integer: true, initial: 1, min: 1 }),
// Small creatures don't block movement through their space
allowsMovementThrough: new fields.BooleanField({ initial: false }),
// Being type for targeting effects
beingType: new fields.StringField({
initial: "humanlike",
choices: [
"humanlike",
"fae",
"cryptid",
"artificial",
"undead",
"primordial",
"hellspawn",
"beast",
],
}),
}), }),
// Favor/Hinder tracking (d20 +/- d6 modifiers) // Favor/Hinder tracking (d20 +/- d6 modifiers)
@ -400,6 +421,178 @@ export default class CharacterData extends VagabondActorBase {
// Track which stats were increased at which level // Track which stats were increased at which level
statIncreasesByLevel: new fields.ObjectField({ initial: {} }), // { "2": "might", "4": "dexterity" } statIncreasesByLevel: new fields.ObjectField({ initial: {} }), // { "2": "might", "4": "dexterity" }
}), }),
// Senses and vision types
senses: new fields.SchemaField({
darksight: new fields.BooleanField({ initial: false }), // Dwarf, Goblin, Orc, Infravision perk
blindsight: new fields.NumberField({ integer: true, initial: 0, min: 0 }), // Range in feet
tremorsense: new fields.NumberField({ integer: true, initial: 0, min: 0 }), // Range in feet
// Special vision abilities from perks/ancestry
specialVision: new fields.SchemaField({
elvenEyes: new fields.BooleanField({ initial: false }), // Favor on sight Detect
witchsight: new fields.BooleanField({ initial: false }), // See Invisible, Favor vs illusions
sixthSense: new fields.BooleanField({ initial: false }), // Ignore Blinded for sight-based checks
}),
}),
// Known languages
languages: new fields.ArrayField(new fields.StringField(), { initial: ["Common"] }),
// Rest and breather tracking
restTracking: new fields.SchemaField({
// Timestamp of last full rest
lastRest: new fields.StringField({ required: false, blank: true }),
// Number of breathers taken in current combat/scene
breathersTaken: new fields.NumberField({ integer: true, initial: 0, min: 0 }),
// Bonuses to rest (Song of Rest, Tricksy, etc.)
restBonuses: new fields.ArrayField(
new fields.SchemaField({
source: new fields.StringField({ required: true }), // "Song of Rest", "Tricksy"
effect: new fields.StringField({ required: true }), // "+PRS HP", "+1 Luck"
}),
{ initial: [] }
),
}),
// Travel and exploration tracking
travel: new fields.SchemaField({
// Miles traveled today (for Padfoot perk)
milesThisDay: new fields.NumberField({ integer: true, initial: 0, min: 0 }),
// Current travel pace
pace: new fields.StringField({
initial: "normal",
choices: ["slow", "normal", "fast"],
}),
// Can forage at normal pace (Hunter Survivalist)
canForage: new fields.BooleanField({ initial: false }),
// Shifts elapsed (time tracking for cooldowns)
shiftsElapsed: new fields.NumberField({ integer: true, initial: 0, min: 0 }),
}),
// Crafting projects in progress
crafting: new fields.SchemaField({
activeProjects: new fields.ArrayField(
new fields.SchemaField({
itemName: new fields.StringField({ required: true }),
targetValue: new fields.NumberField({ integer: true, initial: 0 }), // In silver
materialsCost: new fields.NumberField({ integer: true, initial: 0 }),
shiftsRequired: new fields.NumberField({ integer: true, initial: 1 }),
shiftsCompleted: new fields.NumberField({ integer: true, initial: 0 }),
bonuses: new fields.ArrayField(
new fields.SchemaField({
source: new fields.StringField({ required: true }), // "Master Artisan"
effect: new fields.StringField({ required: true }), // "2× Shifts"
}),
{ initial: [] }
),
}),
{ initial: [] }
),
}),
// Combat positioning and flanking
combat: new fields.SchemaField({
// Is this character currently flanked?
isFlanked: new fields.BooleanField({ initial: false }),
// IDs of allies providing flanking
flankingAllies: new fields.ArrayField(new fields.StringField(), { initial: [] }),
// Ignores flanking penalties (Situational Awareness perk)
ignoresFlankingPenalty: new fields.BooleanField({ initial: false }),
// Current combat zone
currentZone: new fields.StringField({
initial: "",
choices: ["", "frontline", "midline", "backline"],
}),
// Is dual-wielding?
isDualWielding: new fields.BooleanField({ initial: false }),
// Main hand weapon ID
mainHandWeapon: new fields.StringField({ required: false, blank: true }),
// Off hand weapon/shield ID
offHandWeapon: new fields.StringField({ required: false, blank: true }),
}),
// Casting and spell component tracking
casting: new fields.SchemaField({
// Currently equipped trinket item ID
equippedTrinket: new fields.StringField({ required: false, blank: true }),
// Can cast through weapon (Gish perk)
canCastThroughWeapon: new fields.BooleanField({ initial: false }),
// Can cast through musical instrument (Harmonic Resonance)
canCastThroughInstrument: new fields.BooleanField({ initial: false }),
}),
// Downtime activity tracking
downtime: new fields.SchemaField({
activities: new fields.ArrayField(
new fields.SchemaField({
type: new fields.StringField({
initial: "work",
choices: ["craft", "study", "carouse", "work", "research"],
}),
shiftsSpent: new fields.NumberField({ integer: true, initial: 0 }),
result: new fields.StringField({ required: false, blank: true }),
}),
{ initial: [] }
),
}),
// Quest tracking (for cooldowns like Medium perk)
quests: new fields.SchemaField({
activeQuests: new fields.ArrayField(new fields.StringField(), { initial: [] }),
completedQuests: new fields.ArrayField(new fields.StringField(), { initial: [] }),
// For Medium perk cooldown
lastQuestCompleted: new fields.StringField({ required: false, blank: true }),
}),
// Death and dying state
death: new fields.SchemaField({
isDead: new fields.BooleanField({ initial: false }),
deathCause: new fields.StringField({
initial: "",
choices: ["", "hp-zero", "body-destroyed", "fatigue-five"],
}),
canBeRevived: new fields.BooleanField({ initial: true }),
revivedCount: new fields.NumberField({ integer: true, initial: 0, min: 0 }),
// Luminary Revivify used today?
luminaryRevivifyUsed: new fields.BooleanField({ initial: false }),
// Force of Nature used this combat?
forceOfNatureUsed: new fields.BooleanField({ initial: false }),
}),
// Summoned creatures tracking
summons: new fields.SchemaField({
active: new fields.ArrayField(
new fields.SchemaField({
id: new fields.StringField({ required: true }),
name: new fields.StringField({ required: true }),
type: new fields.StringField({
initial: "beast",
choices: ["companion", "familiar", "primordial", "beast", "undead"],
}),
source: new fields.StringField({ required: true }), // "Animal Companion", "Familiar perk"
hd: new fields.NumberField({ integer: true, initial: 1 }),
currentHP: new fields.NumberField({ integer: true, initial: 4 }),
maxHP: new fields.NumberField({ integer: true, initial: 4 }),
usesSkill: new fields.StringField({ initial: "survival" }), // Which skill for checks
commandMethod: new fields.StringField({
initial: "action",
choices: ["action", "skip-move", "automatic"],
}),
duration: new fields.StringField({
initial: "permanent",
choices: ["permanent", "focus", "shift", "scene"],
}),
}),
{ initial: [] }
),
maxConcurrent: new fields.NumberField({ integer: true, initial: 1, min: 1 }),
}),
// Preferred combat zone (from class)
preferredZone: new fields.StringField({
initial: "frontline",
choices: ["frontline", "midline", "backline", "flexible"],
}),
}; };
} }

View File

@ -73,6 +73,24 @@ export default class NPCData extends VagabondActorBase {
max: 12, max: 12,
}), }),
// Morale check tracking
moraleStatus: new fields.SchemaField({
// Has a morale check been triggered this combat?
checkedThisCombat: new fields.BooleanField({ initial: false }),
// What triggered the last check?
lastTrigger: new fields.StringField({
initial: "",
choices: ["", "first-death", "half-hp", "half-incapacitated", "leader-death"],
}),
// Result of the last morale check
lastResult: new fields.StringField({
initial: "",
choices: ["", "passed", "failed-retreat", "failed-surrender"],
}),
// Is this NPC currently fleeing/surrendered?
broken: new fields.BooleanField({ initial: false }),
}),
// Number appearing (for random encounters) // Number appearing (for random encounters)
appearing: new fields.StringField({ initial: "1d6" }), appearing: new fields.StringField({ initial: "1d6" }),
@ -89,6 +107,13 @@ export default class NPCData extends VagabondActorBase {
// Being type (for targeting by certain effects) // Being type (for targeting by certain effects)
beingType: new fields.StringField({ initial: "beast" }), beingType: new fields.StringField({ initial: "beast" }),
// Senses (vision types)
senses: new fields.SchemaField({
darksight: new fields.BooleanField({ initial: false }),
blindsight: new fields.NumberField({ integer: true, initial: 0, min: 0 }), // Range in feet
tremorsense: new fields.NumberField({ integer: true, initial: 0, min: 0 }), // Range in feet
}),
// Movement speed // Movement speed
speed: new fields.SchemaField({ speed: new fields.SchemaField({
value: new fields.NumberField({ integer: true, initial: 30 }), value: new fields.NumberField({ integer: true, initial: 30 }),

View File

@ -33,16 +33,22 @@ export default class ArmorData extends VagabondItemBase {
min: 0, min: 0,
}), }),
// Armor type (light, heavy, shield) // Armor type (none, light, medium, heavy, shield)
armorType: new fields.StringField({ armorType: new fields.StringField({
required: true, required: true,
initial: "light", initial: "light",
choices: ["light", "heavy", "shield"], choices: ["none", "light", "medium", "heavy", "shield"],
}), }),
// Does this armor impose a dodge penalty? // Does this armor impose a dodge penalty? (auto-set based on type for heavy)
dodgePenalty: new fields.BooleanField({ initial: false }), dodgePenalty: new fields.BooleanField({ initial: false }),
// Hinders dodge saves (heavy armor hinders, medium may partially)
hindersDodge: new fields.BooleanField({ initial: false }),
// Prevents certain abilities (Barbarian Rage requires light or no armor)
preventsRage: new fields.BooleanField({ initial: false }),
// Inventory slot cost // Inventory slot cost
slots: new fields.NumberField({ slots: new fields.NumberField({
integer: true, integer: true,

View File

@ -77,6 +77,12 @@ export default class EquipmentData extends VagabondItemBase {
// Tags for filtering/searching // Tags for filtering/searching
tags: new fields.ArrayField(new fields.StringField(), { initial: [] }), tags: new fields.ArrayField(new fields.StringField(), { initial: [] }),
// Is this item a valid spell casting trinket?
isTrinket: new fields.BooleanField({ initial: false }),
// Can spells be cast through this item? (for Familiars, Gish weapons)
canCastThrough: new fields.BooleanField({ initial: false }),
// Relic System - Powerful magic items with unique abilities // Relic System - Powerful magic items with unique abilities
relic: new fields.SchemaField({ relic: new fields.SchemaField({
// Is this item a relic? // Is this item a relic?

View File

@ -33,10 +33,11 @@ export default class WeaponData extends VagabondItemBase {
initial: "1d6", initial: "1d6",
}), }),
// Damage type // Damage type (physical: blunt/piercing/slashing, elemental: fire/cold/shock/acid/poison)
damageType: new fields.StringField({ damageType: new fields.StringField({
required: true, required: true,
initial: "blunt", initial: "blunt",
choices: ["blunt", "piercing", "slashing", "fire", "cold", "shock", "acid", "poison"],
}), }),
// Bonus damage (from magic, etc.) // Bonus damage (from magic, etc.)
@ -106,6 +107,12 @@ export default class WeaponData extends VagabondItemBase {
// Is this weapon equipped? // Is this weapon equipped?
equipped: new fields.BooleanField({ initial: false }), equipped: new fields.BooleanField({ initial: false }),
// Which hand is this weapon equipped in? (for dual-wielding)
equippedHand: new fields.StringField({
initial: "",
choices: ["", "main", "off", "both"],
}),
// Quantity (for ammunition, thrown weapons) // Quantity (for ammunition, thrown weapons)
quantity: new fields.NumberField({ quantity: new fields.NumberField({
integer: true, integer: true,