Skip to content

Commit

Permalink
Merge pull request dmdorman#1648 from aeauseth/main
Browse files Browse the repository at this point in the history
Adjustment ETE tests for AID & DRAIN, any characteristic. Passing in existingEffect for fades.
  • Loading branch information
aeauseth authored Dec 22, 2024
2 parents 7aff673 + acb37c2 commit c13ed61
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 66 deletions.
229 changes: 177 additions & 52 deletions module/testing/end-to-end.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { HeroSystem6eItem } from "../item/item.mjs";
import { determineCostPerActivePoint } from "../utility/adjustment.mjs";

export class HeroSystem6eEndToEndTest {
sceneName = "EndToEndTest";
Expand Down Expand Up @@ -29,21 +30,42 @@ export class HeroSystem6eEndToEndTest {
await this.delay();
}
this.orderedListElement.closest(".dialog").addClass("end-to-end-testing");
//$(".dialog.end-to-end-testing").css("left", 5);
$(".dialog.end-to-end-testing").css("left", 5);

await this.performTests();
}

async performTests() {
await this.createTestScene();
await this.createTestActors();
await this.testAid(this.token6);
await this.testAid(this.token5);

// AID
if (!(await this.testAdjustment(this.token6, this.token5, "AID", "STR"))) return;
if (!(await this.testAdjustment(this.token6, this.token5, "AID", "PD"))) return;
if (!(await this.testAdjustment(this.token6, this.token5, "AID", "END"))) return;
if (!(await this.testAdjustment(this.token6, this.token5, "AID", "DEX"))) return;
if (!(await this.testAdjustment(this.token5, this.token5, "AID", "DEX"))) return;

// reset actors
await this.token5.actor.FullHealth();
await this.token6.actor.FullHealth();

// DRAIN
if (!(await this.testAdjustment(this.token6, this.token5, "DRAIN", "STR"))) return;
if (!(await this.testAdjustment(this.token6, this.token5, "DRAIN", "DEX"))) return;
if (!(await this.testAdjustment(this.token5, this.token6, "DRAIN", "DEX"))) return;
}

log(text, css) {
console.log(text);
if (css) {
console.error(text);
} else {
console.log(text);
}

this.orderedListElement.append(`<li style="${css}">${text}</li>`);
//el[0].scrollIntoView();
$(`.dialog .end-to-end-testing li:last-child`)[0].scrollIntoView();
}

