From 999b78c6fc0f6cc52842ed31a352d9e9106c82ac Mon Sep 17 00:00:00 2001 From: LeRatierBretonnier Date: Fri, 10 Apr 2026 14:47:21 +0200 Subject: [PATCH] Various fixes/update based on first tests feedback --- .gitignore | 27 +++++++++++++ lang/en.json | 16 +++++--- module/applications/hud/action-handler.js | 3 -- module/applications/sheets/ability-sheet.mjs | 2 +- .../applications/sheets/base-item-sheet.mjs | 18 ++++++++- .../applications/sheets/character-sheet.mjs | 8 +--- module/config/system.mjs | 7 +++- module/documents/actor.mjs | 40 +++++++++---------- module/models/ability.mjs | 4 ++ module/models/background.mjs | 5 ++- module/models/kit.mjs | 5 --- templates/ability.hbs | 32 ++++++++++++--- templates/archetype.hbs | 2 +- templates/background.hbs | 25 ++++++++++-- templates/character-equipment.hbs | 1 - templates/character-main.hbs | 14 +++---- templates/equipment.hbs | 2 +- templates/field.hbs | 2 +- templates/kit.hbs | 9 +---- templates/specialization.hbs | 2 +- templates/weapon.hbs | 2 +- 21 files changed, 151 insertions(+), 75 deletions(-) diff --git a/.gitignore b/.gitignore index 4a0f346..6fcca06 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,30 @@ +# Documentation source (game rules, design docs) +_docs/ + +# Dependencies node_modules/ + +# Build output css/ packs/ +dist/ + +# OS +.DS_Store +Thumbs.db + +# Editor +.vscode/ +.idea/ +*.swp +*.swo + +# Logs +*.log +npm-debug.log* + +# Environment +.env +.env.local + +.github/ diff --git a/lang/en.json b/lang/en.json index 37ffea8..6bf4459 100644 --- a/lang/en.json +++ b/lang/en.json @@ -30,15 +30,19 @@ "AWEMMY.Condition.Vulnerable": "Vulnerable", "AWEMMY.Condition.Panel": "Conditions", "AWEMMY.Roll.ConditionBonus": "Condition", + "AWEMMY.Item.Description": "Description", + "AWEMMY.Error.TraitPasteFailed": "Failed to update traits — please try again.", "AWEMMY.Kit.Use": "Use Kit", - "AWEMMY.Kit.Used": "{name} used (charges: {value}/{max})", - "AWEMMY.Kit.Depleted": "{name} has no charges remaining!", + "AWEMMY.Kit.Used": "{name} used", "AWEMMY.Ability.Cost.Free": "Free", + "AWEMMY.Ability.Cost.Variable": "Variable (Δ)", "AWEMMY.Ability.TypeLabel": "Type", "AWEMMY.Ability.Type.Field": "Field", "AWEMMY.Ability.Type.Archetype": "Archetype", "AWEMMY.Ability.Type.General": "General", "AWEMMY.Ability.Type.Beginner": "Beginner", + "AWEMMY.Ability.Type.Advanced": "Advanced", + "AWEMMY.Ability.Type.Pinnacle": "Pinnacle", "AWEMMY.Archetype.PrerequisiteLevel": "Prerequisite Level", "AWEMMY.Item.Ability": "Ability", "AWEMMY.Item.Field": "Field", @@ -105,8 +109,12 @@ "AWEMMY.Ability.Frequency": "Frequency", "AWEMMY.Ability.Requirements": "Requirements", "AWEMMY.Ability.Trigger": "Trigger", + "AWEMMY.Ability.Range": "Range", + "AWEMMY.Ability.Targets": "Targets", + "AWEMMY.Ability.Duration": "Duration", "AWEMMY.Ability.Traits": "Traits", "AWEMMY.Ability.AddTrait": "Add trait...", + "AWEMMY.Ability.IsDaily": "Daily (1/day)", "AWEMMY.Ability.FlowPointCost": "Flow Point Cost", "AWEMMY.Ability.Use": "Use Ability", "AWEMMY.Ability.AlreadyUsed": "{name} has already been used today!", @@ -128,9 +136,8 @@ "AWEMMY.Field.Specializations": "Specializations", "AWEMMY.Field.AddSpecialization": "Add specialization...", "AWEMMY.Field.KnowledgeBonus": "Knowledge Bonus", - "AWEMMY.Background.Bonus": "Background Bonus", + "AWEMMY.Background.AttributeBoosts": "Attribute Boosts", "AWEMMY.Kit.Field": "Field", - "AWEMMY.Kit.Charges": "Charges", "AWEMMY.Equipment.Quantity": "Quantity", "AWEMMY.Equipment.Weight": "Weight", "AWEMMY.Sheet.EditItem": "Edit", @@ -143,7 +150,6 @@ "AWEMMY.Rest.LongRestTitle": "{name} rests for 8 hours", "AWEMMY.Rest.HPRestored": "Recovered {amount} HP (now {max}/{max})", "AWEMMY.Rest.AbilitiesReset": "{count} daily ability(ies) reset", - "AWEMMY.Rest.KitsReplenished": "{count} kit(s) replenished", "AWEMMY.Rest.AlreadyRested": "Already at full health — no recovery needed.", "AWEMMY.TAH.Stats": "Stats", diff --git a/module/applications/hud/action-handler.js b/module/applications/hud/action-handler.js index 49f8572..e4df7bd 100644 --- a/module/applications/hud/action-handler.js +++ b/module/applications/hud/action-handler.js @@ -167,12 +167,9 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { const kits = this.actor.itemTypes?.kit ?? [] const actions = [] for (const kit of kits) { - const charges = kit.system.charges - const chargesText = `${charges.value}/${charges.max}` actions.push({ name: kit.name, id: kit.id, - info1: { text: chargesText }, encodedValue: ['kit', kit.id].join(this.delimiter) }) } diff --git a/module/applications/sheets/ability-sheet.mjs b/module/applications/sheets/ability-sheet.mjs index bfba181..56ffa64 100644 --- a/module/applications/sheets/ability-sheet.mjs +++ b/module/applications/sheets/ability-sheet.mjs @@ -4,7 +4,7 @@ export default class AwEAbilitySheet extends AwEItemSheet { /** @override */ static DEFAULT_OPTIONS = { classes: ["ability"], - position: { width: 620 }, + position: { width: 620, height: 560 }, window: { contentClasses: ["ability-content"] } } diff --git a/module/applications/sheets/base-item-sheet.mjs b/module/applications/sheets/base-item-sheet.mjs index e6e44ec..6db37bd 100644 --- a/module/applications/sheets/base-item-sheet.mjs +++ b/module/applications/sheets/base-item-sheet.mjs @@ -21,7 +21,7 @@ export default class AwEItemSheet extends HandlebarsApplicationMixin(foundry.app classes: ["awemmy", "item"], position: { width: 600, - height: "auto" + height: 480 }, form: { submitOnChange: true @@ -91,6 +91,22 @@ export default class AwEItemSheet extends HandlebarsApplicationMixin(foundry.app const handler = this.options.actions?.[actionName] if (handler) handler.call(this, event, input) }) + // Auto-split comma-separated values on paste + input.addEventListener("paste", async event => { + const pasted = (event.clipboardData ?? window.clipboardData).getData("text") + const parts = pasted.split(",").map(s => s.trim().toLowerCase()).filter(Boolean) + if (parts.length < 2) return // single value: let default paste handle it + event.preventDefault() + const fieldName = input.dataset.field ?? "system.traits" + const current = foundry.utils.getProperty(this.document, fieldName) ?? [] + const merged = [...new Set([...current, ...parts])] + try { + await this.document.update({ [fieldName]: merged }) + } catch (err) { + ui.notifications.error(game.i18n.localize("AWEMMY.Error.TraitPasteFailed")) + console.error("AwE | trait paste update failed:", err) + } + }) }) } diff --git a/module/applications/sheets/character-sheet.mjs b/module/applications/sheets/character-sheet.mjs index 79ed0a6..be2a5b8 100644 --- a/module/applications/sheets/character-sheet.mjs +++ b/module/applications/sheets/character-sheet.mjs @@ -293,12 +293,8 @@ export default class AwECharacterSheet extends AwEActorSheet { } static async #onDailyReset(event, target) { - const actor = this.document - const dailyAbilities = actor.itemTypes.ability.filter(i => i.system.usedToday) - if (!dailyAbilities.length) return - const updates = dailyAbilities.map(i => ({ _id: i.id, "system.usedToday": false })) - await actor.updateEmbeddedDocuments("Item", updates) - ui.notifications.info(game.i18n.localize("AWEMMY.Ability.DailyResetDone")) + const count = await this.document.resetDailyAbilities() + if (count > 0) ui.notifications.info(game.i18n.localize("AWEMMY.Ability.DailyResetDone")) } static async #onLongRest(event, target) { diff --git a/module/config/system.mjs b/module/config/system.mjs index 4db246c..0dc47ab 100644 --- a/module/config/system.mjs +++ b/module/config/system.mjs @@ -3,8 +3,8 @@ export const DEV_MODE = false export const ATTRIBUTES = { agility: { id: "agility", abbrev: "AGI", label: "AWEMMY.Attribute.Agility" }, - fitness: { id: "fitness", abbrev: "FIT", label: "AWEMMY.Attribute.Fitness" }, awareness: { id: "awareness", abbrev: "AWA", label: "AWEMMY.Attribute.Awareness" }, + fitness: { id: "fitness", abbrev: "FIT", label: "AWEMMY.Attribute.Fitness" }, influence: { id: "influence", abbrev: "INF", label: "AWEMMY.Attribute.Influence" } } @@ -26,6 +26,7 @@ export const ABILITY_COST = { "three": { id: "three", label: "ΔΔΔ" }, "reaction": { id: "reaction", label: "↩" }, "free": { id: "free", label: "AWEMMY.Ability.Cost.Free" }, + "variable": { id: "variable", label: "AWEMMY.Ability.Cost.Variable" }, "none": { id: "none", label: "—" } } @@ -33,7 +34,9 @@ export const ABILITY_TYPE = { "field": { id: "field", label: "AWEMMY.Ability.Type.Field" }, "archetype": { id: "archetype", label: "AWEMMY.Ability.Type.Archetype" }, "general": { id: "general", label: "AWEMMY.Ability.Type.General" }, - "beginner": { id: "beginner", label: "AWEMMY.Ability.Type.Beginner" } + "beginner": { id: "beginner", label: "AWEMMY.Ability.Type.Beginner" }, + "advanced": { id: "advanced", label: "AWEMMY.Ability.Type.Advanced" }, + "pinnacle": { id: "pinnacle", label: "AWEMMY.Ability.Type.Pinnacle" } } export const OUTCOME_LABELS = { diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index a643b15..8b1064a 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -146,21 +146,15 @@ export default class AwEActor extends Actor { } /** - * Use a kit item: decrement charges and post a chat message. + * Use a kit item: post a chat message. * @param {string} kitId - The kit item ID. */ async useKit(kitId) { const item = this.items.get(kitId) if (!item) return - const charges = item.system.charges - if (charges.value <= 0) { - ui.notifications.warn(game.i18n.format("AWEMMY.Kit.Depleted", { name: item.name })) - return - } - await item.update({ "system.charges.value": charges.value - 1 }) await ChatMessage.create({ speaker: ChatMessage.getSpeaker({ actor: this }), - content: `

