From 4c36c648c7f3403ffb2925cd4ea41b3b6e1a6ec2 Mon Sep 17 00:00:00 2001 From: dev7355608 Date: Mon, 1 Apr 2024 13:28:53 +0200 Subject: [PATCH] Improve ghost detection --- scripts/detection-modes/blindsight.mjs | 4 +-- scripts/detection-modes/darkvision.mjs | 4 +-- scripts/detection-modes/detect.mjs | 5 +-- scripts/detection-modes/devils-sight.mjs | 5 +-- scripts/detection-modes/divine-sense.mjs | 4 +-- scripts/detection-modes/ghostly-gaze.mjs | 4 +-- scripts/detection-modes/light-perception.mjs | 34 ++++++++++++++++++-- 7 files changed, 46 insertions(+), 14 deletions(-) diff --git a/scripts/detection-modes/blindsight.mjs b/scripts/detection-modes/blindsight.mjs index 6e3a9a0..e6065da 100644 --- a/scripts/detection-modes/blindsight.mjs +++ b/scripts/detection-modes/blindsight.mjs @@ -1,4 +1,5 @@ import { createNameRegExp } from "../utils.js"; +import { isGhost } from "./light-perception.mjs"; /** * The detection mode for Blindsight. @@ -60,8 +61,7 @@ export class DetectionModeBlindsight extends DetectionMode { || source.document.hasStatusEffect(CONFIG.specialStatusEffects.UNCONSCIOUS) || source.document.hasStatusEffect(CONFIG.specialStatusEffects.SLEEP))) && !(target instanceof Token && (target.document.hasStatusEffect(CONFIG.specialStatusEffects.BURROW) - || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) - && !(target.actor?.type === "npc" && target.actor.system.details.type?.value === "undead") + || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) && !isGhost(target.actor) && !(source instanceof Token && source.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL)))); } diff --git a/scripts/detection-modes/darkvision.mjs b/scripts/detection-modes/darkvision.mjs index de828c3..62968b7 100644 --- a/scripts/detection-modes/darkvision.mjs +++ b/scripts/detection-modes/darkvision.mjs @@ -1,4 +1,5 @@ import { createNameRegExp } from "../utils.js"; +import { isGhost } from "./light-perception.mjs"; /** * The detection mode for Darkvision. @@ -44,8 +45,7 @@ export class DetectionModeDarkvision extends DetectionModeBasicSight { || source.document.hasStatusEffect(CONFIG.specialStatusEffects.BURROW))) && !(target instanceof Token && (target.document.hasStatusEffect(CONFIG.specialStatusEffects.INVISIBLE) || target.document.hasStatusEffect(CONFIG.specialStatusEffects.BURROW) - || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) - && !(target.actor?.type === "npc" && target.actor.system.details.type?.value === "undead") + || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) && !isGhost(target.actor) && !(source instanceof Token && source.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL)))); } } diff --git a/scripts/detection-modes/detect.mjs b/scripts/detection-modes/detect.mjs index 12695ed..655eb0a 100644 --- a/scripts/detection-modes/detect.mjs +++ b/scripts/detection-modes/detect.mjs @@ -1,3 +1,5 @@ +import { isGhost } from "./light-perception.mjs"; + /** * Base class for Detect Magic, Thoughts, etc. * @abstract @@ -24,8 +26,7 @@ export class DetectionModeDetect extends DetectionMode { || source.document.hasStatusEffect(CONFIG.specialStatusEffects.SLEEP) || source.document.hasStatusEffect(CONFIG.specialStatusEffects.BURROW))) && !(target.document.hasStatusEffect(CONFIG.specialStatusEffects.BURROW) - || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) - && !(target.actor?.type === "npc" && target.actor.system.details.type?.value === "undead") + || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) && !isGhost(target.actor) && !(source instanceof Token && source.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL))); } } diff --git a/scripts/detection-modes/devils-sight.mjs b/scripts/detection-modes/devils-sight.mjs index 4d588b4..1def750 100644 --- a/scripts/detection-modes/devils-sight.mjs +++ b/scripts/detection-modes/devils-sight.mjs @@ -1,3 +1,5 @@ +import { isGhost } from "./light-perception.mjs"; + /** * The detection mode for Devil's Sight. */ @@ -33,8 +35,7 @@ export class DetectionModeDevilsSight extends DetectionMode { || source.document.hasStatusEffect(CONFIG.specialStatusEffects.BURROW))) && !(target instanceof Token && (target.document.hasStatusEffect(CONFIG.specialStatusEffects.INVISIBLE) || target.document.hasStatusEffect(CONFIG.specialStatusEffects.BURROW) - || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) - && !(target.actor?.type === "npc" && target.actor.system.details.type?.value === "undead") + || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) && !isGhost(target.actor) && !(source instanceof Token && source.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL)))); } } diff --git a/scripts/detection-modes/divine-sense.mjs b/scripts/detection-modes/divine-sense.mjs index 1fecdc7..1c49927 100644 --- a/scripts/detection-modes/divine-sense.mjs +++ b/scripts/detection-modes/divine-sense.mjs @@ -1,4 +1,5 @@ import { createNameRegExp } from "../utils.js"; +import { isGhost } from "./light-perception.mjs"; /** * The detection mode for Divine Sense. @@ -37,8 +38,7 @@ export class DetectionModeDivineSense extends DetectionMode { || source.document.hasStatusEffect(CONFIG.specialStatusEffects.SLEEP) || source.document.hasStatusEffect(CONFIG.specialStatusEffects.BURROW))) || target.document.hasStatusEffect(CONFIG.specialStatusEffects.BURROW) - || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) - && !(target.actor?.type === "npc" && target.actor.system.details.type?.value === "undead") + || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) && !isGhost(target.actor) && !(source instanceof Token && source.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL))) { return false; } diff --git a/scripts/detection-modes/ghostly-gaze.mjs b/scripts/detection-modes/ghostly-gaze.mjs index 8459776..df2b222 100644 --- a/scripts/detection-modes/ghostly-gaze.mjs +++ b/scripts/detection-modes/ghostly-gaze.mjs @@ -1,4 +1,5 @@ import { DetectionModeDarkvision } from "./darkvision.mjs"; +import { isGhost } from "./light-perception.mjs"; /** * The detection mode for Ghostly Gaze. @@ -28,8 +29,7 @@ export class DetectionModeGhostlyGaze extends DetectionModeDarkvision { || source.document.hasStatusEffect(CONFIG.specialStatusEffects.UNCONSCIOUS) || source.document.hasStatusEffect(CONFIG.specialStatusEffects.SLEEP))) && !(target instanceof Token && (target.document.hasStatusEffect(CONFIG.specialStatusEffects.INVISIBLE) - || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) - && !(target.actor?.type === "npc" && target.actor.system.details.type?.value === "undead") + || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) && !isGhost(target.actor) && !(source instanceof Token && source.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL)))); } } diff --git a/scripts/detection-modes/light-perception.mjs b/scripts/detection-modes/light-perception.mjs index ab8a752..e3a881d 100644 --- a/scripts/detection-modes/light-perception.mjs +++ b/scripts/detection-modes/light-perception.mjs @@ -1,3 +1,5 @@ +import { createNameRegExp } from "../utils.js"; + const detectionModeLightPerceptionClass = ((detectionModeLightPerceptionClass) => /** * The detection mode for Light Perception. @@ -21,8 +23,7 @@ const detectionModeLightPerceptionClass = ((detectionModeLightPerceptionClass) = || source.document.hasStatusEffect(CONFIG.specialStatusEffects.BURROW))) && !(target instanceof Token && (target.document.hasStatusEffect(CONFIG.specialStatusEffects.INVISIBLE) || target.document.hasStatusEffect(CONFIG.specialStatusEffects.BURROW) - || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) - && !(target.actor?.type === "npc" && target.actor.system.details.type?.value === "undead") + || target.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL) && !isGhost(target.actor) && !(source instanceof Token && source.document.hasStatusEffect(CONFIG.specialStatusEffects.ETHEREAL)))); } @@ -44,3 +45,32 @@ const detectionModeLightPerceptionClass = ((detectionModeLightPerceptionClass) = )(DetectionModeLightPerception); export { detectionModeLightPerceptionClass as DetectionModeLightPerception }; + +export function isGhost(actor) { + if (!(actor && actor.type === "npc" && actor.system.details.type?.value === "undead")) return false; + let hasEtherealness = false; + let hasIncorporealMovement = false; + for (const item of actor.items) { + if (item.type !== "feat") continue; + hasEtherealness ||= ETHEREALNESS_FEAT.test(item.name); + hasIncorporealMovement ||= INCORPOREAL_MOVEMENT_FEAT.test(item.name); + if (hasEtherealness && hasIncorporealMovement) return true; + } + return false; +} + +const ETHEREALNESS_FEAT = createNameRegExp({ + en: "Etherealness", + de: "Körperlosigkeit", + fr: "Forme éthérée", + es: "Excursion eterea", + "pt-BR": "Forma Etérea", +}); + +const INCORPOREAL_MOVEMENT_FEAT = createNameRegExp({ + en: "Incorporeal Movement", + de: "Körperlose Bewegung", + fr: "Mouvement incorporel", + es: "Movimiento incorpóreo", + "pt-BR": "Movimento Incorpóreo", +});