Feature/167 damage types and resistances (#330)

* Add Resistances

* Relocate Damage Reduction

* Damage Types

* dmg type fallback

* Actor getRollData

* Remove comments
This commit is contained in:
Dapoulp 2025-07-12 20:13:09 +02:00 committed by GitHub
parent 3f4c884974
commit 812a5e8dd7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 167 additions and 97 deletions

View file

@ -76,11 +76,7 @@ export class DHActionDiceData extends foundry.abstract.DataModel {
};
}
getFormula(actor) {
/* const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : actor.system[this.multiplier]?.total;
return this.custom.enabled
? this.custom.formula
: `${multiplier ?? 1}${this.dice}${this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : ''}`; */
getFormula() {
const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : `@${this.multiplier}`,
bonus = this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : '';
return this.custom.enabled ? this.custom.formula : `${multiplier ?? 1}${this.dice}${bonus}`;
@ -93,7 +89,6 @@ export class DHDamageField extends fields.SchemaField {
parts: new fields.ArrayField(new fields.EmbeddedDataField(DHDamageData)),
includeBase: new fields.BooleanField({ initial: false })
};
// if (hasBase) damageFields.includeBase = new fields.BooleanField({ initial: true });
super(damageFields, options, context);
}
}
@ -102,15 +97,19 @@ export class DHDamageData extends foundry.abstract.DataModel {
/** @override */
static defineSchema() {
return {
// ...super.defineSchema(),
base: new fields.BooleanField({ initial: false, readonly: true, label: 'Base' }),
type: new fields.StringField({
choices: CONFIG.DH.GENERAL.damageTypes,
initial: 'physical',
label: 'Type',
nullable: false,
required: true
}),
type: new fields.SetField(
new fields.StringField({
choices: CONFIG.DH.GENERAL.damageTypes,
initial: 'physical',
nullable: false,
required: true
}),
{
label: 'Type',
initial: 'physical',
}
),
resultBased: new fields.BooleanField({
initial: false,
label: 'DAGGERHEART.ACTIONS.Settings.resultBased.label'

View file

@ -179,16 +179,9 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
getRollData(data = {}) {
const actorData = this.actor.getRollData(false);
// Remove when included directly in Actor getRollData
actorData.prof = actorData.proficiency?.total ?? 1;
actorData.cast = actorData.spellcast?.total ?? 1;
// Add Roll results to RollDatas
actorData.result = data.roll?.total ?? 1;
/* actorData.scale = data.costs?.length
? data.costs.reduce((a, c) => {
a[c.type] = c.value;
return a;
}, {})
: 1; */
actorData.scale = data.costs?.length // Right now only return the first scalable cost.
? (data.costs.find(c => c.scalable)?.total ?? 1)
: 1;

View file

@ -10,7 +10,10 @@ export default class DHDamageAction extends DHBaseAction {
}
async rollDamage(event, data) {
let formula = this.damage.parts.map(p => this.getFormulaValue(p, data).getFormula(this.actor)).join(' + ');
let formula = this.damage.parts.map(p => this.getFormulaValue(p, data).getFormula(this.actor)).join(' + '),
damageTypes = [...new Set(this.damage.parts.reduce((a,c) => a.concat([...c.type]), []))];
damageTypes = !damageTypes.length ? ['physical'] : damageTypes;
if (!formula || formula == '') return;
let roll = { formula: formula, total: formula },
@ -25,6 +28,7 @@ export default class DHDamageAction extends DHBaseAction {
hasSave: this.hasSave,
isCritical: data.system?.roll?.isCritical ?? false,
source: data.system?.source,
damageTypes,
event
};
if (this.hasSave) config.onSave = this.save.damageMod;
@ -32,7 +36,7 @@ export default class DHDamageAction extends DHBaseAction {
config.source.message = data._id;
config.directDamage = false;
}
roll = CONFIG.Dice.daggerheart.DamageRoll.build(config);
}
}

View file

@ -5,6 +5,7 @@ import BaseDataActor from './base.mjs';
const resourceField = () =>
new foundry.data.fields.SchemaField({
value: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
bonus: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
max: new foundry.data.fields.NumberField({ initial: 0, integer: true })
});
@ -22,6 +23,7 @@ export default class DhpAdversary extends BaseDataActor {
static defineSchema() {
const fields = foundry.data.fields;
return {
...super.defineSchema(),
tier: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.tiers,
@ -32,7 +34,6 @@ export default class DhpAdversary extends BaseDataActor {
choices: CONFIG.DH.ACTOR.adversaryTypes,
initial: CONFIG.DH.ACTOR.adversaryTypes.standard.id
}),
description: new fields.StringField(),
motivesAndTactics: new fields.StringField(),
notes: new fields.HTMLField(),
difficulty: new fields.NumberField({ required: true, initial: 1, integer: true }),
@ -63,6 +64,7 @@ export default class DhpAdversary extends BaseDataActor {
damage: {
parts: [
{
type: ['physical'],
value: {
multiplier: 'flat'
}
@ -93,4 +95,9 @@ export default class DhpAdversary extends BaseDataActor {
get features() {
return this.parent.items.filter(x => x.type === 'feature');
}
prepareDerivedData() {
this.resources.hitPoints.maxTotal = this.resources.hitPoints.max + this.resources.hitPoints.bonus;
this.resources.stress.maxTotal = this.resources.stress.max + this.resources.stress.bonus;
}
}

View file

@ -1,5 +1,12 @@
import DHBaseActorSettings from "../../applications/sheets/api/actor-setting.mjs";
const resistanceField = () =>
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 })
});
/**
* Describes metadata about the actor data model type
* @typedef {Object} ActorDataModelMetadata
@ -16,6 +23,7 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
type: 'base',
isNPC: true,
settingSheet: null,
hasResistances: true
};
}
@ -27,10 +35,16 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
/** @inheritDoc */
static defineSchema() {
const fields = foundry.data.fields;
const schema = {};
return {
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)
schema.resistance = new fields.SchemaField({
physical: resistanceField(),
magical: resistanceField()
})
return schema;
}
/**

View file

@ -36,6 +36,7 @@ export default class DhCharacter extends BaseDataActor {
const fields = foundry.data.fields;
return {
...super.defineSchema(),
resources: new fields.SchemaField({
hitPoints: new fields.SchemaField({
value: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
@ -100,10 +101,6 @@ export default class DhCharacter extends BaseDataActor {
levelData: new fields.EmbeddedDataField(DhLevelData),
bonuses: new fields.SchemaField({
armorScore: new fields.NumberField({ integer: true, initial: 0 }),
damageReduction: new fields.SchemaField({
physical: new fields.NumberField({ integer: true, initial: 0 }),
magical: new fields.NumberField({ integer: true, initial: 0 })
}),
damageThresholds: new fields.SchemaField({
severe: new fields.NumberField({ integer: true, initial: 0 }),
major: new fields.NumberField({ integer: true, initial: 0 })

View file

@ -20,6 +20,7 @@ export default class DhCompanion extends BaseDataActor {
const fields = foundry.data.fields;
return {
...super.defineSchema(),
partner: new ForeignDocumentUUIDField({ type: 'Actor' }),
resources: new fields.SchemaField({
stress: new fields.SchemaField({
@ -66,6 +67,7 @@ export default class DhCompanion extends BaseDataActor {
damage: {
parts: [
{
type: ['physical'],
value: {
dice: 'd6',
multiplier: 'prof'

View file

@ -9,20 +9,21 @@ export default class DhEnvironment extends BaseDataActor {
return foundry.utils.mergeObject(super.metadata, {
label: 'TYPES.Actor.environment',
type: 'environment',
settingSheet: DHEnvironmentSettings
settingSheet: DHEnvironmentSettings,
hasResistances: false
});
}
static defineSchema() {
const fields = foundry.data.fields;
return {
...super.defineSchema(),
tier: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.tiers,
initial: CONFIG.DH.GENERAL.tiers.tier1.id
}),
type: new fields.StringField({ choices: CONFIG.DH.ACTOR.environmentTypes }),
description: new fields.StringField(),
impulses: new fields.StringField(),
difficulty: new fields.NumberField({ required: true, initial: 11, integer: true }),
potentialAdversaries: new fields.TypedObjectField(

View file

@ -56,6 +56,7 @@ export default class DHWeapon extends BaseDataItem {
damage: {
parts: [
{
type: ['physical'],
value: {
multiplier: 'prof',
dice: 'd8'