diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index f4e9347..8dccab9 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -634,9 +634,10 @@ export default class CharacterData extends VagabondActorBase { // Calculate Item Slots: 8 + Might - Fatigue + bonus const baseSlots = CONFIG.VAGABOND?.baseItemSlots || 8; - // Sum up all bonus sources + // Sum up all bonus sources from the bonuses array and ADD to existing bonus + // (existing bonus may have been set by Active Effects before prepareDerivedData runs) const totalBonus = this.itemSlots.bonuses.reduce((sum, b) => sum + b.value, 0); - this.itemSlots.bonus = totalBonus; + this.itemSlots.bonus += totalBonus; this.itemSlots.max = baseSlots + stats.might.value - this.resources.fatigue.value + this.itemSlots.bonus; // Check if overburdened diff --git a/module/sheets/character-sheet.mjs b/module/sheets/character-sheet.mjs index f906217..a864667 100644 --- a/module/sheets/character-sheet.mjs +++ b/module/sheets/character-sheet.mjs @@ -119,6 +119,45 @@ export default class VagabondCharacterSheet extends VagabondActorSheet { context.classes = context.items.classes; context.className = context.items.classes[0]?.name || "None"; context.ancestryName = context.items.ancestry?.name || "None"; + + // Prepare class features from class items for display + context.classFeatures = this._prepareClassFeatures(); + } + + /** + * Prepare class features for display on the abilities tab. + * Extracts features from class items at or below the character's current level. + * @returns {Object[]} + * @private + */ + _prepareClassFeatures() { + const level = this.actor.system.level || 1; + const classFeatures = []; + + for (const classItem of this.actor.items.filter((i) => i.type === "class")) { + const features = classItem.system.features || []; + for (const feature of features) { + // Only include features at or below current level + if (feature.level <= level) { + classFeatures.push({ + name: feature.name, + description: feature.description, + passive: feature.passive, + level: feature.level, + sourceClass: classItem.name, + img: classItem.img || "icons/svg/book.svg", + }); + } + } + } + + // Sort by level, then alphabetically + classFeatures.sort((a, b) => { + if (a.level !== b.level) return a.level - b.level; + return a.name.localeCompare(b.name); + }); + + return classFeatures; } /** diff --git a/packs/_source/equipment/backpack.json b/packs/_source/equipment/backpack.json index 3926cae..3f0dae0 100644 --- a/packs/_source/equipment/backpack.json +++ b/packs/_source/equipment/backpack.json @@ -38,7 +38,7 @@ "effects": [ { "_id": "backpackSlotBonus", - "_key": "!items.effects!vagabondEquipBackpack.backpackSlotBonus", + "_key": "!items.effects!vgbdEqpbackpack0.backpackSlotBonus", "name": "Backpack Slot Bonus", "icon": "icons/svg/item-bag.svg", "changes": [ diff --git a/styles/scss/sheets/_actor-sheet.scss b/styles/scss/sheets/_actor-sheet.scss index ebac1e3..038c70a 100644 --- a/styles/scss/sheets/_actor-sheet.scss +++ b/styles/scss/sheets/_actor-sheet.scss @@ -609,7 +609,10 @@ .skills-section { .skills-grid { display: grid; + // 2 columns with vertical flow (fills columns top-to-bottom, then left-to-right) grid-template-columns: repeat(2, 1fr); + grid-template-rows: repeat(6, auto); + grid-auto-flow: column; gap: $spacing-2; } diff --git a/templates/actor/character-abilities.hbs b/templates/actor/character-abilities.hbs index 5e05180..0f049dc 100644 --- a/templates/actor/character-abilities.hbs +++ b/templates/actor/character-abilities.hbs @@ -30,6 +30,18 @@

{{localize "VAGABOND.Features"}}