Fixed translation of TrackedAttributeChoices

This commit is contained in:
WBHarry 2025-07-14 21:18:24 +02:00
parent a768b1dfdb
commit ad9a72d494
18 changed files with 410 additions and 91 deletions

View file

@ -61,6 +61,14 @@ Hooks.once('init', () => {
CONFIG.Dice.rolls = [...CONFIG.Dice.rolls, ...[DHRoll, DualityRoll, D20Roll, DamageRoll]]; CONFIG.Dice.rolls = [...CONFIG.Dice.rolls, ...[DHRoll, DualityRoll, D20Roll, DamageRoll]];
CONFIG.MeasuredTemplate.objectClass = placeables.DhMeasuredTemplate; 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; CONFIG.Item.documentClass = documents.DHItem;
//Registering the Item DataModel //Registering the Item DataModel
@ -98,12 +106,12 @@ Hooks.once('init', () => {
CONFIG.ActiveEffect.documentClass = documents.DhActiveEffect; CONFIG.ActiveEffect.documentClass = documents.DhActiveEffect;
CONFIG.ActiveEffect.dataModels = models.activeEffects.config; CONFIG.ActiveEffect.dataModels = models.activeEffects.config;
foundry.applications.apps.DocumentSheetConfig.unregisterSheet( DocumentSheetConfig.unregisterSheet(
CONFIG.ActiveEffect.documentClass, CONFIG.ActiveEffect.documentClass,
'core', 'core',
foundry.applications.sheets.ActiveEffectConfig foundry.applications.sheets.ActiveEffectConfig
); );
foundry.applications.apps.DocumentSheetConfig.registerSheet( DocumentSheetConfig.registerSheet(
CONFIG.ActiveEffect.documentClass, CONFIG.ActiveEffect.documentClass,
SYSTEM.id, SYSTEM.id,
applications.sheetConfigs.ActiveEffectConfig, applications.sheetConfigs.ActiveEffectConfig,

View file

@ -1011,23 +1011,36 @@
"severe": "Severe", "severe": "Severe",
"major": "Major", "major": "Major",
"minor": "Minor", "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": { "DamageResistance": {
"none": "None", "none": "None",
"resistance": "Resistance", "resistance": "Resistance",
"immunity": "Immunity" "immunity": "Immunity",
"physicalReduction": "Physical Damage Reduction",
"magicalReduction": "Magical Damage Reduction"
}, },
"DamageThresholds": { "DamageThresholds": {
"title": "Damage Thresholds", "title": "Damage Thresholds",
"minor": "Minor", "minor": "Minor",
"major": "Major", "major": "Major",
"severe": "Severe" "severe": "Severe",
"majorThreshold": "Major Damage Threshold",
"severeThreshold": "Severe Damage Threshold"
}, },
"Dice": { "Dice": {
"single": "Die", "single": "Die",
"plural": "Dice" "plural": "Dice"
}, },
"Difficulty": {
"all": "Difficulty: all",
"reaction": "Difficulty: reaction"
},
"Disadvantage": { "Disadvantage": {
"full": "Disadvantage", "full": "Disadvantage",
"short": "Dis" "short": "Dis"
@ -1093,6 +1106,25 @@
"single": "Resource", "single": "Resource",
"plural": "Resources" "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": { "Tabs": {
"details": "Details", "details": "Details",
"attack": "Attack", "attack": "Attack",
@ -1137,6 +1169,7 @@
"single": "Trait", "single": "Trait",
"plural": "Traits" "plural": "Traits"
}, },
"armorScore": "Armor Score",
"activeEffects": "Active Effects", "activeEffects": "Active Effects",
"attack": "Attack", "attack": "Attack",
"basics": "Basics", "basics": "Basics",
@ -1155,6 +1188,7 @@
"features": "Features", "features": "Features",
"hitPoints": "Hit Points", "hitPoints": "Hit Points",
"hope": "Hope", "hope": "Hope",
"hordeHp": "Horde HP",
"inactiveEffects": "Inactive Effects", "inactiveEffects": "Inactive Effects",
"inventory": "Inventory", "inventory": "Inventory",
"level": "Level", "level": "Level",
@ -1162,6 +1196,7 @@
"modifier": "Modifier", "modifier": "Modifier",
"multiclass": "Multiclass", "multiclass": "Multiclass",
"none": "None", "none": "None",
"proficiency": "Proficiency",
"quantity": "Quantity", "quantity": "Quantity",
"range": "Range", "range": "Range",
"recovery": "Recovery", "recovery": "Recovery",

View file

@ -3,3 +3,5 @@ export { default as AdversarySettings } from './adversary-settings.mjs';
export { default as CompanionSettings } from './companion-settings.mjs'; export { default as CompanionSettings } from './companion-settings.mjs';
export { default as EnvironmentSettings } from './environment-settings.mjs'; export { default as EnvironmentSettings } from './environment-settings.mjs';
export { default as ActiveEffectConfig } from './activeEffectConfig.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';

View file

@ -1,4 +1,44 @@
import autocomplete from 'autocompleter';
export default class DhActiveEffectConfig extends foundry.applications.sheets.ActiveEffectConfig { 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 = { static DEFAULT_OPTIONS = {
classes: ['daggerheart', 'sheet', 'dh-style'] 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) { async _preparePartContext(partId, context) {
const partContext = await super._preparePartContext(partId, context); const partContext = await super._preparePartContext(partId, context);
switch (partId) { switch (partId) {
case 'changes': 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; break;
} }
return partContext; 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;
}
} }

View file

@ -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
};
}
}

View file

@ -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
};
}
}

View file

@ -2,9 +2,9 @@ import DHAdversarySettings from '../../applications/sheets-configs/adversary-set
import ActionField from '../fields/actionField.mjs'; import ActionField from '../fields/actionField.mjs';
import BaseDataActor from './base.mjs'; import BaseDataActor from './base.mjs';
const resourceField = () => const resourceField = label =>
new foundry.data.fields.SchemaField({ 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 }), max: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
isReversed: new foundry.data.fields.BooleanField({ initial: true }) isReversed: new foundry.data.fields.BooleanField({ initial: true })
}); });
@ -37,14 +37,29 @@ export default class DhpAdversary extends BaseDataActor {
motivesAndTactics: new fields.StringField(), motivesAndTactics: new fields.StringField(),
notes: new fields.HTMLField(), notes: new fields.HTMLField(),
difficulty: new fields.NumberField({ required: true, initial: 1, integer: true }), 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({ damageThresholds: new fields.SchemaField({
major: new fields.NumberField({ required: true, initial: 0, integer: true }), major: new fields.NumberField({
severe: new fields.NumberField({ required: true, initial: 0, integer: true }) 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({ resources: new fields.SchemaField({
hitPoints: resourceField(), hitPoints: resourceField('DAGGERHEART.GENERAL.hitPoints'),
stress: resourceField() stress: resourceField('DAGGERHEART.GENERAL.stress')
}), }),
attack: new ActionField({ attack: new ActionField({
initial: { initial: {
@ -81,8 +96,16 @@ export default class DhpAdversary extends BaseDataActor {
), ),
bonuses: new fields.SchemaField({ bonuses: new fields.SchemaField({
difficulty: new fields.SchemaField({ difficulty: new fields.SchemaField({
all: new fields.NumberField({ integer: true, initial: 0 }), all: new fields.NumberField({
reaction: new fields.NumberField({ integer: true, initial: 0 }) integer: true,
initial: 0,
label: 'DAGGERHEART.GENERAL.Difficulty.all'
}),
reaction: new fields.NumberField({
integer: true,
initial: 0,
label: 'DAGGERHEART.GENERAL.Difficulty.reaction'
})
}) })
}) })
}; };

View file

@ -1,10 +1,10 @@
import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs'; import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs';
const resistanceField = () => const resistanceField = reductionLabel =>
new foundry.data.fields.SchemaField({ new foundry.data.fields.SchemaField({
resistance: new foundry.data.fields.BooleanField({ initial: false }), resistance: new foundry.data.fields.BooleanField({ initial: false }),
immunity: 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.isNPC) schema.description = new fields.HTMLField({ required: true, nullable: true });
if (this.metadata.hasResistances) if (this.metadata.hasResistances)
schema.resistance = new fields.SchemaField({ schema.resistance = new fields.SchemaField({
physical: resistanceField(), physical: resistanceField('DAGGERHEART.GENERAL.DamageResistance.physicalReduction'),
magical: resistanceField() magical: resistanceField('DAGGERHEART.GENERAL.DamageResistance.magicalReduction')
}); });
return schema; return schema;
} }

View file

@ -3,26 +3,28 @@ import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
import DhLevelData from '../levelData.mjs'; import DhLevelData from '../levelData.mjs';
import BaseDataActor from './base.mjs'; import BaseDataActor from './base.mjs';
const attributeField = () => const attributeField = label =>
new foundry.data.fields.SchemaField({ 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 }) tierMarked: new foundry.data.fields.BooleanField({ initial: false })
}); });
const resourceField = (max, reverse = false) => const resourceField = (max, label, reverse = false) =>
new foundry.data.fields.SchemaField({ 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 }), max: new foundry.data.fields.NumberField({ initial: max, integer: true }),
isReversed: new foundry.data.fields.BooleanField({ initial: reverse }) isReversed: new foundry.data.fields.BooleanField({ initial: reverse })
}); });
const stressDamageReductionRule = () => const stressDamageReductionRule = label =>
new foundry.data.fields.SchemaField({ new foundry.data.fields.SchemaField({
enabled: new foundry.data.fields.BooleanField({ required: true, initial: false }), 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 { export default class DhCharacter extends BaseDataActor {
static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Character'];
static get metadata() { static get metadata() {
return foundry.utils.mergeObject(super.metadata, { return foundry.utils.mergeObject(super.metadata, {
label: 'TYPES.Actor.character', label: 'TYPES.Actor.character',
@ -37,24 +39,36 @@ export default class DhCharacter extends BaseDataActor {
return { return {
...super.defineSchema(), ...super.defineSchema(),
resources: new fields.SchemaField({ resources: new fields.SchemaField({
hitPoints: resourceField(0, true), hitPoints: resourceField(0, 'DAGGERHEART.GENERAL.hitPoints', true),
stress: resourceField(6, true), stress: resourceField(6, 'DAGGERHEART.GENERAL.stress', true),
hope: resourceField(6) hope: resourceField(6, 'DAGGERHEART.GENERAL.hope')
}), }),
traits: new fields.SchemaField({ traits: new fields.SchemaField({
agility: attributeField(), agility: attributeField('DAGGERHEART.CONFIG.Traits.agility.name'),
strength: attributeField(), strength: attributeField('DAGGERHEART.CONFIG.Traits.strength.name'),
finesse: attributeField(), finesse: attributeField('DAGGERHEART.CONFIG.Traits.finesse.name'),
instinct: attributeField(), instinct: attributeField('DAGGERHEART.CONFIG.Traits.instinct.name'),
presence: attributeField(), presence: attributeField('DAGGERHEART.CONFIG.Traits.presence.name'),
knowledge: attributeField() knowledge: attributeField('DAGGERHEART.CONFIG.Traits.knowledge.name')
}), }),
proficiency: new fields.NumberField({ initial: 1, integer: true }), proficiency: new fields.NumberField({
evasion: new fields.NumberField({ initial: 0, integer: true }), initial: 1,
armorScore: new fields.NumberField({ integer: true, initial: 0 }), 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({ damageThresholds: new fields.SchemaField({
severe: new fields.NumberField({ integer: true, initial: 0 }), severe: new fields.NumberField({
major: new fields.NumberField({ integer: true, initial: 0 }) 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( experiences: new fields.TypedObjectField(
new fields.SchemaField({ new fields.SchemaField({
@ -94,21 +108,59 @@ export default class DhCharacter extends BaseDataActor {
levelData: new fields.EmbeddedDataField(DhLevelData), levelData: new fields.EmbeddedDataField(DhLevelData),
bonuses: new fields.SchemaField({ bonuses: new fields.SchemaField({
roll: new fields.SchemaField({ roll: new fields.SchemaField({
attack: new fields.NumberField({ integer: true, initial: 0 }), attack: new fields.NumberField({
primaryWeapon: new fields.SchemaField({ integer: true,
attack: new fields.NumberField({ integer: true, initial: 0 }) initial: 0,
label: 'DAGGERHEART.GENERAL.Roll.attack'
}), }),
spellcast: new fields.NumberField({ integer: true, initial: 0 }), primaryWeapon: new fields.SchemaField({
action: new fields.NumberField({ integer: true, initial: 0 }), attack: new fields.NumberField({
hopeOrFear: new fields.NumberField({ integer: true, initial: 0 }) 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({ damage: new fields.SchemaField({
all: new fields.NumberField({ integer: true, initial: 0 }), all: new fields.NumberField({
physical: new fields.NumberField({ integer: true, initial: 0 }), integer: true,
magic: new fields.NumberField({ integer: true, initial: 0 }), 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({ primaryWeapon: new fields.SchemaField({
bonus: new fields.NumberField({ integer: true }), bonus: new fields.NumberField({
extraDice: new fields.NumberField({ integer: true }) 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({ damageReduction: new fields.SchemaField({
maxArmorMarked: new fields.SchemaField({ maxArmorMarked: new fields.SchemaField({
value: new fields.NumberField({ required: true, integer: true, initial: 1 }), value: new fields.NumberField({ required: true, integer: true, initial: 1 }),
bonus: new fields.NumberField({ required: true, integer: true, initial: 0 }), bonus: new fields.NumberField({
stressExtra: new fields.NumberField({ required: true, integer: true, initial: 0 }) 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({ stressDamageReduction: new fields.SchemaField({
severe: stressDamageReductionRule(), severe: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.severe'),
major: stressDamageReductionRule(), major: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.major'),
minor: stressDamageReductionRule() 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 }), magical: new fields.BooleanField({ initial: false }),
physical: 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({ weapon: new fields.SchemaField({
/* Unimplemented /* Unimplemented
-> Should remove the lowest damage dice from weapon damage -> Should remove the lowest damage dice from weapon damage

View file

@ -28,9 +28,15 @@ export default class DhCompanion extends BaseDataActor {
max: new fields.NumberField({ initial: 3, integer: true }), max: new fields.NumberField({ initial: 3, integer: true }),
isReversed: new foundry.data.fields.BooleanField({ initial: 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( experiences: new fields.TypedObjectField(
new fields.SchemaField({ new fields.SchemaField({
name: new fields.StringField({}), name: new fields.StringField({}),

View file

@ -3,4 +3,5 @@ export { default as DHItem } from './item.mjs';
export { default as DhpCombat } from './combat.mjs'; export { default as DhpCombat } from './combat.mjs';
export { default as DhActiveEffect } from './activeEffect.mjs'; export { default as DhActiveEffect } from './activeEffect.mjs';
export { default as DhChatMessage } from './chatMessage.mjs'; export { default as DhChatMessage } from './chatMessage.mjs';
export { default as DhToken } from './token.mjs';
export { default as DhTooltipManager } from './tooltipManager.mjs'; export { default as DhTooltipManager } from './tooltipManager.mjs';

View file

@ -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);
}
}

6
package-lock.json generated
View file

@ -6,6 +6,7 @@
"": { "": {
"dependencies": { "dependencies": {
"@yaireo/tagify": "^4.17.9", "@yaireo/tagify": "^4.17.9",
"autocompleter": "^9.3.2",
"gulp": "^5.0.0", "gulp": "^5.0.0",
"gulp-less": "^5.0.0", "gulp-less": "^5.0.0",
"rollup": "^4.40.0" "rollup": "^4.40.0"
@ -608,6 +609,11 @@
"node": ">= 10.13.0" "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": { "node_modules/available-typed-arrays": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",

View file

@ -1,6 +1,7 @@
{ {
"dependencies": { "dependencies": {
"@yaireo/tagify": "^4.17.9", "@yaireo/tagify": "^4.17.9",
"autocompleter": "^9.3.2",
"gulp": "^5.0.0", "gulp": "^5.0.0",
"gulp-less": "^5.0.0", "gulp-less": "^5.0.0",
"rollup": "^4.40.0" "rollup": "^4.40.0"

View file

@ -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 {
}
}
}

View file

@ -1 +1,2 @@
@import './tooltip/tooltip.less'; @import './tooltip/tooltip.less';
@import './autocomplete/autocomplete.less';

View file

@ -264,7 +264,7 @@
"applyEffect": {} "applyEffect": {}
} }
}, },
"primaryTokenAttribute": "resources.health", "primaryTokenAttribute": "resources.hitPoints",
"secondaryTokenAttribute": "resources.stress", "secondaryTokenAttribute": "resources.stress",
"url": "https://your/hosted/system/repo/", "url": "https://your/hosted/system/repo/",
"manifest": "https://your/hosted/system/repo/system.json", "manifest": "https://your/hosted/system/repo/system.json",

View file

@ -11,12 +11,12 @@
{{#with ../fields.changes.element.fields as |changeFields|}} {{#with ../fields.changes.element.fields as |changeFields|}}
<li data-index="{{i}}"> <li data-index="{{i}}">
<div class="key"> <div class="key">
<input type="text" name="{{concat "changes." i ".key"}}" value="{{change.key}}" list="change-fields" /> <input type="text" class="effect-change-input" name="{{concat "changes." i ".key"}}" value="{{change.key}}" />
<datalist id="change-fields"> {{!-- <datalist id="change-fields">
{{#each @root.fieldPaths}} {{#each @root.fieldPaths}}
<option value="{{this}}">{{this}}</option> <option value="{{this}}">{{this}}</option>
{{/each}} {{/each}}
</datalist> </datalist> --}}
</div> </div>
<div class="mode"> <div class="mode">
{{formInput changeFields.mode name=(concat "changes." i ".mode") value=change.mode choices=@root.modes}} {{formInput changeFields.mode name=(concat "changes." i ".mode") value=change.mode choices=@root.modes}}