Add Resistances

This commit is contained in:
Dapoolp 2025-07-10 15:41:53 +02:00
parent 70239ec06a
commit 7b24cc01eb
11 changed files with 62 additions and 53 deletions

View file

@ -974,6 +974,11 @@
"minor": "Minor", "minor": "Minor",
"none": "None" "none": "None"
}, },
"DamageResistance": {
"none": "None",
"resistance": "Resistance",
"immunity": "Immunity"
},
"DamageThresholds": { "DamageThresholds": {
"title": "Damage Thresholds", "title": "Damage Thresholds",
"minor": "Minor", "minor": "Minor",

View file

@ -76,11 +76,7 @@ export class DHActionDiceData extends foundry.abstract.DataModel {
}; };
} }
getFormula(actor) { getFormula() {
/* 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}`) : ''}`; */
const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : `@${this.multiplier}`, const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : `@${this.multiplier}`,
bonus = this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : ''; bonus = this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : '';
return this.custom.enabled ? this.custom.formula : `${multiplier ?? 1}${this.dice}${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)), parts: new fields.ArrayField(new fields.EmbeddedDataField(DHDamageData)),
includeBase: new fields.BooleanField({ initial: false }) includeBase: new fields.BooleanField({ initial: false })
}; };
// if (hasBase) damageFields.includeBase = new fields.BooleanField({ initial: true });
super(damageFields, options, context); super(damageFields, options, context);
} }
} }

View file

@ -5,6 +5,7 @@ import BaseDataActor from './base.mjs';
const resourceField = () => const resourceField = () =>
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 }),
bonus: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
max: 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() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
...super.defineSchema(),
tier: new fields.StringField({ tier: new fields.StringField({
required: true, required: true,
choices: CONFIG.DH.GENERAL.tiers, choices: CONFIG.DH.GENERAL.tiers,
@ -32,7 +34,6 @@ export default class DhpAdversary extends BaseDataActor {
choices: CONFIG.DH.ACTOR.adversaryTypes, choices: CONFIG.DH.ACTOR.adversaryTypes,
initial: CONFIG.DH.ACTOR.adversaryTypes.standard.id initial: CONFIG.DH.ACTOR.adversaryTypes.standard.id
}), }),
description: new fields.StringField(),
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 }),
@ -93,4 +94,9 @@ export default class DhpAdversary extends BaseDataActor {
get features() { get features() {
return this.parent.items.filter(x => x.type === 'feature'); 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,11 @@
import DHBaseActorSettings from "../../applications/sheets/api/actor-setting.mjs"; 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 })
});
/** /**
* Describes metadata about the actor data model type * Describes metadata about the actor data model type
* @typedef {Object} ActorDataModelMetadata * @typedef {Object} ActorDataModelMetadata
@ -16,6 +22,7 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
type: 'base', type: 'base',
isNPC: true, isNPC: true,
settingSheet: null, settingSheet: null,
hasResistances: true
}; };
} }
@ -27,10 +34,16 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
/** @inheritDoc */ /** @inheritDoc */
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
const schema = {};
return { if(this.metadata.isNPC)
description: new fields.HTMLField({ required: true, nullable: true }) 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; const fields = foundry.data.fields;
return { return {
...super.defineSchema(),
resources: new fields.SchemaField({ resources: new fields.SchemaField({
hitPoints: new fields.SchemaField({ hitPoints: new fields.SchemaField({
value: new foundry.data.fields.NumberField({ initial: 0, integer: true }), value: new foundry.data.fields.NumberField({ initial: 0, integer: true }),

View file

@ -20,6 +20,7 @@ export default class DhCompanion extends BaseDataActor {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
...super.defineSchema(),
partner: new ForeignDocumentUUIDField({ type: 'Actor' }), partner: new ForeignDocumentUUIDField({ type: 'Actor' }),
resources: new fields.SchemaField({ resources: new fields.SchemaField({
stress: new fields.SchemaField({ stress: new fields.SchemaField({

View file

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

View file

@ -480,11 +480,7 @@ export default class DhpActor extends Actor {
return; return;
} }
const flatReduction = this.system.bonuses.damageReduction[type]; const hpDamage = this.calculateDamage(baseDamage, type);
const damage = Math.max(baseDamage - (flatReduction ?? 0), 0);
const hpDamage = this.convertDamageToThreshold(damage);
if (Hooks.call(`${CONFIG.DH.id}.postDamageTreshold`, this, hpDamage, damage, type) === false) return null;
if (!hpDamage) return; if (!hpDamage) return;
@ -511,6 +507,21 @@ export default class DhpActor extends Actor {
if (Hooks.call(`${CONFIG.DH.id}.postTakeDamage`, this, damage, type) === false) return null; if (Hooks.call(`${CONFIG.DH.id}.postTakeDamage`, this, damage, type) === false) return null;
} }
calculateDamage(baseDamage, type) {
if (Hooks.call(`${CONFIG.DH.id}.preCalculateDamage`, this, baseDamage, type) === false) return null;
if(this.system.resistance[type].immunity) return 0;
if(this.system.resistance[type].resistance) baseDamage = Math.ceil(baseDamage / 2);
const flatReduction = this.system.bonuses.damageReduction[type];
const damage = Math.max(baseDamage - (flatReduction ?? 0), 0);
const hpDamage = this.convertDamageToThreshold(damage);
if (Hooks.call(`${CONFIG.DH.id}.postCalculateDamage`, this, baseDamage, type) === false) return null;
return hpDamage;
}
async takeHealing(resources) { async takeHealing(resources) {
resources.forEach(r => (r.value *= -1)); resources.forEach(r => (r.value *= -1));
await this.modifyResource(resources); await this.modifyResource(resources);
@ -553,18 +564,6 @@ export default class DhpActor extends Actor {
u.resources, u.resources,
u.target.uuid u.target.uuid
); );
/* if (game.user.isGM) {
await u.target.update(u.resources);
} else {
await game.socket.emit(`system.${CONFIG.DH.id}`, {
action: socketEvent.GMUpdate,
data: {
action: GMUpdateEvent.UpdateDocument,
uuid: u.target.uuid,
update: u.resources
}
});
} */
} }
}); });
} }

View file

@ -12,6 +12,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
if (this.type === 'dualityRoll') { if (this.type === 'dualityRoll') {
html.classList.add('duality'); html.classList.add('duality');
console.log(this.system)
switch (this.system.roll.result.duality) { switch (this.system.roll.result.duality) {
case 1: case 1:
html.classList.add('hope'); html.classList.add('hope');

View file

@ -236,16 +236,7 @@ Roll.replaceFormulaData = function (formula, data = {}, { missing, warn = false
}; };
export const getDamageKey = damage => { export const getDamageKey = damage => {
switch (damage) { return ['none', 'minor', 'major', 'severe'][damage];
case 3:
return 'severe';
case 2:
return 'major';
case 1:
return 'minor';
case 0:
return 'none';
}
}; };
export const getDamageLabel = damage => { export const getDamageLabel = damage => {
@ -253,16 +244,12 @@ export const getDamageLabel = damage => {
}; };
export const damageKeyToNumber = key => { export const damageKeyToNumber = key => {
switch (key) { return {
case 'severe': 'none': 0,
return 3; 'minor': 1,
case 'major': 'major': 2,
return 2; 'severe': 3
case 'minor': }[key];
return 1;
case 'none':
return 0;
}
}; };
export default function constructHTMLButton({ export default function constructHTMLButton({

View file

@ -10,12 +10,12 @@
<div class='status-value'> <div class='status-value'>
<p><input class="bar-input" name="system.resources.hitPoints.value" value="{{source.system.resources.hitPoints.value}}" type="number"></p> <p><input class="bar-input" name="system.resources.hitPoints.value" value="{{source.system.resources.hitPoints.value}}" type="number"></p>
<p>/</p> <p>/</p>
<p class="bar-label">{{source.system.resources.hitPoints.max}}</p> <p class="bar-label">{{source.system.resources.hitPoints.maxTotal}}</p>
</div> </div>
<progress <progress
class='progress-bar' class='progress-bar'
value='{{source.system.resources.hitPoints.value}}' value='{{source.system.resources.hitPoints.value}}'
max='{{source.system.resources.hitPoints.max}}' max='{{source.system.resources.hitPoints.maxTotal}}'
></progress> ></progress>
<div class="status-label"> <div class="status-label">
<h4>HP</h4> <h4>HP</h4>
@ -26,12 +26,12 @@
<div class='status-value'> <div class='status-value'>
<p><input class="bar-input" name="system.resources.stress.value" value="{{source.system.resources.stress.value}}" type="number"></p> <p><input class="bar-input" name="system.resources.stress.value" value="{{source.system.resources.stress.value}}" type="number"></p>
<p>/</p> <p>/</p>
<p class="bar-label">{{source.system.resources.stress.max}}</p> <p class="bar-label">{{source.system.resources.stress.maxTotal}}</p>
</div> </div>
<progress <progress
class='progress-bar stress-color' class='progress-bar stress-color'
value='{{source.system.resources.stress.value}}' value='{{source.system.resources.stress.value}}'
max='{{source.system.resources.stress.max}}' max='{{source.system.resources.stress.maxTotal}}'
></progress> ></progress>
<div class="status-label"> <div class="status-label">
<h4>Stress</h4> <h4>Stress</h4>