import { BaseSummonEffect } from './summonSupport.js'; export class ZombieEffect extends BaseSummonEffect { get name() { return 'Zombie'; } get icon() { return 'icons/magic/death/hand-dirt-undead-zombie.webp'; } get duration() { return 600; } get modifiers() { const mods = super.modifiers; mods.push( { type: 'number', name: 'Additional Zombies (+1 per zombie)', id: 'additionalAllies', value: 0, default: 0, epic: false, effect: false, }, { type: 'checkbox', name: 'Armed (+1 per zombie)', id: 'armed', value: 0, default: false, epic: false, effect: false, }, { type: 'checkbox', name: 'Armor (+1 per zombie)', id: 'armor', default: false, value: 0, epic: false, effect: true, icon: 'icons/equipment/chest/breastplate-leather-brown-belted.webp', changes: [ { key: 'system.stats.toughness.armor', value: 2, priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD, }, ], }, { type: 'checkbox', name: 'Skeletal (+1 per zombie)', value: 0, id: 'skeletal', epic: false, default: false, effect: true, icon: 'icons/magic/death/hand-undead-skeleton-fire-pink.webp', changes: [ { key: 'system.attributes.agility.die.sides', value: 2, priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD, }, { key: '@Skill{Athletics}[system.die.sides]', value: 2, priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD, }, { key: '@Skill{Fighting}[system.die.sides]', value: 2, priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD, }, { key: '@Skill{Shooting}[system.die.sides]', value: 2, priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD, }, ], }, { type: 'radio', name: 'Mind Rider', id: 'mindRider', default: 'none', epic: false, choices: { none: 'None', single: 'Single', all: 'All' }, values: { none: 0, single: 1, all: 3 }, effects: { none: null, single: { name: 'Mind Rider (single)', icon: 'icons/magic/control/hypnosis-mesmerism-eye.webp', changes: [], description: 'The caster can communicate and sense through the ally.', }, all: { name: 'Mind Rider (all)', icon: 'icons/magic/control/hypnosis-mesmerism-eye.webp', changes: [], description: 'The caster can communicate and sense through the ally.', }, }, }, { type: 'checkbox', name: 'Permanent', id: 'permanent', default: false, epic: false, value: 0, effect: true, icon: 'icons/magic/death/skeleton-worn-skull-tan.webp', changes: [], description: 'This zombie is permanant until dismissed.', }, ); return mods; } actorValue(actor) { const size = actor.system.stats.size; if (size <= -1) { return 2; } return 3 + size; } async parseValuesRaise() { const attrList = ['Agility', 'Smarts', 'Spirit', 'Strength', 'Vigor']; const skillSet = new Set(); for (const skill of this.targetActor.items.filter((i) => i.type === 'skill')) { skillSet.add(skill.name); } const skillList = Array.from(skillSet); skillList.sort(); const html = `
`; const formData = await foundry.applications.api.DialogV2.wait({ window: { title: 'Select trait for raise increase', icon: 'fa-solid fa-biohazard', }, content: html, buttons: [ { action: 'submit', label: 'Submit', callback: (event, button, dialog) => new FormDataExtended(button.form), }, { action: 'cancel', label: 'cancel' }, ], }); const key = formData.trait; this.data.primaryEffectChanges.push({ mode: CONST.ACTIVE_EFFECT_MODES.ADD, value: 2, key, priority: 0, }); } async parseValuesPre() { await super.parseValuesPre(); this.data.primaryEffectChanges = []; this.data.actorUpdates = { name: `${this.source.actor.name}'s raised ${this.targetActor.name}` }; this.data.tokenUpdates = { name: `${this.source.name}'s raised ${this.targetActor.name}` }; this.data.embeddedUpdates = { ActiveEffect: {}, Item: {}, }; if (this.data.armed && this.data.actors['armed_template']) { const armedTemplate = this.data.actors.armed_template; for (const item of armedTemplate.items) { const armedItemDoc = armedTemplate.getEmbeddedDocument('Item', item.id); this.data.embeddedUpdates.Item[item.name] = armedItemDoc; } } if (this.data.raise) { await this.parseValuesRaise(); } } get summonCount() { return 1 + this.data.additionalAllies; } getPrimaryEffectChanges() { return [...super.getPrimaryEffectChanges(), ...this.data.primaryEffectChanges]; } get powerPoints() { const basicZombieNames = ['zombie', 'human zombie', 'zombie, human']; let total = super.powerPoints; const base = this.actorValue(this.targetActor); let additional = basicZombieNames.includes(this.targetActor.name.toLowerCase()) ? 1 : Math.max(1, Math.ceil(base / 2)); total += (this.summonCount - 1) * additional; const mods = [this.data.armed, this.data.armor, this.data.skeletal]; total += mods.map((v) => (v ? 1 : 0)).reduce((a, b) => a + b) * this.summonCount; return total; } get spawnUpdates() { const updates = super.spawnUpdates; foundry.utils.mergeObject(updates.actor, this.data.actorUpdates); foundry.utils.mergeObject(updates.token, this.data.tokenUpdates); foundry.utils.mergeObject(updates.embedded, this.data.embeddedUpdates); return updates; } get description() { let desc = super.description; const summonCount = this.summonCount; const plural = summonCount > 1 ? 's' : ''; desc += `Summon ${summonCount} ${this.targetActor.name}${plural}. `; if (this.data.armed || this.data.armor) { desc += `The zombie${plural} are `; if (this.data.armed) { desc += 'armed '; } if (this.data.armed && this.data.armor) { desc += 'and '; } if (this.data.armor) { desc += 'armored '; } desc += 'with rotting but working equipment. '; } if (this.data.skeletal) { desc += `These particlar zombies have shed the bulk of their flesh, becoming stronger but more skeletal in the process.`; } desc += '
'; return desc; } }