diff --git a/adventures-with-emmy.mjs b/adventures-with-emmy.mjs index d631f18..1b42497 100644 --- a/adventures-with-emmy.mjs +++ b/adventures-with-emmy.mjs @@ -65,6 +65,7 @@ Hooks.once("init", function () { }) CONFIG.ChatMessage.documentClass = documents.AwEChatMessage + CONFIG.Dice.rolls.push(documents.AwERoll) }) Hooks.once("ready", function () { diff --git a/lang/en.json b/lang/en.json index 2afc10a..beeaf2a 100644 --- a/lang/en.json +++ b/lang/en.json @@ -1,4 +1,13 @@ { + "TYPES.Item.ability": "Ability", + "TYPES.Item.field": "Field", + "TYPES.Item.archetype": "Archetype", + "TYPES.Item.background": "Background", + "TYPES.Item.kit": "Kit", + "TYPES.Item.weapon": "Weapon", + "TYPES.Item.equipment": "Equipment", + "TYPES.Actor.character": "Hero", + "TYPES.Actor.creature": "Creature", "AWEMMY.Actor.Character": "Hero", "AWEMMY.Actor.Creature": "Creature", "AWEMMY.Attribute.Agility": "Agility", @@ -19,10 +28,12 @@ "AWEMMY.Condition.Slowed": "Slowed", "AWEMMY.Condition.Vulnerable": "Vulnerable", "AWEMMY.Ability.Cost.Free": "Free", + "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.Archetype.PrerequisiteLevel": "Prerequisite Level", "AWEMMY.Item.Ability": "Ability", "AWEMMY.Item.Field": "Field", "AWEMMY.Item.Archetype": "Archetype", @@ -34,6 +45,13 @@ "AWEMMY.Roll.Success": "Success", "AWEMMY.Roll.Failure": "Failure", "AWEMMY.Roll.CriticalFailure": "Critical Failure", + "AWEMMY.Roll.Check": "Check", + "AWEMMY.Roll.Roll": "Roll", + "AWEMMY.Roll.DialogTitle": "Roll: {name}", + "AWEMMY.Roll.SituationalBonus": "Situational Bonus", + "AWEMMY.Roll.DC": "DC", + "AWEMMY.Roll.Visibility": "Visibility", + "AWEMMY.Roll.Private": "Private Roll", "AWEMMY.Sheet.Tab.Main": "Main", "AWEMMY.Sheet.Tab.Biography": "Biography", "AWEMMY.Sheet.Tab.Equipment": "Equipment", @@ -42,25 +60,41 @@ "AWEMMY.Character.Level": "Level", "AWEMMY.Character.Stride": "Stride", "AWEMMY.Character.HP": "HP", + "AWEMMY.Character.HPTemp": "Temp HP", "AWEMMY.Character.FlowPoints": "Flow Points", + "AWEMMY.Character.FlowPointsTemp": "Temp FP", "AWEMMY.Character.BoostLevel": "Boost Level", "AWEMMY.Character.Mod": "MOD", "AWEMMY.Character.DC": "DC", + "AWEMMY.Character.Bonus": "+/−", + "AWEMMY.Character.Field": "Field", + "AWEMMY.Character.Attribute": "Attribute", + "AWEMMY.Character.Attributes": "Attributes", + "AWEMMY.Character.Identity": "Identity", + "AWEMMY.Character.Description": "Description", + "AWEMMY.Character.Notes": "Notes", + "AWEMMY.Character.Pronouns": "Pronouns", + "AWEMMY.Character.Specialization": "Specialization", "AWEMMY.Creature.EurekaRubric": "Eureka Rubric", "AWEMMY.Creature.Claims": "Claims", "AWEMMY.Creature.Evidence": "Evidence", "AWEMMY.Creature.Hints": "Hints", - "AWEMMY.Ability.Cost": "Cost", + "AWEMMY.Creature.Threshold1": "Threshold 1", + "AWEMMY.Creature.Threshold2": "Threshold 2", + "AWEMMY.Ability.CostLabel": "Cost", "AWEMMY.Ability.Frequency": "Frequency", "AWEMMY.Ability.Requirements": "Requirements", "AWEMMY.Ability.Trigger": "Trigger", "AWEMMY.Ability.Traits": "Traits", + "AWEMMY.Ability.AddTrait": "Add trait...", "AWEMMY.Weapon.Range": "Range", "AWEMMY.Weapon.Damage": "Damage", "AWEMMY.Weapon.DamageType": "Damage Type", "AWEMMY.Weapon.AttackAttribute": "Attack Attribute", "AWEMMY.Field.KeyAttribute": "Key Attribute", + "AWEMMY.Field.KeyAttribute2": "Secondary Key Attribute", "AWEMMY.Field.Specializations": "Specializations", + "AWEMMY.Field.AddSpecialization": "Add specialization...", "AWEMMY.Field.KnowledgeBonus": "Knowledge Bonus", "AWEMMY.Background.Bonus": "Background Bonus", "AWEMMY.Kit.Field": "Field", diff --git a/module/applications/sheets/base-item-sheet.mjs b/module/applications/sheets/base-item-sheet.mjs index f32fa24..60637ed 100644 --- a/module/applications/sheets/base-item-sheet.mjs +++ b/module/applications/sheets/base-item-sheet.mjs @@ -30,7 +30,9 @@ export default class AwEItemSheet extends HandlebarsApplicationMixin(foundry.app dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }], actions: { toggleSheet: AwEItemSheet.#onToggleSheet, - editImage: AwEItemSheet.#onEditImage + editImage: AwEItemSheet.#onEditImage, + addTrait: AwEItemSheet.#onAddTrait, + removeTrait: AwEItemSheet.#onRemoveTrait } } @@ -77,6 +79,16 @@ export default class AwEItemSheet extends HandlebarsApplicationMixin(foundry.app _onRender(context, options) { super._onRender(context, options) this.#dragDrop.forEach(d => d.bind(this.element)) + // Bind Enter key on tag input fields to trigger the addTrait/addSpecialization actions + 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) + }) + }) } // #region Drag-and-Drop Workflow @@ -182,4 +194,34 @@ export default class AwEItemSheet extends HandlebarsApplicationMixin(foundry.app } // #endregion + + // #region Array field helpers (traits, specializations) + /** + * Handle adding a tag (trait, specialization) from the input field. + * @param {PointerEvent|KeyboardEvent} event - The initiating event. + * @param {HTMLElement} target - The input element. + */ + static async #onAddTrait(event, target) { + const value = target.value.trim() + if (!value) return + const fieldName = target.dataset.field ?? "system.traits" + const current = foundry.utils.getProperty(this.document, fieldName) ?? [] + await this.document.update({ [fieldName]: [...current, value] }) + target.value = "" + } + + /** + * Handle removing a tag (trait, specialization) from an array field. + * @param {PointerEvent} event - The initiating click event. + * @param {HTMLElement} target - The remove button. + */ + static async #onRemoveTrait(event, target) { + const index = Number(target.dataset.index) + const fieldName = target.dataset.field ?? "system.traits" + const current = [...(foundry.utils.getProperty(this.document, fieldName) ?? [])] + current.splice(index, 1) + await this.document.update({ [fieldName]: current }) + } + + // #endregion } diff --git a/module/applications/sheets/character-sheet.mjs b/module/applications/sheets/character-sheet.mjs index 1b708d1..f3ec0e0 100644 --- a/module/applications/sheets/character-sheet.mjs +++ b/module/applications/sheets/character-sheet.mjs @@ -1,4 +1,5 @@ import AwEActorSheet from "./base-actor-sheet.mjs" +import { SYSTEM } from "../../config/system.mjs" export default class AwECharacterSheet extends AwEActorSheet { /** @override */ @@ -23,6 +24,9 @@ export default class AwECharacterSheet extends AwEActorSheet { /** @override */ static PARTS = { + header: { + template: "systems/fvtt-adventures-with-emmy/templates/character-header.hbs" + }, main: { template: "systems/fvtt-adventures-with-emmy/templates/character-main.hbs" }, @@ -72,7 +76,10 @@ export default class AwECharacterSheet extends AwEActorSheet { switch (partId) { case "main": context.tab = context.tabs.main - context.abilities = doc.itemTypes.ability + context.abilities = doc.itemTypes.ability.map(item => ({ + ...item, + costLabel: game.i18n.localize(SYSTEM.ABILITY_COST[item.system.cost]?.label ?? item.system.cost) + })) break case "biography": context.tab = context.tabs.biography diff --git a/module/applications/sheets/field-sheet.mjs b/module/applications/sheets/field-sheet.mjs index 9321748..9d21bc2 100644 --- a/module/applications/sheets/field-sheet.mjs +++ b/module/applications/sheets/field-sheet.mjs @@ -5,7 +5,11 @@ export default class AwEFieldSheet extends AwEItemSheet { static DEFAULT_OPTIONS = { classes: ["field"], position: { width: 620 }, - window: { contentClasses: ["field-content"] } + window: { contentClasses: ["field-content"] }, + actions: { + addSpecialization: AwEFieldSheet.#onAddSpecialization, + removeSpecialization: AwEFieldSheet.#onRemoveSpecialization + } } /** @override */ @@ -14,4 +18,29 @@ export default class AwEFieldSheet extends AwEItemSheet { template: "systems/fvtt-adventures-with-emmy/templates/field.hbs" } } + + /** + * Handle adding a specialization. + * @param {PointerEvent} event - The initiating event. + * @param {HTMLElement} target - The input element. + */ + static async #onAddSpecialization(event, target) { + const value = target.value.trim() + if (!value) return + const current = this.document.system.specializations ?? [] + await this.document.update({ "system.specializations": [...current, value] }) + target.value = "" + } + + /** + * Handle removing a specialization. + * @param {PointerEvent} event - The initiating click event. + * @param {HTMLElement} target - The remove button. + */ + static async #onRemoveSpecialization(event, target) { + const index = Number(target.dataset.index) + const current = [...(this.document.system.specializations ?? [])] + current.splice(index, 1) + await this.document.update({ "system.specializations": current }) + } } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 8c5c1cb..b038bbd 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -1,3 +1,5 @@ +import AwERoll from "./roll.mjs" + export default class AwEActor extends Actor { /** @override */ prepareData() { @@ -33,38 +35,20 @@ export default class AwEActor extends Actor { /** * Roll an attribute check. * @param {string} attributeId - The attribute to roll. - * @param {object} options - Roll options. - * @returns {Promise} The roll result. + * @param {object} options - Roll options (passed through to AwERoll.prompt). + * @returns {Promise} The evaluated roll, or null if cancelled. */ async rollAttribute(attributeId, options = {}) { const attribute = this.system.attributes[attributeId] if (!attribute) return null - const mod = attribute.mod ?? 0 - const formula = `1d20 + ${mod}` - const roll = new Roll(formula) - await roll.evaluate() - - // Determine outcome vs DC if provided - let outcome = null - if (options.dc !== undefined) { - const total = roll.total - const dc = options.dc - if (total >= dc + 10) outcome = "criticalSuccess" - else if (total >= dc) outcome = "success" - else if (total <= dc - 10) outcome = "criticalFailure" - else outcome = "failure" - } - - // Send to chat - const attrLabel = attributeId.charAt(0).toUpperCase() + attributeId.slice(1) - const flavor = options.flavor || game.i18n.localize(`AWEMMY.Attribute.${attrLabel}`) - await roll.toMessage({ - speaker: ChatMessage.getSpeaker({ actor: this }), - flavor, - rollMode: game.settings.get("core", "rollMode") + return AwERoll.prompt({ + attributeKey: attributeId, + modifier: attribute.mod ?? 0, + actorId: this.id, + actorName: this.name, + actorImage: this.img, + ...options }) - - return { roll, outcome } } } diff --git a/module/documents/chat-message.mjs b/module/documents/chat-message.mjs index 26f034f..bcfdf7c 100644 --- a/module/documents/chat-message.mjs +++ b/module/documents/chat-message.mjs @@ -1,7 +1,25 @@ +import AwERoll from "./roll.mjs" + export default class AwEChatMessage extends ChatMessage { /** @override */ - async getHTML(...args) { - const html = await super.getHTML(...args) - return html + async _renderRollContent(messageData) { + if (this.rolls[0] instanceof AwERoll) { + const isPrivate = !this.isContentVisible + const roll = this.rolls[0] + + const html = await foundry.applications.handlebars.renderTemplate( + AwERoll.CHAT_TEMPLATE, + { + flavor: this.flavor, + total: roll.total, + outcome: isPrivate ? null : roll.outcome, + dc: roll.dc, + isPrivate + } + ) + messageData.message.content = html + return + } + return super._renderRollContent(messageData) } } diff --git a/module/documents/roll.mjs b/module/documents/roll.mjs index e23cb8b..229a1d7 100644 --- a/module/documents/roll.mjs +++ b/module/documents/roll.mjs @@ -1,5 +1,136 @@ +import { SYSTEM } from "../config/system.mjs" + export default class AwERoll extends Roll { - constructor(formula, data = {}, options = {}) { - super(formula, data, options) + /** @type {string} */ + static CHAT_TEMPLATE = "systems/fvtt-adventures-with-emmy/templates/chat-message.hbs" + + // --- Accessors for roll options --- + + get attributeKey() { return this.options.attributeKey } + get rollName() { return this.options.rollName } + get modifier() { return this.options.modifier ?? 0 } + get bonus() { return this.options.bonus ?? 0 } + get dc() { return this.options.dc } + get outcome() { return this.options.outcome } + get actorId() { return this.options.actorId } + get actorName() { return this.options.actorName } + get actorImage() { return this.options.actorImage } + + // --- Outcome calculation --- + + /** + * Compute the degree of success for a d20 check. + * - Critical Success : total ≥ dc + 10, OR natural 20 upgrades result + * - Success : total ≥ dc + * - Failure : total < dc + * - Critical Failure : total ≤ dc − 10, OR natural 1 downgrades result + * + * @param {number} total The final roll total (d20 + modifiers) + * @param {number} dc The Difficulty Class to compare against + * @param {number} d20Value The raw d20 result (for nat-20 / nat-1 adjustment) + * @returns {"criticalSuccess"|"success"|"failure"|"criticalFailure"} + */ + static computeOutcome(total, dc, d20Value) { + const DEGREES = ["criticalFailure", "failure", "success", "criticalSuccess"] + let idx + if (total >= dc + 10) idx = 3 + else if (total >= dc) idx = 2 + else if (total <= dc - 10) idx = 0 + else idx = 1 + + if (d20Value === 20) idx = Math.min(3, idx + 1) + if (d20Value === 1) idx = Math.max(0, idx - 1) + + return DEGREES[idx] + } + + // --- Prompt dialog --- + + /** + * Open a dialog so the player can add a situational bonus and choose visibility, + * then evaluate and post the roll to chat. + * + * @param {object} options + * @param {string} options.attributeKey Attribute id (agility | fitness | awareness | influence) + * @param {number} options.modifier Base attribute modifier + * @param {number} [options.dc] Pre-set DC (skips DC field if provided) + * @param {string} options.actorId + * @param {string} options.actorName + * @param {string} options.actorImage + * @returns {Promise} Resolved roll, or null if dialog was cancelled + */ + static async prompt(options = {}) { + const attrLabel = options.attributeKey + ? game.i18n.localize(SYSTEM.ATTRIBUTES[options.attributeKey]?.label ?? options.attributeKey) + : (options.rollName ?? game.i18n.localize("AWEMMY.Roll.Check")) + + const rollModes = Object.fromEntries( + Object.entries(CONFIG.Dice.rollModes).map(([k, v]) => [k, game.i18n.localize(v.label ?? v)]) + ) + + const content = await foundry.applications.handlebars.renderTemplate( + "systems/fvtt-adventures-with-emmy/templates/roll-dialog.hbs", + { + attrLabel, + modifier: options.modifier ?? 0, + dc: options.dc ?? "", + rollModes, + visibility: game.settings.get("core", "rollMode") + } + ) + + const result = await foundry.applications.api.DialogV2.wait({ + window: { title: game.i18n.format("AWEMMY.Roll.DialogTitle", { name: attrLabel }) }, + classes: ["awemmy"], + content, + buttons: [{ + label: game.i18n.localize("AWEMMY.Roll.Roll"), + callback: (_event, button) => + Array.from(button.form.elements).reduce((obj, input) => { + if (input.name) obj[input.name] = input.value + return obj + }, {}) + }], + rejectClose: false + }) + + if (!result) return null + + const mod = options.modifier ?? 0 + const bonus = parseInt(result.bonus) || 0 + const dc = result.dc !== "" ? parseInt(result.dc) : undefined + const rollMode = result.visibility ?? game.settings.get("core", "rollMode") + + // Build formula: 1d20 + mod [± bonus] + let formula = `1d20 + ${mod}` + if (bonus > 0) formula += ` + ${bonus}` + else if (bonus < 0) formula += ` - ${Math.abs(bonus)}` + + const roll = new this(formula, {}, { + attributeKey: options.attributeKey, + rollName: attrLabel, + modifier: mod, + bonus, + dc, + actorId: options.actorId, + actorName: options.actorName, + actorImage: options.actorImage + }) + + await roll.evaluate() + + // Compute degree of success when a DC is known + if (dc !== undefined) { + const d20Value = roll.dice[0]?.results[0]?.result ?? 0 + roll.options.outcome = AwERoll.computeOutcome(roll.total, dc, d20Value) + } + + await roll.toMessage({ + speaker: ChatMessage.getSpeaker({ actor: game.actors.get(options.actorId) }), + flavor: attrLabel, + rollMode + }) + + return roll } } diff --git a/module/models/ability.mjs b/module/models/ability.mjs index 3eb1957..939b75d 100644 --- a/module/models/ability.mjs +++ b/module/models/ability.mjs @@ -10,13 +10,13 @@ export default class AwEAbility extends foundry.abstract.TypeDataModel { required: true, nullable: false, initial: "field", - choices: Object.keys(SYSTEM.ABILITY_TYPE) + choices: Object.fromEntries(Object.values(SYSTEM.ABILITY_TYPE).map(a => [a.id, a.label])) }) schema.cost = new fields.StringField({ required: true, nullable: false, initial: "one", - choices: Object.keys(SYSTEM.ABILITY_COST) + choices: Object.fromEntries(Object.values(SYSTEM.ABILITY_COST).map(a => [a.id, a.label])) }) schema.frequency = new fields.StringField({ initial: "", required: false, nullable: true }) schema.requirements = new fields.StringField({ initial: "", required: false, nullable: true }) diff --git a/module/models/character.mjs b/module/models/character.mjs index 189e8fd..0182b6e 100644 --- a/module/models/character.mjs +++ b/module/models/character.mjs @@ -63,12 +63,5 @@ export default class AwECharacter extends foundry.abstract.TypeDataModel { attr.mod = level + attr.boostLevel + attr.bonus attr.dc = 10 + attr.mod } - - // Compute max HP if not overridden - // Base HP = 10 + (level * 2) + fitness modifier - const fitnessMod = this.attributes.fitness.mod ?? 0 - if (this.hp.max === 10) { - this.hp.max = 10 + (level * 2) + fitnessMod - } } } diff --git a/module/models/field.mjs b/module/models/field.mjs index 2612b26..19cae9b 100644 --- a/module/models/field.mjs +++ b/module/models/field.mjs @@ -10,13 +10,14 @@ export default class AwEField extends foundry.abstract.TypeDataModel { required: true, nullable: false, initial: "agility", - choices: Object.keys(SYSTEM.ATTRIBUTES) + choices: Object.fromEntries(Object.values(SYSTEM.ATTRIBUTES).map(a => [a.id, a.label])) }) schema.keyAttribute2 = new fields.StringField({ required: false, nullable: true, - initial: null, - choices: [...Object.keys(SYSTEM.ATTRIBUTES), null] + initial: "", + blank: true, + choices: { "": "—", ...Object.values(SYSTEM.ATTRIBUTES).reduce((o, a) => { o[a.id] = a.label; return o }, {}) } }) schema.specializations = new fields.ArrayField(new fields.StringField()) schema.knowledgeBonus = new fields.StringField({ initial: "", required: false, nullable: true }) diff --git a/module/models/weapon.mjs b/module/models/weapon.mjs index d53bf9f..1fcbeb2 100644 --- a/module/models/weapon.mjs +++ b/module/models/weapon.mjs @@ -14,7 +14,7 @@ export default class AwEWeapon extends foundry.abstract.TypeDataModel { required: true, nullable: false, initial: "agility", - choices: Object.keys(SYSTEM.ATTRIBUTES) + choices: Object.fromEntries(Object.values(SYSTEM.ATTRIBUTES).map(a => [a.id, a.label])) }) schema.traits = new fields.ArrayField(new fields.StringField()) diff --git a/templates/ability.hbs b/templates/ability.hbs index 75be205..c4a5efb 100644 --- a/templates/ability.hbs +++ b/templates/ability.hbs @@ -5,12 +5,12 @@
- + {{formField systemFields.abilityType value=system.abilityType localize=true}}
- - {{formField systemFields.cost value=system.cost}} + + {{formField systemFields.cost value=system.cost localize=true}}
@@ -24,6 +24,15 @@ {{formInput systemFields.trigger value=system.trigger}}
+
+ +
+ {{#each system.traits}} + {{this}} × + {{/each}} + +
+
Description diff --git a/templates/archetype.hbs b/templates/archetype.hbs index b846f1c..84c9887 100644 --- a/templates/archetype.hbs +++ b/templates/archetype.hbs @@ -5,7 +5,7 @@
- + {{formInput systemFields.prerequisiteLevel value=system.prerequisiteLevel}}
diff --git a/templates/character-biography.hbs b/templates/character-biography.hbs index 76194b2..e7c2c4e 100644 --- a/templates/character-biography.hbs +++ b/templates/character-biography.hbs @@ -1,17 +1,17 @@
- Identity + {{localize "AWEMMY.Character.Identity"}}
- + {{formInput systemFields.pronouns value=system.pronouns disabled=isPlayMode}}
- + {{formInput systemFields.fieldName value=system.fieldName disabled=isPlayMode}}
- + {{formInput systemFields.specialization value=system.specialization disabled=isPlayMode}}
@@ -25,7 +25,7 @@
- Description + {{localize "AWEMMY.Character.Description"}} {{formInput systemFields.description enriched=enrichedDescription @@ -36,7 +36,7 @@
- Notes + {{localize "AWEMMY.Character.Notes"}} {{formInput systemFields.notes enriched=enrichedNotes diff --git a/templates/character-equipment.hbs b/templates/character-equipment.hbs index d2a3450..eb3cd66 100644 --- a/templates/character-equipment.hbs +++ b/templates/character-equipment.hbs @@ -34,7 +34,7 @@
{{item.name}}
{{item.system.damageFormula}} ({{item.system.damageType}})
-
Range: {{item.system.range}}
+
{{localize "AWEMMY.Weapon.Range"}}: {{item.system.range}}
{{#if ../isEditMode}} diff --git a/templates/character-header.hbs b/templates/character-header.hbs new file mode 100644 index 0000000..a618be3 --- /dev/null +++ b/templates/character-header.hbs @@ -0,0 +1,56 @@ +
+ +
+ {{formInput fields.name value=source.name classes="actor-name"}} +
+
+ + {{formInput systemFields.level value=system.level disabled=isPlayMode}} +
+
+ + {{formInput systemFields.stride value=system.stride disabled=isPlayMode}} +
+
+
+ +
+ {{!-- HP --}} +
+ +
+ {{formInput systemFields.hp.fields.value value=system.hp.value classes="hp-value"}} + / + {{formInput systemFields.hp.fields.max value=system.hp.max disabled=isPlayMode classes="hp-max"}} +
+
+ + {{formInput systemFields.hp.fields.temp value=system.hp.temp classes="hp-temp"}} +
+
+ + {{!-- Flow Points --}} +
+ +
+ {{formInput systemFields.flowPoints.fields.value value=system.flowPoints.value classes="fp-value"}} +
+
+ + {{formInput systemFields.flowPoints.fields.temp value=system.flowPoints.temp classes="fp-temp"}} +
+ {{#if isPlayMode}} +
+ + +
+ {{/if}} +
+
+ +
+ +
+
diff --git a/templates/character-main.hbs b/templates/character-main.hbs index 9e83727..f9b5923 100644 --- a/templates/character-main.hbs +++ b/templates/character-main.hbs @@ -1,91 +1,46 @@ -
- - {{!-- Header: image + name + basic stats --}} -
- -
- {{formInput fields.name value=source.name classes="actor-name"}} -
-
- - {{formInput systemFields.level value=system.level disabled=isPlayMode}} -
-
- - {{formInput systemFields.stride value=system.stride disabled=isPlayMode}} -
-
-
- -
- {{!-- HP --}} -
- -
- {{formInput systemFields.hp.fields.value value=system.hp.value classes="hp-value"}} - / - {{formInput systemFields.hp.fields.max value=system.hp.max disabled=isPlayMode classes="hp-max"}} -
-
- - {{!-- Flow Points --}} -
- -
- {{formInput systemFields.flowPoints.fields.value value=system.flowPoints.value classes="fp-value"}} -
- {{#if isPlayMode}} -
- - -
- {{/if}} -
-
- -
- -
-
+
{{!-- Attributes Table --}}
- Attributes + {{localize "AWEMMY.Character.Attributes"}} - + + - - + + + - - + + + - - + + + - - + + +
Attribute{{localize "AWEMMY.Character.Attribute"}} {{localize "AWEMMY.Character.BoostLevel"}} {{localize "AWEMMY.Character.Mod"}} {{localize "AWEMMY.Character.DC"}}{{localize "AWEMMY.Character.Bonus"}}
{{localize "AWEMMY.Attribute.Agility"}} {{formInput systemFields.attributes.fields.agility.fields.boostLevel value=system.attributes.agility.boostLevel disabled=isPlayMode}}{{system.attributes.agility.mod}}{{system.attributes.agility.dc}}{{system.attributes.agility.mod}}{{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}}{{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}}{{system.attributes.awareness.mod}}{{system.attributes.awareness.dc}}{{system.attributes.awareness.mod}}{{system.attributes.awareness.dc}}{{formInput systemFields.attributes.fields.awareness.fields.bonus value=system.attributes.awareness.bonus disabled=isPlayMode}}
{{localize "AWEMMY.Attribute.Influence"}} {{formInput systemFields.attributes.fields.influence.fields.boostLevel value=system.attributes.influence.boostLevel disabled=isPlayMode}}{{system.attributes.influence.mod}}{{system.attributes.influence.dc}}{{system.attributes.influence.mod}}{{system.attributes.influence.dc}}{{formInput systemFields.attributes.fields.influence.fields.bonus value=system.attributes.influence.bonus disabled=isPlayMode}}
@@ -99,7 +54,7 @@
{{item.name}}
-
{{item.system.cost}}
+
{{item.costLabel}}
{{#if ../isEditMode}} diff --git a/templates/chat-message.hbs b/templates/chat-message.hbs index ad332f6..9c1cfe8 100644 --- a/templates/chat-message.hbs +++ b/templates/chat-message.hbs @@ -4,7 +4,10 @@
{{#unless isPrivate}} -
{{total}}
+
+ {{total}} + {{#if dc}}/ DC {{dc}}{{/if}} +
{{#if outcome}}
@@ -21,7 +24,7 @@ {{/if}} {{else}}
- Private Roll + {{localize "AWEMMY.Roll.Private"}}
{{/unless}}
diff --git a/templates/creature-main.hbs b/templates/creature-main.hbs index 40a5bc7..99ac54d 100644 --- a/templates/creature-main.hbs +++ b/templates/creature-main.hbs @@ -89,11 +89,11 @@ {{formInput systemFields.eurekaEvidence value=system.eurekaEvidence}}
- + {{formInput systemFields.eurekaThreshold1 value=system.eurekaThreshold1}}
- + {{formInput systemFields.eurekaThreshold2 value=system.eurekaThreshold2}}
diff --git a/templates/field.hbs b/templates/field.hbs index b5cffd1..717430d 100644 --- a/templates/field.hbs +++ b/templates/field.hbs @@ -8,10 +8,23 @@ {{formField systemFields.keyAttribute value=system.keyAttribute localize=true}}
+
+ + {{formField systemFields.keyAttribute2 value=system.keyAttribute2 localize=true}} +
{{formInput systemFields.knowledgeBonus value=system.knowledgeBonus}}
+
+ +
+ {{#each system.specializations}} + {{this}} × + {{/each}} + +
+
Description diff --git a/templates/roll-dialog.hbs b/templates/roll-dialog.hbs new file mode 100644 index 0000000..04a46ba --- /dev/null +++ b/templates/roll-dialog.hbs @@ -0,0 +1,31 @@ +
+ + {{! Attribute name + base modifier (read-only) }} +
+ {{attrLabel}} + + {{#if (gt modifier 0)}}+{{modifier}}{{else}}{{modifier}}{{/if}} + +
+ + {{! Situational bonus / penalty }} +
+ + +
+ + {{! DC (optional) }} +
+ + +
+ + {{! Roll visibility }} +
+ + +
+ +
diff --git a/templates/weapon.hbs b/templates/weapon.hbs index 2f36128..8410aa4 100644 --- a/templates/weapon.hbs +++ b/templates/weapon.hbs @@ -20,6 +20,15 @@ {{formInput systemFields.range value=system.range}} +
+ +
+ {{#each system.traits}} + {{this}} × + {{/each}} + +
+
Description