mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-03-07 14:36:13 +01:00
Merged with development
This commit is contained in:
commit
4944d1ef49
161 changed files with 2733 additions and 694 deletions
|
|
@ -9,3 +9,4 @@ export { default as DhScene } from './scene.mjs';
|
|||
export { default as DhToken } from './token.mjs';
|
||||
export { default as DhTooltipManager } from './tooltipManager.mjs';
|
||||
export { default as DhTemplateManager } from './templateManager.mjs';
|
||||
export { default as DhTokenManager } from './tokenManager.mjs';
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
|
|||
}
|
||||
|
||||
if (this.parent?.type === 'domainCard') {
|
||||
return this.parent.system.inVault;
|
||||
const isVaultSupressed = this.parent.system.isVaultSupressed;
|
||||
const domainTouchedSupressed = this.parent.system.isDomainTouchedSuppressed;
|
||||
|
||||
return isVaultSupressed || domainTouchedSupressed;
|
||||
}
|
||||
|
||||
return super.isSuppressed;
|
||||
|
|
@ -106,23 +109,29 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
|
|||
|
||||
/**@inheritdoc*/
|
||||
static applyField(model, change, field) {
|
||||
const isOriginTarget = change.value.toLowerCase().includes('origin.@');
|
||||
change.value = DhActiveEffect.getChangeValue(model, change, change.effect);
|
||||
super.applyField(model, change, field);
|
||||
}
|
||||
|
||||
/** */
|
||||
static getChangeValue(model, change, effect) {
|
||||
let value = change.value;
|
||||
const isOriginTarget = value.toLowerCase().includes('origin.@');
|
||||
let parseModel = model;
|
||||
if (isOriginTarget && change.effect.origin) {
|
||||
change.value = change.value.replaceAll(/origin\.@/gi, '@');
|
||||
if (isOriginTarget && effect.origin) {
|
||||
value = change.value.replaceAll(/origin\.@/gi, '@');
|
||||
try {
|
||||
const effect = foundry.utils.fromUuidSync(change.effect.origin);
|
||||
const originEffect = foundry.utils.fromUuidSync(effect.origin);
|
||||
const doc =
|
||||
effect.parent?.parent instanceof game.system.api.documents.DhpActor
|
||||
? effect.parent
|
||||
: effect.parent.parent;
|
||||
originEffect.parent?.parent instanceof game.system.api.documents.DhpActor
|
||||
? originEffect.parent
|
||||
: originEffect.parent.parent;
|
||||
if (doc) parseModel = doc;
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
const evalValue = this.effectSafeEval(itemAbleRollParse(change.value, parseModel, change.effect.parent));
|
||||
change.value = evalValue ?? change.value;
|
||||
super.applyField(model, change, field);
|
||||
const evalValue = this.effectSafeEval(itemAbleRollParse(value, parseModel, effect.parent));
|
||||
return evalValue ?? value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -104,6 +104,16 @@ export default class DhpActor extends Actor {
|
|||
}
|
||||
}
|
||||
|
||||
async _preDelete() {
|
||||
if (this.prototypeToken.actorLink) {
|
||||
game.system.registeredTriggers.unregisterItemTriggers(this.items);
|
||||
} else {
|
||||
for (const token of this.getActiveTokens()) {
|
||||
game.system.registeredTriggers.unregisterItemTriggers(token.actor.items);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_onDelete(options, userId) {
|
||||
super._onDelete(options, userId);
|
||||
for (const party of this.parties) {
|
||||
|
|
@ -646,6 +656,19 @@ export default class DhpActor extends Actor {
|
|||
}
|
||||
}
|
||||
|
||||
const results = await game.system.registeredTriggers.runTrigger(
|
||||
CONFIG.DH.TRIGGER.triggers.postDamageReduction.id,
|
||||
this,
|
||||
updates,
|
||||
this
|
||||
);
|
||||
|
||||
if (results?.length) {
|
||||
const resourceMap = new ResourceUpdateMap(results[0].originActor);
|
||||
for (var result of results) resourceMap.addResources(result.updates);
|
||||
resourceMap.updateResources();
|
||||
}
|
||||
|
||||
updates.forEach(
|
||||
u =>
|
||||
(u.value =
|
||||
|
|
|
|||
|
|
@ -157,7 +157,12 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
|||
event.stopPropagation();
|
||||
const config = foundry.utils.deepClone(this.system);
|
||||
config.event = event;
|
||||
await this.system.action?.workflow.get('damage')?.execute(config, this._id, true);
|
||||
if (this.system.action) {
|
||||
const actor = await foundry.utils.fromUuid(config.source.actor);
|
||||
const item = actor?.items.get(config.source.item) ?? null;
|
||||
config.effects = await game.system.api.data.actions.actionsTypes.base.getEffects(actor, item);
|
||||
await this.system.action.workflow.get('damage')?.execute(config, this._id, true);
|
||||
}
|
||||
|
||||
Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll });
|
||||
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||
|
|
@ -189,7 +194,16 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
|||
return ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelectedOrPerm'));
|
||||
|
||||
this.consumeOnSuccess();
|
||||
this.system.action?.workflow.get('applyDamage')?.execute(config, targets, true);
|
||||
if (this.system.action) this.system.action.workflow.get('applyDamage')?.execute(config, targets, true);
|
||||
else {
|
||||
for (const target of targets) {
|
||||
const actor = await foundry.utils.fromUuid(target.actorId);
|
||||
if (!actor) continue;
|
||||
|
||||
if (this.system.hasHealing) actor.takeHealing(this.system.damage);
|
||||
else actor.takeDamage(this.system.damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onRollSave(event) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export default class DHItem extends foundry.documents.Item {
|
|||
static async createDocuments(sources, operation) {
|
||||
// Ensure that items being created are valid to the actor its being added to
|
||||
const actor = operation.parent;
|
||||
sources = actor?.system?.isItemValid ? sources.filter((s) => actor.system.isItemValid(s)) : sources;
|
||||
sources = actor?.system?.isItemValid ? sources.filter(s => actor.system.isItemValid(s)) : sources;
|
||||
return super.createDocuments(sources, operation);
|
||||
}
|
||||
|
||||
|
|
@ -146,6 +146,16 @@ export default class DHItem extends foundry.documents.Item {
|
|||
/* -------------------------------------------- */
|
||||
|
||||
async use(event) {
|
||||
/* DomainCard check. Can be expanded or made neater */
|
||||
if (this.system.isDomainTouchedSuppressed) {
|
||||
return ui.notifications.warn(
|
||||
game.i18n.format('DAGGERHEART.UI.Notifications.domainTouchRequirement', {
|
||||
nr: this.domainTouched,
|
||||
domain: game.i18n.localize(CONFIG.DH.DOMAIN.allDomains()[this.domain].label)
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const actions = new Set(this.system.actionsList);
|
||||
if (actions?.size) {
|
||||
let action = actions.first();
|
||||
|
|
@ -198,4 +208,23 @@ export default class DHItem extends foundry.documents.Item {
|
|||
|
||||
cls.create(msg);
|
||||
}
|
||||
|
||||
deleteTriggers() {
|
||||
const actions = Array.from(this.system.actions ?? []);
|
||||
if (!actions.length) return;
|
||||
|
||||
const triggerKeys = actions.flatMap(action => action.triggers.map(x => x.trigger));
|
||||
|
||||
game.system.registeredTriggers.unregisterTriggers(triggerKeys, this.uuid);
|
||||
|
||||
if (!(this.actor.parent instanceof game.system.api.documents.DhToken)) {
|
||||
for (const token of this.actor.getActiveTokens()) {
|
||||
game.system.registeredTriggers.unregisterTriggers(triggerKeys, `${token.document.uuid}.${this.uuid}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async _preDelete() {
|
||||
this.deleteTriggers();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,4 +37,30 @@ export default class DhScene extends Scene {
|
|||
this.#sizeSyncBatch.clear();
|
||||
this.updateEmbeddedDocuments('Token', entries, { animation: { movementSpeed: 1.5 } });
|
||||
}, 0);
|
||||
|
||||
prepareBaseData() {
|
||||
super.prepareBaseData();
|
||||
|
||||
if (this instanceof game.system.api.documents.DhScene) {
|
||||
const system = new game.system.api.data.scenes.DHScene(this.flags.daggerheart);
|
||||
|
||||
// Register this scene to all environements
|
||||
for (const environment of system.sceneEnvironments) {
|
||||
environment.system.scenes?.add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_onDelete(options, userId) {
|
||||
super._onDelete(options, userId);
|
||||
|
||||
if (this instanceof game.system.api.documents.DhScene) {
|
||||
const system = new game.system.api.data.scenes.DHScene(this.flags.daggerheart);
|
||||
|
||||
// Clear this scene from all environments that aren't deleted
|
||||
for (const environment of system.sceneEnvironments) {
|
||||
environment?.system?.scenes?.delete(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -536,4 +536,10 @@ export default class DHToken extends CONFIG.Token.documentClass {
|
|||
};
|
||||
}
|
||||
//#endregion
|
||||
|
||||
async _preDelete() {
|
||||
if (this.actor && !this.actor.prototypeToken?.actorLink) {
|
||||
game.system.registeredTriggers.unregisterItemTriggers(this.actor.items);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
104
module/documents/tokenManager.mjs
Normal file
104
module/documents/tokenManager.mjs
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* A singleton class that handles preview tokens.
|
||||
*/
|
||||
|
||||
export default class DhTokenManager {
|
||||
#activePreview;
|
||||
#actor;
|
||||
#resolve;
|
||||
|
||||
/**
|
||||
* Create a template preview, deactivating any existing ones.
|
||||
* @param {object} data
|
||||
*/
|
||||
async createPreview(actor, tokenData) {
|
||||
this.#actor = actor;
|
||||
const token = await canvas.tokens._createPreview(
|
||||
{
|
||||
...actor.prototypeToken,
|
||||
displayName: 50,
|
||||
...tokenData
|
||||
},
|
||||
{ renderSheet: false, actor }
|
||||
);
|
||||
|
||||
this.#activePreview = {
|
||||
document: token.document,
|
||||
object: token,
|
||||
origin: { x: token.document.x, y: token.document.y }
|
||||
};
|
||||
|
||||
this.#activePreview.events = {
|
||||
contextmenu: this.#cancelTemplate.bind(this),
|
||||
mousedown: this.#confirmTemplate.bind(this),
|
||||
mousemove: this.#onDragMouseMove.bind(this)
|
||||
};
|
||||
|
||||
canvas.stage.on('mousemove', this.#activePreview.events.mousemove);
|
||||
canvas.stage.on('mousedown', this.#activePreview.events.mousedown);
|
||||
canvas.app.view.addEventListener('contextmenu', this.#activePreview.events.contextmenu);
|
||||
}
|
||||
|
||||
/* Currently intended for using as a preview of where to create a token. (note the flag) */
|
||||
async createPreviewAsync(actor, tokenData = {}) {
|
||||
return new Promise(resolve => {
|
||||
this.#resolve = resolve;
|
||||
this.createPreview(actor, { ...tokenData, flags: { daggerheart: { createPlacement: true } } });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the movement of the token preview on mousedrag.
|
||||
* @param {mousemove Event} event
|
||||
*/
|
||||
#onDragMouseMove(event) {
|
||||
event.stopPropagation();
|
||||
const { moveTime, object } = this.#activePreview;
|
||||
const update = {};
|
||||
|
||||
const now = Date.now();
|
||||
if (now - (moveTime || 0) <= 16) return;
|
||||
this.#activePreview.moveTime = now;
|
||||
|
||||
let cursor = event.getLocalPosition(canvas.templates);
|
||||
|
||||
Object.assign(update, canvas.grid.getTopLeftPoint(cursor));
|
||||
|
||||
object.document.updateSource(update);
|
||||
object.renderFlags.set({ refresh: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the preview token on right-click.
|
||||
* @param {contextmenu Event} event
|
||||
*/
|
||||
#cancelTemplate(_event, resolved) {
|
||||
const { mousemove, mousedown, contextmenu } = this.#activePreview.events;
|
||||
this.#activePreview.object.destroy();
|
||||
|
||||
canvas.stage.off('mousemove', mousemove);
|
||||
canvas.stage.off('mousedown', mousedown);
|
||||
canvas.app.view.removeEventListener('contextmenu', contextmenu);
|
||||
if (this.#resolve && !resolved) this.#resolve(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a real Actor and token at the preview location and cancels the preview.
|
||||
* @param {click Event} event
|
||||
*/
|
||||
async #confirmTemplate(event) {
|
||||
event.stopPropagation();
|
||||
this.#cancelTemplate(event, true);
|
||||
|
||||
const actor = this.#actor.inCompendium
|
||||
? await game.system.api.documents.DhpActor.create(this.#actor.toObject())
|
||||
: this.#actor;
|
||||
const tokenData = await actor.getTokenDocument();
|
||||
const result = await canvas.scene.createEmbeddedDocuments('Token', [
|
||||
{ ...tokenData, x: this.#activePreview.document.x, y: this.#activePreview.document.y }
|
||||
]);
|
||||
|
||||
this.#activePreview = undefined;
|
||||
if (this.#resolve && result.length) this.#resolve(result[0]);
|
||||
}
|
||||
}
|
||||
|
|
@ -67,7 +67,7 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
|||
if (item) {
|
||||
const isAction = item instanceof game.system.api.models.actions.actionsTypes.base;
|
||||
const isEffect = item instanceof ActiveEffect;
|
||||
await this.enrichText(item, isAction || isEffect);
|
||||
await this.enrichText(item);
|
||||
|
||||
const type = isAction ? 'action' : isEffect ? 'effect' : item.type;
|
||||
html = await foundry.applications.handlebars.renderTemplate(
|
||||
|
|
@ -202,10 +202,20 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
|||
}
|
||||
}
|
||||
|
||||
async enrichText(item, flatStructure) {
|
||||
async enrichText(item) {
|
||||
const { TextEditor } = foundry.applications.ux;
|
||||
|
||||
if (item.system?.metadata?.hasDescription) {
|
||||
const enrichedValue =
|
||||
(await item.system?.getEnrichedDescription?.()) ??
|
||||
(await TextEditor.enrichHTML(item.system.description));
|
||||
foundry.utils.setProperty(item, 'system.enrichedDescription', enrichedValue);
|
||||
} else if (item.description) {
|
||||
const enrichedValue = await TextEditor.enrichHTML(item.description);
|
||||
foundry.utils.setProperty(item, 'enrichedDescription', enrichedValue);
|
||||
}
|
||||
|
||||
const enrichPaths = [
|
||||
{ path: flatStructure ? '' : 'system', name: 'description' },
|
||||
{ path: 'system', name: 'features' },
|
||||
{ path: 'system', name: 'actions' },
|
||||
{ path: 'system', name: 'customActions' }
|
||||
|
|
@ -220,12 +230,15 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
|||
for (const [index, itemValue] of pathValue.entries()) {
|
||||
const itemIsAction = itemValue instanceof game.system.api.models.actions.actionsTypes.base;
|
||||
const value = itemIsAction || !itemValue?.item ? itemValue : itemValue.item;
|
||||
const enrichedValue = await TextEditor.enrichHTML(value.system?.description ?? value.description);
|
||||
const enrichedValue =
|
||||
(await value.system?.getEnrichedDescription?.()) ??
|
||||
(await TextEditor.enrichHTML(value.system?.description ?? value.description));
|
||||
if (itemIsAction) value.enrichedDescription = enrichedValue;
|
||||
else foundry.utils.setProperty(item, `${basePath}.${index}.enrichedDescription`, enrichedValue);
|
||||
}
|
||||
} else {
|
||||
const enrichedValue = await TextEditor.enrichHTML(pathValue);
|
||||
const enrichedValue =
|
||||
(await item.system?.getEnrichedDescription?.()) ?? (await TextEditor.enrichHTML(pathValue));
|
||||
foundry.utils.setProperty(
|
||||
item,
|
||||
`${data.path ? `${data.path}.` : ''}enriched${data.name.capitalize()}`,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue