Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exploit Vulnerability as an action #181

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/module/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import { recallEsotericKnowledge } from "./actions/recallKnowledge.js";
import { rootToLife } from "./feats/rootToLife.js";
import { intensifyImplement } from "./implements/intensifyImplement.js";
import { constructChildImplement } from "./implements/impDict.js";
import {
EXPLOIT_VULNERABILITY_DC_UUID,
EXPLOIT_VULNERABILITY_DC_PWOL_UUID,
} from "./utils/index.js";

Hooks.on("init", async () => {
game.pf2eThaumVuln = {
Expand Down Expand Up @@ -60,6 +64,24 @@ Hooks.on("init", async () => {
}
}

const EV = this.itemTypes.feat.find(
(f) => f.slug === "exploit-vulnerability"
);
if (EV) {
this.rules.push(
new game.pf2e.RuleElements.builtin.EphemeralEffect(
{
key: "EphemeralEffect",
selectors: ["esoteric-lore", "esoteric", "lore-esoteric"],
uuid: game.pf2e.settings.variants.pwol.enabled
? EXPLOIT_VULNERABILITY_DC_PWOL_UUID
: EXPLOIT_VULNERABILITY_DC_UUID,
},
{ parent: EV }
)
);
}

wrapped(...args);
}
);
Expand Down
175 changes: 56 additions & 119 deletions src/module/feats/exploit-vulnerability/exploitVulnerability.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,140 +87,39 @@ async function exploitVuln() {
)
);
}
const dc = game.settings.get("pf2e", "proficiencyVariant")
? {
"-2": 13,
"-1": 13,
...Object.fromEntries(
Object.entries([
14, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19,
19, 20, 20, 20, 21, 21, 21, 22, 22,
])
),
}[t.actor.level]
: {
"-2": 12,
"-1": 13,
...Object.fromEntries(
Object.entries([
14, 15, 16, 18, 19, 20, 22, 23, 24, 26, 27, 28, 30, 31, 32, 34, 35,
36, 38, 39, 40, 42, 44, 46, 48, 50,
])
),
}[t.actor.level];
if (!dc) {
return ui.notifications.warn(
game.i18n.localize(
"pf2e-thaum-vuln.notifications.warn.exploitVulnerability.noMatchingDC"
)
);
}

const rollOptions = sa.getRollOptions(["skill-check", skill.slug]);

const outcomes = {
criticalSuccess: game.i18n.localize(
"pf2e-thaum-vuln.exploitVulnerability.degreeOfSuccess.criticalSuccess"
),
success: game.i18n.localize(
"pf2e-thaum-vuln.exploitVulnerability.degreeOfSuccess.success"
),
failure: game.i18n.localize(
"pf2e-thaum-vuln.exploitVulnerability.degreeOfSuccess.failure"
),
criticalFailure: game.i18n.localize(
"pf2e-thaum-vuln.exploitVulnerability.degreeOfSuccess.criticalFailure"
),
};

const notes = Object.entries(outcomes).map(([outcome, text]) => ({
title: game.i18n.localize("PF2E.Check.Result.Degree.Check." + outcome),
text,
outcome: [outcome],
}));

if (hasFeat(sa, "esoteric-warden")) {
notes.push({
title: game.i18n.localize("pf2e-thaum-vuln.esotericWarden.name"),
text: game.i18n.localize("pf2e-thaum-vuln.esotericWarden.flavor"),
outcome: ["success", "criticalSuccess"],
});
}

let notes = [];
if (hasFeat(sa, "diverse-lore")) {
// todo: put npc identify data in the document and then show secret text for it.
// TODO: Error checking for rolling against PCs
const dc =
(game.settings.get("pf2e", "proficiencyVariant")
? {
"-2": 13,
"-1": 13,
...Object.fromEntries(
Object.entries([
14, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19,
19, 19, 20, 20, 20, 21, 21, 21, 22, 22,
])
),
}[t.actor.level]
: {
"-2": 12,
"-1": 13,
...Object.fromEntries(
Object.entries([
14, 15, 16, 18, 19, 20, 22, 23, 24, 26, 27, 28, 30, 31, 32, 34,
35, 36, 38, 39, 40, 42, 44, 46, 48, 50,
])
),
}[t.actor.level]) +
game.settings.get("pf2e-thaum-vuln", "esotericLoreModifier");
14 +
Math.floor(t.actor.level / 3) +
game.settings.get("pf2e-thaum-vuln", "esotericLoreModifier") +
(game.pf2e.settings.variants.pwol.enabled
? 0
: t.actor.level + (t.actor.level < 0));
const diverseLoreDC = dc
? `<br/><span data-visibility="gm">Recall Knowledge DC ${dc}</span>`
: "";

notes.push({
title: game.i18n.localize("pf2e-thaum-vuln.diverseLore.name"),
text: `${
game.i18n.localize("pf2e-thaum-vuln.diverseLore.flavor") + diverseLoreDC
}`,
text:
game.i18n.localize("pf2e-thaum-vuln.diverseLore.flavor") +
diverseLoreDC,
outcome: ["success", "criticalSuccess"],
predicate: ["feat:diverse-lore"],
});
}

const flavor = `${game.i18n.localize(
"pf2e-thaum-vuln.exploitVulnerability.name"
)}: ${skill.label}`;
const checkModifier = new game.pf2e.CheckModifier(flavor, skill);
const traits = ["esoterica", "manipulate", "thaumaturge"];
const evRoll = await game.pf2e.Check.roll(
checkModifier,
{
actor: sa,
target: {
actor: t.actor,
token: t.document,
},
type: "skill-check",
options: rollOptions,
notes,
dc: { value: dc },
traits: traits,
flavor: `
<strong>${game.i18n.localize(
"pf2e-thaum-vuln.exploitVulnerability.frequency.label"
)}</strong> ${game.i18n.localize(
"pf2e-thaum-vuln.exploitVulnerability.frequency.text"
)}<br/>
<strong>${game.i18n.localize(
"pf2e-thaum-vuln.exploitVulnerability.requirements.label"
)}</strong> ${game.i18n.localize(
"pf2e-thaum-vuln.exploitVulnerability.requirements.text"
)}<br/>
<hr/>
<p>${game.i18n.localize("pf2e-thaum-vuln.exploitVulnerability.flavor")}</p>
`,
},
event
);
const result = await game.pf2e.actions.get("exploit-vulnerability").use({
actors: [sa],
target: t.document,
notes,
event,
});
const evRoll = result[0].roll;

const rollDOS = evRoll?.degreeOfSuccess;
//Apply effect based on Degrees of success
Expand Down Expand Up @@ -268,4 +167,42 @@ function preDeleteEffect(a, sa = undefined) {
return effects;
}

Hooks.once("init", () => {
const hide = game.pf2e.actions.get("hide");
const SingleCheckAction = Object.getPrototypeOf(hide).constructor;
const notes = [
"criticalSuccess",
"success",
"failure",
"criticalFailure",
].map((dos) => ({
title: game.i18n.localize(`PF2E.Check.Result.Degree.Check.${dos}`),
text: game.i18n.localize(
`pf2e-thaum-vuln.exploitVulnerability.degreeOfSuccess.${dos}`
),
outcome: [dos],
}));

notes.push({
title: game.i18n.localize("pf2e-thaum-vuln.esotericWarden.name"),
text: game.i18n.localize("pf2e-thaum-vuln.esotericWarden.flavor"),
outcome: ["success", "criticalSuccess"],
predicate: ["feat:esoteric-warden"],
});

const ExploitVulnerability = new SingleCheckAction({
cost: 1,
description: "pf2e-thaum-vuln.exploitVulnerability.flavor",
name: "pf2e-thaum-vuln.exploitVulnerability.name",
notes,
rollOptions: ["action:exploit-vulnerability"],
slug: "exploit-vulnerability",
difficultyClass: "exploit-vulnerability",
statistic: "esoteric-lore",
traits: ["esoterica", "manipulate", "thaumaturge"],
});

game.pf2e.actions.set("exploit-vulnerability", ExploitVulnerability);
});

export { exploitVuln, preDeleteEffect };
6 changes: 6 additions & 0 deletions src/module/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ const CHALICE_ADEPT_ENABLED_UUID =
"Compendium.pf2e-thaum-vuln.thaumaturge-effects.Item.Zl40i1PmitlIxZIK";
const CHALICE_INTENSIFY_ENABLED_UUID =
"Compendium.pf2e-thaum-vuln.thaumaturge-effects.Item.MKztdugJAUnHLfE2";
const EXPLOIT_VULNERABILITY_DC_UUID =
"Compendium.pf2e-thaum-vuln.thaumaturge-effects.Item.wDe6oD0iFZIx5Cf1";
const EXPLOIT_VULNERABILITY_DC_PWOL_UUID =
"Compendium.pf2e-thaum-vuln.thaumaturge-effects.Item.YPeliP0yNMlH0RPp";

const SupportedActions = [
"exploit-vulnerability",
Expand Down Expand Up @@ -117,4 +121,6 @@ export {
CHALICE_DRAINED_EFFECT_UUID,
CHALICE_ADEPT_ENABLED_UUID,
CHALICE_INTENSIFY_ENABLED_UUID,
EXPLOIT_VULNERABILITY_DC_UUID,
EXPLOIT_VULNERABILITY_DC_PWOL_UUID,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{
"name": "Effect: Exploit Vulnerability DC (PwoL)",
"type": "effect",
"effects": [],
"system": {
"description": {
"gm": "",
"value": "<p>Provide an Exploit Vulnerability DC to roll a check against.</p><p>For the Proficiency without Level variant</p>"
},
"rules": [
{
"key": "SpecialStatistic",
"label": "Exploit Vulnerability DC",
"slug": "exploit-vulnerability",
"type": "check"
},
{
"key": "FlatModifier",
"label": "Standard Level DC",
"selector": "exploit-vulnerability",
"value": "4+floor(@actor.level/3)",
"type": "proficiency"
}
],
"slug": "exploit-vulnerability-dc",
"_migration": {
"version": 0.933,
"lastMigration": null
},
"traits": {
"otherTags": [],
"value": []
},
"publication": {
"title": "Pathfinder Dark Archive",
"authors": "",
"license": "OGL",
"remaster": false
},
"level": {
"value": 1
},
"duration": {
"value": -1,
"unit": "unlimited",
"expiry": null,
"sustained": false
},
"start": {
"value": 0,
"initiative": null
},
"tokenIcon": {
"show": false
},
"badge": null,
"context": null,
"unidentified": false
},
"img": null,
"folder": null,
"ownership": {
"default": 0
},
"flags": {
"core": {}
},
"_stats": {
"systemId": "pf2e",
"systemVersion": "6.5.0",
"coreVersion": "12.331",
"createdTime": 1731014803000,
"modifiedTime": 1731014803000,
"compendiumSource": "Compendium.pf2e-thaum-vuln.thaumaturge-effects.Item.YPeliP0yNMlH0RPp",
"duplicateSource": null
},
"_id": "YPeliP0yNMlH0RPp",
"sort": 0,
"_key": "!items!YPeliP0yNMlH0RPp"
}
Loading
Loading