zombie and summonable refactoring
This commit is contained in:
parent
5965b89b66
commit
5cb15bcedd
@ -56,13 +56,14 @@ import { SmiteEffect } from './smite.js';
|
|||||||
import { SoundSilenceEffect } from './soundSilence.js';
|
import { SoundSilenceEffect } from './soundSilence.js';
|
||||||
import { SpeakLanguageEffect } from './speakLanguage.js';
|
import { SpeakLanguageEffect } from './speakLanguage.js';
|
||||||
import { StunEffect } from './stun.js';
|
import { StunEffect } from './stun.js';
|
||||||
import { SummonAllyEffect, ZombieEffect } from './summon.js';
|
import { SummonAllyEffect } from './summon.js';
|
||||||
import { TelekinesisEffect } from './telekinesis.js';
|
import { TelekinesisEffect } from './telekinesis.js';
|
||||||
import { TeleportEffect } from './teleport.js';
|
import { TeleportEffect } from './teleport.js';
|
||||||
import { TimeStopEffect } from './timeStop.js';
|
import { TimeStopEffect } from './timeStop.js';
|
||||||
import { WallWalkerEffect } from './wallWalker.js';
|
import { WallWalkerEffect } from './wallWalker.js';
|
||||||
import { WarriorsGiftEffect } from './warriorsGift.js';
|
import { WarriorsGiftEffect } from './warriorsGift.js';
|
||||||
import { WishEffect } from './wish.js';
|
import { WishEffect } from './wish.js';
|
||||||
|
import { ZombieEffect } from './zombie.js';
|
||||||
|
|
||||||
const PowerClasses = {
|
const PowerClasses = {
|
||||||
'arcane-protection': ArcaneProtectionEffect,
|
'arcane-protection': ArcaneProtectionEffect,
|
||||||
|
|||||||
@ -1,50 +1,4 @@
|
|||||||
/* globals Portal */
|
import { BaseSummonEffect } from './summonSupport.js';
|
||||||
import { moduleName } from '../globals.js';
|
|
||||||
import { ActorFolderEffect } from './basePowers.js';
|
|
||||||
|
|
||||||
class BaseSummonEffect extends ActorFolderEffect {
|
|
||||||
get name() {
|
|
||||||
return 'Base Summon';
|
|
||||||
}
|
|
||||||
|
|
||||||
get actorFolderBase() {
|
|
||||||
return 'Summonables';
|
|
||||||
}
|
|
||||||
|
|
||||||
get summonCount() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
async parseValuesPre() {}
|
|
||||||
|
|
||||||
async parseValuesMid() {}
|
|
||||||
|
|
||||||
async parseValuesPost() {}
|
|
||||||
|
|
||||||
async parseValues() {
|
|
||||||
await super.parseValues();
|
|
||||||
await this.parseValuesPre();
|
|
||||||
await this.parseValuesMid();
|
|
||||||
await this.parseValuesPost();
|
|
||||||
}
|
|
||||||
|
|
||||||
async spawn() {
|
|
||||||
const spawned = await new Portal()
|
|
||||||
.addCreature(this.targetTokenDoc, { count: this.summonCount })
|
|
||||||
.texture(this.targetTokenDoc.texture.src)
|
|
||||||
.spawn();
|
|
||||||
return spawned;
|
|
||||||
}
|
|
||||||
|
|
||||||
async apply() {
|
|
||||||
await super.apply();
|
|
||||||
const maintainDoc = await this.createMaintainEffect(this.data.maintId);
|
|
||||||
maintainDoc.flags[moduleName].targetIds = this.data.spawned.map((t) => t.id);
|
|
||||||
if (this.duration > 0) {
|
|
||||||
await this.applyActiveEffects(this.source, [maintainDoc]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BaseAllyEffect extends BaseSummonEffect {
|
class BaseAllyEffect extends BaseSummonEffect {
|
||||||
get values() {
|
get values() {
|
||||||
@ -267,6 +221,10 @@ export class SummonAllyEffect extends BaseAllyEffect {
|
|||||||
return 'Summon Ally';
|
return 'Summon Ally';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get actorFolder() {
|
||||||
|
return `${this.actorFolderBase}/${this.name}`;
|
||||||
|
}
|
||||||
|
|
||||||
get icon() {
|
get icon() {
|
||||||
return 'icons/magic/control/silhouette-hold-beam-blue.webp';
|
return 'icons/magic/control/silhouette-hold-beam-blue.webp';
|
||||||
}
|
}
|
||||||
@ -443,219 +401,3 @@ export class SummonAllyEffect extends BaseAllyEffect {
|
|||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ZombieEffect extends BaseSummonEffect {
|
|
||||||
get name() {
|
|
||||||
return 'Zombie';
|
|
||||||
}
|
|
||||||
|
|
||||||
get icon() {
|
|
||||||
return 'icons/magic/death/hand-dirt-undead-zombie.webp';
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
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 = `<form><h2>Raise Effect - raise one trait a die type</h2>
|
|
||||||
<p>All raised zombies will have the chosen trait raised one die type.</p>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Trait: <select name="trait">
|
|
||||||
<optgroup label="Attributes">
|
|
||||||
${attrList.map((attr) => `<option value="system.attributes.${attr.toLowerCase()}.die.sides">${attr}</option>`).join('')}
|
|
||||||
</optgroup>
|
|
||||||
<optgroup label="Skills">
|
|
||||||
${skillList.map((skill) => `<option value="@Skill{${skill}}[system.die.sides]">${skill}</option>`).join('')}
|
|
||||||
</optgroup>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
`;
|
|
||||||
const formData = await Dialog.wait({
|
|
||||||
title: 'Select trait for raise increase',
|
|
||||||
content: html,
|
|
||||||
buttons: {
|
|
||||||
submit: {
|
|
||||||
label: 'Submit',
|
|
||||||
callback: (html) => {
|
|
||||||
const formElement = html[0].querySelector('form');
|
|
||||||
const formData = new FormDataExtended(formElement);
|
|
||||||
return formData.object;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
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 spawnUpdates() {
|
|
||||||
const updates = super.spawnUpdates;
|
|
||||||
mergeObject(updates.actor, this.data.actorUpdates);
|
|
||||||
mergeObject(updates.token, this.data.tokenUpdates);
|
|
||||||
mergeObject(updates.embedded, this.data.embeddedUpdates);
|
|
||||||
return updates;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
51
src/module/powers/summonSupport.js
Normal file
51
src/module/powers/summonSupport.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/* globals Portal */
|
||||||
|
import { moduleName } from '../globals.js';
|
||||||
|
import { ActorFolderEffect } from './basePowers.js';
|
||||||
|
|
||||||
|
export class BaseSummonEffect extends ActorFolderEffect {
|
||||||
|
get name() {
|
||||||
|
return 'Base Summon';
|
||||||
|
}
|
||||||
|
|
||||||
|
get actorFolderBase() {
|
||||||
|
return 'Summonables';
|
||||||
|
}
|
||||||
|
|
||||||
|
get actorFolder() {
|
||||||
|
return `${this.actorFolderBase}/Creatures`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get summonCount() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async parseValuesPre() {}
|
||||||
|
|
||||||
|
async parseValuesMid() {}
|
||||||
|
|
||||||
|
async parseValuesPost() {}
|
||||||
|
|
||||||
|
async parseValues() {
|
||||||
|
await super.parseValues();
|
||||||
|
await this.parseValuesPre();
|
||||||
|
await this.parseValuesMid();
|
||||||
|
await this.parseValuesPost();
|
||||||
|
}
|
||||||
|
|
||||||
|
async spawn() {
|
||||||
|
const spawned = await new Portal()
|
||||||
|
.addCreature(this.targetTokenDoc, { count: this.summonCount })
|
||||||
|
.texture(this.targetTokenDoc.texture.src)
|
||||||
|
.spawn();
|
||||||
|
return spawned;
|
||||||
|
}
|
||||||
|
|
||||||
|
async apply() {
|
||||||
|
await super.apply();
|
||||||
|
const maintainDoc = await this.createMaintainEffect(this.data.maintId);
|
||||||
|
maintainDoc.flags[moduleName].targetIds = this.data.spawned.map((t) => t.id);
|
||||||
|
if (this.duration > 0) {
|
||||||
|
await this.applyActiveEffects(this.source, [maintainDoc]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
262
src/module/powers/zombie.js
Normal file
262
src/module/powers/zombie.js
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
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 = `<form><h2>Raise Effect - raise one trait a die type</h2>
|
||||||
|
<p>All raised zombies will have the chosen trait raised one die type.</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Trait: <select name="trait">
|
||||||
|
<optgroup label="Attributes">
|
||||||
|
${attrList.map((attr) => `<option value="system.attributes.${attr.toLowerCase()}.die.sides">${attr}</option>`).join('')}
|
||||||
|
</optgroup>
|
||||||
|
<optgroup label="Skills">
|
||||||
|
${skillList.map((skill) => `<option value="@Skill{${skill}}[system.die.sides]">${skill}</option>`).join('')}
|
||||||
|
</optgroup>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
const formData = await Dialog.wait({
|
||||||
|
title: 'Select trait for raise increase',
|
||||||
|
content: html,
|
||||||
|
buttons: {
|
||||||
|
submit: {
|
||||||
|
label: 'Submit',
|
||||||
|
callback: (html) => {
|
||||||
|
const formElement = html[0].querySelector('form');
|
||||||
|
const formData = new FormDataExtended(formElement);
|
||||||
|
return formData.object;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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;
|
||||||
|
mergeObject(updates.actor, this.data.actorUpdates);
|
||||||
|
mergeObject(updates.token, this.data.tokenUpdates);
|
||||||
|
mergeObject(updates.embedded, this.data.embeddedUpdates);
|
||||||
|
return updates;
|
||||||
|
}
|
||||||
|
|
||||||
|
get description() {
|
||||||
|
let desc = super.description;
|
||||||
|
const summonCount = this.summonCount;
|
||||||
|
const plural = summonCount > 1 ? 's' : '';
|
||||||
|
desc += `<p>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 += '</p>';
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user