Skip to content

Commit

Permalink
Merge pull request #188 from League-of-Fabulous-Developers/dev
Browse files Browse the repository at this point in the history
V2.4.8 Update
  • Loading branch information
spyrella authored Dec 25, 2024
2 parents 266e582 + 92a930b commit 9539451
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 53 deletions.
68 changes: 48 additions & 20 deletions module/expressions/expressions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,54 @@ import { MathHelper } from '../helpers/math-helper.mjs';
* @property {FUActor} actor
* @property {FUItem} item
* @property {FUActor[]} targets
* @remarks Do not serialize this class, as it references full objects. Instead store their uuids
* and resolve them with the static constructor
*/
export class ExpressionContext {
constructor(actor, item, targets) {
this.actor = actor;
this.item = item;
this.targets = targets;
}

/**
* @param {String} actorUuid
* @param {String} itemUuid
* @param {FUActor[]} targets
* @returns {ExpressionContext}
*/
static fromUuid(actorUuid, itemUuid, targets) {
let actor = undefined;
if (actorUuid !== undefined) {
actor = fromUuidSync(actorUuid);
}

let item = undefined;
if (itemUuid !== undefined) {
item = fromUuidSync(itemUuid);
}
return new ExpressionContext(actor, item, targets);
}

/**
* @param {String} match
*/
assertActor(match) {
if (this.actor == null) {
ui.notifications.warn('FU.ChatEvaluateAmountNoActor', { localize: true });
throw new Error(`No reference to an actor provided while evaluating expression "${match}"`);
}
}

/**
* @param {String} match
*/
assertItem(match) {
if (this.item == null) {
ui.notifications.warn('FU.ChatEvaluateAmountNoItem', { localize: true });
throw new Error(`No reference to an item provided while evaluating expression "${match}"`);
}
}
}

// DSL supported by the inline amount expression
Expand Down Expand Up @@ -63,20 +104,6 @@ function evaluate(expression, context) {
return result;
}

function assertActorInContext(context, match) {
if (context.actor == null) {
ui.notifications.warn('FU.ChatEvaluateAmountNoActor', { localize: true });
throw new Error(`No reference to an actor provided while evaluating "${match}"`);
}
}

function assertItemInContext(context, match) {
if (context.item == null) {
ui.notifications.warn('FU.ChatEvaluateAmountNoItem', { localize: true });
throw new Error(`No reference to an item provided while evaluating expression "${match}"`);
}
}

