Various fixes

This commit is contained in:
WBHarry 2025-07-27 13:06:26 +02:00
parent 5cd9075732
commit e55809f988
16 changed files with 152 additions and 74 deletions

View file

@ -196,9 +196,9 @@ Hooks.on('chatMessage', (_, message) => {
const traitValue = rollCommand.trait?.toLowerCase(); const traitValue = rollCommand.trait?.toLowerCase();
const advantage = rollCommand.advantage const advantage = rollCommand.advantage
? CONFIG.DH.ACTIONS.advandtageState.advantage.value ? CONFIG.DH.ACTIONS.advantageState.advantage.value
: rollCommand.disadvantage : rollCommand.disadvantage
? CONFIG.DH.ACTIONS.advandtageState.disadvantage.value ? CONFIG.DH.ACTIONS.advantageState.disadvantage.value
: undefined; : undefined;
const difficulty = rollCommand.difficulty; const difficulty = rollCommand.difficulty;

View file

@ -28,26 +28,6 @@
}, },
"DAGGERHEART": { "DAGGERHEART": {
"ACTIONS": { "ACTIONS": {
"Config": {
"beastform": {
"exact": "Beastform Max Tier",
"exactHint": "The Character's Tier is used if empty",
"label": "Beastform"
},
"displayInChat": "Display in chat"
},
"Settings": {
"attackBonus": "Attack Bonus",
"attackName": "Attack Name",
"includeBase": { "label": "Include Item Damage" },
"multiplier": "Multiplier",
"resultBased": {
"label": "Formula based on Hope/Fear result."
},
"applyTo": {
"label": "Targeted Resource"
}
},
"TYPES": { "TYPES": {
"attack": { "attack": {
"name": "Attack", "name": "Attack",
@ -77,6 +57,35 @@
"name": "Summon", "name": "Summon",
"tooltip": "Create tokens in the scene." "tooltip": "Create tokens in the scene."
} }
},
"Config": {
"beastform": {
"exact": "Beastform Max Tier",
"exactHint": "The Character's Tier is used if empty",
"label": "Beastform"
},
"displayInChat": "Display in chat"
},
"RollField": {
"diceRolling": {
"compare": "Should be",
"dice": "Dice Type",
"flatMultiplier": "Flat Multiplier",
"multiplier": "Dice Number",
"threshold": "Threshold"
}
},
"Settings": {
"attackBonus": "Attack Bonus",
"attackName": "Attack Name",
"includeBase": { "label": "Include Item Damage" },
"multiplier": "Multiplier",
"resultBased": {
"label": "Formula based on Hope/Fear result."
},
"applyTo": {
"label": "Targeted Resource"
}
} }
}, },
"ACTORS": { "ACTORS": {
@ -1107,10 +1116,30 @@
}, },
"DamageResistance": { "DamageResistance": {
"none": "None", "none": "None",
"resistance": "Resistance", "physicalResistance": {
"immunity": "Immunity", "label": "Damage Resistance: Physical",
"physicalReduction": "Physical Damage Reduction", "hint": "Physical Damage is halved if this is set to 1"
"magicalReduction": "Magical Damage Reduction" },
"magicalResistance": {
"label": "Damage Resistance: Magical",
"hint": "Magical Damage is halved if this is set to 1"
},
"physicalImmunity": {
"label": "Damage Immunity: Physical",
"hint": "Immune to Physical Damage if this is set to 1"
},
"magicalImmunity": {
"label": "Damage Immunity: Magical",
"hint": "Immune to Magical Damage if this is set to 1"
},
"physicalReduction": {
"label": "Damage Reduction: Physical",
"hint": "Physical Damage is reduced by the amount set here"
},
"magicalReduction": {
"label": "Damage Reduction: Magical",
"hint": "Magical Damage is reduced by the amount set here"
}
}, },
"DamageThresholds": { "DamageThresholds": {
"title": "Damage Thresholds", "title": "Damage Thresholds",

View file

@ -249,12 +249,20 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
const target = event.target.closest('fieldset.drop-section'); const target = event.target.closest('fieldset.drop-section');
const item = await fromUuid(data.uuid); const item = await fromUuid(data.uuid);
if (item?.type === 'feature') { if (item?.type === 'feature') {
if (target.dataset.type) {
await this.document.update({ await this.document.update({
'system.features': [...this.document.system.features, { type: target.dataset.type, item }].map(x => ({ 'system.features': [...this.document.system.features, { type: target.dataset.type, item }].map(
x => ({
...x, ...x,
item: x.item?.uuid item: x.item?.uuid
})) })
)
});
} else {
await this.document.update({
'system.features': [...this.document.system.features, item].map(x => x.uuid)
}); });
} }
} }
}
} }

