shape change part 2
This commit is contained in:
parent
08d2be4ea0
commit
e438fd36e8
@ -733,4 +733,171 @@ export class ActorFolderEffect extends PowerEffect {
|
||||
}
|
||||
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';
|
||||
|
||||
export class ShapeChangeEffect extends ActorFolderEffect {
|
||||
@ -17,6 +18,10 @@ export class ShapeChangeEffect extends ActorFolderEffect {
|
||||
return true;
|
||||
}
|
||||
|
||||
get oneTarget() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get isRaisable() {
|
||||
return true;
|
||||
}
|
||||
@ -33,48 +38,24 @@ export class ShapeChangeEffect extends ActorFolderEffect {
|
||||
return 'Morphables';
|
||||
}
|
||||
|
||||
getShapeChangeActors() {
|
||||
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;
|
||||
const size = this.data.actors[key].system.stats.size;
|
||||
let value = 3;
|
||||
if (size >= 5) {
|
||||
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 };
|
||||
actorValue(actor) {
|
||||
const size = actor.system.stats.size;
|
||||
let value = 3;
|
||||
if (size >= 5) {
|
||||
value = 15;
|
||||
} else if (size >= 3) {
|
||||
value = 11;
|
||||
} else if (size >= 1) {
|
||||
value = 8;
|
||||
} else if (size >= 0) {
|
||||
value = 5;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
get modifiers() {
|
||||
const { choices, effects, values } = this.getShapeChangeActors();
|
||||
return [
|
||||
...super.modifiers,
|
||||
{
|
||||
name: 'Shape Change Into',
|
||||
id: 'actorId',
|
||||
type: 'select',
|
||||
choices,
|
||||
effects,
|
||||
values,
|
||||
epic: false,
|
||||
effect: false,
|
||||
},
|
||||
{
|
||||
name: 'Duration',
|
||||
type: 'checkbox',
|
||||
@ -84,7 +65,7 @@ export class ShapeChangeEffect extends ActorFolderEffect {
|
||||
effect: false,
|
||||
},
|
||||
{
|
||||
name: 'Transform',
|
||||
name: 'Transform Other?',
|
||||
type: 'select',
|
||||
default: 'none',
|
||||
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() {
|
||||
let desc = super.description;
|
||||
return desc;
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
{{#if targets.length}}
|
||||
<p>
|
||||
<strong>Targets</strong>:
|
||||
{{#each targets}}{{#if @index}}, {{/if}}{{this}}{{/each}}
|
||||
{{#each targets}}{{#if @index}}, {{/if}}{{{this}}}{{/each}}
|
||||
{{#if recipients.cost}}
|
||||
<br>({{#if recipients.epic}}⭐ {{/if}}Additional Recipients
|
||||
{{recipients.cost}}pp each × {{recipients.count}} = {{recipients.total}})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user