Various fixes/update based on first tests feedback

This commit is contained in:
2026-04-10 14:47:21 +02:00
parent 63da2ef664
commit 999b78c6fc
21 changed files with 151 additions and 75 deletions
@@ -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)
})
}
+1 -1
View File
@@ -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"] }
}
+17 -1
View File
@@ -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)
}
})
})
}
@@ -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) {
+5 -2
View File
@@ -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 = {
+19 -21
View File
@@ -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: `<p>${game.i18n.format("AWEMMY.Kit.Used", { name: item.name, value: charges.value - 1, max: charges.max })}</p>`
content: `<p>${game.i18n.format("AWEMMY.Kit.Used", { name: item.name })}</p>`
})
}
@@ -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<void>}
*/
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 => `<li>${s}</li>`).join("")
+4
View File
@@ -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 })
+4 -1
View File
@@ -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
}
-5
View File
@@ -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
}