mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-04-22 07:23:37 +02:00
Removed last traces of ArmorEffect
This commit is contained in:
parent
6d964ddd43
commit
bfcbb9f290
8 changed files with 41 additions and 273 deletions
25
lang/en.json
25
lang/en.json
|
|
@ -1864,6 +1864,17 @@
|
||||||
"name": "Healing Roll"
|
"name": "Healing Roll"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ChangeTypes": {
|
||||||
|
"armor": {
|
||||||
|
"newArmorEffect": "Armor Effect",
|
||||||
|
"FIELDS": {
|
||||||
|
"armorInteraction": {
|
||||||
|
"label": "Armor Interaction",
|
||||||
|
"hint": "Does the character wearing armor suppress this effect?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Duration": {
|
"Duration": {
|
||||||
"passive": "Passive",
|
"passive": "Passive",
|
||||||
"temporary": "Temporary"
|
"temporary": "Temporary"
|
||||||
|
|
@ -1885,15 +1896,6 @@
|
||||||
"Attachments": {
|
"Attachments": {
|
||||||
"attachHint": "Drop items here to attach them",
|
"attachHint": "Drop items here to attach them",
|
||||||
"transferHint": "If checked, this effect will be applied to any actor that owns this Effect's parent Item. The effect is always applied if this Item is attached to another one."
|
"transferHint": "If checked, this effect will be applied to any actor that owns this Effect's parent Item. The effect is always applied if this Item is attached to another one."
|
||||||
},
|
|
||||||
"Armor": {
|
|
||||||
"newArmorEffect": "Armor Effect",
|
|
||||||
"FIELDS": {
|
|
||||||
"armorInteraction": {
|
|
||||||
"label": "Armor Interaction",
|
|
||||||
"hint": "Does the character wearing armor suppress this effect?"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"GENERAL": {
|
"GENERAL": {
|
||||||
|
|
@ -3079,10 +3081,7 @@
|
||||||
"tokenActorsMissing": "[{names}] missing Actors",
|
"tokenActorsMissing": "[{names}] missing Actors",
|
||||||
"domainTouchRequirement": "This domain card requires {nr} {domain} cards in the loadout to be used",
|
"domainTouchRequirement": "This domain card requires {nr} {domain} cards in the loadout to be used",
|
||||||
"knowTheTide": "Know The Tide gained a token",
|
"knowTheTide": "Know The Tide gained a token",
|
||||||
"lackingItemTransferPermission": "User {user} lacks owner permission needed to transfer items to {target}",
|
"lackingItemTransferPermission": "User {user} lacks owner permission needed to transfer items to {target}"
|
||||||
"cannotAlterArmorEffectChanges": "You cannot alter the changes length of an armor effect",
|
|
||||||
"cannotAlterArmorEffectType": "You cannot alter the type of armor effect changes",
|
|
||||||
"cannotAlterArmorEffectKey": "You cannot alter they key of armor effect changes"
|
|
||||||
},
|
},
|
||||||
"Progress": {
|
"Progress": {
|
||||||
"migrationLabel": "Performing system migration. Please wait and do not close Foundry."
|
"migrationLabel": "Performing system migration. Please wait and do not close Foundry."
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ export default class ArmorSheet extends ItemAttachmentSheet(DHBaseItemSheet) {
|
||||||
const armorEffect = this.document.system.armorEffect;
|
const armorEffect = this.document.system.armorEffect;
|
||||||
if (Number.isNaN(value) || !armorEffect) return;
|
if (Number.isNaN(value) || !armorEffect) return;
|
||||||
|
|
||||||
await armorEffect.system.updateArmorMax(value);
|
await armorEffect.system.armorChange.typeData.updateArmorMax(value);
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,244 +0,0 @@
|
||||||
import { getScrollTextData, itemAbleRollParse } from '../../helpers/utils.mjs';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ArmorEffects are ActiveEffects that have a static changes field of length 1. It includes current and maximum armor.
|
|
||||||
* When applied to a character, it adds to their currently marked and maximum armor.
|
|
||||||
*/
|
|
||||||
export default class ArmorEffect extends foundry.data.ActiveEffectTypeDataModel {
|
|
||||||
static defineSchema() {
|
|
||||||
const fields = foundry.data.fields;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...super.defineSchema(),
|
|
||||||
changes: new fields.ArrayField(
|
|
||||||
new fields.SchemaField({
|
|
||||||
key: new fields.StringField({
|
|
||||||
required: true,
|
|
||||||
nullable: false,
|
|
||||||
initial: 'system.armorScore'
|
|
||||||
}),
|
|
||||||
type: new fields.StringField({
|
|
||||||
required: true,
|
|
||||||
blank: false,
|
|
||||||
initial: CONFIG.DH.GENERAL.activeEffectModes.armor.id,
|
|
||||||
validate: ArmorEffect.#validateType
|
|
||||||
}),
|
|
||||||
phase: new fields.StringField({ required: true, blank: false, initial: 'initial' }),
|
|
||||||
priority: new fields.NumberField({ integer: true, initial: 20 }),
|
|
||||||
value: new fields.NumberField({
|
|
||||||
required: true,
|
|
||||||
integer: true,
|
|
||||||
initial: 0,
|
|
||||||
min: 0,
|
|
||||||
label: 'DAGGERHEART.GENERAL.value'
|
|
||||||
}),
|
|
||||||
max: new fields.StringField({
|
|
||||||
required: true,
|
|
||||||
nullable: false,
|
|
||||||
initial: '1',
|
|
||||||
label: 'DAGGERHEART.GENERAL.max'
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
initial: [
|
|
||||||
{
|
|
||||||
key: 'system.armorScore',
|
|
||||||
type: CONFIG.DH.GENERAL.activeEffectModes.armor.id,
|
|
||||||
phase: 'initial',
|
|
||||||
priority: 20,
|
|
||||||
value: 0,
|
|
||||||
max: '1'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
),
|
|
||||||
armorInteraction: new fields.StringField({
|
|
||||||
required: true,
|
|
||||||
choices: CONFIG.DH.GENERAL.activeEffectArmorInteraction,
|
|
||||||
initial: CONFIG.DH.GENERAL.activeEffectArmorInteraction.none.id,
|
|
||||||
label: 'DAGGERHEART.EFFECTS.Armor.FIELDS.armorInteraction.label',
|
|
||||||
hint: 'DAGGERHEART.EFFECTS.Armor.FIELDS.armorInteraction.hint'
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
get isSuppressed() {
|
|
||||||
if (this.parent.actor?.type !== 'character') return false;
|
|
||||||
|
|
||||||
switch (this.armorInteraction) {
|
|
||||||
case CONFIG.DH.GENERAL.activeEffectArmorInteraction.active.id:
|
|
||||||
return !this.parent.actor.system.armor;
|
|
||||||
case CONFIG.DH.GENERAL.activeEffectArmorInteraction.inactive.id:
|
|
||||||
return Boolean(this.parent.actor.system.armor);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Type Functions */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate that an {@link EffectChangeData#type} string is well-formed.
|
|
||||||
* @param {string} type The string to be validated
|
|
||||||
* @returns {true}
|
|
||||||
* @throws {Error} An error if the type string is malformed
|
|
||||||
*/
|
|
||||||
static #validateType(type) {
|
|
||||||
if (type !== CONFIG.DH.GENERAL.activeEffectModes.armor.id)
|
|
||||||
throw new Error('An armor effect must have change.type "armor"');
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static armorChangeEffect = {
|
|
||||||
label: 'Armor',
|
|
||||||
defaultPriortiy: 20,
|
|
||||||
handler: (actor, change, _options, _field, replacementData) => {
|
|
||||||
game.system.api.documents.DhActiveEffect.applyChange(
|
|
||||||
actor,
|
|
||||||
{
|
|
||||||
...change,
|
|
||||||
key: 'system.armorScore.value',
|
|
||||||
type: CONFIG.DH.GENERAL.activeEffectModes.add.id,
|
|
||||||
value: change.value
|
|
||||||
},
|
|
||||||
replacementData
|
|
||||||
);
|
|
||||||
game.system.api.documents.DhActiveEffect.applyChange(
|
|
||||||
actor,
|
|
||||||
{
|
|
||||||
...change,
|
|
||||||
key: 'system.armorScore.max',
|
|
||||||
type: CONFIG.DH.GENERAL.activeEffectModes.add.id,
|
|
||||||
value: change.max
|
|
||||||
},
|
|
||||||
replacementData
|
|
||||||
);
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
render: null
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Helpers */
|
|
||||||
|
|
||||||
get armorChange() {
|
|
||||||
if (this.changes.length !== 1)
|
|
||||||
throw new Error('Unexpected error. An armor effect should have a changes field of length 1.');
|
|
||||||
|
|
||||||
const actor = this.parent.actor?.type === 'character' ? this.parent.actor : null;
|
|
||||||
const changeData = this.changes[0];
|
|
||||||
const maxParse = actor ? itemAbleRollParse(changeData.max, actor, this.parent.parent) : null;
|
|
||||||
const maxRoll = maxParse ? new Roll(maxParse).evaluateSync() : null;
|
|
||||||
const maxEvaluated = maxRoll ? (maxRoll.isDeterministic ? maxRoll.total : null) : null;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...changeData,
|
|
||||||
max: maxEvaluated ?? changeData.max
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
get armorData() {
|
|
||||||
return { value: this.armorChange.value, max: this.armorChange.max };
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateArmorMax(newMax) {
|
|
||||||
const { effect, ...baseChange } = this.armorChange;
|
|
||||||
const newChanges = [
|
|
||||||
{
|
|
||||||
...baseChange,
|
|
||||||
max: newMax,
|
|
||||||
value: Math.min(this.armorChange.value, newMax)
|
|
||||||
}
|
|
||||||
];
|
|
||||||
await this.parent.update({ 'system.changes': newChanges });
|
|
||||||
}
|
|
||||||
|
|
||||||
static orderEffectsForAutoChange(armorEffects, increasing) {
|
|
||||||
const getEffectWeight = effect => {
|
|
||||||
switch (effect.parent.type) {
|
|
||||||
case 'class':
|
|
||||||
case 'subclass':
|
|
||||||
case 'ancestry':
|
|
||||||
case 'community':
|
|
||||||
case 'feature':
|
|
||||||
case 'domainCard':
|
|
||||||
return 2;
|
|
||||||
case 'armor':
|
|
||||||
return 3;
|
|
||||||
case 'loot':
|
|
||||||
case 'consumable':
|
|
||||||
return 4;
|
|
||||||
case 'weapon':
|
|
||||||
return 5;
|
|
||||||
case 'character':
|
|
||||||
return 6;
|
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return armorEffects
|
|
||||||
.filter(x => !x.disabled && !x.isSuppressed)
|
|
||||||
.sort((a, b) =>
|
|
||||||
increasing ? getEffectWeight(b) - getEffectWeight(a) : getEffectWeight(a) - getEffectWeight(b)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Overrides */
|
|
||||||
|
|
||||||
static getDefaultObject() {
|
|
||||||
return {
|
|
||||||
key: 'system.armorScore',
|
|
||||||
type: 'armor',
|
|
||||||
name: game.i18n.localize('DAGGERHEART.EFFECTS.Armor.newArmorEffect'),
|
|
||||||
img: 'icons/equipment/chest/breastplate-helmet-metal.webp'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async _preUpdate(changes, options, user) {
|
|
||||||
const allowed = await super._preUpdate(changes, options, user);
|
|
||||||
if (allowed === false) return false;
|
|
||||||
|
|
||||||
if (changes.system?.changes) {
|
|
||||||
const changesChanged = changes.system.changes.length !== this.changes.length;
|
|
||||||
if (changesChanged) {
|
|
||||||
ui.notifications.error(
|
|
||||||
game.i18n.localize('DAGGERHEART.UI.Notifications.cannotAlterArmorEffectChanges')
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changes.system.changes.length === 1) {
|
|
||||||
if (changes.system.changes[0].type !== CONFIG.DH.GENERAL.activeEffectModes.armor.id) {
|
|
||||||
ui.notifications.error(
|
|
||||||
game.i18n.localize('DAGGERHEART.UI.Notifications.cannotAlterArmorEffectType')
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changes.system.changes[0].key !== 'system.armorScore') {
|
|
||||||
ui.notifications.error(
|
|
||||||
game.i18n.localize('DAGGERHEART.UI.Notifications.cannotAlterArmorEffectKey')
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
changes.system.changes[0].value !== this.armorChange.value &&
|
|
||||||
this.parent.actor?.type === 'character'
|
|
||||||
) {
|
|
||||||
options.scrollingTextData = [
|
|
||||||
getScrollTextData(this.parent.actor, changes.system.changes[0], 'armor')
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_onUpdate(changes, options, userId) {
|
|
||||||
super._onUpdate(changes, options, userId);
|
|
||||||
|
|
||||||
if (options.scrollingTextData && this.parent.actor?.type === 'character')
|
|
||||||
this.parent.actor.queueScrollText(options.scrollingTextData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -16,8 +16,8 @@ export default class Armor extends foundry.abstract.DataModel {
|
||||||
required: true,
|
required: true,
|
||||||
choices: CONFIG.DH.GENERAL.activeEffectArmorInteraction,
|
choices: CONFIG.DH.GENERAL.activeEffectArmorInteraction,
|
||||||
initial: CONFIG.DH.GENERAL.activeEffectArmorInteraction.none.id,
|
initial: CONFIG.DH.GENERAL.activeEffectArmorInteraction.none.id,
|
||||||
label: 'DAGGERHEART.EFFECTS.Armor.FIELDS.armorInteraction.label',
|
label: 'DAGGERHEART.EFFECTS.ChangeTypes.armor.FIELDS.armorInteraction.label',
|
||||||
hint: 'DAGGERHEART.EFFECTS.Armor.FIELDS.armorInteraction.hint'
|
hint: 'DAGGERHEART.EFFECTS.ChangeTypes.armor.FIELDS.armorInteraction.hint'
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -62,20 +62,31 @@ export default class Armor extends foundry.abstract.DataModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getInitialValue() {
|
static getInitialValue(locked) {
|
||||||
return {
|
return {
|
||||||
key: 'Armor',
|
key: 'Armor',
|
||||||
type: CONFIG.DH.GENERAL.activeEffectModes.armor.id,
|
type: CONFIG.DH.GENERAL.activeEffectModes.armor.id,
|
||||||
value: 0,
|
value: 0,
|
||||||
typeData: {
|
typeData: {
|
||||||
type: 'armor',
|
type: 'armor',
|
||||||
max: 0
|
max: 0,
|
||||||
|
locked
|
||||||
},
|
},
|
||||||
phase: 'initial',
|
phase: 'initial',
|
||||||
priority: 20
|
priority: 20
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getDefaultArmorEffect() {
|
||||||
|
return {
|
||||||
|
name: game.i18n.localize('DAGGERHEART.EFFECTS.ChangeTypes.armor.newArmorEffect'),
|
||||||
|
img: 'icons/equipment/chest/breastplate-helmet-metal.webp',
|
||||||
|
system: {
|
||||||
|
changes: [Armor.getInitialValue(true)]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/* Helpers */
|
/* Helpers */
|
||||||
|
|
||||||
getArmorData(parentChange) {
|
getArmorData(parentChange) {
|
||||||
|
|
@ -94,7 +105,7 @@ export default class Armor extends foundry.abstract.DataModel {
|
||||||
const newChanges = [
|
const newChanges = [
|
||||||
...this.parent.changes.map(change => ({
|
...this.parent.changes.map(change => ({
|
||||||
...change,
|
...change,
|
||||||
value: change.type === 'armor' ? Math.min(this.parent.value, newMax) : change.value,
|
value: change.type === 'armor' ? Math.min(change.value, newMax) : change.value,
|
||||||
typeData: change.type === 'armor' ? { ...change.typeData, max: newMax } : change.typeData
|
typeData: change.type === 'armor' ? { ...change.typeData, max: newMax } : change.typeData
|
||||||
}))
|
}))
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ export default class DHArmor extends AttachableItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
get armorEffect() {
|
get armorEffect() {
|
||||||
return this.parent.effects.find(x => x.type === 'armor');
|
return this.parent.effects.find(x => x.system.armorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
get armorData() {
|
get armorData() {
|
||||||
|
|
@ -80,9 +80,9 @@ export default class DHArmor extends AttachableItem {
|
||||||
async _onCreate(_data, _options, userId) {
|
async _onCreate(_data, _options, userId) {
|
||||||
if (userId !== game.user.id) return;
|
if (userId !== game.user.id) return;
|
||||||
|
|
||||||
if (!this.parent.effects.some(x => x.type === 'armor')) {
|
if (!this.parent.effects.some(x => x.system.armorData)) {
|
||||||
this.parent.createEmbeddedDocuments('ActiveEffect', [
|
this.parent.createEmbeddedDocuments('ActiveEffect', [
|
||||||
game.system.api.data.activeEffects.ArmorEffect.getDefaultObject()
|
game.system.api.data.activeEffects.changeTypes.armor.getDefaultArmorEffect()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -374,16 +374,19 @@ export async function runMigrations() {
|
||||||
if (migrationArmorScore !== undefined && !hasArmorEffect) {
|
if (migrationArmorScore !== undefined && !hasArmorEffect) {
|
||||||
await item.createEmbeddedDocuments('ActiveEffect', [
|
await item.createEmbeddedDocuments('ActiveEffect', [
|
||||||
{
|
{
|
||||||
...game.system.api.data.activeEffects.ArmorEffect.getDefaultObject(),
|
...game.system.api.data.activeEffects.changeTypes.armor.getDefaultArmorEffect(),
|
||||||
changes: [
|
changes: [
|
||||||
{
|
{
|
||||||
key: 'system.armorScore',
|
key: 'Armor',
|
||||||
type: CONFIG.DH.GENERAL.activeEffectModes.armor.id,
|
type: CONFIG.DH.GENERAL.activeEffectModes.armor,
|
||||||
phase: 'initial',
|
phase: 'initial',
|
||||||
priority: 20,
|
priority: 20,
|
||||||
value: 0,
|
value: 0,
|
||||||
|
typeData: {
|
||||||
|
type: 'armor',
|
||||||
max: migrationArmorScore.toString()
|
max: migrationArmorScore.toString()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
|
|
@ -278,8 +278,7 @@
|
||||||
},
|
},
|
||||||
"ActiveEffect": {
|
"ActiveEffect": {
|
||||||
"beastform": {},
|
"beastform": {},
|
||||||
"horde": {},
|
"horde": {}
|
||||||
"armor": {}
|
|
||||||
},
|
},
|
||||||
"Combat": {
|
"Combat": {
|
||||||
"combat": {}
|
"combat": {}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<fieldset class="armor-change-container {{#unless typedChanges.armor}}empty{{/unless}}">
|
<fieldset class="armor-change-container">
|
||||||
<legend>{{localize "DAGGERHEART.GENERAL.armor"}} <input type="checkbox" class="armor-change-checkbox" data-index="{{typedChanges.armor.index}}" {{checked typedChanges.armor}} /></legend>
|
<legend>{{localize "DAGGERHEART.GENERAL.armor"}} <input type="checkbox" class="armor-change-checkbox" data-index="{{typedChanges.armor.index}}" {{checked typedChanges.armor}} /></legend>
|
||||||
{{#if typedChanges.armor}}
|
{{#if typedChanges.armor}}
|
||||||
<header>
|
<header>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue