summon part 2

This commit is contained in:
Mike Bloy 2024-06-04 00:01:41 -05:00
parent 4bdd6176e8
commit 6fe743130d
5 changed files with 227 additions and 33 deletions

View File

@ -117,7 +117,7 @@ export class PowerFormApplication extends FormApplication {
formData.submit = ev?.submitter?.value ?? 'cancel'; formData.submit = ev?.submitter?.value ?? 'cancel';
if (formData.submit !== 'cancel') { if (formData.submit !== 'cancel') {
this.powerEffect.formData = formData; this.powerEffect.formData = formData;
await this.powerEffect.applyEffect(); this.powerEffect.applyEffect();
} }
} }
} }
@ -447,15 +447,7 @@ export class PowerEffect {
} }
} }
async createSecondaryEffects(maintId) { enhanceSecondaryEffect(maintId, doc) {
const docs = [];
for (const mod of this.modifiers) {
const modValue = this.data[mod.id];
if (modValue && (mod?.effect || (mod?.effects?.[modValue] ?? false))) {
const icon = 'effects' in mod ? mod.effects[modValue].icon : mod.icon;
const name = 'effects' in mod ? mod.effects[modValue].name : mod.name;
const changes = 'effects' in mod ? mod.effects[modValue].changes : mod.changes;
const doc = this.createEffectDocument(icon, name, changes);
doc.statuses = doc.statuses ?? []; doc.statuses = doc.statuses ?? [];
doc.statuses.push('powerEffect'); doc.statuses.push('powerEffect');
if (this.duration === 0 && !this.usePrimaryEffect) { if (this.duration === 0 && !this.usePrimaryEffect) {
@ -475,6 +467,18 @@ export class PowerEffect {
doc.duration.seconds = 594; doc.duration.seconds = 594;
} }
} }
return doc;
}
async createSecondaryEffects(maintId) {
const docs = [];
for (const mod of this.modifiers) {
const modValue = this.data[mod.id];
if (modValue && (mod?.effect || (mod?.effects?.[modValue] ?? false))) {
const icon = 'effects' in mod ? mod.effects[modValue].icon : mod.icon;
const name = 'effects' in mod ? mod.effects[modValue].name : mod.name;
const changes = 'effects' in mod ? mod.effects[modValue].changes : mod.changes;
const doc = this.enhanceSecondaryEffect(maintId, this.createEffectDocument(icon, name, changes));
docs.push(doc); docs.push(doc);
} }
} }

View File

@ -69,7 +69,7 @@ export class BlindEffect extends PowerEffect {
const docs = await super.createSecondaryEffects(maintId); const docs = await super.createSecondaryEffects(maintId);
if (this.data.raise) { if (this.data.raise) {
const strong = this.data.strong; const strong = this.data.strong;
const doc = this.createEffectDocument(this.icon, `Blinded (${strong ? 'Strong, ' : ''}Raise)`, [ let doc = this.createEffectDocument(this.icon, `Blinded (${strong ? 'Strong, ' : ''}Raise)`, [
{ {
key: 'system.stats.globalMods.trait', key: 'system.stats.globalMods.trait',
value: -2, value: -2,
@ -77,9 +77,8 @@ export class BlindEffect extends PowerEffect {
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
}, },
]); ]);
doc.duration.seconds = 594; doc = this.enhanceSecondaryEffect(maintId, doc);
doc.description = this.description + '<p>This is the raise effect which can be shaken off separately.</p>'; doc.description = this.description + '<p>This is the raise effect which can be shaken off separately.</p>';
doc.flags[moduleName].maintId = maintId;
docs.push(doc); docs.push(doc);
} }
return docs; return docs;

View File

@ -70,10 +70,8 @@ export class BoostLowerTraitEffect extends PowerEffect {
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
}, },
]; ];
const doc = this.createEffectDocument(this.icon, name, changes); const doc = this.enhanceSecondaryEffect(maintId, this.createEffectDocument(this.icon, name, changes));
doc.duration.seconds = 594;
doc.description = this.description + '<p>This is the raise effect which can be shaken off separately.</p>'; doc.description = this.description + '<p>This is the raise effect which can be shaken off separately.</p>';
doc.flags[moduleName].maintId = maintId;
docs.push(doc); docs.push(doc);
} }
return docs; return docs;