/**
* @description Evaluates functions within the expression using the available context
* @param {String} expression
Expand All @@ -88,7 +115,7 @@ function evaluateReferencedFunctions(expression, context) {

function evaluate(match, label, path, p3, args, groups) {
if (match.includes(actorLabel)) {
assertActorInContext(context, match);
context.assertActor(match);
let splitArgs = args.split(',');

const functionPath = `system.${path}`;
Expand Down Expand Up @@ -140,12 +167,12 @@ function evaluateVariables(expression, context) {
return ImprovisedEffect.calculateAmountFromContext(symbol, context);
// Character level
case 'cl':
assertActorInContext(context, match);
context.assertActor(match);
return context.actor.system.level.value;
// Item level / skill level
case 'il':
case 'sl':
assertItemInContext(context, match);
context.assertItem(match);
return context.item.system.level.value;
default:
throw new Error(`Unsupported symbol ${symbol}`);
Expand All @@ -167,8 +194,9 @@ function evaluateMacros(expression, context) {
const splitArgs = params.split(',');
switch (name) {
case `sl`: {
assertActorInContext(context, match);
context.assertActor(match);
const skillId = splitArgs[0].match(/(\w+-*\s*)+/gm)[0];
console.debug(`Resolved actor ${context.actor} from chat message`);
const skill = context.actor.getSingleItemByFuid(skillId, 'skill');
if (!skill) {
ui.notifications.warn('FU.ChatEvaluateNoSkill', { localize: true });
Expand Down Expand Up @@ -219,11 +247,11 @@ function evaluateReferencedProperties(expression, context) {
let propertyPath = '';

if (match.includes(itemLabel)) {
assertItemInContext(context, match);
context.assertItem(match);
root = context.item;
propertyPath = match.replace(`${referenceSymbol}${itemLabel}.`, 'system.');
} else if (match.includes(actorLabel)) {
assertActorInContext(context, match);
context.assertActor(match);
root = context.actor;
propertyPath = match.replace(`${referenceSymbol}${actorLabel}.`, 'system.');
}
Expand Down
2 changes: 1 addition & 1 deletion module/helpers/improvised-effect.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function calculateAmountFromContext(effect, context) {
}

let level = 5;
if (context.actor !== undefined) {
if (context.actor) {
level = context.actor.system.level.value;
console.debug(`Used the source actor to calculate level`);
} else {
Expand Down
12 changes: 6 additions & 6 deletions module/helpers/inline-damage.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ function activateListeners(document, html) {
if (targets.length > 0) {
const sourceInfo = InlineHelper.determineSource(document, this);
const type = this.dataset.type;
const context = new ExpressionContext(sourceInfo.actor, sourceInfo.item, targets);
const context = ExpressionContext.fromUuid(sourceInfo.actorUuid, sourceInfo.itemUuid, targets);
const amount = Expressions.evaluate(this.dataset.amount, context);

const baseDamageInfo = { type, total: amount, modifierTotal: 0 };
await applyDamagePipelineWithHook({ event: null, targets, sourceUuid: sourceInfo.uuid, sourceName: sourceInfo.name || 'inline damage', baseDamageInfo, extraDamageInfo: {}, clickModifiers: null });
await applyDamagePipelineWithHook({ event: null, targets, sourceUuid: sourceInfo.actorUuid, sourceName: sourceInfo.name || 'inline damage', baseDamageInfo, extraDamageInfo: {}, clickModifiers: null });
}
})
.on('dragstart', function (event) {
Expand All @@ -78,7 +78,7 @@ function activateListeners(document, html) {
const sourceInfo = InlineHelper.determineSource(document, this);
const data = {
type: INLINE_DAMAGE,
source: sourceInfo,
sourceInfo: sourceInfo,
damageType: this.dataset.type,
amount: this.dataset.amount,
};
Expand All @@ -88,12 +88,12 @@ function activateListeners(document, html) {
}

// TODO: Implement
function onDropActor(actor, sheet, { type, damageType, amount, source, ignore }) {
function onDropActor(actor, sheet, { type, damageType, amount, sourceInfo, ignore }) {
if (type === INLINE_DAMAGE) {
const context = new ExpressionContext(source.actor, source.item, [actor]);
const context = ExpressionContext.fromUuid(sourceInfo.actorUuid, sourceInfo.itemUuid, [actor]);
const _amount = Expressions.evaluate(amount, context);
const baseDamageInfo = { type: damageType, total: _amount, modifierTotal: 0 };
applyDamagePipelineWithHook({ event: null, targets: [actor], sourceUuid: source.uuid, sourceName: source.name || 'inline damage', baseDamageInfo, extraDamageInfo: {}, clickModifiers: null });
applyDamagePipelineWithHook({ event: null, targets: [actor], sourceUuid: sourceInfo.actorUuid, sourceName: sourceInfo.name || 'inline damage', baseDamageInfo, extraDamageInfo: {}, clickModifiers: null });
return false;
}
}
Expand Down
43 changes: 20 additions & 23 deletions module/helpers/inline-helper.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@ import { Expressions } from '../expressions/expressions.mjs';
/**
* @description Information about a lookup for the source of an inline element
* @property {String} name
* @property {Number} uuid
* @property {FUActor} actor
* @property {FUItem} item
* @property {String} itemUuid
* @property {String} actorUuid
*/
export class InlineSourceInfo {
constructor(name, uuid, actor, item) {
constructor(name, actorUuid, itemUuid) {
this.name = name;
this.uuid = uuid;
this.actor = actor;
this.item = item;
this.itemUuid = itemUuid;
this.actorUuid = actorUuid;
}
}

Expand All @@ -28,45 +26,44 @@ export class InlineSourceInfo {
*/
function determineSource(document, element) {
let name = game.i18n.localize('FU.UnknownDamageSource');
let uuid = null;
let actor = undefined;
let item = null;
let itemUuid = null;
let actorUuid = null;

// Happens when clicked from the actor window
if (document instanceof FUActor) {
actor = document;
actorUuid = document.uuid;
console.debug(`Determining source document as Actor ${actorUuid}`);
const itemId = $(element).closest('[data-item-id]').data('itemId');
if (itemId) {
item = document.items.get(itemId);
let item = document.items.get(itemId);
itemUuid = itemId;
name = item.name;
uuid = item.uuid;
} else {
name = document.name;
uuid = document.uuid;
}
} else if (document instanceof FUItem) {
item = document;
name = document.name;
uuid = document.uuid;
itemUuid = document.uuid;
console.debug(`Determining source document as Item ${itemUuid}`);
} else if (document instanceof ChatMessage) {
const speakerActor = ChatMessage.getSpeakerActor(document.speaker);
if (speakerActor) {
actor = speakerActor;
actorUuid = speakerActor.uuid;
name = speakerActor.name;
uuid = speakerActor.uuid;
}
const check = document.getFlag(SYSTEM, Flags.ChatMessage.CheckV2);
if (check) {
const itemUuid = check.itemUuid;
item = fromUuidSync(itemUuid);
itemUuid = check.itemUuid;
} else {
item = document.getFlag(SYSTEM, Flags.ChatMessage.Item);
let item = document.getFlag(SYSTEM, Flags.ChatMessage.Item);
if (item) {
name = item.name;
uuid = item.uuid;
itemUuid = item.uuid;
}
}
console.debug(`Determining source document as ChatMessage ${name}`);
}
return new InlineSourceInfo(name, uuid, actor, item);
return new InlineSourceInfo(name, actorUuid, itemUuid);
}

/**
Expand Down
6 changes: 3 additions & 3 deletions module/helpers/inline-resources.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ function activateListeners(document, html) {
const sourceInfo = InlineHelper.determineSource(document, this);
const type = this.dataset.type;
const uncapped = this.dataset.uncapped === 'true';
const context = new ExpressionContext(sourceInfo.actor, sourceInfo.item, targets);
const context = ExpressionContext.fromUuid(sourceInfo.actorUuid, sourceInfo.itemUuid, targets);
const amount = Expressions.evaluate(this.dataset.amount, context);

if (this.classList.contains(classInlineRecovery)) {
Expand All @@ -136,8 +136,8 @@ function activateListeners(document, html) {
if (!(this instanceof HTMLElement) || !event.dataTransfer) {
return;
}
const sourceInfo = InlineHelper.determineSource(document, this);

const sourceInfo = InlineHelper.determineSource(document, this);
const data = {
type: this.classList.contains(classInlineRecovery) ? INLINE_RECOVERY : INLINE_LOSS,
sourceInfo: sourceInfo,
Expand All @@ -151,7 +151,7 @@ function activateListeners(document, html) {
}

function onDropActor(actor, sheet, { type, recoveryType, amount, sourceInfo, uncapped }) {
const context = new ExpressionContext(sourceInfo.actor, sourceInfo.item, [actor]);
const context = ExpressionContext.fromUuid(sourceInfo.actorUuid, sourceInfo.itemUuid, [actor]);
amount = Expressions.evaluate(amount, context);

if (type === INLINE_RECOVERY && !Number.isNaN(amount)) {
Expand Down

0 comments on commit 9539451

Please sign in to comment.