Skip to content

Commit

Permalink
Merge pull request dmdorman#1599 from aeauseth/main
Browse files Browse the repository at this point in the history
SIGHTGROUP/BLIND. Adjustment POWERDEFENSE.
  • Loading branch information
aeauseth authored Dec 8, 2024
2 parents 6560277 + 88d6c04 commit 8e14e70
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 35 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# 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)
- Fixed issue with some enhanced visions not showing map in the dark.
- Adjustment powers now work with POWERDEFENSE.

## 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)
Expand Down
37 changes: 23 additions & 14 deletions module/actor/actor-token.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ export class HeroSystem6eTokenDocument extends TokenDocument {

if (!this.isOwner) return;

if (!this.id) return;

if (this.sight.visionMode != "basic") {
super._prepareDetectionModes();
return;
Expand Down Expand Up @@ -135,33 +137,40 @@ export class HeroSystem6eTokenDocument extends TokenDocument {
//item.system.OPTIONID === undefined && // DETECT
item.isActive,
);

if (this.name === "Onyx") {
console.log(this);
}

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
}

// 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,
// );
// 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) {
Expand Down
4 changes: 3 additions & 1 deletion module/actor/actor.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
2 changes: 1 addition & 1 deletion module/config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5682,7 +5682,7 @@ function addPower(powerDescription6e, powerOverrideFor5e) {
let value = 0;
switch (options.attackDefenseVs) {
case "POWERDEFENSE":
value = parseInt(actorItemDefense.system.LEVELS) || 0;
value = actorItemDefense.adjustedLevels; //parseInt(actorItemDefense.system.LEVELS) || 0;
break;
}
if (value > 0) {
Expand Down
15 changes: 9 additions & 6 deletions module/item/item-attack.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1678,7 +1678,7 @@ export async function _onRollDamage(event) {
attackTags: getAttackTags(item),
targetTokens: targetTokens,
user: game.user,
action,
actionData: JSON.stringify(action),
};

// render card
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -2203,15 +2204,15 @@ 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
const adjustment = getPowerInfo({
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({
Expand Down Expand Up @@ -2343,6 +2344,7 @@ export async function _onApplyDamageToSpecificToken(event, tokenId) {
tags: defenseTags.filter((o) => !o.options?.knockback),
attackTags: getAttackTags(item),
targetToken: token,
actionData: JSON.stringify(action),
};

// render card
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -2765,6 +2767,7 @@ async function _onApplyAdjustmentToSpecificToken(adjustmentItem, token, damageDe
damageDetail.effects,
false,
reductionTargetActor,
action,
),
);
}
Expand Down
15 changes: 14 additions & 1 deletion module/item/item.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -5290,6 +5290,19 @@ export class HeroSystem6eItem extends Item {

return RoundFavorPlayerDown(cost) + costSuffix;
}

/// Get Levels with AID/DRAIN Active Effects
get adjustedLevels() {
let _adjustedLevels = parseInt(this.system.LEVELS || 0);

for (const ae of this.actor.temporaryEffects.filter(
(effect) => effect.flags.XMLID === "DRAIN" && effect.flags.key === "POWERDEFENSE",
)) {
console.log(ae);
_adjustedLevels += parseInt(ae.changes?.[0].value || 0);
}
return Math.max(0, _adjustedLevels);
}
}

export function getItem(id) {
Expand Down
36 changes: 30 additions & 6 deletions module/utility/adjustment.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ function _findExistingMatchingEffect(item, potentialCharacteristic, powerTargetN
return targetSystem.effects.find(
(effect) =>
effect.origin === item.uuid &&
effect.flags.target[0] === (potentialCharacteristic || powerTargetName?.uuid),
effect.flags.target[0] === (powerTargetName?.uuid || potentialCharacteristic),
);
}

Expand Down Expand Up @@ -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
}`,
Expand All @@ -285,8 +295,10 @@ function _createNewAdjustmentEffect(
affectedPoints: 0,
XMLID: item.system.XMLID,
source: targetActor.name,
target: [potentialCharacteristic || targetPower?.uuid],
key: potentialCharacteristic,
target: [targetPower?.uuid || potentialCharacteristic],
key: targetPower?.system?.XMLID || potentialCharacteristic,
itemTokenName,
attackerTokenId: action?.current?.attackerTokenId,
},
origin: item.uuid,
//description: item.system.description, // Issues with core FoundryVTT where description doesn't show, nor is editable.
Expand Down Expand Up @@ -324,6 +336,7 @@ export async function performAdjustment(
effectsDescription,
isFade,
targetActor,
action,
) {
const isHealing = item.system.XMLID === "HEALING";
const isOnlyToStartingValues = item.findModsByXmlid("ONLYTOSTARTING") || isHealing;
Expand Down Expand Up @@ -381,7 +394,9 @@ export async function performAdjustment(

// Do we have a target?
if (!targetCharacteristic && !targetPower) {
await ui.notifications.error(`${nameOfCharOrPower} is an invalid target for the adjustment power ${item.name}`);
await ui.notifications.warn(
`${nameOfCharOrPower} is an invalid target for the adjustment power ${item.name}. Perhaps ${targetActor.name} does not have that characteristic or power.`,
);
return;
}

Expand All @@ -408,6 +423,7 @@ export async function performAdjustment(
thisAttackRawActivePointsDamage,
targetActor,
targetSystem,
action,
);

// Healing doesn't fade
Expand Down Expand Up @@ -548,10 +564,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;
Expand Down
11 changes: 8 additions & 3 deletions module/utility/vision.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -13,13 +16,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;
Expand Down Expand Up @@ -87,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;
}
Expand Down
6 changes: 3 additions & 3 deletions templates/chat/item-damage-card.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
</div>

<div data-visibility="gm">
<button class="apply-damage" title="Apply damage to selected tokens." data-itemId="{{item.uuid}}"
<button class="apply-damage" title="Apply damage to selected tokens." data-itemId="{{item.uuid}}" data-action-data="{{actionData}}"
data-body-damage="{{bodyDamage}}" data-body-damage-effective="{{bodyDamageEffective}}"
data-stun-damage="{{stunDamage}}" data-stun-damage-effective="{{stunDamageEffective}}"
data-roller="{{roller}}" data-stun-multiplier="{{stunMultiplier}}" data-hit-location="{{hitLocation}}" data-target-Entangle="{{targetEntangle}}">
Expand All @@ -52,7 +52,7 @@
</button>

{{#each targetTokens as |target id|}}
<button class="apply-damage" title="Apply damage to {{target.token.name}}." data-itemId="{{../item.uuid}}"
<button class="apply-damage" title="Apply damage to {{target.token.name}}." data-itemId="{{../item.uuid}}" data-action-data="{{actionData}}"
data-target-token-id="{{target.token.id}}"
data-body-damage="{{../bodyDamage}}" data-body-damage-effective="{{../bodyDamageEffective}}"
data-stun-damage="{{../stunDamage}}" data-stun-damage-effective="{{../stunDamageEffective}}"
Expand All @@ -70,7 +70,7 @@
{{/each}}

{{#if targetIds}}
<button class="apply-damage" title="Apply damage to ALL tokens that were hit." data-itemId="{{item.uuid}}"
<button class="apply-damage" title="Apply damage to ALL tokens that were hit." data-itemId="{{item.uuid}}" data-action-data="{{actionData}}"
data-target-Ids="{{targetIds}}"
data-body-damage="{{bodyDamage}}" data-body-damage-effective="{{bodyDamageEffective}}"
data-stun-damage="{{stunDamage}}" data-stun-damage-effective="{{stunDamageEffective}}"
Expand Down

0 comments on commit 8e14e70

Please sign in to comment.