diff --git a/lang/en.json b/lang/en.json index 02ea41eb..a7197047 100755 --- a/lang/en.json +++ b/lang/en.json @@ -974,6 +974,11 @@ "minor": "Minor", "none": "None" }, + "DamageResistance": { + "none": "None", + "resistance": "Resistance", + "immunity": "Immunity" + }, "DamageThresholds": { "title": "Damage Thresholds", "minor": "Minor", diff --git a/module/data/action/actionDice.mjs b/module/data/action/actionDice.mjs index 8b5bbe40..39fc6c92 100644 --- a/module/data/action/actionDice.mjs +++ b/module/data/action/actionDice.mjs @@ -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); } } diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index 9bb5d5f8..717c7532 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -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 }), @@ -93,4 +94,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; + } } diff --git a/module/data/actor/base.mjs b/module/data/actor/base.mjs index 1b90968d..e5e38716 100644 --- a/module/data/actor/base.mjs +++ b/module/data/actor/base.mjs @@ -1,5 +1,11 @@ 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 * @typedef {Object} ActorDataModelMetadata @@ -16,6 +22,7 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel { type: 'base', isNPC: true, settingSheet: null, + hasResistances: true }; } @@ -27,10 +34,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; } /** diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 93926d9a..b4dada8f 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -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 }), diff --git a/module/data/actor/companion.mjs b/module/data/actor/companion.mjs index 1203cc96..5ca50df7 100644 --- a/module/data/actor/companion.mjs +++ b/module/data/actor/companion.mjs @@ -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({ diff --git a/module/data/actor/environment.mjs b/module/data/actor/environment.mjs index 76990e88..2db1f039 100644 --- a/module/data/actor/environment.mjs +++ b/module/data/actor/environment.mjs @@ -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( diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index aba0e0fa..533a91e0 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -480,11 +480,7 @@ export default class DhpActor extends Actor { return; } - 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}.postDamageTreshold`, this, hpDamage, damage, type) === false) return null; + const hpDamage = this.calculateDamage(baseDamage, type); 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; } + 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) { resources.forEach(r => (r.value *= -1)); await this.modifyResource(resources); @@ -553,18 +564,6 @@ export default class DhpActor extends Actor { u.resources, 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 - } - }); - } */ } }); } diff --git a/module/documents/chatMessage.mjs b/module/documents/chatMessage.mjs index ef76d18f..a9a31073 100644 --- a/module/documents/chatMessage.mjs +++ b/module/documents/chatMessage.mjs @@ -12,6 +12,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { if (this.type === 'dualityRoll') { html.classList.add('duality'); + console.log(this.system) switch (this.system.roll.result.duality) { case 1: html.classList.add('hope'); diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 8156736d..40a71ac7 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -236,16 +236,7 @@ Roll.replaceFormulaData = function (formula, data = {}, { missing, warn = false }; export const getDamageKey = damage => { - switch (damage) { - case 3: - return 'severe'; - case 2: - return 'major'; - case 1: - return 'minor'; - case 0: - return 'none'; - } + return ['none', 'minor', 'major', 'severe'][damage]; }; export const getDamageLabel = damage => { @@ -253,16 +244,12 @@ export const getDamageLabel = damage => { }; export const damageKeyToNumber = key => { - switch (key) { - case 'severe': - return 3; - case 'major': - return 2; - case 'minor': - return 1; - case 'none': - return 0; - } + return { + 'none': 0, + 'minor': 1, + 'major': 2, + 'severe': 3 + }[key]; }; export default function constructHTMLButton({ diff --git a/templates/sheets/actors/adversary/sidebar.hbs b/templates/sheets/actors/adversary/sidebar.hbs index b26c1b81..ad23ab25 100644 --- a/templates/sheets/actors/adversary/sidebar.hbs +++ b/templates/sheets/actors/adversary/sidebar.hbs @@ -10,12 +10,12 @@
/
- +/
- +