View File

@ -56,6 +56,7 @@ 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 } from './summon.js';
const PowerClasses = { const PowerClasses = {
'arcane-protection': ArcaneProtectionEffect, 'arcane-protection': ArcaneProtectionEffect,
@ -132,6 +133,7 @@ const PowerClasses = {
sound: SoundSilenceEffect, sound: SoundSilenceEffect,
'speak-language': SpeakLanguageEffect, 'speak-language': SpeakLanguageEffect,
stun: StunEffect, stun: StunEffect,
'summon-ally': SummonAllyEffect,
}; };
/* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */

View File

@ -1,4 +1,5 @@
/* globals Portal */ /* globals Portal */
import { moduleName } from '../globals.js';
import { ActorFolderEffect } from './basePowers.js'; import { ActorFolderEffect } from './basePowers.js';
class BaseSummonEffect extends ActorFolderEffect { class BaseSummonEffect extends ActorFolderEffect {
@ -80,16 +81,79 @@ class BaseSummonEffect extends ActorFolderEffect {
if (!(this.hasIncreasedTrait && this?.data?.increasedTrait)) { if (!(this.hasIncreasedTrait && this?.data?.increasedTrait)) {
return; return;
} }
const skillSet = new Set();
for (const skill of this.targetActor.items.filter((i) => i.type === 'skill')) {
skillSet.add(skill.name);
} }
for (const item of Object.values(this.data.embeddedUpdates.Item).filter((i) => i.type === 'skill')) {
skillSet.add(item.name);
}
const skillList = Array.from(skillSet);
skillList.sort();
const attrList = ['Agility', 'Smarts', 'Spirit', 'Strength', 'Vigor'];
let html = `<form><h2>Increase Attributes</h2><p>(+1 pp each)</p>`;
html += attrList
.map(
(name) => `<div class="form-group">
<label><input type="checkbox" name="${name}">${name}</label>
</div>`,
)
.join('');
html += `<h2>Increase Skills</h2><p>(+1 pp each)</p>`;
html += skillList
.map(
(name) => `<div class="form-group">
<label><input type="checkbox" name="${name}">${name}</label>
</div>`,
)
.join('');
const formData = await Dialog.wait({
title: 'Select Trait increases',
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 mode = CONST.ACTIVE_EFFECT_MODES.ADD;
const value = 2;
const priority = 0;
this.data.increasedTraitChanges = [];
for (const attr of attrList) {
if (formData[attr]) {
this.data.increasedTraitChanges.push({
key: `system.attributes.${attr.toLowerCase()}.die.sides`,
value,
mode,
priority,
});
}
}
for (const skill of skillList) {
if (formData[skill]) {
this.data.increasedTraitChanges.push({
key: `@Skill{${skill}}[system.die.sides]`,
value,
mode,
priority,
});
}
}
}
async prePrep() {}
async parseValues() { async parseValues() {
await super.parseValues(); await super.parseValues();
this.data.actorUpdates = { this.data.actorUpdates = {
name: `${this.source.actor.name}'s summoned ${this.targetActor.name}`, name: `${this.source.actor.name}'s summoned ${this.targetActor.name}`,
system: {
wildcard: this.source.actor.system.wildcard,
attributes: {},
},
}; };
this.data.tokenUpdates = { this.data.tokenUpdates = {
actorLink: false, actorLink: false,
@ -103,9 +167,35 @@ class BaseSummonEffect extends ActorFolderEffect {
ActiveEffect: {}, ActiveEffect: {},
Item: {}, Item: {},
}; };
this.data.primaryEffectChanges = [];
await this.prePrep();
await this.prepIncreasedTrait(); await this.prepIncreasedTrait();
} }
getPrimaryEffectChanges() {
return [...super.getPrimaryEffectChanges(), ...this.data.primaryEffectChanges];
}
async createSecondaryEffects(maintId) {
const effects = await super.createSecondaryEffects(maintId);
if (this.data.mindRider) {
const doc = this.enhanceSecondaryEffect(
maintId,
this.createEffectDocument('icons/magic/control/hypnosis-mesmerism-eye.webp', 'Mind Rider', []),
);
doc.description = `The caster can communicate and sense through the ally`;
effects.push(doc);
}
if ((this.data?.increasedTraitChanges?.length ?? 0) > 0) {
const doc = this.enhanceSecondaryEffect(
maintId,
this.createEffectDocument(this.icon, 'Increased Trait', this.data.increasedTraitChanges),
);
effects.push(doc);
}
return effects;
}
get spawnUpdates() { get spawnUpdates() {
const updates = super.spawnUpdates; const updates = super.spawnUpdates;
mergeObject(updates.actor, this.data.actorUpdates); mergeObject(updates.actor, this.data.actorUpdates);
@ -116,14 +206,23 @@ class BaseSummonEffect extends ActorFolderEffect {
async spawn() { async spawn() {
const spawned = await new Portal() const spawned = await new Portal()
.addCreature(this.targetTokenDoc) .addCreature(this.targetTokenDoc, { count: this.summonCount })
.texture(this.targetTokenDoc.texture.src) .texture(this.targetTokenDoc.texture.src)
.spawn(); .spawn();
return spawned; 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]);
}
}
} }
export class SummonAllyEffect extends BaseSummonEffect() { export class SummonAllyEffect extends BaseSummonEffect {
get name() { get name() {
return 'Summon Ally'; return 'Summon Ally';
} }
@ -132,6 +231,18 @@ export class SummonAllyEffect extends BaseSummonEffect() {
return 0; return 0;
} }
get duration() {
return 5;
}
get icon() {
return 'icons/magic/control/silhouette-hold-beam-blue.webp';
}
get isTargeted() {
return false;
}
get values() { get values() {
return { return {
attendant: 1, attendant: 1,
@ -181,6 +292,86 @@ export class SummonAllyEffect extends BaseSummonEffect() {
epic: false, epic: false,
effect: false, effect: false,
}); });
const { choices, effects, values } = this._edges;
return mods; return mods;
} }
async prePrep() {
await super.prePrep();
if (this.data.raise && this.data.actors['raise_template']) {
const raiseTemplate = this.summonableActors.raise_template;
for (const item of raiseTemplate.items) {
const raiseItemDoc = await raiseTemplate.getEmbeddedDocument('Item', item.id);
this.data.embeddedUpdates.Item[item.name] = raiseItemDoc;
}
}
if (this.targetActor.name !== 'Mirror Self') {
return;
}
const mirrorActor = this.source.actor;
mergeObject(this.data.actorUpdates, {
system: mirrorActor.system
.clone({
'fatigue.value': 0,
'wounds.value': 0,
'wounds.max': 0,
'bennies.max': 0,
'bennies.value': 0,
})
.toObject(),
name: `Mirror ${mirrorActor.name}`,
img: mirrorActor.img,
});
this.data.actorUpdates.system.wildcard = false;
mergeObject(this.data.tokenUpdates, {
name: `Mirror ${this.source.name}`,
texture: {
src: this.source.document.texture.src,
scaleX: this.source.document.texture.scaleX * -1,
scaleY: this.source.document.texture.scaleY,
},
});
this.data.mirrorChanges = [];
for (const mirrorItem of mirrorActor.items) {
if (
mirrorItem.type === 'power' &&
(mirrorItem.system?.swid === 'summon-ally' || mirrorItem.name === 'Summon Ally')
) {
continue;
}
if (['weapon', 'armor', 'consumable', 'gear'].includes(mirrorItem.type)) {
continue;
}
this.data.embeddedUpdates.Item[mirrorItem.name] = await mirrorActor.getEmbeddedDocument('Item', mirrorItem.id);
if (mirrorItem.type === 'skill') {
this.data.mirrorChanges.push({
key: `@Skill{${mirrorItem.name}}[system.die.sides]`,
mode: CONST.ACTIVE_EFFECT_MODES.ADD,
value: -2,
priority: 0,
});
}
}
}
async parseValues() {
await super.parseValues();
}
async createSecondaryEffects(maintId) {
const effects = await super.createSecondaryEffects(maintId);
if ((this.data?.mirrorChanges?.length ?? 0) > 0) {
const doc = this.enhanceSecondaryEffect(
maintId,
this.createEffectDocument(
'icons/magic/control/mouth-smile-deception-purple.webp',
'Mirror Self',
this.data.mirrorChanges,
),
);
doc.description = 'A mirror self ally has skills 1 die type worse than the caster';
effects.push(doc);
}
return effects;
}
} }