View file

@ -66,8 +66,8 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
super.close(options); super.close(options);
} }
async getActor(id) { async getActor(uuid) {
return await fromUuid(id); return await foundry.utils.fromUuid(uuid);
} }
getAction(actor, itemId, actionId) { getAction(actor, itemId, actionId) {

View file

@ -108,7 +108,7 @@ export const diceCompare = {
} }
}; };
export const advandtageState = { export const advantageState = {
disadvantage: { disadvantage: {
label: 'DAGGERHEART.GENERAL.Disadvantage.full', label: 'DAGGERHEART.GENERAL.Disadvantage.full',
value: -1 value: -1

View file

@ -164,7 +164,8 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
title: this.item.name, title: this.item.name,
source: { source: {
item: this.item._id, item: this.item._id,
action: this._id action: this._id,
actor: this.actor.uuid
}, },
dialog: {}, dialog: {},
type: this.type, type: this.type,
@ -191,7 +192,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
difficulty: this.roll?.difficulty, difficulty: this.roll?.difficulty,
formula: this.roll.getFormula(), formula: this.roll.getFormula(),
bonus: this.roll.bonus, bonus: this.roll.bonus,
advantage: CONFIG.DH.ACTIONS.advandtageState[this.roll.advState].value advantage: CONFIG.DH.ACTIONS.advantageState[this.roll.advState].value
}; };
if (this.roll?.type === 'diceSet') roll.lite = true; if (this.roll?.type === 'diceSet') roll.lite = true;
@ -256,6 +257,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
/* EFFECTS */ /* EFFECTS */
async applyEffects(event, data, targets) { async applyEffects(event, data, targets) {
targets ??= data.system.targets; targets ??= data.system.targets;
const force = true; /* Where should this come from? */
if (!this.effects?.length || !targets.length) return; if (!this.effects?.length || !targets.length) return;
let effects = this.effects; let effects = this.effects;
targets.forEach(async token => { targets.forEach(async token => {

View file

@ -1,10 +1,23 @@
import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs'; import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs';
const resistanceField = reductionLabel => const resistanceField = (resistanceLabel, immunityLabel, 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({
immunity: new foundry.data.fields.BooleanField({ initial: false }), initial: false,
reduction: new foundry.data.fields.NumberField({ integer: true, initial: 0, label: reductionLabel }) label: `${resistanceLabel}.label`,
hint: `${resistanceLabel}.hint`
}),
immunity: new foundry.data.fields.BooleanField({
initial: false,
label: `${immunityLabel}.label`,
hint: `${immunityLabel}.hint`
}),
reduction: new foundry.data.fields.NumberField({
integer: true,
initial: 0,
label: `${reductionLabel}.label`,
hint: `${reductionLabel}.hint`
})
}); });
/** /**
@ -40,8 +53,16 @@ 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('DAGGERHEART.GENERAL.DamageResistance.physicalReduction'), physical: resistanceField(
magical: resistanceField('DAGGERHEART.GENERAL.DamageResistance.magicalReduction') 'DAGGERHEART.GENERAL.DamageResistance.physicalResistance',
'DAGGERHEART.GENERAL.DamageResistance.physicalImmunity',
'DAGGERHEART.GENERAL.DamageResistance.physicalReduction'
),
magical: resistanceField(
'DAGGERHEART.GENERAL.DamageResistance.magicalResistance',
'DAGGERHEART.GENERAL.DamageResistance.magicalImmunity',
'DAGGERHEART.GENERAL.DamageResistance.magicalReduction'
)
}); });
return schema; return schema;
} }

View file

@ -45,12 +45,12 @@ export default class DhCharacter extends BaseDataActor {
severe: new fields.NumberField({ severe: new fields.NumberField({
integer: true, integer: true,
initial: 0, initial: 0,
label: 'DAGGERHEART.GENERAL.DamageThresholds.majorThreshold' label: 'DAGGERHEART.GENERAL.DamageThresholds.severeThreshold'
}), }),
major: new fields.NumberField({ major: new fields.NumberField({
integer: true, integer: true,
initial: 0, initial: 0,
label: 'DAGGERHEART.GENERAL.DamageThresholds.severeThreshold' label: 'DAGGERHEART.GENERAL.DamageThresholds.majorThreshold'
}) })
}), }),
experiences: new fields.TypedObjectField( experiences: new fields.TypedObjectField(

View file

@ -8,25 +8,38 @@ export class DHActionRollData extends foundry.abstract.DataModel {
trait: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.ACTOR.abilities }), trait: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.ACTOR.abilities }),
difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }), difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }),
bonus: new fields.NumberField({ nullable: true, initial: null, integer: true }), bonus: new fields.NumberField({ nullable: true, initial: null, integer: true }),
advState: new fields.StringField({ choices: CONFIG.DH.ACTIONS.advandtageState, initial: 'neutral' }), advState: new fields.StringField({
choices: CONFIG.DH.ACTIONS.advantageState,
initial: CONFIG.DH.ACTIONS.advantageState.neutral.label
}),
diceRolling: new fields.SchemaField({ diceRolling: new fields.SchemaField({
multiplier: new fields.StringField({ multiplier: new fields.StringField({
choices: CONFIG.DH.GENERAL.diceSetNumbers, choices: CONFIG.DH.GENERAL.diceSetNumbers,
initial: 'prof', initial: CONFIG.DH.GENERAL.diceSetNumbers.prof,
label: 'Dice Number' label: 'DAGGERHEART.ACTIONS.RollField.diceRolling.multiplier'
}),
flatMultiplier: new fields.NumberField({
nullable: true,
initial: 1,
label: 'DAGGERHEART.ACTIONS.RollField.diceRolling.flatMultiplier'
}), }),
flatMultiplier: new fields.NumberField({ nullable: true, initial: 1, label: 'Flat Multiplier' }),
dice: new fields.StringField({ dice: new fields.StringField({
choices: CONFIG.DH.GENERAL.diceTypes, choices: CONFIG.DH.GENERAL.diceTypes,
initial: 'd6', initial: CONFIG.DH.GENERAL.diceTypes.d6,
label: 'Dice Type' label: 'DAGGERHEART.ACTIONS.RollField.diceRolling.dice'
}), }),
compare: new fields.StringField({ compare: new fields.StringField({
choices: CONFIG.DH.ACTIONS.diceCompare, choices: CONFIG.DH.ACTIONS.diceCompare,
initial: 'above', nullable: true,
label: 'Should be' initial: null,
label: 'DAGGERHEART.ACTIONS.RollField.diceRolling.compare'
}), }),
treshold: new fields.NumberField({ initial: 1, integer: true, min: 1, label: 'Treshold' }) treshold: new fields.NumberField({
integer: true,
nullable: true,
initial: null,
label: 'DAGGERHEART.ACTIONS.RollField.diceRolling.threshold'
})
}), }),
useDefault: new fields.BooleanField({ initial: false }) useDefault: new fields.BooleanField({ initial: false })
}; };
@ -41,7 +54,11 @@ export class DHActionRollData extends foundry.abstract.DataModel {
this.diceRolling.multiplier === 'flat' this.diceRolling.multiplier === 'flat'
? this.diceRolling.flatMultiplier ? this.diceRolling.flatMultiplier
: `@${this.diceRolling.multiplier}`; : `@${this.diceRolling.multiplier}`;
if (this.diceRolling.compare && this.diceRolling.threshold) {
formula = `${multiplier}${this.diceRolling.dice}cs${CONFIG.DH.ACTIONS.diceCompare[this.diceRolling.compare].operator}${this.diceRolling.treshold}`; formula = `${multiplier}${this.diceRolling.dice}cs${CONFIG.DH.ACTIONS.diceCompare[this.diceRolling.compare].operator}${this.diceRolling.treshold}`;
} else {
formula = `${multiplier}${this.diceRolling.dice}`;
}
break; break;
default: default:
formula = ''; formula = '';

View file

@ -1,5 +1,4 @@
import AttachableItem from './attachableItem.mjs'; import AttachableItem from './attachableItem.mjs';
import { ActionsField } from '../fields/actionField.mjs';
import { armorFeatures } from '../../config/itemConfig.mjs'; import { armorFeatures } from '../../config/itemConfig.mjs';
export default class DHArmor extends AttachableItem { export default class DHArmor extends AttachableItem {

View file

@ -152,6 +152,7 @@ export default class DHBeastform extends BaseDataItem {
_onCreate(_data, _options, userId) { _onCreate(_data, _options, userId) {
if (userId !== game.user.id) return; if (userId !== game.user.id) return;
if (!this.parent.effects.find(x => x.type === 'beastform')) {
this.parent.createEmbeddedDocuments('ActiveEffect', [ this.parent.createEmbeddedDocuments('ActiveEffect', [
{ {
type: 'beastform', type: 'beastform',
@ -160,4 +161,5 @@ export default class DHBeastform extends BaseDataItem {
} }
]); ]);
} }
}
} }

View file

@ -22,14 +22,14 @@ function getDualityMessage(roll) {
: game.i18n.localize('DAGGERHEART.GENERAL.duality'); : game.i18n.localize('DAGGERHEART.GENERAL.duality');
const advantage = roll.advantage const advantage = roll.advantage
? CONFIG.DH.ACTIONS.advandtageState.advantage.value ? CONFIG.DH.ACTIONS.advantageState.advantage.value
: roll.disadvantage : roll.disadvantage
? CONFIG.DH.ACTIONS.advandtageState.disadvantage.value ? CONFIG.DH.ACTIONS.advantageState.disadvantage.value
: undefined; : undefined;
const advantageLabel = const advantageLabel =
advantage === CONFIG.DH.ACTIONS.advandtageState.advantage.value advantage === CONFIG.DH.ACTIONS.advantageState.advantage.value
? 'Advantage' ? 'Advantage'
: advantage === CONFIG.DH.ACTIONS.advandtageState.disadvantage.value : advantage === CONFIG.DH.ACTIONS.advantageState.disadvantage.value
? 'Disadvantage' ? 'Disadvantage'
: undefined; : undefined;

View file

@ -271,14 +271,14 @@ export function addLinkedItemsDiff(changedItems, currentItems, options) {
newItems newItems
.difference(prevItems) .difference(prevItems)
.map(item => item?.item ?? item) .map(item => item?.item ?? item)
.filter(x => (typeof x === 'object' ? x.item : x)) .filter(x => (typeof x === 'object' ? x?.item : x))
); );
options.toUnlink = Array.from( options.toUnlink = Array.from(
prevItems prevItems
.difference(newItems) .difference(newItems)
.map(item => item?.item?.uuid ?? item?.uuid ?? item) .map(item => item?.item?.uuid ?? item?.uuid ?? item)
.filter(x => (typeof x === 'object' ? x.item : x)) .filter(x => (typeof x === 'object' ? x?.item : x))
); );
} }
} }

View file

@ -11,9 +11,9 @@
{{#if (eq source.type "diceSet")}} {{#if (eq source.type "diceSet")}}
<div class="nest-inputs"> <div class="nest-inputs">
{{formField fields.diceRolling.fields.multiplier name="roll.diceRolling.multiplier" value=source.diceRolling.multiplier localize=true}} {{formField fields.diceRolling.fields.multiplier name="roll.diceRolling.multiplier" value=source.diceRolling.multiplier localize=true}}
{{#if (eq source.diceRolling.multiplier 'flat')}}{{formField fields.diceRolling.fields.flatMultiplier value=source.diceRolling.flatMultiplier name="roll.diceRolling.flatMultiplier" }}{{/if}} {{#if (eq source.diceRolling.multiplier 'flat')}}{{formField fields.diceRolling.fields.flatMultiplier value=source.diceRolling.flatMultiplier name="roll.diceRolling.flatMultiplier" localize=true }}{{/if}}
{{formField fields.diceRolling.fields.dice name="roll.diceRolling.dice" value=source.diceRolling.dice}} {{formField fields.diceRolling.fields.dice name="roll.diceRolling.dice" value=source.diceRolling.dice localize=true}}
{{formField fields.diceRolling.fields.compare name="roll.diceRolling.compare" value=source.diceRolling.compare localize=true}} {{formField fields.diceRolling.fields.compare name="roll.diceRolling.compare" value=source.diceRolling.compare localize=true blank=""}}
{{formField fields.diceRolling.fields.treshold name="roll.diceRolling.treshold" value=source.diceRolling.treshold localize=true}} {{formField fields.diceRolling.fields.treshold name="roll.diceRolling.treshold" value=source.diceRolling.treshold localize=true}}
</div> </div>
{{else}} {{else}}

View file

@ -22,7 +22,7 @@ Parameters:
- showActions {boolean} : If true show feature's actions. - showActions {boolean} : If true show feature's actions.
--}} --}}
<fieldset class="{{#if isGlassy}}glassy{{/if}}"> <fieldset class="{{#if isGlassy}}glassy{{/if}} drop-section">
<legend> <legend>
{{localize title}} {{localize title}}
{{#if canCreate}} {{#if canCreate}}

View file

@ -189,7 +189,7 @@
{{/if}} {{/if}}
{{/if}} {{/if}}
{{#if hasEffect}} {{#if hasEffect}}
<button class="duality-action{{#if (or hasDamage hasHealing)}} duality-action-effect{{/if}}" data-value="{{roll.total}}"><span>{{localize "DAGGERHEART.UI.Chat.attackRoll.applyEffect"}}</span></button> <button class="duality-action-effect" data-value="{{roll.total}}"><span>{{localize "DAGGERHEART.UI.Chat.attackRoll.applyEffect"}}</span></button>
{{/if}} {{/if}}
<div class="duality-result"> <div class="duality-result">
<div>{{roll.total}} <div>{{roll.total}}