${game.i18n.format("AWEMMY.Kit.Used", { name: item.name, value: charges.value - 1, max: charges.max })}

` + content: `

${game.i18n.format("AWEMMY.Kit.Used", { name: item.name })}

` }) } @@ -173,7 +167,8 @@ export default class AwEActor extends Actor { if (!item) return const sys = item.system - if (sys.usedToday) { + const isDaily = sys.isDaily + if (isDaily && sys.usedToday) { ui.notifications.warn(game.i18n.format("AWEMMY.Ability.AlreadyUsed", { name: item.name })) return } @@ -187,7 +182,6 @@ export default class AwEActor extends Actor { await this.update({ "system.flowPoints.value": fp - sys.flowPointCost }) } - const isDaily = sys.frequency?.toLowerCase().includes("day") if (isDaily) await item.update({ "system.usedToday": true }) const abilityTypeLabel = game.i18n.localize(SYSTEM.ABILITY_TYPE[sys.abilityType]?.label ?? sys.abilityType) @@ -212,7 +206,18 @@ export default class AwEActor extends Actor { } /** - * Perform a long rest: restore HP, reset daily abilities, refill kits, post chat card. + * Reset all once-per-day abilities (usedToday → false). + * @returns {Promise} + */ + async resetDailyAbilities() { + const dailyAbilities = this.itemTypes.ability.filter(i => i.system.usedToday) + if (!dailyAbilities.length) return 0 + await this.updateEmbeddedDocuments("Item", dailyAbilities.map(i => ({ _id: i.id, "system.usedToday": false }))) + return dailyAbilities.length + } + + /** + * Perform a long rest: restore HP, reset daily abilities, post chat card. * No confirmation dialog — caller is responsible for confirming if needed. */ async longRest() { @@ -227,16 +232,9 @@ export default class AwEActor extends Actor { } if (Object.keys(updates).length > 0) await this.update(updates) - const dailyAbilities = this.itemTypes.ability.filter(i => i.system.usedToday) - if (dailyAbilities.length) { - await this.updateEmbeddedDocuments("Item", dailyAbilities.map(i => ({ _id: i.id, "system.usedToday": false }))) - summary.push(game.i18n.format("AWEMMY.Rest.AbilitiesReset", { count: dailyAbilities.length })) - } - - const depleted = this.itemTypes.kit.filter(i => i.system.charges.value < i.system.charges.max) - if (depleted.length) { - await this.updateEmbeddedDocuments("Item", depleted.map(i => ({ _id: i.id, "system.charges.value": i.system.charges.max }))) - summary.push(game.i18n.format("AWEMMY.Rest.KitsReplenished", { count: depleted.length })) + const resetCount = await this.resetDailyAbilities() + if (resetCount > 0) { + summary.push(game.i18n.format("AWEMMY.Rest.AbilitiesReset", { count: resetCount })) } const bulletList = summary.map(s => `
  • ${s}
  • `).join("") diff --git a/module/models/ability.mjs b/module/models/ability.mjs index 0d6c08f..2779b0c 100644 --- a/module/models/ability.mjs +++ b/module/models/ability.mjs @@ -21,7 +21,11 @@ export default class AwEAbility extends foundry.abstract.TypeDataModel { schema.frequency = new fields.StringField({ initial: "", required: false, nullable: true }) schema.requirements = new fields.StringField({ initial: "", required: false, nullable: true }) schema.trigger = new fields.StringField({ initial: "", required: false, nullable: true }) + schema.range = new fields.StringField({ initial: "", required: false, nullable: true }) + schema.targets = new fields.StringField({ initial: "", required: false, nullable: true }) + schema.duration = new fields.StringField({ initial: "", required: false, nullable: true }) schema.traits = new fields.ArrayField(new fields.StringField()) + schema.isDaily = new fields.BooleanField({ required: true, initial: false }) schema.flowPointCost = new fields.NumberField({ required: true, nullable: false, initial: 0, min: 0, integer: true }) schema.usedToday = new fields.BooleanField({ required: true, initial: false }) diff --git a/module/models/background.mjs b/module/models/background.mjs index cbac466..ccd1636 100644 --- a/module/models/background.mjs +++ b/module/models/background.mjs @@ -4,7 +4,10 @@ export default class AwEBackground extends foundry.abstract.TypeDataModel { const schema = {} schema.description = new fields.HTMLField({ required: true, textSearch: true }) - schema.bonus = new fields.StringField({ initial: "", required: false, nullable: true }) + schema.boostAgility = new fields.BooleanField({ initial: false }) + schema.boostAwareness = new fields.BooleanField({ initial: false }) + schema.boostFitness = new fields.BooleanField({ initial: false }) + schema.boostInfluence = new fields.BooleanField({ initial: false }) return schema } diff --git a/module/models/kit.mjs b/module/models/kit.mjs index dd70b3f..c12287b 100644 --- a/module/models/kit.mjs +++ b/module/models/kit.mjs @@ -1,15 +1,10 @@ export default class AwEKit 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 }) schema.fieldName = new fields.StringField({ initial: "", required: false, nullable: true }) - schema.charges = new fields.SchemaField({ - value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }), - max: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) - }) return schema } diff --git a/templates/ability.hbs b/templates/ability.hbs index d90148d..2ee22a4 100644 --- a/templates/ability.hbs +++ b/templates/ability.hbs @@ -14,10 +14,6 @@ {{formField systemFields.cost value=system.cost localize=true}} -
    - - {{formInput systemFields.flowPointCost value=system.flowPointCost}} -
    @@ -35,6 +31,32 @@ {{formInput systemFields.trigger value=system.trigger}}
    +
    +
    + + {{formInput systemFields.range value=system.range}} +
    +
    + + {{formInput systemFields.targets value=system.targets}} +
    +
    + + {{formInput systemFields.duration value=system.duration}} +
    +
    + +
    +
    + + {{formInput systemFields.isDaily value=system.isDaily}} +
    +
    + + {{formInput systemFields.flowPointCost value=system.flowPointCost}} +
    +
    +
    @@ -51,7 +73,7 @@
    - Description + {{localize "AWEMMY.Item.Description"}} {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
    diff --git a/templates/archetype.hbs b/templates/archetype.hbs index f4470a5..1634188 100644 --- a/templates/archetype.hbs +++ b/templates/archetype.hbs @@ -11,7 +11,7 @@
    - Description + {{localize "AWEMMY.Item.Description"}} {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
    diff --git a/templates/background.hbs b/templates/background.hbs index 78dd0f5..ba67b22 100644 --- a/templates/background.hbs +++ b/templates/background.hbs @@ -5,13 +5,30 @@
    -
    - - {{formInput systemFields.bonus value=system.bonus}} +
    + +
    + + + + +
    - Description + {{localize "AWEMMY.Item.Description"}} {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
    diff --git a/templates/character-equipment.hbs b/templates/character-equipment.hbs index c42d51a..a150612 100644 --- a/templates/character-equipment.hbs +++ b/templates/character-equipment.hbs @@ -8,7 +8,6 @@
    {{item.name}}
    -
    {{item.system.charges.value}}/{{item.system.charges.max}}
    diff --git a/templates/character-main.hbs b/templates/character-main.hbs index d42d98d..06a8336 100644 --- a/templates/character-main.hbs +++ b/templates/character-main.hbs @@ -21,13 +21,6 @@ {{system.attributes.agility.dc}} {{formInput systemFields.attributes.fields.agility.fields.bonus value=system.attributes.agility.bonus disabled=isPlayMode}} - - {{localize "AWEMMY.Attribute.Fitness"}} - {{formInput systemFields.attributes.fields.fitness.fields.boostLevel value=system.attributes.fitness.boostLevel disabled=isPlayMode}} - {{system.attributes.fitness.mod}} - {{system.attributes.fitness.dc}} - {{formInput systemFields.attributes.fields.fitness.fields.bonus value=system.attributes.fitness.bonus disabled=isPlayMode}} - {{localize "AWEMMY.Attribute.Awareness"}} {{formInput systemFields.attributes.fields.awareness.fields.boostLevel value=system.attributes.awareness.boostLevel disabled=isPlayMode}} @@ -35,6 +28,13 @@ {{system.attributes.awareness.dc}} {{formInput systemFields.attributes.fields.awareness.fields.bonus value=system.attributes.awareness.bonus disabled=isPlayMode}} + + {{localize "AWEMMY.Attribute.Fitness"}} + {{formInput systemFields.attributes.fields.fitness.fields.boostLevel value=system.attributes.fitness.boostLevel disabled=isPlayMode}} + {{system.attributes.fitness.mod}} + {{system.attributes.fitness.dc}} + {{formInput systemFields.attributes.fields.fitness.fields.bonus value=system.attributes.fitness.bonus disabled=isPlayMode}} + {{localize "AWEMMY.Attribute.Influence"}} {{formInput systemFields.attributes.fields.influence.fields.boostLevel value=system.attributes.influence.boostLevel disabled=isPlayMode}} diff --git a/templates/equipment.hbs b/templates/equipment.hbs index 6443ec3..41cac37 100644 --- a/templates/equipment.hbs +++ b/templates/equipment.hbs @@ -17,7 +17,7 @@
    - Description + {{localize "AWEMMY.Item.Description"}} {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
    diff --git a/templates/field.hbs b/templates/field.hbs index 3af9f2e..01f416a 100644 --- a/templates/field.hbs +++ b/templates/field.hbs @@ -22,7 +22,7 @@
    - Description + {{localize "AWEMMY.Item.Description"}} {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
    diff --git a/templates/kit.hbs b/templates/kit.hbs index 497b71a..e7edd41 100644 --- a/templates/kit.hbs +++ b/templates/kit.hbs @@ -10,15 +10,8 @@ {{formInput systemFields.fieldName value=system.fieldName}}
    -
    - - {{formInput systemFields.charges.fields.value value=system.charges.value}} - / - {{formInput systemFields.charges.fields.max value=system.charges.max}} -
    -
    - Description + {{localize "AWEMMY.Item.Description"}} {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
    diff --git a/templates/specialization.hbs b/templates/specialization.hbs index 2fe9f99..5c11f07 100644 --- a/templates/specialization.hbs +++ b/templates/specialization.hbs @@ -32,7 +32,7 @@
    - Description + {{localize "AWEMMY.Item.Description"}} {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
    diff --git a/templates/weapon.hbs b/templates/weapon.hbs index 1163052..d36296d 100644 --- a/templates/weapon.hbs +++ b/templates/weapon.hbs @@ -42,7 +42,7 @@
    - Description + {{localize "AWEMMY.Item.Description"}} {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}