From ad9a72d494965d80c8fe5d4f30e1146ff2893fe3 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Mon, 14 Jul 2025 21:18:24 +0200 Subject: [PATCH] Fixed translation of TrackedAttributeChoices --- daggerheart.mjs | 12 +- lang/en.json | 41 ++++- .../applications/sheets-configs/_module.mjs | 2 + .../sheets-configs/activeEffectConfig.mjs | 111 ++++++++++--- .../sheets-configs/prototype-token-config.mjs | 20 +++ .../sheets-configs/token-config.mjs | 20 +++ module/data/actor/adversary.mjs | 41 +++-- module/data/actor/base.mjs | 8 +- module/data/actor/character.mjs | 147 ++++++++++++------ module/data/actor/companion.mjs | 10 +- module/documents/_module.mjs | 1 + module/documents/token.mjs | 33 ++++ package-lock.json | 6 + package.json | 1 + styles/less/ux/autocomplete/autocomplete.less | 39 +++++ styles/less/ux/index.less | 1 + system.json | 2 +- templates/sheets/activeEffect/changes.hbs | 6 +- 18 files changed, 410 insertions(+), 91 deletions(-) create mode 100644 module/applications/sheets-configs/prototype-token-config.mjs create mode 100644 module/applications/sheets-configs/token-config.mjs create mode 100644 module/documents/token.mjs create mode 100644 styles/less/ux/autocomplete/autocomplete.less diff --git a/daggerheart.mjs b/daggerheart.mjs index 5a6d8193..a1742641 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -61,6 +61,14 @@ Hooks.once('init', () => { CONFIG.Dice.rolls = [...CONFIG.Dice.rolls, ...[DHRoll, DualityRoll, D20Roll, DamageRoll]]; CONFIG.MeasuredTemplate.objectClass = placeables.DhMeasuredTemplate; + const { DocumentSheetConfig } = foundry.applications.apps; + CONFIG.Token.documentClass = documents.DhToken; + CONFIG.Token.prototypeSheetClass = applications.sheetConfigs.DhPrototypeTokenConfig; + DocumentSheetConfig.unregisterSheet(TokenDocument, 'core', foundry.applications.sheets.TokenConfig); + DocumentSheetConfig.registerSheet(TokenDocument, 'dnd5e', applications.sheetConfigs.DhTokenConfig, { + makeDefault: true + }); + CONFIG.Item.documentClass = documents.DHItem; //Registering the Item DataModel @@ -98,12 +106,12 @@ Hooks.once('init', () => { CONFIG.ActiveEffect.documentClass = documents.DhActiveEffect; CONFIG.ActiveEffect.dataModels = models.activeEffects.config; - foundry.applications.apps.DocumentSheetConfig.unregisterSheet( + DocumentSheetConfig.unregisterSheet( CONFIG.ActiveEffect.documentClass, 'core', foundry.applications.sheets.ActiveEffectConfig ); - foundry.applications.apps.DocumentSheetConfig.registerSheet( + DocumentSheetConfig.registerSheet( CONFIG.ActiveEffect.documentClass, SYSTEM.id, applications.sheetConfigs.ActiveEffectConfig, diff --git a/lang/en.json b/lang/en.json index 96f5a9dd..78db7e7a 100755 --- a/lang/en.json +++ b/lang/en.json @@ -1011,23 +1011,36 @@ "severe": "Severe", "major": "Major", "minor": "Minor", - "none": "None" + "none": "None", + "allDamage": "All Damage", + "physicalDamage": "Physical Damage", + "magicalDamage": "Magical Damage", + "primaryDamageBonus": "Primary Weapon Damage", + "primaryDamageDice": "Primary Weapon Extra Dice" }, "DamageResistance": { "none": "None", "resistance": "Resistance", - "immunity": "Immunity" + "immunity": "Immunity", + "physicalReduction": "Physical Damage Reduction", + "magicalReduction": "Magical Damage Reduction" }, "DamageThresholds": { "title": "Damage Thresholds", "minor": "Minor", "major": "Major", - "severe": "Severe" + "severe": "Severe", + "majorThreshold": "Major Damage Threshold", + "severeThreshold": "Severe Damage Threshold" }, "Dice": { "single": "Die", "plural": "Dice" }, + "Difficulty": { + "all": "Difficulty: all", + "reaction": "Difficulty: reaction" + }, "Disadvantage": { "full": "Disadvantage", "short": "Dis" @@ -1093,6 +1106,25 @@ "single": "Resource", "plural": "Resources" }, + "Roll": { + "attack": "Attack Roll", + "primaryWeaponAttack": "Primary Weapon Attack Roll", + "spellcast": "Spellcast Roll", + "action": "Action Roll", + "hopeOrFear": "Hope Or Fear Roll" + }, + "Rules": { + "damageReduction": { + "increasePerArmorMark": "Armor Block Per Mark", + "maxArmorMarkedBonus": "Max Armor Used", + "maxArmorMarkedStress": "Max Armor Used With Stress", + "stress": { + "severe": "Stress Damage Reduction: Severe", + "major": "Stress Damage Reduction: Major", + "minor": "Stress Damage Reduction: Minor" + } + } + }, "Tabs": { "details": "Details", "attack": "Attack", @@ -1137,6 +1169,7 @@ "single": "Trait", "plural": "Traits" }, + "armorScore": "Armor Score", "activeEffects": "Active Effects", "attack": "Attack", "basics": "Basics", @@ -1155,6 +1188,7 @@ "features": "Features", "hitPoints": "Hit Points", "hope": "Hope", + "hordeHp": "Horde HP", "inactiveEffects": "Inactive Effects", "inventory": "Inventory", "level": "Level", @@ -1162,6 +1196,7 @@ "modifier": "Modifier", "multiclass": "Multiclass", "none": "None", + "proficiency": "Proficiency", "quantity": "Quantity", "range": "Range", "recovery": "Recovery", diff --git a/module/applications/sheets-configs/_module.mjs b/module/applications/sheets-configs/_module.mjs index e1ae8fe2..fafb1fcf 100644 --- a/module/applications/sheets-configs/_module.mjs +++ b/module/applications/sheets-configs/_module.mjs @@ -3,3 +3,5 @@ export { default as AdversarySettings } from './adversary-settings.mjs'; export { default as CompanionSettings } from './companion-settings.mjs'; export { default as EnvironmentSettings } from './environment-settings.mjs'; export { default as ActiveEffectConfig } from './activeEffectConfig.mjs'; +export { default as DhTokenConfig } from './token-config.mjs'; +export { default as DhPrototypeTokenConfig } from './prototype-token-config.mjs'; diff --git a/module/applications/sheets-configs/activeEffectConfig.mjs b/module/applications/sheets-configs/activeEffectConfig.mjs index 6a629583..b704b195 100644 --- a/module/applications/sheets-configs/activeEffectConfig.mjs +++ b/module/applications/sheets-configs/activeEffectConfig.mjs @@ -1,4 +1,44 @@ +import autocomplete from 'autocompleter'; + export default class DhActiveEffectConfig extends foundry.applications.sheets.ActiveEffectConfig { + constructor(options) { + super(options); + + const ignoredActorKeys = ['config', 'DhEnvironment']; + const actorAttributes = Object.keys(game.system.api.models.actors).reduce((acc, key) => { + if (!ignoredActorKeys.includes(key)) { + const model = game.system.api.models.actors[key]; + const attributes = CONFIG.Token.documentClass.getTrackedAttributes(model); + acc[game.i18n.localize(model.metadata.label)] = CONFIG.Token.documentClass.getTrackedAttributeChoices( + attributes, + model + ); + } + return acc; + }, {}); + console.log(actorAttributes); + + // const allowedItemKeys = ['DHArmor']; + // const itemAttributes = Object.keys(game.system.api.models.items).reduce((acc, key) => { + // if(allowedItemKeys.includes(key)) { + // const model = game.system.api.models.items[key]; + // acc[game.i18n.localize(model.metadata.label)] = CONFIG.Token.documentClass.getTrackedAttributes(model); + // } + // return acc; + // }, {}); + + // this.selectChoices = [ + // ...Object.keys(actorAttributes).flatMap(name => { + // const attribute = actorAttributes[name]; + // return { group: name, label: attribute, value: attribute }; + // }), + // ...Object.keys(itemAttributes).flatMap(name => { + // const attribute = itemAttributes[name]; + // return { group: name, label: attribute, value: attribute }; + // }) + // ]; + } + static DEFAULT_OPTIONS = { classes: ['daggerheart', 'sheet', 'dh-style'] }; @@ -27,36 +67,61 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac } }; + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + const selectChoices = this.selectChoices; + + htmlElement.querySelectorAll('.effect-change-input').forEach(element => { + autocomplete({ + input: element, + fetch: function (text, update) { + if (!text) { + update(selectChoices); + } else { + text = text.toLowerCase(); + var suggestions = selectChoices.filter(n => n.label.toLowerCase().includes(text)); + update(suggestions); + } + }, + render: function (item, search) { + const label = game.i18n.localize(item.label); + const matchIndex = label.toLowerCase().indexOf(search); + + const base = document.createElement('div'); + base.textContent = label.slice(0, matchIndex); + + const matchText = document.createElement('div'); + matchText.textContent = label.slice(matchIndex, matchIndex + search.length); + matchText.classList.add('matched'); + + const after = document.createElement('div'); + after.textContent = label.slice(matchIndex + search.length, label.length); + + base.insertAdjacentElement('beforeend', matchText); + base.insertAdjacentElement('beforeend', after); + return base; + }, + renderGroup: function (label) { + const itemElement = document.createElement('div'); + itemElement.textContent = game.i18n.localize(label); + return itemElement; + }, + onSelect: function (item) { + element.value = item.value; + }, + click: e => e.fetch(), + minLength: 0 + }); + }); + } + async _preparePartContext(partId, context) { const partContext = await super._preparePartContext(partId, context); switch (partId) { case 'changes': - const fieldPaths = []; - const validFieldPath = fieldPath => this.validFieldPath(fieldPath, this.#unapplicablePaths); - context.document.parent.system.schema.apply(function () { - if (!(this instanceof foundry.data.fields.SchemaField)) { - if (validFieldPath(this.fieldPath)) { - fieldPaths.push(this.fieldPath); - } - } - }); - - context.fieldPaths = fieldPaths; - break; } return partContext; } - - #unapplicablePaths = ['story', 'pronouns', 'description']; - validFieldPath(fieldPath, unapplicablePaths) { - const splitPath = fieldPath.split('.'); - if (splitPath.length > 1 && unapplicablePaths.includes(splitPath[1])) return false; - - /* The current value of a resource should not be modified */ - if (new RegExp(/resources.*\.value/).exec(fieldPath)) return false; - - return true; - } } diff --git a/module/applications/sheets-configs/prototype-token-config.mjs b/module/applications/sheets-configs/prototype-token-config.mjs new file mode 100644 index 00000000..24c9dabb --- /dev/null +++ b/module/applications/sheets-configs/prototype-token-config.mjs @@ -0,0 +1,20 @@ +export default class DhPrototypeTokenConfig extends foundry.applications.sheets.PrototypeTokenConfig { + /** @inheritDoc */ + async _prepareResourcesTab() { + const token = this.token; + const usesTrackableAttributes = !foundry.utils.isEmpty(CONFIG.Actor.trackableAttributes); + const attributeSource = + this.actor?.system instanceof foundry.abstract.DataModel && usesTrackableAttributes + ? this.actor?.type + : this.actor?.system; + const TokenDocument = foundry.utils.getDocumentClass('Token'); + const attributes = TokenDocument.getTrackedAttributes(attributeSource); + return { + barAttributes: TokenDocument.getTrackedAttributeChoices(attributes, attributeSource), + bar1: token.getBarAttribute?.('bar1'), + bar2: token.getBarAttribute?.('bar2'), + turnMarkerModes: DhPrototypeTokenConfig.TURN_MARKER_MODES, + turnMarkerAnimations: CONFIG.Combat.settings.turnMarkerAnimations + }; + } +} diff --git a/module/applications/sheets-configs/token-config.mjs b/module/applications/sheets-configs/token-config.mjs new file mode 100644 index 00000000..ee573e5d --- /dev/null +++ b/module/applications/sheets-configs/token-config.mjs @@ -0,0 +1,20 @@ +export default class DhTokenConfig extends foundry.applications.sheets.TokenConfig { + /** @inheritDoc */ + async _prepareResourcesTab() { + const token = this.token; + const usesTrackableAttributes = !foundry.utils.isEmpty(CONFIG.Actor.trackableAttributes); + const attributeSource = + this.actor?.system instanceof foundry.abstract.DataModel && usesTrackableAttributes + ? this.actor?.type + : this.actor?.system; + const TokenDocument = foundry.utils.getDocumentClass('Token'); + const attributes = TokenDocument.getTrackedAttributes(attributeSource); + return { + barAttributes: TokenDocument.getTrackedAttributeChoices(attributes, attributeSource), + bar1: token.getBarAttribute?.('bar1'), + bar2: token.getBarAttribute?.('bar2'), + turnMarkerModes: DhTokenConfig.TURN_MARKER_MODES, + turnMarkerAnimations: CONFIG.Combat.settings.turnMarkerAnimations + }; + } +} diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index 78e08323..ba7d1143 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -2,9 +2,9 @@ import DHAdversarySettings from '../../applications/sheets-configs/adversary-set import ActionField from '../fields/actionField.mjs'; import BaseDataActor from './base.mjs'; -const resourceField = () => +const resourceField = label => new foundry.data.fields.SchemaField({ - value: new foundry.data.fields.NumberField({ initial: 0, integer: true }), + value: new foundry.data.fields.NumberField({ initial: 0, integer: true, label }), max: new foundry.data.fields.NumberField({ initial: 0, integer: true }), isReversed: new foundry.data.fields.BooleanField({ initial: true }) }); @@ -37,14 +37,29 @@ export default class DhpAdversary extends BaseDataActor { motivesAndTactics: new fields.StringField(), notes: new fields.HTMLField(), difficulty: new fields.NumberField({ required: true, initial: 1, integer: true }), - hordeHp: new fields.NumberField({ required: true, initial: 1, integer: true }), + hordeHp: new fields.NumberField({ + required: true, + initial: 1, + integer: true, + label: 'DAGGERHEART.GENERAL.hordeHp' + }), damageThresholds: new fields.SchemaField({ - major: new fields.NumberField({ required: true, initial: 0, integer: true }), - severe: new fields.NumberField({ required: true, initial: 0, integer: true }) + major: new fields.NumberField({ + required: true, + initial: 0, + integer: true, + label: 'DAGGERHEART.GENERAL.DamageThresholds.majorThreshold' + }), + severe: new fields.NumberField({ + required: true, + initial: 0, + integer: true, + label: 'DAGGERHEART.GENERAL.DamageThresholds.severeThreshold' + }) }), resources: new fields.SchemaField({ - hitPoints: resourceField(), - stress: resourceField() + hitPoints: resourceField('DAGGERHEART.GENERAL.hitPoints'), + stress: resourceField('DAGGERHEART.GENERAL.stress') }), attack: new ActionField({ initial: { @@ -81,8 +96,16 @@ export default class DhpAdversary extends BaseDataActor { ), bonuses: new fields.SchemaField({ difficulty: new fields.SchemaField({ - all: new fields.NumberField({ integer: true, initial: 0 }), - reaction: new fields.NumberField({ integer: true, initial: 0 }) + all: new fields.NumberField({ + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.Difficulty.all' + }), + reaction: new fields.NumberField({ + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.Difficulty.reaction' + }) }) }) }; diff --git a/module/data/actor/base.mjs b/module/data/actor/base.mjs index cf1eebb1..19de7b06 100644 --- a/module/data/actor/base.mjs +++ b/module/data/actor/base.mjs @@ -1,10 +1,10 @@ import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs'; -const resistanceField = () => +const resistanceField = reductionLabel => new foundry.data.fields.SchemaField({ resistance: new foundry.data.fields.BooleanField({ initial: false }), immunity: new foundry.data.fields.BooleanField({ initial: false }), - reduction: new foundry.data.fields.NumberField({ integer: true, initial: 0 }) + reduction: new foundry.data.fields.NumberField({ integer: true, initial: 0, label: reductionLabel }) }); /** @@ -40,8 +40,8 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel { if (this.metadata.isNPC) schema.description = new fields.HTMLField({ required: true, nullable: true }); if (this.metadata.hasResistances) schema.resistance = new fields.SchemaField({ - physical: resistanceField(), - magical: resistanceField() + physical: resistanceField('DAGGERHEART.GENERAL.DamageResistance.physicalReduction'), + magical: resistanceField('DAGGERHEART.GENERAL.DamageResistance.magicalReduction') }); return schema; } diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 3ee7c980..10731b3b 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -3,26 +3,28 @@ import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs'; import DhLevelData from '../levelData.mjs'; import BaseDataActor from './base.mjs'; -const attributeField = () => +const attributeField = label => new foundry.data.fields.SchemaField({ - value: new foundry.data.fields.NumberField({ initial: 0, integer: true }), + value: new foundry.data.fields.NumberField({ initial: 0, integer: true, label: label }), tierMarked: new foundry.data.fields.BooleanField({ initial: false }) }); -const resourceField = (max, reverse = false) => +const resourceField = (max, label, reverse = false) => new foundry.data.fields.SchemaField({ - value: new foundry.data.fields.NumberField({ initial: 0, integer: true }), + value: new foundry.data.fields.NumberField({ initial: 0, integer: true, label: label }), max: new foundry.data.fields.NumberField({ initial: max, integer: true }), isReversed: new foundry.data.fields.BooleanField({ initial: reverse }) }); -const stressDamageReductionRule = () => +const stressDamageReductionRule = label => new foundry.data.fields.SchemaField({ enabled: new foundry.data.fields.BooleanField({ required: true, initial: false }), - cost: new foundry.data.fields.NumberField({ integer: true }) + cost: new foundry.data.fields.NumberField({ integer: true, label }) }); export default class DhCharacter extends BaseDataActor { + static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Character']; + static get metadata() { return foundry.utils.mergeObject(super.metadata, { label: 'TYPES.Actor.character', @@ -37,24 +39,36 @@ export default class DhCharacter extends BaseDataActor { return { ...super.defineSchema(), resources: new fields.SchemaField({ - hitPoints: resourceField(0, true), - stress: resourceField(6, true), - hope: resourceField(6) + hitPoints: resourceField(0, 'DAGGERHEART.GENERAL.hitPoints', true), + stress: resourceField(6, 'DAGGERHEART.GENERAL.stress', true), + hope: resourceField(6, 'DAGGERHEART.GENERAL.hope') }), traits: new fields.SchemaField({ - agility: attributeField(), - strength: attributeField(), - finesse: attributeField(), - instinct: attributeField(), - presence: attributeField(), - knowledge: attributeField() + agility: attributeField('DAGGERHEART.CONFIG.Traits.agility.name'), + strength: attributeField('DAGGERHEART.CONFIG.Traits.strength.name'), + finesse: attributeField('DAGGERHEART.CONFIG.Traits.finesse.name'), + instinct: attributeField('DAGGERHEART.CONFIG.Traits.instinct.name'), + presence: attributeField('DAGGERHEART.CONFIG.Traits.presence.name'), + knowledge: attributeField('DAGGERHEART.CONFIG.Traits.knowledge.name') }), - proficiency: new fields.NumberField({ initial: 1, integer: true }), - evasion: new fields.NumberField({ initial: 0, integer: true }), - armorScore: new fields.NumberField({ integer: true, initial: 0 }), + proficiency: new fields.NumberField({ + initial: 1, + integer: true, + label: 'DAGGERHEART.GENERAL.proficiency' + }), + evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.evasion' }), + armorScore: new fields.NumberField({ integer: true, initial: 0, label: 'DAGGERHEART.GENERAL.armorScore' }), damageThresholds: new fields.SchemaField({ - severe: new fields.NumberField({ integer: true, initial: 0 }), - major: new fields.NumberField({ integer: true, initial: 0 }) + severe: new fields.NumberField({ + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.DamageThresholds.majorThreshold' + }), + major: new fields.NumberField({ + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.DamageThresholds.severeThreshold' + }) }), experiences: new fields.TypedObjectField( new fields.SchemaField({ @@ -94,21 +108,59 @@ export default class DhCharacter extends BaseDataActor { levelData: new fields.EmbeddedDataField(DhLevelData), bonuses: new fields.SchemaField({ roll: new fields.SchemaField({ - attack: new fields.NumberField({ integer: true, initial: 0 }), - primaryWeapon: new fields.SchemaField({ - attack: new fields.NumberField({ integer: true, initial: 0 }) + attack: new fields.NumberField({ + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.Roll.attack' }), - spellcast: new fields.NumberField({ integer: true, initial: 0 }), - action: new fields.NumberField({ integer: true, initial: 0 }), - hopeOrFear: new fields.NumberField({ integer: true, initial: 0 }) + primaryWeapon: new fields.SchemaField({ + attack: new fields.NumberField({ + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.Roll.primaryWeaponAttack' + }) + }), + spellcast: new fields.NumberField({ + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.Roll.spellcast' + }), + action: new fields.NumberField({ + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.Roll.action' + }), + hopeOrFear: new fields.NumberField({ + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.Roll.hopeOrFear' + }) }), damage: new fields.SchemaField({ - all: new fields.NumberField({ integer: true, initial: 0 }), - physical: new fields.NumberField({ integer: true, initial: 0 }), - magic: new fields.NumberField({ integer: true, initial: 0 }), + all: new fields.NumberField({ + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.Damage.allDamage' + }), + physical: new fields.NumberField({ + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.Damage.physicalDamage' + }), + magic: new fields.NumberField({ + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.Damage.magicalDamage' + }), primaryWeapon: new fields.SchemaField({ - bonus: new fields.NumberField({ integer: true }), - extraDice: new fields.NumberField({ integer: true }) + bonus: new fields.NumberField({ + integer: true, + label: 'DAGGERHEART.GENERAL.Damage.primaryDamageBonus' + }), + extraDice: new fields.NumberField({ + integer: true, + label: 'DAGGERHEART.GENERAL.Damage.primaryDamageDice' + }) }) }) }), @@ -117,25 +169,32 @@ export default class DhCharacter extends BaseDataActor { damageReduction: new fields.SchemaField({ maxArmorMarked: new fields.SchemaField({ value: new fields.NumberField({ required: true, integer: true, initial: 1 }), - bonus: new fields.NumberField({ required: true, integer: true, initial: 0 }), - stressExtra: new fields.NumberField({ required: true, integer: true, initial: 0 }) + bonus: new fields.NumberField({ + required: true, + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedBonus' + }), + stressExtra: new fields.NumberField({ + required: true, + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedStress' + }) }), stressDamageReduction: new fields.SchemaField({ - severe: stressDamageReductionRule(), - major: stressDamageReductionRule(), - minor: stressDamageReductionRule() + severe: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.severe'), + major: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.major'), + minor: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.minor') + }), + increasePerArmorMark: new fields.NumberField({ + integer: true, + initial: 1, + label: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark' }), - increasePerArmorMark: new fields.NumberField({ integer: true, initial: 1 }), magical: new fields.BooleanField({ initial: false }), physical: new fields.BooleanField({ initial: false }) }), - strangePatterns: new fields.NumberField({ - integer: true, - min: 1, - max: 12, - nullable: true, - initial: null - }), weapon: new fields.SchemaField({ /* Unimplemented -> Should remove the lowest damage dice from weapon damage diff --git a/module/data/actor/companion.mjs b/module/data/actor/companion.mjs index ea417bd8..8784032e 100644 --- a/module/data/actor/companion.mjs +++ b/module/data/actor/companion.mjs @@ -28,9 +28,15 @@ export default class DhCompanion extends BaseDataActor { max: new fields.NumberField({ initial: 3, integer: true }), isReversed: new foundry.data.fields.BooleanField({ initial: true }) }), - hope: new fields.NumberField({ initial: 0, integer: true }) + hope: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.hope' }) + }), + evasion: new fields.NumberField({ + required: true, + min: 1, + initial: 10, + integer: true, + label: 'DAGGERHEART.GENERAL.evasion' }), - evasion: new fields.NumberField({ required: true, min: 1, initial: 10, integer: true }), experiences: new fields.TypedObjectField( new fields.SchemaField({ name: new fields.StringField({}), diff --git a/module/documents/_module.mjs b/module/documents/_module.mjs index 4dfa6264..540b06c1 100644 --- a/module/documents/_module.mjs +++ b/module/documents/_module.mjs @@ -3,4 +3,5 @@ export { default as DHItem } from './item.mjs'; export { default as DhpCombat } from './combat.mjs'; export { default as DhActiveEffect } from './activeEffect.mjs'; export { default as DhChatMessage } from './chatMessage.mjs'; +export { default as DhToken } from './token.mjs'; export { default as DhTooltipManager } from './tooltipManager.mjs'; diff --git a/module/documents/token.mjs b/module/documents/token.mjs new file mode 100644 index 00000000..edb0e404 --- /dev/null +++ b/module/documents/token.mjs @@ -0,0 +1,33 @@ +export default class DHToken extends TokenDocument { + /** + * Inspect the Actor data model and identify the set of attributes which could be used for a Token Bar. + * @param {object} attributes The tracked attributes which can be chosen from + * @returns {object} A nested object of attribute choices to display + */ + static getTrackedAttributeChoices(attributes, model) { + attributes = attributes || this.getTrackedAttributes(); + const barGroup = game.i18n.localize('TOKEN.BarAttributes'); + const valueGroup = game.i18n.localize('TOKEN.BarValues'); + + const bars = attributes.bar.map(v => { + const a = v.join('.'); + const modelLabel = model ? game.i18n.localize(model.schema.getField(`${a}.value`).label) : null; + return { group: barGroup, value: a, label: modelLabel ? modelLabel : a }; + }); + bars.sort((a, b) => a.label.compare(b.label)); + + const invalidAttributes = ['gold', 'levelData', 'rules.damageReduction.maxArmorMarked.value']; + const values = attributes.value.reduce((acc, v) => { + const a = v.join('.'); + if (invalidAttributes.some(x => a.startsWith(x))) return acc; + + const modelLabel = model ? game.i18n.localize(model.schema.getField(a).label) : null; + acc.push({ group: valueGroup, value: a, label: modelLabel ? modelLabel : a }); + + return acc; + }, []); + values.sort((a, b) => a.label.compare(b.label)); + + return bars.concat(values); + } +} diff --git a/package-lock.json b/package-lock.json index 7b1bed60..864d027c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "": { "dependencies": { "@yaireo/tagify": "^4.17.9", + "autocompleter": "^9.3.2", "gulp": "^5.0.0", "gulp-less": "^5.0.0", "rollup": "^4.40.0" @@ -608,6 +609,11 @@ "node": ">= 10.13.0" } }, + "node_modules/autocompleter": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/autocompleter/-/autocompleter-9.3.2.tgz", + "integrity": "sha512-rLbf2TLGOD7y+gOS36ksrZdIsvoHa2KXc2A7503w+NBRPrcF73zzFeYBxEcV/iMPjaBH3jFhNIYObZ7zt1fkCQ==" + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", diff --git a/package.json b/package.json index d7b51dfd..a7dd69b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "dependencies": { "@yaireo/tagify": "^4.17.9", + "autocompleter": "^9.3.2", "gulp": "^5.0.0", "gulp-less": "^5.0.0", "rollup": "^4.40.0" diff --git a/styles/less/ux/autocomplete/autocomplete.less b/styles/less/ux/autocomplete/autocomplete.less new file mode 100644 index 00000000..04f11bef --- /dev/null +++ b/styles/less/ux/autocomplete/autocomplete.less @@ -0,0 +1,39 @@ +.theme-light .autocomplete { + background-image: url('../assets/parchments/dh-parchment-dark.png'); +} + +.autocomplete { + padding: 2px; + border-width: 0 1px 1px 1px; + border-style: solid; + border-color: light-dark(@dark-blue, @beige); + border-radius: 6px; + color: light-dark(@beige, @dark); + background-image: url('../assets/parchments/dh-parchment-light.png'); + z-index: 200; + + .group { + font-weight: bold; + font-size: 14px; + padding-left: 8px; + } + + div[role='option'] { + font-size: 14; + padding-left: 16px; + cursor: pointer; + display: flex; + + &:hover { + background: light-dark(@beige-50, @dark-blue); + color: light-dark(@dark, @beige); + } + + .matched { + font-weight: bold; + } + + &.selected { + } + } +} diff --git a/styles/less/ux/index.less b/styles/less/ux/index.less index ff645288..68cfc7e5 100644 --- a/styles/less/ux/index.less +++ b/styles/less/ux/index.less @@ -1 +1,2 @@ @import './tooltip/tooltip.less'; +@import './autocomplete/autocomplete.less'; diff --git a/system.json b/system.json index 7bd337f0..1af469e0 100644 --- a/system.json +++ b/system.json @@ -264,7 +264,7 @@ "applyEffect": {} } }, - "primaryTokenAttribute": "resources.health", + "primaryTokenAttribute": "resources.hitPoints", "secondaryTokenAttribute": "resources.stress", "url": "https://your/hosted/system/repo/", "manifest": "https://your/hosted/system/repo/system.json", diff --git a/templates/sheets/activeEffect/changes.hbs b/templates/sheets/activeEffect/changes.hbs index c1047206..60a90b1f 100644 --- a/templates/sheets/activeEffect/changes.hbs +++ b/templates/sheets/activeEffect/changes.hbs @@ -11,12 +11,12 @@ {{#with ../fields.changes.element.fields as |changeFields|}}
  • - - + + {{!-- {{#each @root.fieldPaths}} {{/each}} - + --}}
    {{formInput changeFields.mode name=(concat "changes." i ".mode") value=change.mode choices=@root.modes}}