From d5d5d08f6822529c09dcd171de3c7c8509307644 Mon Sep 17 00:00:00 2001 From: aeauseth Date: Fri, 6 Dec 2024 21:20:41 -0800 Subject: [PATCH 1/7] quench test fix for -=uploading --- module/actor/actor.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/module/actor/actor.mjs b/module/actor/actor.mjs index 6b4c5256..163ccb27 100644 --- a/module/actor/actor.mjs +++ b/module/actor/actor.mjs @@ -1974,7 +1974,9 @@ export class HeroSystem6eActor extends Actor { } } - await this.update({ "flags.-=uploading": null }); + if (this.id) { + await this.update({ "flags.-=uploading": null }); + } uploadPerformance.retainedDamage = new Date() - uploadPerformance._d; uploadPerformance._d = new Date(); From 5d5df9d5a6de9dc9cf78260093e30353e786984b Mon Sep 17 00:00:00 2001 From: aeauseth Date: Sat, 7 Dec 2024 10:38:32 -0800 Subject: [PATCH 2/7] SIGHTGROUP visions now respect the BLIND status. #1590 --- CHANGELOG.md | 5 +++++ module/actor/actor-token.mjs | 27 +++++++++++++++------------ module/utility/vision.mjs | 6 ++++-- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e03e1692..a0901cb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Releases +## Version 4.0.13 [Hero System 6e (Unofficial) v2](https://github.com/dmdorman/hero6e-foundryvtt) + +- Enhanced Senses improvements: + - SIGHTGROUP visions now respect the BLIND status. [#1590](https://github.com/dmdorman/hero6e-foundryvtt/issues/1590) + ## Version 4.0.12 [Hero System 6e (Unofficial) v2](https://github.com/dmdorman/hero6e-foundryvtt) - Fix for SPD purchased as a power not contributing to final values during upload. [#1439](https://github.com/dmdorman/hero6e-foundryvtt/issues/1439) diff --git a/module/actor/actor-token.mjs b/module/actor/actor-token.mjs index b8b70dd9..14000acc 100644 --- a/module/actor/actor-token.mjs +++ b/module/actor/actor-token.mjs @@ -127,18 +127,21 @@ export class HeroSystem6eTokenDocument extends TokenDocument { } try { - // GENERIC SIGHTGROUP (no lights required; INFRAREDPERCEPTION, NIGHTVISION, etc) - const SIGHTGROUP = this.actor?.items.find( - (item) => - item.isSense && - item.system.GROUP === "SIGHTGROUP" && - //item.system.OPTIONID === undefined && // DETECT - item.isActive, - ); - if (SIGHTGROUP && !this.actor?.statuses.has("blind")) { - const basicMode = this.detectionModes.find((m) => m.id === "basicSight"); - basicMode.range = maxRange; - this.sight.range = maxRange; // You can see without a light source + if (!this.actor?.statuses.has("blind")) { + // GENERIC SIGHTGROUP (no lights required; INFRAREDPERCEPTION, NIGHTVISION, etc) + const SIGHTGROUP = this.actor?.items.find( + (item) => + item.isSense && + item.system.GROUP === "SIGHTGROUP" && + //item.system.OPTIONID === undefined && // DETECT + item.isActive, + ); + + if (SIGHTGROUP) { + const basicMode = this.detectionModes.find((m) => m.id === "basicSight"); + basicMode.range = maxRange; + this.sight.range = maxRange; // You can see without a light source + } } // GENERIC NON-SIGHTGROUP (not including MENTALGROUP which is unsupported) diff --git a/module/utility/vision.mjs b/module/utility/vision.mjs index 4d54ce86..6c5c9e9f 100644 --- a/module/utility/vision.mjs +++ b/module/utility/vision.mjs @@ -13,13 +13,15 @@ export class HeroPointVisionSource extends foundry.canvas.sources.PointVisionSou // Some visions have SENSE/RANGE (built in) // SightGroup/ToughGroup/HearingGroup/RadioGroup/SmellGroup have SENSE builtIn // Assuming only SIGHT/TOUCH/SMELL or TARGETING can actually SEE (you can see, touch, smell a wall) - const blindVisionItem = this.token?.actor?.items.find( + let blindVisionItem = this.token?.actor?.items.find( (i) => i.isActive && i.isSense && i.isRangedSense && - (i.isTargeting || ["TOUCHGROUP", "SMELLGROUP"].includes(i.system.GROUP)), + (i.isTargeting || ["TOUCHGROUP", "SMELLGROUP"].includes(i.system.GROUP)) && + (!this.token?.actor?.statuses.has("blind") || i.system.GROUP !== "SIGHTGROUP"), ); + if (blindVisionItem) { //console.log("blindVisionItem", blindVisionItem); return false; From b417400c7c91086b4df95c62d3d51b41910fd78a Mon Sep 17 00:00:00 2001 From: aeauseth Date: Sat, 7 Dec 2024 11:24:31 -0800 Subject: [PATCH 3/7] minor fix for tokenless release/control --- module/item/item.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/item/item.mjs b/module/item/item.mjs index 64c82af2..b7ee58b3 100644 --- a/module/item/item.mjs +++ b/module/item/item.mjs @@ -688,7 +688,7 @@ export class HeroSystem6eItem extends Item { // If we have control of this token, re-acquire to update movement types const myToken = this.actor?.getActiveTokens()?.[0]; - if (canvas.tokens.controlled.find((t) => t.id == myToken.id)) { + if (canvas.tokens.controlled?.find((t) => t.id == myToken.id)) { myToken.release(); myToken.control(); } From 51d887e8b22e52439d74409e1139d79d02c74267 Mon Sep 17 00:00:00 2001 From: aeauseth Date: Sat, 7 Dec 2024 12:22:24 -0800 Subject: [PATCH 4/7] Fixed issue with some enhanced visions not showing map in the dark --- CHANGELOG.md | 1 + module/actor/actor-token.mjs | 62 +++++++++++++++++++----------------- module/utility/vision.mjs | 5 ++- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0901cb3..70994255 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Enhanced Senses improvements: - SIGHTGROUP visions now respect the BLIND status. [#1590](https://github.com/dmdorman/hero6e-foundryvtt/issues/1590) + - Fixed issue with some enhanced visions not showing map in the dark. ## Version 4.0.12 [Hero System 6e (Unofficial) v2](https://github.com/dmdorman/hero6e-foundryvtt) diff --git a/module/actor/actor-token.mjs b/module/actor/actor-token.mjs index 14000acc..969c4bfa 100644 --- a/module/actor/actor-token.mjs +++ b/module/actor/actor-token.mjs @@ -127,44 +127,48 @@ export class HeroSystem6eTokenDocument extends TokenDocument { } try { - if (!this.actor?.statuses.has("blind")) { - // GENERIC SIGHTGROUP (no lights required; INFRAREDPERCEPTION, NIGHTVISION, etc) - const SIGHTGROUP = this.actor?.items.find( - (item) => - item.isSense && - item.system.GROUP === "SIGHTGROUP" && - //item.system.OPTIONID === undefined && // DETECT - item.isActive, - ); - - if (SIGHTGROUP) { - const basicMode = this.detectionModes.find((m) => m.id === "basicSight"); - basicMode.range = maxRange; - this.sight.range = maxRange; // You can see without a light source - } + // GENERIC SIGHTGROUP (no lights required; INFRAREDPERCEPTION, NIGHTVISION, etc) + const SIGHTGROUP = this.actor?.items.find( + (item) => + item.isSense && + item.system.GROUP === "SIGHTGROUP" && + //item.system.OPTIONID === undefined && // DETECT + item.isActive, + ); + + if (this.name === "Onyx") { + console.log(this); } - // GENERIC NON-SIGHTGROUP (not including MENTALGROUP which is unsupported) - // const NONSIGHTGROUP = this.actor?.items.find( - // (item) => - // item.isSense && - // item.system.GROUP !== "SIGHTGROUP" && - // item.system.GROUP !== "MENTALGROUP" && - // item.isActive, - // ); + if (SIGHTGROUP && !this.actor?.statuses.has("blind")) { + const basicMode = this.detectionModes.find((m) => m.id === "basicSight"); + basicMode.range = maxRange; + this.sight.range = maxRange; // You can see without a light source + } + + // A special vision that can see the map (like targeting touch) + let blindVisionItem = this.actor?.items.find( + (i) => + i.isActive && + i.isSense && + i.isRangedSense && + (i.isTargeting || ["TOUCHGROUP", "SMELLGROUP"].includes(i.system.GROUP)) && + (!this.token?.actor?.statuses.has("blind") || i.system.GROUP !== "SIGHTGROUP"), + ); + if (blindVisionItem) { + const basicMode = this.detectionModes.find((m) => m.id === "basicSight"); + basicMode.range = maxRange; + this.sight.range = maxRange; // You can see without a light source + } + + // Assume we can use non-targeting senses to detect tokens const heroDetectSight = this.detectionModes.find((m) => m.id === "heroDetectSight"); - // if (SIGHTGROUP || NONSIGHTGROUP) { if (!heroDetectSight) { this.detectionModes.push({ id: "heroDetectSight", enabled: true, range: maxRange }); } else { heroDetectSight.range = maxRange; heroDetectSight.enabled = true; } - // } else { - // if (heroDetectSight) { - // heroDetectSight.enabled = false; - // } - // } // Update Sight so people don't get confused when looking at the UI if (initialRange !== this.sight.range) { diff --git a/module/utility/vision.mjs b/module/utility/vision.mjs index 6c5c9e9f..472d4828 100644 --- a/module/utility/vision.mjs +++ b/module/utility/vision.mjs @@ -2,6 +2,9 @@ import { calculateDistanceBetween } from "./range.mjs"; export class HeroPointVisionSource extends foundry.canvas.sources.PointVisionSource { get isBlinded() { + // if (this.token?.name === "Onyx") { + // debugger; + // } const defaultBlind = (this.data.radius === 0 && (this.data.lightRadius === 0 || !this.visionMode?.perceivesLight)) || Object.values(this.blinded).includes(true); @@ -89,7 +92,7 @@ export function setPerceptionModes() { return (filter2.thickness = 1), filter2; } _canDetect(visionSource, target) { - if (super._canDetect(visionSource, target)) return false; // handled by standard vision + if (super._canDetect(visionSource, target)) return true; // handled by standard vision if (!target.document.hidden && !target.document.hasStatusEffect("invisible")) { return true; } From e87c6c04356ad008186dc07df1d8b9f3c5479981 Mon Sep 17 00:00:00 2001 From: aeauseth Date: Sat, 7 Dec 2024 13:13:20 -0800 Subject: [PATCH 5/7] passing action thru the pipeline to we can determine token not just the actor --- module/item/item-attack.mjs | 15 +++++++++------ module/utility/adjustment.mjs | 26 ++++++++++++++++++++++++-- templates/chat/item-damage-card.hbs | 6 +++--- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/module/item/item-attack.mjs b/module/item/item-attack.mjs index 5bc6250c..522e17f7 100644 --- a/module/item/item-attack.mjs +++ b/module/item/item-attack.mjs @@ -1678,7 +1678,7 @@ export async function _onRollDamage(event) { attackTags: getAttackTags(item), targetTokens: targetTokens, user: game.user, - action, + actionData: JSON.stringify(action), }; // render card @@ -1996,9 +1996,10 @@ export async function _onApplyDamageToSpecificToken(event, tokenId) { const originalRoll = heroRoller.clone(); const automation = game.settings.get(HEROSYS.module, "automation"); + const action = damageData.actionData ? JSON.parse(damageData.actionData) : null; if (item.system.XMLID === "ENTANGLE") { - return _onApplyEntangleToSpecificToken(item, token, originalRoll); + return _onApplyEntangleToSpecificToken(item, token, originalRoll, action); } // Target ENTANGLE @@ -2031,7 +2032,7 @@ export async function _onApplyDamageToSpecificToken(event, tokenId) { } if (targetEntangle && entangleAE) { - return _onApplyDamageToEntangle(item, token, originalRoll, entangleAE); + return _onApplyDamageToEntangle(item, token, originalRoll, entangleAE, action); } } @@ -2203,7 +2204,7 @@ export async function _onApplyDamageToSpecificToken(event, tokenId) { item: item, })?.XMLID === "TRANSFORM"; if (transformation) { - return _onApplyTransformationToSpecificToken(item, token, damageDetail, defense, defenseTags); + return _onApplyTransformationToSpecificToken(item, token, damageDetail, defense, defenseTags, action); } // AID, DRAIN or any adjustment powers @@ -2211,7 +2212,7 @@ export async function _onApplyDamageToSpecificToken(event, tokenId) { item: item, })?.type?.includes("adjustment"); if (adjustment) { - return _onApplyAdjustmentToSpecificToken(item, token, damageDetail, defense, defenseTags); + return _onApplyAdjustmentToSpecificToken(item, token, damageDetail, defense, defenseTags, action); } const senseAffecting = getPowerInfo({ @@ -2343,6 +2344,7 @@ export async function _onApplyDamageToSpecificToken(event, tokenId) { tags: defenseTags.filter((o) => !o.options?.knockback), attackTags: getAttackTags(item), targetToken: token, + actionData: JSON.parse(action), }; // render card @@ -2672,7 +2674,7 @@ async function _onApplyTransformationToSpecificToken(transformationItem, token, ui.notifications.warn("TRANSFORM damage & defenses are not yet implemented."); } -async function _onApplyAdjustmentToSpecificToken(adjustmentItem, token, damageDetail, defense, defenseTags) { +async function _onApplyAdjustmentToSpecificToken(adjustmentItem, token, damageDetail, defense, defenseTags, action) { if ( adjustmentItem.actor.id === token.actor.id && ["DISPEL", "DRAIN", "SUPPRESS", "TRANSFER"].includes(adjustmentItem.system.XMLID) @@ -2765,6 +2767,7 @@ async function _onApplyAdjustmentToSpecificToken(adjustmentItem, token, damageDe damageDetail.effects, false, reductionTargetActor, + action, ), ); } diff --git a/module/utility/adjustment.mjs b/module/utility/adjustment.mjs index dd99aa6b..51adbed2 100644 --- a/module/utility/adjustment.mjs +++ b/module/utility/adjustment.mjs @@ -263,13 +263,23 @@ function _createNewAdjustmentEffect( rawActivePointsDamage, targetActor, targetSystem, + action, ) { // Create new ActiveEffect // TODO: Add a document field + + // Educated guess for token + const itemTokenName = + canvas.tokens.get(action?.current?.attackerTokenId)?.name || + item.actor?.getActiveTokens().find((t) => canvas.tokens.controlled.find((c) => c.id === t.id))?.name || + item.actor?.getActiveTokens()?.[0].name || + targetActor.name || + "undefined"; + const activeEffect = { name: `${item.system.XMLID || "undefined"} 0 ${ (targetPower?.name || potentialCharacteristic)?.toUpperCase() // TODO: This will need to change for multiple effects - } (0 AP) [by ${item.actor.name || "undefined"}]`, + } (0 AP) [by ${itemTokenName}]`, id: `${item.system.XMLID}.${item.id}.${ targetPower?.name || potentialCharacteristic // TODO: This will need to change for multiple effects }`, @@ -287,6 +297,8 @@ function _createNewAdjustmentEffect( source: targetActor.name, target: [potentialCharacteristic || targetPower?.uuid], key: potentialCharacteristic, + itemTokenName, + attackerTokenId: canvas.tokens.get(action?.current?.attackerTokenId), }, origin: item.uuid, //description: item.system.description, // Issues with core FoundryVTT where description doesn't show, nor is editable. @@ -324,6 +336,7 @@ export async function performAdjustment( effectsDescription, isFade, targetActor, + action, ) { const isHealing = item.system.XMLID === "HEALING"; const isOnlyToStartingValues = item.findModsByXmlid("ONLYTOSTARTING") || isHealing; @@ -408,6 +421,7 @@ export async function performAdjustment( thisAttackRawActivePointsDamage, targetActor, targetSystem, + action, ); // Healing doesn't fade @@ -548,10 +562,18 @@ export async function performAdjustment( parseInt(activeEffect.changes[2].value) + (newCalculatedValue - oldCalculatedValue); } + // Educated guess for token + const itemTokenName = + canvas.tokens.get(action?.current?.attackerTokenId)?.name || + item.actor?.getActiveTokens().find((t) => canvas.tokens.controlled.find((c) => c.id === t.id))?.name || + item.actor?.getActiveTokens()?.[0].name || + targetActor.name || + "undefined"; + // Update the effect max value(s) activeEffect.name = `${item.system.XMLID || "undefined"} ${Math.abs(totalActivePointsThatShouldBeAffected)} ${( targetPower?.name || potentialCharacteristic - )?.toUpperCase()} (${Math.abs(totalAdjustmentNewActivePoints)} AP) [by ${item.actor.name || "undefined"}]`; + )?.toUpperCase()} (${Math.abs(totalAdjustmentNewActivePoints)} AP) [by ${itemTokenName}]`; activeEffect.flags.affectedPoints = totalActivePointsThatShouldBeAffected; activeEffect.flags.adjustmentActivePoints = totalAdjustmentNewActivePoints; diff --git a/templates/chat/item-damage-card.hbs b/templates/chat/item-damage-card.hbs index d200c0c9..1d014c26 100644 --- a/templates/chat/item-damage-card.hbs +++ b/templates/chat/item-damage-card.hbs @@ -40,7 +40,7 @@
- {{#each targetTokens as |target id|}} -