diff --git a/css/adventures-with-emmy.css b/css/adventures-with-emmy.css index f269a7c..56f3779 100644 --- a/css/adventures-with-emmy.css +++ b/css/adventures-with-emmy.css @@ -1456,6 +1456,47 @@ a.ability-used-btn { flex: 1; } +/* Creature traits tags */ +.awemmy .creature-content .creature-main fieldset .tags-list { + display: flex; + flex-wrap: wrap; + gap: 0.3rem; + align-items: center; + min-height: 2rem; + padding: 0.3rem 0.4rem; + background: rgba(0,0,0,0.03); + border: 1px solid #7a7a88; + border-radius: 4px; +} +.awemmy .creature-content .creature-main fieldset .tags-list .tag { + display: inline-flex; + align-items: center; + gap: 0.2rem; + padding: 0.15rem 0.5rem; + background: #cfdaeb; + border: 1px solid #7a7a88; + border-radius: 12px; + font-size: 0.78rem; + color: #2c2c2c; +} +.awemmy .creature-content .creature-main fieldset .tags-list .tag a { + color: #6c6c6c; + cursor: pointer; + font-weight: bold; + line-height: 1; +} +.awemmy .creature-content .creature-main fieldset .tags-list .tag a:hover { + color: #e8a020; +} +.awemmy .creature-content .creature-main fieldset .tags-list .new-tag { + flex: 1; + min-width: 120px; + font-size: 0.78rem; + padding: 0.15rem 0.4rem; + border-style: dashed; + background: transparent; +} + /* ============================================================ */ /* Token Action HUD - Conditions styling */ /* ============================================================ */ diff --git a/module/applications/sheets/creature-sheet.mjs b/module/applications/sheets/creature-sheet.mjs index 48554bd..3ef88d8 100644 --- a/module/applications/sheets/creature-sheet.mjs +++ b/module/applications/sheets/creature-sheet.mjs @@ -20,7 +20,11 @@ export default class AwECreatureSheet extends AwEActorSheet { createKit: AwECreatureSheet.#onCreateKit, createEquipment: AwECreatureSheet.#onCreateEquipment, rollWeapon: AwECreatureSheet.#onRollWeapon, - rollDamage: AwECreatureSheet.#onRollDamage + rollDamage: AwECreatureSheet.#onRollDamage, + useAbility: AwECreatureSheet.#onUseAbility, + toggleCondition: AwECreatureSheet.#onToggleCondition, + addTrait: AwECreatureSheet.#onAddTrait, + removeTrait: AwECreatureSheet.#onRemoveTrait } } @@ -86,7 +90,8 @@ export default class AwECreatureSheet extends AwEActorSheet { name: item.name, img: item.img, system: item.system, - costLabel: game.i18n.localize(SYSTEM.ABILITY_COST[item.system.cost]?.label ?? item.system.cost) + costLabel: game.i18n.localize(SYSTEM.ABILITY_COST[item.system.cost]?.label ?? item.system.cost), + usedToday: item.system.usedToday })) context.skills = this.document.itemTypes.skill.map(item => ({ id: item.id, @@ -102,6 +107,19 @@ export default class AwECreatureSheet extends AwEActorSheet { img: item.img, system: item.system })) + const doc = this.document + context.conditions = Object.values(SYSTEM.CONDITIONS).map(c => ({ + ...c, + label: game.i18n.localize(c.label), + img: `systems/fvtt-adventures-with-emmy/assets/conditions/${c.id}.svg`, + active: doc.statuses.has(c.id) + })) + context.inhibitedActive = doc.statuses.has("inhibited") + context.vulnerableActive = doc.statuses.has("vulnerable") + context.inhibitedPenalty = doc.system.inhibitedPenalty + context.vulnerablePenalty = doc.system.vulnerablePenalty + context.hasConditionPenalties = context.inhibitedActive || context.vulnerableActive + context.traitSuggestions = SYSTEM.TRAITS break case "inventory": context.tab = context.tabs.inventory @@ -135,6 +153,20 @@ export default class AwECreatureSheet extends AwEActorSheet { return super._onDropItem(item) } + /** @override */ + _onRender(context, options) { + super._onRender(context, options) + this.element.querySelectorAll("input.new-tag[data-action]").forEach(input => { + input.addEventListener("keydown", event => { + if (event.key !== "Enter") return + event.preventDefault() + const actionName = input.dataset.action + const handler = this.options.actions?.[actionName] + if (handler) handler.call(this, event, input) + }) + }) + } + static #onCreateAbility(event, target) { const type = "ability" this.document.createEmbeddedDocuments("Item", [{ name: CONFIG.Item.documentClass.defaultName({ type }), type }]) @@ -165,6 +197,16 @@ export default class AwECreatureSheet extends AwEActorSheet { this.document.createEmbeddedDocuments("Item", [{ name: CONFIG.Item.documentClass.defaultName({ type }), type }]) } + static async #onUseAbility(event, target) { + const itemId = target.closest("[data-item-id]")?.dataset.itemId + await this.document.useAbility(itemId) + } + + static async #onToggleCondition(event, target) { + const conditionId = target.dataset.conditionId + await this.document.toggleStatusEffect(conditionId) + } + static async #onRollWeapon(event, target) { const itemId = target.closest("[data-item-id]")?.dataset.itemId const item = this.document.items.get(itemId) @@ -178,4 +220,19 @@ export default class AwECreatureSheet extends AwEActorSheet { if (!item) return await this.document.rollDamage(item) } + + static async #onAddTrait(event, target) { + const value = target.value.trim() + if (!value) return + const current = foundry.utils.getProperty(this.document, "system.traits") ?? [] + await this.document.update({ "system.traits": [...current, value] }) + target.value = "" + } + + static async #onRemoveTrait(event, target) { + const index = Number(target.dataset.index) + const current = [...(foundry.utils.getProperty(this.document, "system.traits") ?? [])] + current.splice(index, 1) + await this.document.update({ "system.traits": current }) + } } diff --git a/module/documents/roll.mjs b/module/documents/roll.mjs index a4a5cf6..b8d88c8 100644 --- a/module/documents/roll.mjs +++ b/module/documents/roll.mjs @@ -84,8 +84,8 @@ export default class AwERoll extends Roll { Object.entries(CONFIG.Dice.rollModes).map(([k, v]) => [k, game.i18n.localize(v.label ?? v)]) ) - // Bonus choices: -5 to +5 - const bonusChoices = Array.from({length: 11}, (_, i) => i - 5) + // Bonus choices: -10 to +10 + const bonusChoices = Array.from({length: 21}, (_, i) => i - 10) .map(v => ({ value: v, label: v > 0 ? `+${v}` : String(v), selected: v === 0 })) // DC choices: blank + 10..30 diff --git a/module/models/character.mjs b/module/models/character.mjs index 1e7aad6..59c8bba 100644 --- a/module/models/character.mjs +++ b/module/models/character.mjs @@ -51,6 +51,13 @@ export default class AwECharacter extends foundry.abstract.TypeDataModel { }, {}) ) + schema.keyAttribute = new fields.StringField({ + required: true, + nullable: false, + initial: "agility", + choices: Object.fromEntries(Object.values(SYSTEM.ATTRIBUTES).map(a => [a.id, a.label])) + }) + // Condition penalty magnitudes (used when the respective condition is active) schema.inhibitedPenalty = new fields.NumberField({ required: true, nullable: false, integer: true, initial: 2, min: 0 }) schema.vulnerablePenalty = new fields.NumberField({ required: true, nullable: false, integer: true, initial: 2, min: 0 }) @@ -70,5 +77,8 @@ export default class AwECharacter extends foundry.abstract.TypeDataModel { const bonusPart = attr.bonus !== 0 ? ` + Bonus ${attr.bonus >= 0 ? '+' : ''}${attr.bonus}` : '' attr.modBreakdown = `Level ${level} + Boosts ${attr.boostLevel}${bonusPart} = ${attr.mod >= 0 ? '+' : ''}${attr.mod}` } + + this.hp.max = (10 * level) + this.attributes.fitness.mod + this.hp.value = Math.min(this.hp.value, this.hp.max) } } diff --git a/module/models/creature.mjs b/module/models/creature.mjs index acc0671..723b315 100644 --- a/module/models/creature.mjs +++ b/module/models/creature.mjs @@ -34,6 +34,10 @@ export default class AwECreature extends foundry.abstract.TypeDataModel { }) }) + schema.traits = new fields.ArrayField(new fields.StringField()) + schema.inhibitedPenalty = new fields.NumberField({ required: true, nullable: false, integer: true, initial: 2, min: 0 }) + schema.vulnerablePenalty = new fields.NumberField({ required: true, nullable: false, integer: true, initial: 2, min: 0 }) + // Eureka Rubric schema.eurekaClaims = new fields.StringField({ initial: "", required: false, nullable: true }) schema.eurekaEvidence = new fields.StringField({ initial: "", required: false, nullable: true }) diff --git a/templates/character-header.hbs b/templates/character-header.hbs index ec63716..950f0cd 100644 --- a/templates/character-header.hbs +++ b/templates/character-header.hbs @@ -21,7 +21,7 @@