diff --git a/lang/en.json b/lang/en.json index 26cedccb..78532b49 100755 --- a/lang/en.json +++ b/lang/en.json @@ -268,45 +268,47 @@ "tier4": "Tier 4" }, "Adversary": { - "Bruiser": { - "Name": "Bruiser", - "Description": "Tough adversaries with powerful attacks." - }, - "Horde": { - "Name": "Horde", - "Description": "A Horde represents a number of foes working in a group." - }, - "Leader": { - "Name": "Leader", - "Description": "Adversaries that command and summon other adversaries." - }, - "Minion": { - "Name": "Minion", - "Description": "Basic enemies that are easily dispatched but dangerous in numbers." - }, - "Ranged": { - "Name": "Ranged", - "Description": "Adversaries that attack from a distance." - }, - "Skulker": { - "Name": "Skulker", - "Description": "Adversaries that maneuver and exploit opportunities to ambush their opponents." - }, - "Social": { - "Name": "Social", - "Description": "Adversaries that are primarily interpersonal threats or challenges." - }, - "Solo": { - "Name": "Solo", - "Description": "Designed to present a challenge to a whole party." - }, - "Standard": { - "Name": "Standard", - "Description": "Rank and File adversaries." - }, - "Support": { - "Name": "Support", - "Description": "Enemies that enhance their allies and/or disrupt their opponents." + "Type": { + "Bruiser": { + "label": "Bruiser", + "Description": "Tough adversaries with powerful attacks." + }, + "Horde": { + "label": "Horde", + "Description": "A Horde represents a number of foes working in a group." + }, + "Leader": { + "label": "Leader", + "Description": "Adversaries that command and summon other adversaries." + }, + "Minion": { + "label": "Minion", + "Description": "Basic enemies that are easily dispatched but dangerous in numbers." + }, + "Ranged": { + "label": "Ranged", + "Description": "Adversaries that attack from a distance." + }, + "Skulk": { + "label": "Skulk", + "Description": "Adversaries that maneuver and exploit opportunities to ambush their opponents." + }, + "Social": { + "label": "Social", + "Description": "Adversaries that are primarily interpersonal threats or challenges." + }, + "Solo": { + "label": "Solo", + "Description": "Designed to present a challenge to a whole party." + }, + "Standard": { + "label": "Standard", + "Description": "Rank and File adversaries." + }, + "Support": { + "label": "Support", + "Description": "Enemies that enhance their allies and/or disrupt their opponents." + } }, "Trait": { "Relentless": { @@ -1025,35 +1027,52 @@ } }, "Adversary": { - "Description": "Description", - "MotivesAndTactics": "Motives & Tactics", - "Tier": "Tier", - "Type": "Type", - "Attack": { - "Title": "Attack", - "Modifier": "Attack Modifier", - "Name": "Name", - "Range": "Range", - "Damage": { - "Title": "Damage", - "Value": "Value", - "Type": "Type" + "FIELDS": { + "tier": { "label": "Tier" }, + "type": { "label": "Type" }, + "description": { "label": "Description" }, + "motivesAndTactics": { "label": "Motives & Tactics" }, + "difficulty": { "label": "Difficulty" }, + "damageThresholds": { + "major": { "label": "Major" }, + "severe": { "label": "Severe" } + }, + "resources": { + "hitPoints": { + "value": { "label": "Current" }, + "max": { "label": "Max" } + }, + "stress": { + "value": { "label": "Current" }, + "max": { "label": "Max" } + } + }, + "experiences": { + "element": { + "name": { "label": "Name" }, + "value": { "label": "Modifier" } + } + }, + "attack": { + "name": { "label": "Name" }, + "modifier": { "label": "Modifier" }, + "range": { "label": "Range" }, + "damage": { + "value": { "label": "Damage" }, + "type": { "label": "Damage Type" } + } } }, - "Difficulty": "Difficulty", - "Reaction": "Reaction Roll", - "DamageThresholds": { - "Title": "Damage Thresholds", - "Minor": "Minor", - "Major": "Major", - "Severe": "Severe" + "Tabs": { + "Main": "Data", + "Information": "Information" }, - "HP": "HP", + "General": "General", + "DamageThresholds": "Damage Thresholds", + "HitPoints": "Hit Points", "Stress": "Stress", - "Experience": "Experience", "Experiences": "Experiences", - "Features": "Features", - "NewFeature": "New Feature" + "Attack": "Attack" }, "Environment": { "FIELDS": { diff --git a/module/applications/chatMessage.mjs b/module/applications/chatMessage.mjs index 30bd0a27..aef05bae 100644 --- a/module/applications/chatMessage.mjs +++ b/module/applications/chatMessage.mjs @@ -1,12 +1,8 @@ import { DualityRollColor } from '../data/settings/Appearance.mjs'; -import DHDualityRoll from "../data/chat-message/dualityRoll.mjs"; +import DHDualityRoll from '../data/chat-message/dualityRoll.mjs'; export default class DhpChatMessage extends foundry.documents.ChatMessage { async renderHTML() { - if (this.type === 'dualityRoll' || this.type === 'adversaryRoll' || this.type === 'abilityUse') { - this.content = await foundry.applications.handlebars.renderTemplate(this.content, this.system); - } - /* We can change to fully implementing the renderHTML function if needed, instead of augmenting it. */ const html = await super.renderHTML(); diff --git a/module/applications/sheets/adversary.mjs b/module/applications/sheets/adversary.mjs index b9180bf3..8345b532 100644 --- a/module/applications/sheets/adversary.mjs +++ b/module/applications/sheets/adversary.mjs @@ -1,219 +1,12 @@ -// import DhpApplicationMixin from '../daggerheart-sheet.mjs'; - -// export class Teest extends DhpApplicationMixin(ActorSheet) { -// static documentType = "adversary"; - -// constructor(options){ -// super(options); - -// this.editMode = false; -// } - -// /** @override */ -// static get defaultOptions() { -// return foundry.utils.mergeObject(super.defaultOptions, { -// classes: ["daggerheart", "sheet", "adversary"], -// width: 600, -// height: 'auto', -// resizable: false, -// }); -// } - -// async getData() { -// const context = super.getData(); -// context.config = SYSTEM; -// context.editMode = this.editMode; -// context.title = `${this.actor.name} - ${game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.actor.system.type].name)}`; - -// context.data = { -// description: this.object.system.description, -// motivesAndTactics: this.object.system.motivesAndTactics.join(', '), -// tier: this.object.system.tier, -// type: game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.object.system.type].name), -// attack: { -// name: this.object.system.attack.name, -// attackModifier: this.object.system.attackModifier, -// range: this.object.system.attack.range ? game.i18n.localize(SYSTEM.GENERAL.range[this.object.system.attack.range].name) : null, -// damage: { -// value: this.object.system.attack.damage.value, -// type: this.object.system.attack.damage.type, -// typeName: this.object.system.attack.damage.type ? game.i18n.localize(SYSTEM.GENERAL.damageTypes[this.object.system.attack.damage.type].abbreviation).toLowerCase() : null, -// }, -// }, -// damageThresholds: this.object.system.damageThresholds, -// difficulty: this.object.system.difficulty, -// hp: { ...this.object.system.resources.health, lastRowIndex: Math.floor(this.object.system.resources.health.max/5)*5 }, -// stress: { ...this.object.system.resources.stress, lastRowIndex: Math.floor(this.object.system.resources.stress.max/5)*5 }, -// moves: this.object.system.moves, -// }; - -// return context; -// } - -// async _handleAction(action, event, button) { -// switch(action){ -// case 'viewMove': -// await this.viewMove(button); -// break; -// case 'addMove': -// this.addMove(); -// break; -// case 'removeMove': -// await this.removeMove(button); -// break; -// case 'toggleSlider': -// this.toggleEditMode(); -// break; -// case 'addMotive': -// await this.addMotive(); -// break; -// case 'removeMotive': -// await this.removeMotive(button); -// break; -// case 'reactionRoll': -// await this.reactionRoll(event); -// break; -// case 'attackRoll': -// await this.attackRoll(event); -// break; -// case 'addExperience': -// await this.addExperience(); -// break; -// case 'removeExperience': -// await this.removeExperience(button); -// break; -// case 'toggleHP': -// await this.toggleHP(button); -// break; -// case 'toggleStress': -// await this.toggleStress(button); -// break; -// } -// } - -// async viewMove(button){ -// const move = await fromUuid(button.dataset.move); -// move.sheet.render(true); -// } - -// async addMove(){ -// const result = await this.object.createEmbeddedDocuments("Item", [{ -// name: game.i18n.localize('DAGGERHEART.Sheets.Adversary.NewMove'), -// type: 'feature', -// }]); - -// await result[0].sheet.render(true); -// } - -// async removeMove(button){ -// await this.object.items.find(x => x.uuid === button.dataset.move).delete(); -// } - -// toggleEditMode(){ -// this.editMode = !this.editMode; -// this.render(); -// } - -// async addMotive(){ -// await this.object.update({ "system.motivesAndTactics": [...this.object.system.motivesAndTactics, ''] }); -// } - -// async removeMotive(button){ -// await this.object.update({ "system.motivesAndTactics": this.object.system.motivesAndTactics.filter((_, index) => index !== Number.parseInt(button.dataset.motive) )}); -// } - -// async reactionRoll(event){ -// const { roll, diceResults, modifiers } = await this.actor.diceRoll({ title: `${this.actor.name} - Reaction Roll`, value: 0 }, event.shiftKey); - -// const cls = getDocumentClass("ChatMessage"); -// const msg = new cls({ -// type: 'adversaryRoll', -// system: { -// roll: roll._formula, -// total: roll._total, -// modifiers: modifiers, -// diceResults: diceResults, -// }, -// content: "systems/daggerheart/templates/chat/adversary-roll.hbs", -// rolls: [roll] -// }); - -// cls.create(msg.toObject()); -// } - -// async attackRoll(event){ -// const modifier = Number.parseInt(event.currentTarget.dataset.value); - -// const { roll, diceResults, modifiers } = await this.actor.diceRoll({ title: `${this.actor.name} - Attack Roll`, value: modifier }, event.shiftKey); - -// const targets = Array.from(game.user.targets).map(x => ({ -// id: x.id, -// name: x.actor.name, -// img: x.actor.img, -// difficulty: x.actor.system.difficulty, -// evasion: x.actor.system.evasion, -// })); - -// const cls = getDocumentClass("ChatMessage"); -// const msg = new cls({ -// type: 'adversaryRoll', -// system: { -// roll: roll._formula, -// total: roll._total, -// modifiers: modifiers, -// diceResults: diceResults, -// targets: targets, -// damage: { value: event.currentTarget.dataset.damage, type: event.currentTarget.dataset.damageType }, -// }, -// content: "systems/daggerheart/templates/chat/adversary-attack-roll.hbs", -// rolls: [roll] -// }); - -// cls.create(msg.toObject()); -// } - -// async addExperience(){ -// await this.object.update({ "system.experiences": [...this.object.system.experiences, { name: 'Experience', value: 1 }] }); -// } - -// async removeExperience(button){ -// await this.object.update({ "system.experiences": this.object.system.experiences.filter((_, index) => index !== Number.parseInt(button.dataset.experience) )}); -// } - -// async toggleHP(button){ -// const index = Number.parseInt(button.dataset.index); -// const newHP = index < this.object.system.resources.health.value ? index : index+1; -// await this.object.update({ "system.resources.health.value": newHP }); -// } - -// async toggleStress(button){ -// const index = Number.parseInt(button.dataset.index); -// const newStress = index < this.object.system.resources.stress.value ? index : index+1; -// await this.object.update({ "system.resources.stress.value": newStress }); -// } -// } - import DaggerheartSheet from './daggerheart-sheet.mjs'; const { ActorSheetV2 } = foundry.applications.sheets; export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) { - constructor(options = {}) { - super(options); - - this.editMode = false; - } - static DEFAULT_OPTIONS = { tag: 'form', - classes: ['daggerheart', 'sheet', 'adversary'], - position: { width: 600 }, + classes: ['daggerheart', 'sheet', 'actor', 'dh-style', 'adversary'], + position: { width: 450, height: 1000 }, actions: { - viewMove: this.viewMove, - addMove: this.addMove, - removeMove: this.removeMove, - toggleSlider: this.toggleEditMode, - addMotive: this.addMotive, - removeMotive: this.removeMotive, reactionRoll: this.reactionRoll, attackRoll: this.attackRoll, addExperience: this.addExperience, @@ -229,54 +22,35 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) { }; static PARTS = { - form: { - id: 'feature', - template: 'systems/daggerheart/templates/sheets/adversary.hbs' + header: { template: 'systems/daggerheart/templates/sheets/actors/adversary/header.hbs' }, + tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }, + main: { template: 'systems/daggerheart/templates/sheets/actors/adversary/main.hbs' }, + information: { template: 'systems/daggerheart/templates/sheets/actors/adversary/information.hbs' } + }; + + static TABS = { + main: { + active: true, + cssClass: '', + group: 'primary', + id: 'main', + icon: null, + label: 'DAGGERHEART.Sheets.Adversary.Tabs.Main' + }, + information: { + active: false, + cssClass: '', + group: 'primary', + id: 'information', + icon: null, + label: 'DAGGERHEART.Sheets.Adversary.Tabs.Information' } }; async _prepareContext(_options) { const context = await super._prepareContext(_options); context.document = this.document; - context.config = SYSTEM; - context.editMode = this.editMode; - context.title = `${this.actor.name} - ${game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.actor.system.type].name)}`; - - context.data = { - description: this.document.system.description, - motivesAndTactics: this.document.system.motivesAndTactics.join(', '), - tier: this.document.system.tier, - type: game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.document.system.type].name), - attack: { - name: this.document.system.attack.name, - attackModifier: this.document.system.attackModifier, - range: this.document.system.attack.range - ? game.i18n.localize(SYSTEM.GENERAL.range[this.document.system.attack.range].name) - : null, - damage: { - value: this.document.system.attack.damage.value, - type: this.document.system.attack.damage.type, - typeName: this.document.system.attack.damage.type - ? game.i18n - .localize( - SYSTEM.GENERAL.damageTypes[this.document.system.attack.damage.type].abbreviation - ) - .toLowerCase() - : null - } - }, - damageThresholds: this.document.system.damageThresholds, - difficulty: this.document.system.difficulty, - hp: { - ...this.document.system.resources.health, - lastRowIndex: Math.floor(this.document.system.resources.health.max / 5) * 5 - }, - stress: { - ...this.document.system.resources.stress, - lastRowIndex: Math.floor(this.document.system.resources.stress.max / 5) * 5 - }, - moves: this.document.system.moves - }; + context.tabs = super._getTabs(this.constructor.TABS); return context; } @@ -286,43 +60,6 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) { this.render(); } - static async viewMove(_, button) { - const move = await fromUuid(button.dataset.move); - move.sheet.render(true); - } - - static async addMove() { - const result = await this.document.createEmbeddedDocuments('Item', [ - { - name: game.i18n.localize('DAGGERHEART.Sheets.Adversary.NewMove'), - type: 'feature' - } - ]); - - await result[0].sheet.render(true); - } - - static async removeMove(_, button) { - await this.document.items.find(x => x.uuid === button.dataset.move).delete(); - } - - static toggleEditMode() { - this.editMode = !this.editMode; - this.render(); - } - - static async addMotive() { - await this.document.update({ 'system.motivesAndTactics': [...this.document.system.motivesAndTactics, ''] }); - } - - static async removeMotive(button) { - await this.document.update({ - 'system.motivesAndTactics': this.document.system.motivesAndTactics.filter( - (_, index) => index !== Number.parseInt(button.dataset.motive) - ) - }); - } - static async reactionRoll(event) { const { roll, diceResults, modifiers } = await this.actor.diceRoll( { title: `${this.actor.name} - Reaction Roll`, value: 0 }, @@ -349,9 +86,8 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) { cls.create(msg.toObject()); } - static async attackRoll(event, button) { - const modifier = Number.parseInt(button.dataset.value); - + static async attackRoll() { + const { modifier, damage, name: attackName } = this.actor.system.attack; const { roll, dice, advantageState, modifiers } = await this.actor.diceRoll( { title: `${this.actor.name} - Attack Roll`, value: modifier }, event.shiftKey @@ -367,7 +103,7 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) { const cls = getDocumentClass('ChatMessage'); const systemData = { - title: button.dataset.name, + title: attackName, origin: this.document.id, roll: roll._formula, advantageState, @@ -375,7 +111,7 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) { modifiers: modifiers, dice: dice, targets: targets, - damage: { value: button.dataset.damage, type: button.dataset.damageType } + damage: { value: damage.value, type: damage.type } }; const msg = new cls({ type: 'adversaryRoll', diff --git a/module/config/actorConfig.mjs b/module/config/actorConfig.mjs index bcb6ee8b..dcd85cdb 100644 --- a/module/config/actorConfig.mjs +++ b/module/config/actorConfig.mjs @@ -82,43 +82,53 @@ export const featureProperties = { export const adversaryTypes = { bruiser: { - name: 'DAGGERHEART.Adversary.Bruiser.Name', + id: 'bruiser', + label: 'DAGGERHEART.Adversary.Type.Bruiser.label', description: 'DAGGERHEART.Adversary.Bruiser.Description' }, horde: { - name: 'DAGGERHEART.Adversary.Horde.Name', + id: 'horde', + label: 'DAGGERHEART.Adversary.Type.Horde.label', description: 'DAGGERHEART.Adversary.Horde.Description' }, leader: { - name: 'DAGGERHEART.Adversary.Leader.Name', + id: 'leader', + label: 'DAGGERHEART.Adversary.Type.Leader.label', description: 'DAGGERHEART.Adversary.Leader.Description' }, minion: { - name: 'DAGGERHEART.Adversary.Minion.Name', + id: 'minion', + label: 'DAGGERHEART.Adversary.Type.Minion.label', description: 'DAGGERHEART.Adversary.Minion.Description' }, ranged: { - name: 'DAGGERHEART.Adversary.Ranged.Name', + id: 'ranged', + label: 'DAGGERHEART.Adversary.Type.Ranged.label', description: 'DAGGERHEART.Adversary.Ranged.Description' }, - skulker: { - name: 'DAGGERHEART.Adversary.Skulker.Name', - description: 'DAGGERHEART.Adversary.Skulker.Description' + skulk: { + id: 'skulk', + label: 'DAGGERHEART.Adversary.Type.Skulk.label', + description: 'DAGGERHEART.Adversary.Skulk.Description' }, social: { - name: 'DAGGERHEART.Adversary.Social.Name', + id: 'social', + label: 'DAGGERHEART.Adversary.Type.Social.label', description: 'DAGGERHEART.Adversary.Social.Description' }, solo: { - name: 'DAGGERHEART.Adversary.Solo.Name', + id: 'solo', + label: 'DAGGERHEART.Adversary.Type.Solo.label', description: 'DAGGERHEART.Adversary.Solo.Description' }, standard: { - name: 'DAGGERHEART.Adversary.Standard.Name', + id: 'standard', + label: 'DAGGERHEART.Adversary.Type.Standard.label', description: 'DAGGERHEART.Adversary.Standard.Description' }, support: { - name: 'DAGGERHEART.Adversary.Support.Name', + id: 'support', + label: 'DAGGERHEART.Adversary.Type.Support.label', description: 'DAGGERHEART.Adversary.Support.Description' } }; diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 47736284..fecb939e 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -1,25 +1,30 @@ export const range = { melee: { + id: 'melee', label: 'DAGGERHEART.Range.melee.name', description: 'DAGGERHEART.Range.melee.description', distance: 1 }, veryClose: { + id: 'veryClose', label: 'DAGGERHEART.Range.veryClose.name', description: 'DAGGERHEART.Range.veryClose.description', distance: 3 }, close: { + id: 'close', label: 'DAGGERHEART.Range.close.name', description: 'DAGGERHEART.Range.close.description', distance: 10 }, far: { + id: 'far', label: 'DAGGERHEART.Range.far.name', description: 'DAGGERHEART.Range.far.description', distance: 20 }, veryFar: { + id: 'veryFar', label: 'DAGGERHEART.Range.veryFar.name', description: 'DAGGERHEART.Range.veryFar.description', distance: 30 diff --git a/module/data/adversary.mjs b/module/data/adversary.mjs index 0f25b62d..7e4c28f1 100644 --- a/module/data/adversary.mjs +++ b/module/data/adversary.mjs @@ -1,55 +1,60 @@ +const resourceField = () => + new foundry.data.fields.SchemaField({ + value: new foundry.data.fields.NumberField({ initial: 0, integer: true }), + max: new foundry.data.fields.NumberField({ initial: 0, integer: true }) + }); + export default class DhpAdversary extends foundry.abstract.TypeDataModel { + static LOCALIZATION_PREFIXES = ['DAGGERHEART.Sheets.Adversary']; + static defineSchema() { const fields = foundry.data.fields; return { - resources: new fields.SchemaField({ - health: new fields.SchemaField({ - value: new fields.NumberField({ initial: 0, integer: true }), - min: new fields.NumberField({ initial: 0, integer: true }), - max: new fields.NumberField({ initial: 0, integer: true }) - }), - stress: new fields.SchemaField({ - value: new fields.NumberField({ initial: 0, integer: true }), - min: new fields.NumberField({ initial: 0, integer: true }), - max: new fields.NumberField({ initial: 0, integer: true }) - }) - }), tier: new fields.StringField({ - choices: Object.keys(SYSTEM.GENERAL.tiers), + required: true, + choices: SYSTEM.GENERAL.tiers, initial: SYSTEM.GENERAL.tiers.tier1.id }), type: new fields.StringField({ - choices: Object.keys(SYSTEM.ACTOR.adversaryTypes), - integer: false, - initial: Object.keys(SYSTEM.ACTOR.adversaryTypes).find(x => x === 'standard') + required: true, + choices: SYSTEM.ACTOR.adversaryTypes, + initial: SYSTEM.ACTOR.adversaryTypes.standard.id + }), + description: new fields.HTMLField(), + motivesAndTactics: new fields.HTMLField(), + difficulty: new fields.NumberField({ required: true, initial: 1, integer: true }), + damageThresholds: new fields.SchemaField({ + major: new fields.NumberField({ required: true, initial: 0, integer: true }), + severe: new fields.NumberField({ required: true, initial: 0, integer: true }) + }), + resources: new fields.SchemaField({ + hitPoints: resourceField(), + stress: resourceField() }), - description: new fields.StringField({}), - motivesAndTactics: new fields.ArrayField(new fields.StringField({})), - attackModifier: new fields.NumberField({ integer: true, nullabe: true, initial: null }), attack: new fields.SchemaField({ name: new fields.StringField({}), - range: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.range), integer: false }), + modifier: new fields.NumberField({ required: true, integer: true, initial: 0 }), + range: new fields.StringField({ + required: true, + choices: SYSTEM.GENERAL.range, + initial: SYSTEM.GENERAL.range.melee.id + }), damage: new fields.SchemaField({ - value: new fields.StringField({}), - type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }) + value: new fields.StringField(), + type: new fields.StringField({ + required: true, + choices: SYSTEM.GENERAL.damageTypes, + initial: SYSTEM.GENERAL.damageTypes.physical.id + }) }) }), - difficulty: new fields.NumberField({ initial: 1, integer: true }), - damageThresholds: new fields.SchemaField({ - major: new fields.NumberField({ initial: 0, integer: true }), - severe: new fields.NumberField({ initial: 0, integer: true }) - }), experiences: new fields.TypedObjectField( new fields.SchemaField({ - id: new fields.StringField({ required: true }), name: new fields.StringField(), - value: new fields.NumberField({ integer: true, nullable: true, initial: null }) + value: new fields.NumberField({ required: true, integer: true, initial: 1 }) }) ) + /* Features waiting on pseudo-document data model addition */ }; } - - get features() { - return this.parent.items.filter(x => x.type === 'feature'); - } } diff --git a/styles/daggerheart.css b/styles/daggerheart.css index cb4ede19..96b949fc 100755 --- a/styles/daggerheart.css +++ b/styles/daggerheart.css @@ -2370,251 +2370,6 @@ div.daggerheart.views.multiclass { align-items: center; gap: 5px; } -.daggerheart.sheet.adversary .adversary-header-container { - position: relative; - background-color: grey; - display: flex; -} -.daggerheart.sheet.adversary .adversary-header-container .adversary-header { - flex: 1; -} -.daggerheart.sheet.adversary .adversary-header-container .adversary-header img { - height: 60px; - width: 60px; -} -.daggerheart.sheet.adversary .adversary-header-container .adversary-header .adversary-title { - display: flex; - align-items: center; - text-align: center; - font-size: 28px; -} -.daggerheart.sheet.adversary .adversary-header-container .adversary-header .adversary-title .title-text { - width: 100%; -} -.daggerheart.sheet.adversary .adversary-header-container .adversary-header .adversary-title input { - font-size: 28px; - border: 0; - height: 100%; -} -.daggerheart.sheet.adversary .adversary-header-container .adversary-toggle { - position: absolute; - top: 0; - right: 0; - background-color: white; - color: black; - flex: 0; -} -.daggerheart.sheet.adversary .motive-container { - background: lightgrey; - margin-bottom: 8px; - padding-bottom: 4px; -} -.daggerheart.sheet.adversary .motive-container .motive-title { - display: flex; - align-items: center; - justify-content: center; - flex-wrap: wrap; -} -.daggerheart.sheet.adversary .motive-container .motive-title .motive-title-base { - font-size: 21px; -} -.daggerheart.sheet.adversary .motive-container .motive-title .motive-title-value { - font-style: italic; - position: relative; - top: 2px; -} -.daggerheart.sheet.adversary .motive-container .motive-title i { - margin-left: 4px; - cursor: pointer; -} -.daggerheart.sheet.adversary .motive-container .motive-title i:hover { - filter: drop-shadow(0 0 3px red); -} -.daggerheart.sheet.adversary .adversary-content-container { - display: flex; - align-items: baseline; -} -.daggerheart.sheet.adversary .adversary-statistics-container { - flex: 1; - margin-right: 24px; - display: flex; - flex-direction: column; - gap: 12px; -} -.daggerheart.sheet.adversary .adversary-statistics-container .statistic-title { - flex: 0; - white-space: nowrap; - font-weight: bold; -} -.daggerheart.sheet.adversary .adversary-statistics-container .statistic-row { - display: flex; - align-items: center; -} -.daggerheart.sheet.adversary .adversary-statistics-container .statistic-row .statistic-value { - flex: 0; - white-space: nowrap; - margin-left: 4px; -} -.daggerheart.sheet.adversary .adversary-statistics-container .statistic-row .adversary-roll { - border: 0; - width: 16px; - margin-left: 4px; - align-self: baseline; - transition: transform 0.2s; -} -.daggerheart.sheet.adversary .adversary-statistics-container .statistic-row .adversary-roll:hover { - transform: rotate(30deg); - filter: drop-shadow(0px 0px 3px red); - cursor: pointer; -} -.daggerheart.sheet.adversary .adversary-statistics-container .statistic-resource-container { - display: flex; - align-items: center; -} -.daggerheart.sheet.adversary .adversary-statistics-container .statistic-resource-container label { - min-width: 44px; -} -.daggerheart.sheet.adversary .adversary-statistics-container .statistic-resource-container .statistic-resource-inner-container { - display: flex; - align-items: center; - flex-wrap: wrap; - gap: 4px; -} -.daggerheart.sheet.adversary .adversary-statistics-container .statistic-resource-container .resource-title { - align-self: center; - font-weight: bold; -} -.daggerheart.sheet.adversary .adversary-statistics-container .statistic-resource-container .statistic-resource-input { - margin: 0; - flex: 0; - min-width: 16px; -} -.daggerheart.sheet.adversary .adversary-statistics-container .attack-container { - border: 1px solid black dotted; -} -.daggerheart.sheet.adversary .adversary-statistics-container .experience-row { - display: flex; -} -.daggerheart.sheet.adversary .adversary-statistics-container .experience-row * { - flex: 0; - white-space: nowrap; -} -.daggerheart.sheet.adversary .adversary-statistics-container .experience-container i { - margin-left: 4px; - cursor: pointer; -} -.daggerheart.sheet.adversary .adversary-statistics-container .experience-container i:hover { - filter: drop-shadow(0 0 3px red); -} -.daggerheart.sheet.adversary .adversary-statistics-container .experience-chip { - border: 2px solid #708090; - border-radius: 6px; - display: flex; - align-items: center; - padding: 4px; - margin-bottom: 6px; -} -.daggerheart.sheet.adversary .adversary-statistics-container .experience-chip .experience-text { - flex: 1; -} -.daggerheart.sheet.adversary .adversary-statistics-container .experience-chip .experience-value { - flex: 0; - min-width: 26px; - margin: 0 4px; -} -.daggerheart.sheet.adversary .adversary-statistics-container .experience-chip .experience-button { - flex: 0; - border-radius: 50%; - height: 20px; - width: 20px; - display: flex; - align-items: center; - justify-content: center; - padding: 12px; -} -.daggerheart.sheet.adversary .adversary-damage-threshold-container input { - min-width: 26px; -} -.daggerheart.sheet.adversary .adversary-moves-container { - flex: 2.5; -} -.daggerheart.sheet.adversary .adversary-moves-container .moves-title { - text-decoration: underline; - font-weight: bold; -} -.daggerheart.sheet.adversary .adversary-moves-container .move-container { - cursor: pointer; -} -.daggerheart.sheet.adversary .adversary-moves-container .move-container:hover { - background: #2f4f4f40; -} -.daggerheart.sheet.adversary .adversary-moves-container .move-container .moves-name { - font-weight: bold; - text-decoration: none; -} -.daggerheart.sheet.adversary .adversary-moves-container .move-container .move-description p { - margin-top: 0; -} -.daggerheart.sheet.adversary .adversary-moves-container .moves-edit-container i { - margin-left: 4px; - cursor: pointer; -} -.daggerheart.sheet.adversary .adversary-moves-container .moves-edit-container i:hover { - filter: drop-shadow(0 0 3px red); -} -.daggerheart.sheet.adversary .chip-container { - display: flex; - align-items: center; - justify-content: space-between; - background: #778899; - padding: 8px; - border: 2px solid black; - border-radius: 6px; -} -.daggerheart.sheet.adversary .chip-container:not(:last-child) { - margin-bottom: 8px; -} -.daggerheart.sheet.adversary .chip-container .chip-inner-container { - display: flex; - align-items: center; -} -.daggerheart.sheet.adversary .chip-container .chip-inner-container img { - height: 40px; - width: 40px; - margin-right: 8px; -} -.daggerheart.sheet.adversary .chip-container .chip-inner-container .chip-title { - font-size: 22px; - font-weight: bold; - font-style: italic; -} -.daggerheart.sheet.adversary .chip-container button { - height: 40px; - width: 40px; - background: white; -} -.daggerheart.sheet.actor.environment .potential-adversary-container { - width: 100%; - height: 50px; -} -.daggerheart.sheet.actor.environment .potential-adversary-container .adversary-placeholder { - font-style: italic; - text-align: center; - opacity: 0.6; -} -.daggerheart.sheet.actor.environment .potential-adversary-container .adversaries-container { - display: flex; - gap: 8px; -} -.daggerheart.sheet.actor.environment .potential-adversary-container .adversaries-container .adversary-container { - border: 1px solid var(--color-dark-5); - border-radius: 6px; - padding: 0 2px; - font-weight: bold; - cursor: pointer; - background-image: url(../assets/parchments/dh-parchment-dark.png); - color: var(--color-light-3); -} .daggerheart.sheet .title-container { display: flex; gap: 8px; @@ -3100,6 +2855,31 @@ div.daggerheart.views.multiclass { #resources:has(.fear-bar) { min-width: 200px; } +.application.sheet.daggerheart.actor.dh-style.adversary .window-content { + overflow: auto; +} +.daggerheart.sheet.actor.environment .potential-adversary-container { + width: 100%; + height: 50px; +} +.daggerheart.sheet.actor.environment .potential-adversary-container .adversary-placeholder { + font-style: italic; + text-align: center; + opacity: 0.6; +} +.daggerheart.sheet.actor.environment .potential-adversary-container .adversaries-container { + display: flex; + gap: 8px; +} +.daggerheart.sheet.actor.environment .potential-adversary-container .adversaries-container .adversary-container { + border: 1px solid var(--color-dark-5); + border-radius: 6px; + padding: 0 2px; + font-weight: bold; + cursor: pointer; + background-image: url(../assets/parchments/dh-parchment-dark.png); + color: var(--color-light-3); +} .application.sheet.daggerheart.dh-style.feature .item-sheet-header { display: flex; } @@ -3379,6 +3159,9 @@ div.daggerheart.views.multiclass { .application.sheet.dh-style fieldset.two-columns.even { grid-template-columns: 1fr 1fr; } +.application.sheet.dh-style fieldset.two-columns .full-width { + grid-column: span 2; +} .application.sheet.dh-style fieldset legend { font-family: 'Montserrat', sans-serif; font-weight: bold; diff --git a/styles/daggerheart.less b/styles/daggerheart.less index 6869e316..8ec94054 100755 --- a/styles/daggerheart.less +++ b/styles/daggerheart.less @@ -13,6 +13,9 @@ @import './resources.less'; // new styles imports +@import './less/actors/adversary.less'; +@import './less/actors/environment.less'; + @import './less/items/feature.less'; @import './less/items/domainCard.less'; @import './less/items/class.less'; diff --git a/styles/less/actors/adversary.less b/styles/less/actors/adversary.less new file mode 100644 index 00000000..5b4feb26 --- /dev/null +++ b/styles/less/actors/adversary.less @@ -0,0 +1,5 @@ +.application.sheet.daggerheart.actor.dh-style.adversary { + .window-content { + overflow: auto; + } +} diff --git a/styles/sheets/environment.less b/styles/less/actors/environment.less similarity index 100% rename from styles/sheets/environment.less rename to styles/less/actors/environment.less diff --git a/styles/less/global/elements.less b/styles/less/global/elements.less index 14345ca6..797b2328 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -107,6 +107,10 @@ &.even { grid-template-columns: 1fr 1fr; } + + .full-width { + grid-column: span 2; + } } legend { diff --git a/styles/sheets/adversary.less b/styles/sheets/adversary.less deleted file mode 100644 index 657ce218..00000000 --- a/styles/sheets/adversary.less +++ /dev/null @@ -1,280 +0,0 @@ -.daggerheart.sheet.adversary { - .adversary-header-container { - position: relative; - background-color: grey; - display: flex; - - .adversary-header { - flex: 1; - - img { - height: 60px; - width: 60px; - } - - .adversary-title { - display: flex; - align-items: center; - text-align: center; - font-size: 28px; - - .title-text { - width: 100%; - } - - input { - font-size: 28px; - border: 0; - height: 100%; - } - } - } - - .adversary-toggle { - position: absolute; - top: 0; - right: 0; - background-color: white; - color: black; - flex: 0; - } - } - - .motive-container { - background: lightgrey; - margin-bottom: @fullMargin; - padding-bottom: @fullPadding; - - .motive-title { - display: flex; - align-items: center; - justify-content: center; - flex-wrap: wrap; - - .motive-title-base { - font-size: 21px; - } - - .motive-title-value { - font-style: italic; - position: relative; - top: 2px; - } - - i { - margin-left: 4px; - cursor: pointer; - - &:hover { - filter: drop-shadow(0 0 3px red); - } - } - } - } - - .adversary-content-container { - display: flex; - align-items: baseline; - } - - .adversary-statistics-container { - flex: 1; - margin-right: 24px; - display: flex; - flex-direction: column; - gap: @mediumMargin; - - .statistic-title { - flex: 0; - white-space: nowrap; - font-weight: bold; - } - - .statistic-row { - display: flex; - align-items: center; - - .statistic-value { - flex: 0; - white-space: nowrap; - margin-left: 4px; - } - - .adversary-roll { - border: 0; - width: 16px; - margin-left: 4px; - align-self: baseline; - transition: transform 0.2s; - - &:hover { - transform: rotate(30deg); - filter: drop-shadow(0px 0px 3px red); - cursor: pointer; - } - } - } - - .statistic-resource-container { - display: flex; - align-items: center; - - label { - min-width: 44px; - } - - .statistic-resource-inner-container { - display: flex; - align-items: center; - flex-wrap: wrap; - gap: @halfMargin; - } - - .resource-title { - align-self: center; - font-weight: bold; - } - - .statistic-resource-input { - margin: 0; - flex: 0; - min-width: 16px; - } - } - - .attack-container { - border: 1px solid black dotted; - } - - .experience-row { - display: flex; - - * { - flex: 0; - white-space: nowrap; - } - } - - .experience-container { - i { - margin-left: 4px; - cursor: pointer; - - &:hover { - filter: drop-shadow(0 0 3px red); - } - } - } - - .experience-chip { - border: 2px solid @secondaryAccent; - border-radius: 6px; - display: flex; - align-items: center; - padding: 4px; - margin-bottom: 6px; - - .experience-text { - flex: 1; - } - - .experience-value { - flex: 0; - min-width: @inputSingleMinWidth; - margin: 0 4px; - } - - .experience-button { - flex: 0; - border-radius: 50%; - height: 20px; - width: 20px; - display: flex; - align-items: center; - justify-content: center; - padding: 12px; - } - } - } - - .adversary-damage-threshold-container { - input { - min-width: @inputSingleMinWidth; - } - } - - .adversary-moves-container { - flex: 2.5; - - .moves-title { - text-decoration: underline; - font-weight: bold; - } - .move-container { - cursor: pointer; - - &:hover { - background: @hoverBackground; - } - - .moves-name { - font-weight: bold; - text-decoration: none; - } - - .move-description { - p { - margin-top: 0; - } - } - } - - .moves-edit-container { - i { - margin-left: 4px; - cursor: pointer; - - &:hover { - filter: drop-shadow(0 0 3px red); - } - } - } - } - - .chip-container { - display: flex; - align-items: center; - justify-content: space-between; - background: @primaryAccent; - padding: 8px; - border: 2px solid black; - border-radius: 6px; - - &:not(:last-child) { - margin-bottom: 8px; - } - - .chip-inner-container { - display: flex; - align-items: center; - - img { - height: 40px; - width: 40px; - margin-right: 8px; - } - - .chip-title { - font-size: 22px; - font-weight: bold; - font-style: italic; - } - } - - button { - height: 40px; - width: 40px; - background: white; - } - } -} diff --git a/styles/sheets/sheets.less b/styles/sheets/sheets.less index 3ce23be8..5a49a010 100644 --- a/styles/sheets/sheets.less +++ b/styles/sheets/sheets.less @@ -1,7 +1,5 @@ @import './heritage.less'; @import './class.less'; -@import './adversary.less'; -@import './environment.less'; .daggerheart.sheet { .title-container { diff --git a/system.json b/system.json index 1717e6e6..c402b837 100644 --- a/system.json +++ b/system.json @@ -204,7 +204,9 @@ "documentTypes": { "Actor": { "pc": {}, - "adversary": {}, + "adversary": { + "htmlFields": ["description", "motivesAndTactics"] + }, "environment": { "htmlFields": ["description", "impulses"] } diff --git a/templates/chat/adversary-attack-roll.hbs b/templates/chat/adversary-attack-roll.hbs index 3e805de9..d7cd9ecc 100644 --- a/templates/chat/adversary-attack-roll.hbs +++ b/templates/chat/adversary-attack-roll.hbs @@ -39,7 +39,7 @@ {{/if}}
- +
\ No newline at end of file diff --git a/templates/sheets/actors/adversary/header.hbs b/templates/sheets/actors/adversary/header.hbs new file mode 100644 index 00000000..e3914c32 --- /dev/null +++ b/templates/sheets/actors/adversary/header.hbs @@ -0,0 +1,9 @@ +
+ +
+

+
+

{{localize 'TYPES.Actor.adversary'}}

+
+
+
\ No newline at end of file diff --git a/templates/sheets/actors/adversary/information.hbs b/templates/sheets/actors/adversary/information.hbs new file mode 100644 index 00000000..6d6efb21 --- /dev/null +++ b/templates/sheets/actors/adversary/information.hbs @@ -0,0 +1,17 @@ +
+
+ {{localize "DAGGERHEART.Sheets.Adversary.Description" }} + + {{formGroup systemFields.description value=source.system.description}} +
+ +
+ {{localize "DAGGERHEART.Sheets.Adversary.MotivesAndTactics" }} + + {{formGroup systemFields.motivesAndTactics value=source.system.motivesAndTactics}} +
+
diff --git a/templates/sheets/actors/adversary/main.hbs b/templates/sheets/actors/adversary/main.hbs new file mode 100644 index 00000000..788af5ea --- /dev/null +++ b/templates/sheets/actors/adversary/main.hbs @@ -0,0 +1,60 @@ +
+
+
+ {{localize "DAGGERHEART.Sheets.Adversary.General"}} + + {{formGroup systemFields.tier value=source.system.tier localize=true}} + {{formGroup systemFields.type value=source.system.type localize=true}} +
{{formGroup systemFields.difficulty value=source.system.difficulty}}
+ +
+ {{localize "DAGGERHEART.Sheets.Adversary.DamageThresholds"}} + + {{formGroup systemFields.damageThresholds.fields.major value=source.system.damageThresholds.major}} + {{formGroup systemFields.damageThresholds.fields.severe value=source.system.damageThresholds.severe}} +
+ +
+ {{localize "DAGGERHEART.Sheets.Adversary.HitPoints"}} + + {{formGroup systemFields.resources.fields.hitPoints.fields.value value=source.system.resources.hitPoints.value}} + {{formGroup systemFields.resources.fields.hitPoints.fields.max value=source.system.resources.hitPoints.max}} +
+ +
+ {{localize "DAGGERHEART.Sheets.Adversary.Stress"}} + + {{formGroup systemFields.resources.fields.stress.fields.value value=source.system.resources.stress.value}} + {{formGroup systemFields.resources.fields.stress.fields.max value=source.system.resources.stress.max}} +
+ +
+ {{localize "DAGGERHEART.Sheets.Adversary.Experiences"}} + + {{#each source.system.experiences}} +
+ {{this.name}} + + {{formGroup @root.systemFields.experiences.element.fields.name name=(concat "system.experiences." @key ".name") value=this.name }} + {{formGroup @root.systemFields.experiences.element.fields.value name=(concat "system.experiences." @key ".value") value=this.value }} +
+ {{/each}} +
+
+ +
+ {{localize "DAGGERHEART.Sheets.Adversary.Attack"}} + + {{formGroup systemFields.attack.fields.name value=source.system.attack.name}} + + {{formGroup systemFields.attack.fields.modifier value=source.system.attack.modifier}} + {{formGroup systemFields.attack.fields.range value=source.system.attack.range localize=true}} + {{formGroup systemFields.attack.fields.damage.fields.value value=source.system.attack.damage.value}} + {{formGroup systemFields.attack.fields.damage.fields.type value=source.system.attack.damage.type localize=true}} +
+
+