vagabond-rpg-foundryvtt/module/data/item/armor.mjs
Cal Corum 1a36139387 Add slotsWhenEquipped system and equipment Active Effect sync
- Add getTotalSlots() method to base-item.mjs as unified interface
- Add slotsWhenEquipped field to weapon, armor, and equipment schemas
- Implement getTotalSlots() in each item type respecting equipped state
- Update actor slot calculation to use getTotalSlots() uniformly
- Add _onUpdate hook to sync equipment effects with equipped state
- Update backpack with slotsWhenEquipped: 0 and +2 slot bonus effect

Backpack now correctly:
- Costs 1 slot when unequipped, 0 when equipped
- Grants +2 max item slots via Active Effect when equipped

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 00:34:16 -06:00

183 lines
4.9 KiB
JavaScript

/**
* Armor Item Data Model
*
* Defines the data schema for armor in Vagabond RPG.
*
* Armor Types:
* - Light: Basic protection, no dodge penalty
* - Heavy: Better protection, may have dodge penalty
* - Shield: Adds to armor, held in hand
*
* @extends VagabondItemBase
*/
import VagabondItemBase from "./base-item.mjs";
export default class ArmorData extends VagabondItemBase {
/**
* Define the schema for armor items.
*
* @returns {Object} The schema definition
*/
static defineSchema() {
const fields = foundry.data.fields;
const baseSchema = super.defineSchema();
return {
...baseSchema,
// Armor value provided
armorValue: new fields.NumberField({
required: true,
integer: true,
initial: 1,
min: 0,
}),
// Armor type (none, light, medium, heavy, shield)
armorType: new fields.StringField({
required: true,
initial: "light",
choices: ["none", "light", "medium", "heavy", "shield"],
}),
// Does this armor impose a dodge penalty? (auto-set based on type for heavy)
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
slots: new fields.NumberField({
integer: true,
initial: 1,
min: 0,
}),
// Slot cost when equipped (null means same as slots)
// Allows magic armor to reduce slot cost when worn
slotsWhenEquipped: new fields.NumberField({
integer: true,
initial: null,
nullable: true,
min: 0,
}),
// Monetary value (in copper)
value: new fields.NumberField({
integer: true,
initial: 0,
min: 0,
}),
// Is this armor equipped?
equipped: new fields.BooleanField({ initial: false }),
// Bonus effects (magical armor)
magicBonus: new fields.NumberField({
integer: true,
initial: 0,
}),
// Special properties or enchantments
properties: new fields.ArrayField(new fields.StringField(), { initial: [] }),
// Relic System - Powerful magic items with unique abilities
relic: new fields.SchemaField({
// Is this item a relic?
isRelic: new fields.BooleanField({ initial: false }),
// Relic tier (determines power level)
tier: new fields.NumberField({
integer: true,
initial: 1,
min: 1,
max: 5,
}),
// Unique ability name
abilityName: new fields.StringField({ required: false, blank: true }),
// Unique ability description
abilityDescription: new fields.HTMLField({ required: false, blank: true }),
// Activation cost (mana, luck, etc.)
activationCost: new fields.StringField({ required: false, blank: true }),
// Uses per day (0 = unlimited or passive)
usesPerDay: new fields.NumberField({ integer: true, initial: 0, min: 0 }),
// Current uses remaining
usesRemaining: new fields.NumberField({ integer: true, initial: 0, min: 0 }),
// Attunement required?
requiresAttunement: new fields.BooleanField({ initial: false }),
// Currently attuned?
attuned: new fields.BooleanField({ initial: false }),
// Lore/history of the relic
lore: new fields.HTMLField({ required: false, blank: true }),
}),
};
}
/**
* Get the total armor value including magic bonus.
*
* @returns {number} Total armor value
*/
getTotalArmorValue() {
return this.armorValue + this.magicBonus;
}
/**
* Get the effective armor when equipped.
*
* @returns {number} Armor value if equipped, 0 otherwise
*/
getEquippedArmor() {
return this.equipped ? this.getTotalArmorValue() : 0;
}
/**
* Calculate the total inventory slot cost for this armor.
* Respects slotsWhenEquipped for magic armor that reduces slot cost when worn.
*
* @returns {number} Total slots used
*/
getTotalSlots() {
if (this.equipped && this.slotsWhenEquipped !== null) {
return this.slotsWhenEquipped;
}
return this.slots || 0;
}
/**
* Check if this armor imposes dodge penalty when equipped.
*
* @returns {boolean} True if equipped and has dodge penalty
*/
hasActiveDodgePenalty() {
return this.equipped && this.dodgePenalty;
}
/**
* Get chat card data for displaying armor information.
*
* @returns {Object} Chat card data
*/
getChatData() {
const data = super.getChatData();
data.armorValue = this.getTotalArmorValue();
data.armorType = this.armorType;
data.dodgePenalty = this.dodgePenalty;
data.properties = this.properties;
return data;
}
}