/** * Extend the base Actor document by defining a custom roll data structure which is ideal for the Simple system. * @extends {Actor} */ export class VermineActor extends Actor { /** @override */ prepareData() { // Prepare data for the actor. Calling the super version of this executes // the following, in order: data reset (to clear active effects), // prepareBaseData(), prepareEmbeddedDocuments() (including active effects), // prepareDerivedData(). super.prepareData(); } /** @override */ prepareBaseData() { // Data modifications in this step occur before processing embedded // documents or derived data. if (this.type == 'character') { this._setAgeType(); this._setCharacterEffort(); this._setCharacterSelfControl(); this._setCharacterThresholds(); } } /** * @override * Augment the basic actor data with additional dynamic data. Typically, * you'll want to handle most of your calculated/derived data in this step. * Data calculated in this step should generally not exist in template.json * (such as ability modifiers rather than ability scores) and should be * available both inside and outside of character sheets (such as if an actor * is queried and has a roll executed directly from it). */ prepareDerivedData() { const actorData = this; const systemData = actorData.system; const flags = actorData.flags.vermine2047 || {}; // Make separate methods for each Actor type (character, npc, etc.) to keep // things organized. this._prepareCharacterData(actorData); this._prepareNpcData(actorData); } /** * Prepare Character type specific data */ _prepareCharacterData(actorData) { if (actorData.type !== 'character') return; // Make modifications to data here. For example: const systemData = actorData.system; // Loop through ability scores, and add their modifiers to our sheet output. for (let [key, ability] of Object.entries(systemData.abilities)) { // Calculate the modifier using d20 rules. ability.mod = Math.floor((ability.value - 10) / 2); } } /** * Prepare NPC type specific data. */ _prepareNpcData(actorData) { if (actorData.type !== 'npc') return; // Make modifications to data here. For example: const systemData = actorData.system; systemData.xp = (systemData.cr * systemData.cr) * 100; } /** * Override getRollData() that's supplied to rolls. */ getRollData() { const data = super.getRollData(); // Prepare character roll data. this._getCharacterRollData(data); this._getNpcRollData(data); return data; } /** * Prepare character roll data. */ _getCharacterRollData(data) { if (this.type !== 'character') return; // Copy the ability scores to the top level, so that rolls can use // formulas like `@str.mod + 4`. if (data.abilities) { for (let [k, v] of Object.entries(data.abilities)) { data[k] = foundry.utils.deepClone(v); } } // Add level for easier access, or fall back to 0. if (data.attributes.level) { data.lvl = data.attributes.level.value ?? 0; } } /** * Prepare NPC roll data. */ _getNpcRollData(data) { if (this.type !== 'npc') return; // Process additional NPC data here. } _setCharacterSelfControl() { this.system.attributes.self_control.max = 0 + Object.values(this.system.abilities).filter(i => i.category === "mental" || i.category === "social").map((i) => i.value).reduce((acc, curr) => acc + curr, 0) + this.modFromAgeSelfControl; } _setCharacterEffort() { this.system.attributes.effort.max = 0 + Object.values(this.system.abilities).filter(i => i.category === "physical" || i.category === "manual").map((i) => i.value).reduce((acc, curr) => acc + curr, 0) + this.modFromAgeEffort; } _setCharacterThresholds() { const health = this.system.abilities.health.value; this.system.minorWound.threshold = health; this.system.majorWound.threshold = health + 3; this.system.deadlyWound.threshold = (health + 7 < 11) ? health + 7 : 10; this.system.minorWound.max = 4 + this.modFromAgeWounds.l; this.system.majorWound.max = 3 + this.modFromAgeWounds.h; this.system.deadlyWound.max = 2 + this.modFromAgeWounds.d; } _setAgeType() { Object.keys(CONFIG.VERMINE.AgeTypes).forEach((type) => { if (this.system.identity.age >= parseInt(CONFIG.VERMINE.AgeTypes[type].beginning, 10)) { this.system.identity.ageType = type; } }); } get ageType() { return this.system.identity.ageType; } get modFromAgeSelfControl() { return this.ageType == 1 ? -1 : 0; } get modFromAgeEffort() { if (this.ageType == 1) return -1; if (this.ageType == 3) return -2; return 0; } get modFromAgeWounds() { if (this.ageType == 1) return { l: 0, h: 0, d: -1 }; if (this.ageType == 3) return { l: -1, h: -1, d: -1 }; return { l: 0, h: 0, d: 0 }; } }