shape change part 2
This commit is contained in:
parent
08d2be4ea0
commit
e438fd36e8
@ -733,4 +733,171 @@ export class ActorFolderEffect extends PowerEffect {
|
|||||||
}
|
}
|
||||||
return actors;
|
return actors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
actorValue(actor) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getActors() {
|
||||||
|
this.data.actors = this.prepActors();
|
||||||
|
const choices = {};
|
||||||
|
const effects = {};
|
||||||
|
const values = {};
|
||||||
|
Object.keys(this.data.actors)
|
||||||
|
.filter((k) => !k.includes('_template'))
|
||||||
|
.sort()
|
||||||
|
.forEach((key) => {
|
||||||
|
const id = this.data.actors[key].id;
|
||||||
|
choices[id] = key;
|
||||||
|
effects[id] = null;
|
||||||
|
values[id] = this.actorValue(this.data.actors[key]);
|
||||||
|
});
|
||||||
|
return { choices, effects, values };
|
||||||
|
}
|
||||||
|
|
||||||
|
get modifiers() {
|
||||||
|
const { choices, effects, values } = this.getActors();
|
||||||
|
return [
|
||||||
|
...super.modifiers,
|
||||||
|
{
|
||||||
|
name: 'Select Creature',
|
||||||
|
id: 'actorId',
|
||||||
|
type: 'select',
|
||||||
|
choices,
|
||||||
|
effects,
|
||||||
|
values,
|
||||||
|
epic: false,
|
||||||
|
effect: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
get spawnUpdates() {
|
||||||
|
const updates = {
|
||||||
|
actor: {},
|
||||||
|
token: {
|
||||||
|
actorLink: false,
|
||||||
|
},
|
||||||
|
embedded: {
|
||||||
|
ActiveEffect: {},
|
||||||
|
Item: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return updates;
|
||||||
|
}
|
||||||
|
|
||||||
|
#documentFinder(documentType, oldDoc, newDoc) {
|
||||||
|
if (documentType === 'Item') {
|
||||||
|
return oldDoc.name.toLowerCase() === newDoc.name.toLowerCase() && oldDoc.type === newDoc.type;
|
||||||
|
}
|
||||||
|
return oldDoc.name.toLowerCase() === newDoc.name.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateEmbedded(actor, newDocs) {
|
||||||
|
const adds = {};
|
||||||
|
const updates = {};
|
||||||
|
for (const documentType of Object.keys(newDocs ?? {})) {
|
||||||
|
const collection = actor.getEmbeddedCollection(documentType);
|
||||||
|
adds[documentType] = [];
|
||||||
|
updates[documentType] = [];
|
||||||
|
for (const newDocKey in newDocs[documentType]) {
|
||||||
|
const newDoc = newDocs[documentType][newDocKey];
|
||||||
|
const oldDoc = collection.find((doc) => this.#documentFinder(documentType, doc, newDoc));
|
||||||
|
if (oldDoc) {
|
||||||
|
const _id = oldDoc.id;
|
||||||
|
updates[documentType].push({ ...newDoc, _id });
|
||||||
|
} else {
|
||||||
|
adds[documentType].push(newDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const updateOpts = {};
|
||||||
|
if (documentType === 'Item') {
|
||||||
|
updateOpts.renderSheet = null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (adds[documentType].length > 0) {
|
||||||
|
actor.createEmbeddedDocuments(documentType, adds[documentType], updateOpts);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log('ERROR', e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (updates[documentType].length > 0) {
|
||||||
|
actor.updateEmbeddedDocuments(documentType, updates[documentType], updateOpts);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log('ERROR', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async parseValues() {
|
||||||
|
await super.parseValues();
|
||||||
|
this.data.maintid = randomID();
|
||||||
|
this.targetActor = await game.actors.get(this.data.actorId);
|
||||||
|
this.targetTokenDoc = await this.targetActor.getTokenDocument();
|
||||||
|
const sourceUpdates = {
|
||||||
|
delta: {
|
||||||
|
ownership: {
|
||||||
|
[game.user.id]: CONST.DOCUMENT_PERMISSION_LEVELS.OWNER,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this.targetTokenDoc.updateSource(sourceUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
async spawn() {
|
||||||
|
this.targetTokenDoc.updateSource({
|
||||||
|
x: this.source.x,
|
||||||
|
y: this.source.y,
|
||||||
|
elevation: this.source.elevation,
|
||||||
|
});
|
||||||
|
return this.source.scene.createEmbeddedDocuments('Token', [this.targetTokenDoc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async apply() {
|
||||||
|
this.data.spawned = await this.spawn();
|
||||||
|
const updates = this.spawnUpdates;
|
||||||
|
const secondaryDocs = await this.createSecondaryEffects(this.data.maintId);
|
||||||
|
const primaryDoc = await this.createPrimaryEffect(this.data.maintId);
|
||||||
|
const promises = [];
|
||||||
|
for (const token of this.data.spawned) {
|
||||||
|
if (updates?.token) {
|
||||||
|
promises.push(token.update(updates.token));
|
||||||
|
}
|
||||||
|
if (updates?.actor) {
|
||||||
|
promises.push(token.actor.update(updates.actor));
|
||||||
|
}
|
||||||
|
if (updates?.embedded) {
|
||||||
|
promises.push(this.updateEmbedded(token.actor, updates.embedded));
|
||||||
|
}
|
||||||
|
const activeEffects = await this.secondaryDocsForTarget(secondaryDocs, token);
|
||||||
|
activeEffects.push(await this.primaryDocForTarget(primaryDoc, token));
|
||||||
|
promises.push(token.actor.createEmbeddedDocuments('ActiveEffect', activeEffects));
|
||||||
|
}
|
||||||
|
const maintainDoc = await this.createMaintainEffect(this.data.maintId);
|
||||||
|
if (this.duration > 0) {
|
||||||
|
promises.push(this.applyActiveEffects(this.source, [maintainDoc]));
|
||||||
|
}
|
||||||
|
await Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
async sideEffects() {
|
||||||
|
if (this.data.fatigue) {
|
||||||
|
for (const target of this.data.spawned) {
|
||||||
|
const actor = target.actor;
|
||||||
|
const update = {
|
||||||
|
system: {
|
||||||
|
fatigue: {
|
||||||
|
value: actor.system.fatigue.value + 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (actor.system.fatigue.value < actor.system.fatigue.max) {
|
||||||
|
await actor.update(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { moduleName } from '../globals.js';
|
||||||
import { ActorFolderEffect } from './basePowers.js';
|
import { ActorFolderEffect } from './basePowers.js';
|
||||||
|
|
||||||
export class ShapeChangeEffect extends ActorFolderEffect {
|
export class ShapeChangeEffect extends ActorFolderEffect {
|
||||||
@ -17,6 +18,10 @@ export class ShapeChangeEffect extends ActorFolderEffect {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get oneTarget() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
get isRaisable() {
|
get isRaisable() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -33,48 +38,24 @@ export class ShapeChangeEffect extends ActorFolderEffect {
|
|||||||
return 'Morphables';
|
return 'Morphables';
|
||||||
}
|
}
|
||||||
|
|
||||||
getShapeChangeActors() {
|
actorValue(actor) {
|
||||||
this.data.actors = this.prepActors();
|
const size = actor.system.stats.size;
|
||||||
const choices = {};
|
let value = 3;
|
||||||
const effects = {};
|
if (size >= 5) {
|
||||||
const values = {};
|
value = 15;
|
||||||
Object.keys(this.data.actors)
|
} else if (size >= 3) {
|
||||||
.filter((k) => !k.includes('_template'))
|
value = 11;
|
||||||
.sort()
|
} else if (size >= 1) {
|
||||||
.forEach((key) => {
|
value = 8;
|
||||||
const id = this.data.actors[key].id;
|
} else if (size >= 0) {
|
||||||
const size = this.data.actors[key].system.stats.size;
|
value = 5;
|
||||||
let value = 3;
|
}
|
||||||
if (size >= 5) {
|
return value;
|
||||||
value = 15;
|
|
||||||
} else if (size >= 3) {
|
|
||||||
value = 11;
|
|
||||||
} else if (size >= 1) {
|
|
||||||
value = 8;
|
|
||||||
} else if (size >= 0) {
|
|
||||||
value = 5;
|
|
||||||
}
|
|
||||||
choices[id] = key;
|
|
||||||
effects[id] = null;
|
|
||||||
values[id] = value;
|
|
||||||
});
|
|
||||||
return { choices, effects, values };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get modifiers() {
|
get modifiers() {
|
||||||
const { choices, effects, values } = this.getShapeChangeActors();
|
|
||||||
return [
|
return [
|
||||||
...super.modifiers,
|
...super.modifiers,
|
||||||
{
|
|
||||||
name: 'Shape Change Into',
|
|
||||||
id: 'actorId',
|
|
||||||
type: 'select',
|
|
||||||
choices,
|
|
||||||
effects,
|
|
||||||
values,
|
|
||||||
epic: false,
|
|
||||||
effect: false,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'Duration',
|
name: 'Duration',
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
@ -84,7 +65,7 @@ export class ShapeChangeEffect extends ActorFolderEffect {
|
|||||||
effect: false,
|
effect: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Transform',
|
name: 'Transform Other?',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
default: 'none',
|
default: 'none',
|
||||||
id: 'transform',
|
id: 'transform',
|
||||||
@ -100,6 +81,87 @@ export class ShapeChangeEffect extends ActorFolderEffect {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async parseValues() {
|
||||||
|
await super.parseValues();
|
||||||
|
this.target = this?.targets?.[0] ?? this.source;
|
||||||
|
this.data.actorUpdates = {
|
||||||
|
name: `${this.target.actor.name} (${this.targetActor.name} form)`,
|
||||||
|
system: {
|
||||||
|
wildcard: this.target.actor.system.wildcard,
|
||||||
|
attributes: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
for (const stat of ['smarts', 'spirit']) {
|
||||||
|
this.data.actorUpdates.system.attributes[stat] = {
|
||||||
|
die: this.target.actor.system.attributes[stat].die,
|
||||||
|
'wild-die': this.target.actor.system.attributes[stat]['wild-die'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.data.tokenUpdates = {
|
||||||
|
flags: {
|
||||||
|
[moduleName]: { 'shapeChange.srcTokenId': this.target.id },
|
||||||
|
},
|
||||||
|
actorLink: false,
|
||||||
|
name: `${this.target.name} (${this.targetActor.prototypeToken.name} form)`,
|
||||||
|
disposition: this.target.document.disposition,
|
||||||
|
sight: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this.data.embeddedUpdates = {
|
||||||
|
ActiveEffect: {},
|
||||||
|
Item: {},
|
||||||
|
};
|
||||||
|
for (const effect of this.target.actor.effects) {
|
||||||
|
const doc = await this.target.actor.getEmbeddedDocument('ActiveEffect', effect.id);
|
||||||
|
this.data.embeddedUpdates.ActiveEffect[effect.name] = doc;
|
||||||
|
}
|
||||||
|
for (const item of this.target.actor.items.filter(
|
||||||
|
(i) =>
|
||||||
|
(i.type === 'skill' && ['smarts', 'spirit'].includes(i.system.attribute)) ||
|
||||||
|
['power', 'edge', 'hindrance', 'action'].includes(i.type),
|
||||||
|
)) {
|
||||||
|
const doc = await this.target.actor.getEmbeddedDocument('Item', item.id);
|
||||||
|
this.data.embeddedUpdates.Item[item.name] = doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async spawn() {
|
||||||
|
this.targetTokenDoc.updateSource({
|
||||||
|
x: this.target.x,
|
||||||
|
y: this.target.y,
|
||||||
|
elevation: this.target.elevation,
|
||||||
|
});
|
||||||
|
return this.source.scene.createEmbeddedDocuments('Token', [this.targetTokenDoc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
get effectName() {
|
||||||
|
return `Shape Change into ${this.targetActor.prototypeToken.name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPrimaryEffectChanges() {
|
||||||
|
const changes = super.getPrimaryEffectChanges();
|
||||||
|
if (this.data.raise) {
|
||||||
|
for (const stat of ['vigor', 'strength']) {
|
||||||
|
changes.push({
|
||||||
|
key: `system.attributes.${stat}.die.sides`,
|
||||||
|
mode: CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||||
|
value: 2,
|
||||||
|
priority: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
get description() {
|
||||||
let desc = super.description;
|
let desc = super.description;
|
||||||
return desc;
|
return desc;
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
{{#if targets.length}}
|
{{#if targets.length}}
|
||||||
<p>
|
<p>
|
||||||
<strong>Targets</strong>:
|
<strong>Targets</strong>:
|
||||||
{{#each targets}}{{#if @index}}, {{/if}}{{this}}{{/each}}
|
{{#each targets}}{{#if @index}}, {{/if}}{{{this}}}{{/each}}
|
||||||
{{#if recipients.cost}}
|
{{#if recipients.cost}}
|
||||||
<br>({{#if recipients.epic}}⭐ {{/if}}Additional Recipients
|
<br>({{#if recipients.epic}}⭐ {{/if}}Additional Recipients
|
||||||
{{recipients.cost}}pp each × {{recipients.count}} = {{recipients.total}})
|
{{recipients.cost}}pp each × {{recipients.count}} = {{recipients.total}})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user