Skip to content

Commit

Permalink
Merge pull request dmdorman#1353 from phBalance/phBalance/clean-up-me…
Browse files Browse the repository at this point in the history
…ssages

fix(resources): fix up chat messages and refactor
  • Loading branch information
phBalance authored Oct 19, 2024
2 parents d0cf5f3 + 6927807 commit d4aa648
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 69 deletions.
5 changes: 4 additions & 1 deletion module/actor/actor-sheet.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,7 @@ export class HeroSystemActorSheet extends ActorSheet {
error: resourceError,
warning: resourceWarning,
resourcesUsedDescription,
resourcesUsedDescriptionRenderedRoll,
} = await userInteractiveVerifyOptionallyPromptThenSpendResources(item, strengthUsed);
if (resourceError) {
return ui.notifications.error(resourceError);
Expand All @@ -976,7 +977,9 @@ export class HeroSystemActorSheet extends ActorSheet {
item,
targetEntangle: "true",

resourcesUsedDescription,
resourcesUsedDescription: resourcesUsedDescription
? `Spent ${resourcesUsedDescription}${resourcesUsedDescriptionRenderedRoll}`
: "",

// dice rolls
renderedDamageRoll: damageRenderedResult,
Expand Down
6 changes: 2 additions & 4 deletions module/actor/actor.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1290,7 +1290,7 @@ export class HeroSystem6eActor extends Actor {
heroJson.CHARACTER.POWERS.length +
heroJson.CHARACTER.SKILLS.length +
heroJson.CHARACTER.TALENTS.length +
(this.type === "pc" || this.type === "npc" ? 1 : 0) +
(this.type === "pc" || this.type === "npc" ? 1 : 0) + // Free stuff
1 + // Validating adjustment and powers
1 + // Images
1 + // Final save
Expand Down Expand Up @@ -1337,8 +1337,6 @@ export class HeroSystem6eActor extends Actor {
}
break;
}
// Indicate we're processing this aspect of the HDC. If it crashes it should remain showing this progress note.
//uploadProgressBar.advance(`${this.name}: Adding ${itemTag} ${itemData.name}`);

if (this.id) {
itemsToCreate.push(itemData);
Expand Down Expand Up @@ -1468,7 +1466,7 @@ export class HeroSystem6eActor extends Actor {
uploadPerformance.itemPromiseArray = new Date() - uploadPerformance._d;
uploadPerformance._d = new Date();

// Do CSL's last so we can property select the attacks
// Do CSLs last so we can property select the attacks
await Promise.all(
this.items
.filter((o) => !["COMBAT_LEVELS", "MENTAL_COMBAT_LEVELS"].includes(o.system.XMLID))
Expand Down
144 changes: 91 additions & 53 deletions module/item/item-attack.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,7 @@ export async function AttackToHit(item, options) {
warning: resourceWarning,
resourcesRequired,
resourcesUsedDescription,
resourcesUsedDescriptionRenderedRoll,
} = await userInteractiveVerifyOptionallyPromptThenSpendResources(item, {
...options,
...{ noResourceUse: false },
Expand Down Expand Up @@ -720,7 +721,7 @@ export async function AttackToHit(item, options) {
const chatData = {
user: game.user._id,
type: CONST.CHAT_MESSAGE_TYPES.OTHER,
content: resourcesUsedDescription,
content: `${resourcesUsedDescription}${resourcesUsedDescriptionRenderedRoll}`,
whisper: ChatMessage.getWhisperRecipients("GM"),
speaker,
};
Expand Down Expand Up @@ -782,7 +783,7 @@ export async function AttackToHit(item, options) {

// endurance
useEnd: resourcesRequired.end,
resourcesUsedDescription,
resourcesUsedDescription: `${resourcesUsedDescription}${resourcesUsedDescriptionRenderedRoll}`,

// misc
tags: heroRoller.tags(),
Expand Down Expand Up @@ -3055,6 +3056,7 @@ async function _calcKnockback(body, item, options, knockbackMultiplier) {
*
* @param {HeroSystem6eItem} item
* @param {Object} options
* @param {boolean} options.noResourceUse - true to not consume resources but still indicate how many would have been consumed
*
* @returns Object discriminated union based on error or warning being falsy/truthy
*/
Expand Down Expand Up @@ -3124,7 +3126,7 @@ export async function userInteractiveVerifyOptionallyPromptThenSpendResources(it
}

// The actor is now committed to spending the resources to activate the power
const resourcesUsedDescription = await spendResourcesToUse(
const { resourcesUsedDescription, resourcesUsedDescriptionRenderedRoll } = await spendResourcesToUse(
item,
enduranceReserve,
resourcesRequired.end,
Expand All @@ -3134,8 +3136,8 @@ export async function userInteractiveVerifyOptionallyPromptThenSpendResources(it
!useResources,
);

// Let users know what resources were not consumed
if (!useResources) {
// Let users know what resources were not consumed only if there were any to be consumed
if (!useResources && resourcesUsedDescription) {
const speaker = ChatMessage.getSpeaker({
actor: actor,
});
Expand All @@ -3144,7 +3146,7 @@ export async function userInteractiveVerifyOptionallyPromptThenSpendResources(it
const chatData = {
user: game.user._id,
type: CONST.CHAT_MESSAGE_TYPES.OTHER,
content: `${game.user.name} is using SHIFT to override using ${resourcesUsedDescription} for <b>${item.name}</b>`,
content: `${game.user.name} is using SHIFT to override using ${resourcesUsedDescription} for <b>${item.name}</b>${resourcesUsedDescriptionRenderedRoll}`,
whisper: whisperUserTargetsForActor(this),
speaker,
};
Expand All @@ -3153,9 +3155,14 @@ export async function userInteractiveVerifyOptionallyPromptThenSpendResources(it

return {
resourcesRequired,

// Provide a wordy description of what was used. Indicate if resource use was overridden except if no would have been used.
resourcesUsedDescription: useResources
? `Spent ${resourcesUsedDescription}`
: `${resourcesUsedDescription} overridden with SHIFT`,
? `${resourcesUsedDescription}`
: resourcesUsedDescription
? `${resourcesUsedDescription} overridden with SHIFT`
: resourcesUsedDescription,
resourcesUsedDescriptionRenderedRoll,
};
}

Expand Down Expand Up @@ -3301,6 +3308,37 @@ async function rollStunForEnd(stunDice) {
};
}

/**
* Parse the automation setting for the system. Return what should be automated for
* this actor type.
*
* none: "No Automation",
* npcOnly: "NPCs Only (end, stun, body)",
* pcEndOnly: "PCs (end) and NPCs (end, stun, body)",
* all: "PCs and NPCs (end, stun, body)"
*
* @typedef {Object} HeroSystem6eActorAutomation
* @param {boolean} endurance - Automate END use/tracking
* @param {boolean} stun - Automate STUN use/tracking
* @param {boolean} body - Automate BODY use/tracking
*/
/**
* @param {HeroSystem6eActor} actor
* @returns {HeroSystem6eActorAutomation}
*/
export function actorAutomation(actor) {
const automation = game.settings.get(HEROSYS.module, "automation");

return {
endurance:
automation === "all" ||
(automation === "npcOnly" && actor.type == "npc") ||
(automation === "pcEndOnly" && actor.type === "pc"),
stun: automation === "all" || (automation === "npcOnly" && actor.type == "npc"),
body: automation === "all" || (automation === "npcOnly" && actor.type == "npc"),
};
}

/**
* Spend all resources (END, STUN, charges) provided. Assumes numbers are possible.
*
Expand All @@ -3311,7 +3349,7 @@ async function rollStunForEnd(stunDice) {
* @param {HeroRoller} stunToSpendRoller
* @param {number} chargesToSpend
* @param {boolean} noResourceUse - true if you would like to simulate the resources being used without using them (aka dry run)
* @returns
* @returns {Object}
*/
async function spendResourcesToUse(
item,
Expand All @@ -3323,29 +3361,26 @@ async function spendResourcesToUse(
noResourceUse,
) {
const actor = item.actor;
let resourceUsageDescription = "";
const expectedAutomation = actorAutomation(actor);
const canSpendResources = !noResourceUse;
const canSpendEndurance =
canSpendResources &&
actor.inCombat && // TODO: Not sure if we should have this or not. We had it in toggle() but not elsewhere.
expectedAutomation.endurance;
const canSpendStun = canSpendResources && expectedAutomation.stun;
const canSpendCharges = canSpendResources;
let resourcesUsedDescription = "";
let resourcesUsedDescriptionRenderedRoll = "";

// Deduct endurance
// none: "No Automation",
// npcOnly: "NPCs Only (end, stun, body)",
// pcEndOnly: "PCs (end) and NPCs (end, stun, body)",
// all: "PCs and NPCs (end, stun, body)"
const automation = game.settings.get(HEROSYS.module, "automation");
const actorInCombat = actor.inCombat;
const noEnduranceUse =
!actorInCombat && // TODO: Not sure if we should have this or not. We had it in toggle() but not elsewhere.
(automation === "all" ||
(automation === "npcOnly" && actor.type == "npc") ||
(automation === "pcEndOnly" && actor.type === "pc"));

if (item.system.USE_END_RESERVE) {
if (item.system.USE_END_RESERVE && endToSpend) {
if (enduranceReserve) {
const reserveEnd = parseInt(enduranceReserve?.system.value || 0);
const actorNewEndurance = reserveEnd - endToSpend;

resourceUsageDescription = `${endToSpend} END from Endurance Reserve`;
resourcesUsedDescription = `${endToSpend} END from Endurance Reserve`;

if (!noResourceUse && !noEnduranceUse) {
if (canSpendEndurance) {
await enduranceReserve.update({
"system.value": actorNewEndurance,
"system.description": enduranceReserve.system.description,
Expand All @@ -3356,52 +3391,55 @@ async function spendResourcesToUse(
const actorStun = actor.system.characteristics.stun.value;
const actorEndurance = actor.system.characteristics.end.value;
const actorNewEndurance = actorEndurance - endToSpend;

const actorChanges = {};

if (stunToSpend > 0) {
resourceUsageDescription = `
<span>
${endToSpend} END and ${stunToSpend} STUN
<i class="fal fa-circle-info" data-tooltip="<b>USING STUN FOR ENDURANCE</b><br>
A character at 0 END who still wishes to perform Actions
may use STUN as END. The character takes 1d6 STUN Only
damage (with no defense) for every 2 END (or fraction thereof)
expended. Yes, characters can Knock themselves out this way.
"></i>
</span>
`;

const stunRenderedResult = await stunToSpendRoller.render();
resourceUsageDescription += stunRenderedResult;

await ui.notifications.warn(`${actor.name} used ${stunToSpend} STUN for ENDURANCE.`);

// NOTE: Can have a negative END for reasons other than spending END (e.g. drains), however, spend END on
// an attack can't lower it beyond its starting value or 0 (whichever is smaller).
actorChanges["system.characteristics.stun.value"] = actorStun - stunToSpend;
resourcesUsedDescription = `
<span>
${endToSpend} END and ${stunToSpend} STUN
<i class="fal fa-circle-info" data-tooltip="<b>USING STUN FOR ENDURANCE</b><br>
A character at 0 END who still wishes to perform Actions
may use STUN as END. The character takes 1d6 STUN Only
damage (with no defense) for every 2 END (or fraction thereof)
expended. Yes, characters can Knock themselves out this way.
"></i>
</span>
`;

resourcesUsedDescriptionRenderedRoll = await stunToSpendRoller.render();

if (canSpendStun) {
await ui.notifications.warn(`${actor.name} used ${stunToSpend} STUN for ENDURANCE.`);

// NOTE: Can have a negative END for reasons other than spending END (e.g. drains), however, spend END on
// an attack can't lower it beyond its starting value or 0 (whichever is smaller).
actorChanges["system.characteristics.stun.value"] = actorStun - stunToSpend;
}
} else {
resourceUsageDescription = `${endToSpend} END`;
resourcesUsedDescription = `${endToSpend} END`;
}

actorChanges["system.characteristics.end.value"] = actorNewEndurance;
if (canSpendEndurance) {
actorChanges["system.characteristics.end.value"] = actorNewEndurance;

if (!noResourceUse && !noEnduranceUse) {
await actor.update(actorChanges);
}
}

// Spend charges
if (chargesToSpend > 0) {
resourceUsageDescription = `${resourceUsageDescription}${
resourceUsageDescription ? " and " : ""
resourcesUsedDescription = `${resourcesUsedDescription}${
resourcesUsedDescription ? " and " : ""
}${chargesToSpend} charge${chargesToSpend > 1 ? "s" : ""}`;

if (!noResourceUse) {
if (canSpendCharges) {
const startingCharges = parseInt(item.system.charges?.value || 0);
await item.update({ "system.charges.value": startingCharges - chargesToSpend });
}
}

return resourceUsageDescription;
return {
resourcesUsedDescription,
resourcesUsedDescriptionRenderedRoll,
};
}
24 changes: 18 additions & 6 deletions module/item/item.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,9 @@ export class HeroSystem6eItem extends Item {
error: resourceError,
warning: resourceWarning,
resourcesUsedDescription,
resourcesUsedDescriptionRenderedRoll,
} = await userInteractiveVerifyOptionallyPromptThenSpendResources(item, {
userForceOverride: !!event?.shiftKey,
noResourceUse: !!event?.shiftKey,
});
if (resourceError) {
return ui.notifications.error(resourceError);
Expand All @@ -485,7 +486,7 @@ export class HeroSystem6eItem extends Item {
const chatData = {
user: game.user._id,
type: CONST.CHAT_MESSAGE_TYPES.OTHER,
content: `${resourcesUsedDescription} to attempt to activate ${item.name} but attempt failed`,
content: `${resourcesUsedDescription ? `Spent ${resourcesUsedDescription} to attempt` : "Attempted"} to activate ${item.name} but attempt failed${resourcesUsedDescriptionRenderedRoll}`,
whisper: whisperUserTargetsForActor(item.actor),
speaker,
};
Expand All @@ -499,13 +500,13 @@ export class HeroSystem6eItem extends Item {
const chatData = {
user: game.user._id,
type: CONST.CHAT_MESSAGE_TYPES.OTHER,
content: `${resourcesUsedDescription} to activate ${item.name}`,
content: `${resourcesUsedDescription ? `Spent ${resourcesUsedDescription} to activate` : "Activated "} ${item.name}${resourcesUsedDescriptionRenderedRoll}`,
whisper: whisperUserTargetsForActor(item.actor),
speaker,
};
await ChatMessage.create(chatData);

// A continuing charge's use is tracked by an active effect. Start it.
// A continuing charges use is tracked by an active effect. Start it.
await _startIfIsAContinuingCharge(this);

// Invisibility status effect for SIGHTGROUP?
Expand Down Expand Up @@ -1443,8 +1444,10 @@ export class HeroSystem6eItem extends Item {
this.system.charges = {
...this.system.charges,
max: parseInt(CHARGES.OPTION_ALIAS),
recoverable: (CHARGES.ADDER || []).find((o) => o.XMLID == "RECOVERABLE") ? true : false,
continuing: (CHARGES.ADDER || []).find((o) => o.XMLID == "CONTINUING")?.OPTIONID,
recoverable: !!(CHARGES.ADDER || []).find((o) => o.XMLID === "RECOVERABLE"),
continuing: (CHARGES.ADDER || []).find((o) => o.XMLID === "CONTINUING")?.OPTIONID,
boostable: !!(CHARGES.ADDER || []).find((o) => o.XMLID === "BOOSTABLE"),
fuel: !!(CHARGES.ADDER || []).find((o) => o.XMLID === "FUEL"),
};
if (this.system.charges?.value === undefined || this.system.charges?.value === null) {
console.log("Invalid charges. Resetting to max", this);
Expand Down Expand Up @@ -2283,6 +2286,15 @@ export class HeroSystem6eItem extends Item {
if (this.system.XMLID === "WEAPONSMITH" && adderCost > 0) {
adder.BASECOST_total = 1;
}
// else if (this.system.XMLID === "ENTANGLE") {
// // 5E is just a straight 5 points per adder level, but
// // 6E costs 3 points for the first LEVEL and 2 points for the next and so on (typical cost of resistent defense).
// if (adder.XMLID === "ADDITIONALED" || adder.XMLID === "ADDITIONALPD") {
// const groupsOfTwo = Math.floor(adderLevels / 2);
// const cost = 5 * groupsOfTwo + 3 * (adderLevels - 2 * groupsOfTwo);
// adder.BASECOST_total = cost;
// }
// }
} else {
adder.BASECOST_total = 0;
}
Expand Down
7 changes: 4 additions & 3 deletions module/item/skill.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ async function skillRoll(item, actor, target, event) {
const {
error: resourceError,
warning: resourceWarning,
resourcesRequired,
resourcesUsedDescription,
resourcesUsedDescriptionRenderedRoll,
} = await userInteractiveVerifyOptionallyPromptThenSpendResources(item, { noResourceUse: event.shiftKey });
if (resourceError || resourceWarning) {
const chatData = {
Expand Down Expand Up @@ -167,8 +167,9 @@ async function skillRoll(item, actor, target, event) {
}),
rolls: skillRoller.rawRolls(),
renderedRoll: rollHtml,
resourcesUsedDescription:
resourcesRequired.charges > 0 || resourcesRequired.end > 0 ? resourcesUsedDescription : undefined,
resourcesUsedDescription: resourcesUsedDescription
? `Spent ${resourcesUsedDescription}${resourcesUsedDescriptionRenderedRoll}`
: "",
user: game.user._id,
speaker: speaker,
};
Expand Down
2 changes: 1 addition & 1 deletion templates/chat/item-toHit-block-card.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
<div class="hit-roll">
{{#if resourcesUsedDescription}}
<div class="card-section">
<div class="description-tiny">{{{ resourcesUsedDescription }}}</div>
<div class="description-tiny">Spent {{{ resourcesUsedDescription }}}</div>
</div>
{{/if}}

Expand Down
Loading

0 comments on commit d4aa648

Please sign in to comment.