import { SYSTEM } from "../config/system.mjs" export default class OathHammerWeapon extends foundry.abstract.TypeDataModel { static defineSchema() { const fields = foundry.data.fields const requiredInteger = { required: true, nullable: false, integer: true } const schema = {} schema.description = new fields.HTMLField({ required: true, textSearch: true }) // Proficiency group (Common, Dueling, Heavy, Polearms, Bows, Throwing) schema.proficiencyGroup = new fields.StringField({ required: true, initial: "common", choices: SYSTEM.WEAPON_PROFICIENCY_GROUPS }) // Damage: melee/throwing = Might rank + damageMod dice; bows = baseDice (fixed, no Might) // usesMight is now derived from proficiencyGroup (see getter below) schema.damageMod = new fields.NumberField({ ...requiredInteger, initial: 0, min: -4, max: 16 }) // AP (Armor Penetration): penalty imposed on armor/defense rolls schema.ap = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 16 }) // Reach (melee, in ft: 5 / 10 / 15) — ignored for ranged/throwing schema.reach = new fields.NumberField({ ...requiredInteger, initial: 5, min: 5 }) // Range (ranged & throwing, in ft): short and long schema.shortRange = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) schema.longRange = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) // Traits — stored as a Set of trait keys (Block, Brutal, Nimble, Parry, etc.) schema.traits = new fields.SetField( new fields.StringField({ choices: SYSTEM.WEAPON_TRAITS }), { required: true, initial: [] } ) // Special Properties — crafting enhancements (Accurate, Master-Crafted, etc. p.98) schema.specialProperties = new fields.SetField( new fields.StringField({ choices: SYSTEM.WEAPON_SPECIAL_PROPERTIES }), { required: true, initial: [] } ) // Item slots (when stowed; 0 = does not occupy slots) schema.slots = new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }) schema.rarity = new fields.StringField({ required: true, initial: "common", choices: SYSTEM.RARITY_CHOICES }) schema.equipped = new fields.BooleanField({ required: true, initial: false }) schema.cost = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) schema.currency = new fields.StringField({ required: true, initial: "gp", choices: SYSTEM.CURRENCY_CHOICES }) // --- Magic properties (only relevant when isMagic = true) --- schema.isMagic = new fields.BooleanField({ initial: false }) schema.magicQuality = new fields.StringField({ required: false, nullable: true, initial: null, choices: SYSTEM.MAGIC_QUALITY_CHOICES }) schema.isCursed = new fields.BooleanField({ initial: false }) // Enchantment description (displayed when isMagic is true) schema.magicEffect = new fields.HTMLField({ required: false, textSearch: true }) // Class/lineage restriction, e.g. "Dwarves only" (empty = no restriction) schema.classRestriction = new fields.StringField({ required: false, nullable: true, initial: null, choices: SYSTEM.CLASS_RESTRICTION_CHOICES }) // Override which skill (and its linked attribute) is used for attack rolls. // Null / "" = auto-detect (fighting for melee, shooting for ranged). // Use this for abilities like Magic Bolt that roll Magic+Willpower instead. schema.skillOverride = new fields.StringField({ required: false, nullable: true, initial: null }) return schema } static LOCALIZATION_PREFIXES = ["OATHHAMMER.Weapon"] static migrateData(source) { if (typeof source.rarity === "number") { const map = { 0: "common", 1: "uncommon", 2: "rare", 3: "very-rare", 4: "legendary", 5: "legendary", 6: "legendary" } source.rarity = map[source.rarity] ?? "common" } // Remove legacy usesMight field — now derived from proficiencyGroup delete source.usesMight return super.migrateData(source) } /** Derived: only bows skip Might for damage. Throwing weapons keep Might (arm strength). */ get usesMight() { return this.proficiencyGroup !== "bows" } /** * Human-readable damage formula for display, e.g. "M+2", "M-1", "6" */ get damageLabel() { if (this.usesMight) { const mod = this.damageMod if (mod === 0) return "M+0" return mod > 0 ? `M+${mod}` : `M${mod}` } return String(this.damageMod) // bows: store base dice count in damageMod } }