async createTestScene() {
Expand Down Expand Up @@ -121,25 +143,38 @@ export class HeroSystem6eEndToEndTest {
this.token6 = this.actor6.getActiveTokens()[0];
}

async testAid(token) {
async testAdjustment(tokenSource, tokenTarget, powerXMLID, targetXMLID) {
// Create AID
const xml = `
<POWER XMLID="AID" ID="1734814179562" BASECOST="0.0" LEVELS="2" ALIAS="Aid" POSITION="1" MULTIPLIER="1.0" GRAPHIC="Burst" COLOR="255 255 255" SFX="Default" SHOW_ACTIVE_COST="Yes" INCLUDE_NOTES_IN_PRINTOUT="Yes" NAME="" INPUT="STR" USESTANDARDEFFECT="No" QUANTITY="1" AFFECTS_PRIMARY="No" AFFECTS_TOTAL="Yes">
<POWER XMLID="${powerXMLID}" ID="1734814179562" BASECOST="0.0" LEVELS="2" ALIAS="${powerXMLID.titleCase()}" POSITION="1"
MULTIPLIER="1.0" GRAPHIC="Burst" COLOR="255 255 255" SFX="Default" SHOW_ACTIVE_COST="Yes"
INCLUDE_NOTES_IN_PRINTOUT="Yes" NAME="" INPUT="${targetXMLID}" USESTANDARDEFFECT="No" QUANTITY="1"
AFFECTS_PRIMARY="No" AFFECTS_TOTAL="Yes">
</POWER>
`;
const itemData = HeroSystem6eItem.itemDataFromXml(xml, token.actor);
const aidItem = await HeroSystem6eItem.create(itemData, { parent: token.actor });
await aidItem._postUpload();
this.log(`Added <b>${aidItem.name}</b> to <b>${aidItem.actor.name}</b>`);
const itemData = HeroSystem6eItem.itemDataFromXml(xml, tokenSource.actor);
const adjustmentItem = await HeroSystem6eItem.create(itemData, { parent: tokenSource.actor });
await adjustmentItem._postUpload();
this.log(
`Added <b>${adjustmentItem.name} ${adjustmentItem.system.INPUT}</b> to <b>${adjustmentItem.actor.name}</b>`,
);

// Target tokenTarget
await game.user.updateTokenTargets([tokenTarget.id]);
await game.user.broadcastActivity({
targets: Array.from(game.user.targets.map((t) => t.id)),
});

// Control targetToken (when we miss we don't have the APPLY to X button)
tokenTarget.control();

// Target ourselves
await game.user.updateTokenTargets([token.id]);
// await game.user.broadcastActivity({
// targets: [this.token6.id],
// });
// for (let i = 0; i < 50; i++) {
// if (game.user.targets.first()?.id === tokenTarget.id) break;
// this.delay(); // For some reson targets don't always update right away.
// }

// Roll
await aidItem.roll();
await adjustmentItem.roll();

// Wait for application to render then Click "Roll to Hit"
let button;
Expand All @@ -148,100 +183,190 @@ export class HeroSystem6eEndToEndTest {
await this.delay();
}
button.click();
this.log(`<b>${aidItem.name}</b> toHit`);
this.log(`CLICK: ${button.text().trim()}`);

// Wait for chat chard then Roll AID
for (let i = 0; i < 50; i++) {
if (
(button = $(`ol#chat-log .chat-message:last-child button.roll-damage[data-item-id='${aidItem.uuid}']`))
.length === 1
(button = $(
`ol#chat-log .chat-message:last-child button.roll-damage[data-item-id='${adjustmentItem.uuid}']`,
)).length === 1
)
break;
await this.delay();
}
// const actionData = JSON.parse(button[0].dataset.actionData);
// if (actionData?.current?.attacks?.[0].targets?.[0].targetId !== tokenTarget.id) {
// this.log(`FAIL: Missing token target. Known async issue, unclear how to resolve.`, "color:red");
// return false;
// }
button.click();
this.log(`Roll <b>${aidItem.name}</b>`);
this.log(`CLICK: ${button.text().trim()}`);

// Wait for chat chard then Apply AID
for (let i = 0; i < 50; i++) {
if (
(button = $(
`ol#chat-log .chat-message:last-child button.apply-damage[data-item-id='${aidItem.uuid}']:last-child`,
`ol#chat-log .chat-message:last-child button.apply-damage[data-item-id='${adjustmentItem.uuid}']:last-child`,
)).length === 1
)
break;
await this.delay();
}
// if (!button.text().trim().includes(" to ")) {
// this.log(`FAIL: Is "Apply ${powerXMLID} to ${tokenTarget.name}" in the chatcard?`, "color:red");
// return false;
// }
button.click();
this.log(`Apply <b>${aidItem.name}</b>`);
this.log(`CLICK: ${button.text().trim()}`);

// Get AID Active Effect
let aidActiveEffect;
// Get Active Effect
let adjustmentActiveEffect;
for (let i = 0; i < 50; i++) {
if ((aidActiveEffect = token.actor.temporaryEffects?.[0])) break;
if ((adjustmentActiveEffect = tokenTarget.actor.temporaryEffects?.[0])) break;
await this.delay();
}
this.log(`Active Effect: ${aidActiveEffect.changes[0].key} ${aidActiveEffect.changes[0].value}`);
if (!adjustmentActiveEffect) {
this.log(
`FAIL: unable to locate AE. Is "Apply ${powerXMLID} to ${tokenTarget.name}" in the chatcard?`,
"color:red",
);
return false;
}
this.log(
`Active Effect: ${adjustmentActiveEffect.changes?.[0].key} ${adjustmentActiveEffect.changes?.[0].value}`,
);

// Confirm STR has been aided
let aidValue = parseInt(aidActiveEffect.changes[0].value);
let actorStrValue = 10 + aidValue;
if (token.actor.system.characteristics.str.value !== actorStrValue) {
this.log(`FAIL`, "color:red");
// Confirm Characteristic has been aided
let adjustmentValue = parseInt(adjustmentActiveEffect.changes[0].value);
let adjustmentActivePoints = -adjustmentActiveEffect.flags.adjustmentActivePoints;
let actorCharaisticValue =
tokenTarget.actor.system.characteristics[targetXMLID.toLowerCase()].core + adjustmentValue;
if (tokenTarget.actor.system.characteristics[targetXMLID.toLowerCase()].value !== actorCharaisticValue) {
this.log(`FAIL: ${targetXMLID.toLowerCase()}.value !== actorCharaisticValue`, "color:red");
return;
}

if (aidActiveEffect.changes.length !== 1) {
if (adjustmentActiveEffect.changes.length !== 1) {
this.log(`FAIL: AE has more than 1 change`, "color:red");
return;
}

const costPerActivePoint = determineCostPerActivePoint(targetXMLID, null, tokenTarget.actor);
// if (aidActiveEffect.flags.costPerActivePoint !== costPerActivePoint) {
// this.log(
// `FAIL costPerActivePoint: ${aidActiveEffect.flags.costPerActivePoint} !== ${costPerActivePoint}`,
// "color:red",
// );
// return;
// }

//const saveWorldTime = game.time.worldTime;

while (aidValue !== 0) {
// Advance world time 12 seconds
while (adjustmentValue !== 0) {
// Make sure AP = change.value
if (parseInt(adjustmentActiveEffect.changes[0].value) !== -adjustmentActiveEffect.flags.affectedPoints) {
this.log(
`FAIL aidActiveEffect.flags.affectedPoints: ${adjustmentActiveEffect.changes[0].value} !== ${-adjustmentActiveEffect.flags.affectedPoints}`,
"color:red",
);
return;
}

if (adjustmentActivePoints !== -adjustmentActiveEffect.flags.adjustmentActivePoints) {
this.log(
`FAIL aidActivePoints: ${adjustmentActivePoints} !== ${-adjustmentActiveEffect.flags.adjustmentActivePoints}`,
"color:red",
);
return;
}

if (
parseInt(adjustmentActiveEffect.changes[0].value) !==
Math.floor(-adjustmentActiveEffect.flags.adjustmentActivePoints / costPerActivePoint)
) {
this.log(
`FAIL adjustmentActiveEffect.changes[0].value: ${adjustmentActiveEffect.changes[0].value} !== ${Math.floor(-adjustmentActiveEffect.flags.adjustmentActivePoints / costPerActivePoint)})`,
"color:red",
);
return;
}

if (
-adjustmentActiveEffect.flags.affectedPoints !==
Math.floor(-adjustmentActiveEffect.flags.adjustmentActivePoints / costPerActivePoint)
) {
this.log(
`FAIL adjustmentActiveEffect.flags.affectedPoints: ${-adjustmentActiveEffect.flags.affectedPoints} !== ${Math.floor(-adjustmentActiveEffect.flags.adjustmentActivePoints / costPerActivePoint)})`,
"color:red",
);
return;
}

// Advance world time 12 seconds
this.log(`worldTime + 12 seconds`);
await game.time.advance(12);

// Wait for AE to update/fade
for (let i = 0; i < 50; i++) {
if (token.actor.system.characteristics.str.value !== actorStrValue) break;
if (tokenTarget.actor.system.characteristics[targetXMLID.toLowerCase()].value !== actorCharaisticValue)
break;
await this.delay();
}
aidActiveEffect = token.actor.temporaryEffects?.[0]; // Make sure we have latest updates
adjustmentActiveEffect = tokenTarget.actor.temporaryEffects?.[0]; // Make sure we have latest updates

if (aidActiveEffect && aidActiveEffect.changes.length !== 1) {
if (adjustmentActiveEffect && adjustmentActiveEffect.changes.length !== 1) {
this.log(`FAIL: AE has more than 1 change`, "color:red");
return;
}

// Check for fade
this.log(`Active Effect: ${aidActiveEffect?.changes[0].key} ${aidActiveEffect?.changes[0].value}`);
const aidNewValue = Math.max(0, aidValue - 5);
const actorNewStrValue = Math.max(10, actorStrValue - 5);
this.log(
`Active Effect: ${adjustmentActiveEffect?.changes[0].key} ${adjustmentActiveEffect?.changes[0].value}`,
);
const newAidActivePoints =
powerXMLID === "AID"
? Math.max(0, adjustmentActivePoints - 5)
: Math.min(0, adjustmentActivePoints + 5);
// const aidNewValue = aidActiveEffect
// ? Math.max(0, Math.floor(-aidActiveEffect.flags.adjustmentActivePoints - 5 / costPerActivePoint))
// : 0;
const adjustmentNewValue = Math.floor(newAidActivePoints / costPerActivePoint);
// const actorNewCharacteristicValue = Math.max(
// token.actor.system.characteristics[XMLID.toLowerCase()].core,
// actorCharaisticValue - 5 / costPerActivePoint,
// );
const actorNewCharacteristicValue =
tokenTarget.actor.system.characteristics[targetXMLID.toLowerCase()].core + adjustmentNewValue;
if (
(!aidActiveEffect && aidNewValue === 0) ||
token.actor.system.characteristics.str.value === actorNewStrValue
(!adjustmentActiveEffect && adjustmentNewValue === 0) ||
tokenTarget.actor.system.characteristics[targetXMLID.toLowerCase()].value ===
actorNewCharacteristicValue
) {
this.log(`Fade from ${aidValue} to ${aidNewValue} was successful. STR=${actorNewStrValue}`);
this.log(
`Fade from ${adjustmentValue} to ${adjustmentNewValue} was successful. ${targetXMLID}=${actorNewCharacteristicValue}`,
);
} else {
this.log(
`Excpected actor STR=${actorNewStrValue} got ${token.actor.system.characteristics.str.value}`,
`Expected actor ${targetXMLID}=${actorNewCharacteristicValue} got ${tokenTarget.actor.system.characteristics[targetXMLID.toLowerCase()].value}`,
"color:red",
);
this.log(
`Expected change.value=${adjustmentNewValue} got ${adjustmentActiveEffect?.changes[0].value}`,
"color:red",
);
this.log(`Excpected change.value=${aidNewValue} got ${aidActiveEffect?.changes[0].value}`, "color:red");

// await this.delay();
// this.log(`Active Effect: ${aidActiveEffect.changes[0].key} ${aidActiveEffect.changes[0].value}`);

return;
}

// fade again?
aidValue = parseInt(aidActiveEffect?.changes[0].value || 0);
actorStrValue = 10 + aidValue;
adjustmentActivePoints = newAidActivePoints;
adjustmentValue = adjustmentNewValue;
actorCharaisticValue = actorNewCharacteristicValue;
}
this.log(`Active Effect: Fade completed succesfully`);
this.log(
`AID Active Effect <b>${targetXMLID}</b> for <b>${tokenTarget.actor.name}</b>: Fade completed succesfully`,
);

return true; // true = success
}
}
13 changes: 10 additions & 3 deletions module/utility/adjustment.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,8 @@ function _findExistingMatchingEffect(item, potentialCharacteristic, powerTargetN
return targetSystem.effects.find(
(effect) =>
effect.origin === item.uuid &&
effect.flags.target[0] === (powerTargetName?.uuid || potentialCharacteristic) &&
parseInt(effect.changes?.[0].value || 0) >= 0,
effect.flags.target[0] === (powerTargetName?.uuid || potentialCharacteristic), //&&
//parseInt(effect.changes?.[0].value || 0) >= 0,
);
}

Expand Down Expand Up @@ -365,6 +365,7 @@ export async function performAdjustment(
isFade,
token,
action,
existingEffect,
) {
const targetActor = token.actor || token;

Expand Down Expand Up @@ -456,7 +457,13 @@ export async function performAdjustment(

// Check for previous adjustment (i.e ActiveEffect) from same power against this target
// and calculate the total effect
const existingEffect = _findExistingMatchingEffect(item, targetUpperCaseName, targetPower, targetSystem);
// AARON: Just pass in the previous AE so we don't get confused.
const existingEffect2 = _findExistingMatchingEffect(item, targetUpperCaseName, targetPower, targetSystem);
if (existingEffect && existingEffect2 && existingEffect.id !== existingEffect2.id) {
// We are going to use the AE that was passed in.
// There is another AE that has same item source and targetSystem, likely multiple drains. The partial
console.warn("Possible confusion over which ActiveEffect is being adjusted.", existingEffect);
}

const activeEffect =
existingEffect ||
Expand Down
14 changes: 8 additions & 6 deletions module/utility/util.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,14 @@ export async function expireEffects(actor) {
adjustmentChatMessages.push(
await performAdjustment(
item,
ae.flags.target[0],
-_fade,
"None - Effect Fade",
"",
true,
ae.target || actor,
ae.flags.target[0], // nameOfCharOrPower
-_fade, // thisAttackRawActivePointsDamage
"None - Effect Fade", // defenseDescription
"", // effectsDescription
true, // isFade
ae.target || actor, // token
null, // action
ae,
),
);
} else {
Expand Down
Loading

0 comments on commit c13ed61

Please sign in to comment.