From 4de2f6c6611c6f3b02e2570c0f0e4753fdaff6e1 Mon Sep 17 00:00:00 2001 From: Jack Holloway Date: Wed, 8 Nov 2023 22:10:53 +0000 Subject: [PATCH] Deathly Choir effect --- CHANGELOG.md | 2 ++ macros/monsterFeatures/deathlyChoir.js | 10 ++++++++++ src/effects/monsterFeatures/deathlyChoir.js | 11 +++++++++++ src/effects/specialFeats.js | 5 +++++ src/effects/specialMonsters.js | 20 +++++++++++++++++--- 5 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 macros/monsterFeatures/deathlyChoir.js create mode 100644 src/effects/monsterFeatures/deathlyChoir.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 83c858bc4..9f190f4b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ - Sleep Spell Effect improvements for elfs and half-elfs - Stone of Good Luck no longer needs a initiative boosting effect separately to checks. +- Mask of the Wild effect: PC's and NPC's will now roll stealth if this ability is clicked. (Thanks @MotoMoto) +- Rahadin Deathly Choir effect exclusions (Thanks MotoMoto) # 3.5.8 diff --git a/macros/monsterFeatures/deathlyChoir.js b/macros/monsterFeatures/deathlyChoir.js new file mode 100644 index 000000000..73c0d0346 --- /dev/null +++ b/macros/monsterFeatures/deathlyChoir.js @@ -0,0 +1,10 @@ +if (args[0].macroPass === "preambleComplete") { + if (workflow.targets.size === 0) return; + let validTargets = []; + for (let i of Array.from(workflow.targets)) { + const nullEffects = game.modules.get("ddb-importer").api.effects.findEffects(i.actor, ["Deafened", "Dead", "Mind Blank"]); + if (nullEffects.length > 0) continue; + validTargets.push(i.id); + } + game.modules.get("ddb-importer").api.effects.updateTargets(validTargets); +} diff --git a/src/effects/monsterFeatures/deathlyChoir.js b/src/effects/monsterFeatures/deathlyChoir.js new file mode 100644 index 000000000..26ae2e4a0 --- /dev/null +++ b/src/effects/monsterFeatures/deathlyChoir.js @@ -0,0 +1,11 @@ +import DDBMacros from "../macros.js"; + +export async function deathlyChoirEffect(document) { + await DDBMacros.setItemMacroFlag(document, "monsterFeature", "deathlyChoir.js"); + DDBMacros.setMidiOnUseMacroFlag(document, "monsterFeature", "deathlyChoir.js", ["preambleComplete"]); + + setProperty(document, "system.target", { value: 10, width: null, units: "ft", type: "creature" }); + setProperty(document, "system.range", { value: null, long: null, units: "spec" }); + + return document; +} diff --git a/src/effects/specialFeats.js b/src/effects/specialFeats.js index 3a1b97cfb..eb1237e70 100644 --- a/src/effects/specialFeats.js +++ b/src/effects/specialFeats.js @@ -65,6 +65,7 @@ import { deftStrikeEffect } from "./feats/deftStike.js"; import { hadozeDodgeEffect } from "./feats/hadozeeDodge.js"; import { mindLinkEffect } from "./feats/mindLink.js"; import { holdBreathEffect } from "./feats/holdBreath.js"; +import { maskOfTheWildEffect } from "./feats/maskOfTheWild.js"; export function baseFeatEffect(document, label) { let effect = { @@ -252,6 +253,10 @@ export async function featureEffectAdjustment(ddb, character, document) { document = await mantleOfInspirationEffect(document); break; } + case "Mask of the Wild": { + document = await maskOfTheWildEffect(document); + break; + } case "Patient Defense": { document = patientDefenseEffect(document); break; diff --git a/src/effects/specialMonsters.js b/src/effects/specialMonsters.js index a906f2769..7988d7714 100644 --- a/src/effects/specialMonsters.js +++ b/src/effects/specialMonsters.js @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop */ /* eslint-disable require-atomic-updates */ import { effectModules, forceItemEffect, generateStatusEffectChange } from "./effects.js"; import { uncannyDodgeEffect } from "./feats/uncannyDodge.js"; @@ -14,6 +15,8 @@ import { venomTrollEffects } from "./monsterFeatures/venomTroll.js"; import { quasitEffects } from "./monsterFeatures/quasit.js"; import { invisibilityFeatureEffect } from "./monsterFeatures/invisibility.js"; import { recklessAttackEffect } from "./feats/recklessAttack.js"; +import { maskOfTheWildEffect } from "./feats/maskOfTheWild.js"; +import { deathlyChoirEffect } from "./monsterFeatures/deathlyChoir.js"; export function baseMonsterFeatureEffect(document, label) { let effect = { @@ -75,6 +78,7 @@ export function transferEffectsToActor(document) { * This function is mainly for effects that can't be dynamically generated * @param {*} document */ +// eslint-disable-next-line complexity export async function monsterFeatureEffectAdjustment(ddbMonster) { let npc = duplicate(ddbMonster.npc); @@ -86,7 +90,7 @@ export async function monsterFeatureEffectAdjustment(ddbMonster) { } // damage over time effects - npc.items.forEach(function(item, index) { + for (let [index, item] of npc.items.entries()) { // Legendary Resistance Effects if (item.name.startsWith("Legendary Resistance")) item = generateLegendaryEffect(item); else if (item.name.startsWith("Pack Tactics")) item = generatePackTacticsEffect(item); @@ -97,16 +101,18 @@ export async function monsterFeatureEffectAdjustment(ddbMonster) { else if (["Shared Invisibility", "Fallible Invisibility", "Invisibility", "Superior Invisibility"].includes(item.name)) item = invisibilityFeatureEffect(item); else if (item.name.includes("Absorption")) item = absorptionEffect(item); + else if (item.name === "Mask of the Wild") item = await maskOfTheWildEffect(item); // auto overtime effect if (item.type !== "spell") { const overTimeResults = generateOverTimeEffect(ddbMonster, npc, item); - this[index] = overTimeResults.document; + item = overTimeResults.document; npc = overTimeResults.actor; } item = forceItemEffect(item); - }, npc.items); + npc.items[index] = item; + }; switch (npc.name) { case "Bard": { @@ -132,6 +138,14 @@ export async function monsterFeatureEffectAdjustment(ddbMonster) { npc = await quasitEffects(npc); break; } + case "Rahadin": { + for (let [index, item] of npc.items.entries()) { + if (item.name === "Deathly Choir") { + npc.items[index] = await deathlyChoirEffect(item); + } + } + break; + } case "Skeletal Juggernaut": { npc = await skeletalJuggernautEffects(npc); break;