Skip to content
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
3 changes: 2 additions & 1 deletion build/duplicates.json
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,8 @@
],
"equipment-effects": [
"Effect: Parry",
"Effect: Raise a Shield"
"Effect: Raise a Shield",
"Effect: Boost"
],
"feats": [
"Adapted Cantrip",
Expand Down
43 changes: 43 additions & 0 deletions packs/pf2e/equipment-effects/effect-boost.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"_id": "YVm3rVSAYxoSrOvb",
"img": "systems/pf2e/icons/abilities/blue-battery.webp",
"name": "Effect: Boost",
"system": {
"description": {
"value": "<p>The weapon is currently boosted.</p>"
},
"duration": {
"expiry": "turn-end",
"sustained": false,
"unit": "rounds",
"value": 1
},
"fromSpell": false,
"level": {
"value": 1
},
"publication": {
"license": "ORC",
"remaster": true,
"title": "Starfinder Player Core"
},
"rules": [
{
"key": "RollOption",
"domain": "strike-damage",
"option": "item:weapon:boosted"
}
],
"start": {
"initiative": null,
"value": 0
},
"tokenIcon": {
"show": true
},
"traits": {
"value": []
}
},
"type": "effect"
}
26 changes: 25 additions & 1 deletion src/module/actor/character/auxiliary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import { getActionGlyph, localizeList, sluggify } from "@util";
import { traitSlugToObject } from "@util/tags.ts";
import * as R from "remeda";
import { CharacterPF2e } from "./document.ts";
import type { RollOptionRuleElement } from "@module/rules/rule-element/roll-option/rule-element.ts";

interface AuxiliaryInteractParams {
weapon: WeaponPF2e<CharacterPF2e>;
action: "interact";
annotation: "draw" | "grip" | "modular" | "pick-up" | "retrieve" | "sheathe";
annotation: "draw" | "grip" | "modular" | "pick-up" | "retrieve" | "sheathe" | "boost";
hands?: ZeroToTwo;
}

Expand Down Expand Up @@ -85,6 +86,8 @@ class WeaponAuxiliaryAction {
return [1, null, annotation];
case "drop":
return [0, "dropped", annotation];
case "boost":
return [1, null, annotation];
case "tower-shield": {
const cost = this.action === "take-cover" ? 1 : 0;
return [cost, null, null];
Expand Down Expand Up @@ -157,6 +160,27 @@ class WeaponAuxiliaryAction {
selected: Number(selection),
});
if (!updated) return;
} else if (this.annotation === "boost") {
const isBoosted = actor.itemTypes.effect.some(
(e) => e.slug === "effect-boost" && e.flags.sf2e.grantedBy?.id === weapon.id,
);
// No op if the weapon is already boosted
if (isBoosted) return;
const effect = await fromUuid(`Compendium.${SYSTEM_ID}.equipment-effects.Item.YVm3rVSAYxoSrOvb`);
if (effect instanceof EffectPF2e) {
const data = { ...effect.toObject(), _id: null };
data.flags[SYSTEM_ID] = { grantedBy: { id: weapon.id, onDelete: "cascade" } };
// Change rule to affect the specific weapon.
data.system.rules = [
{
key: "RollOption",
domain: `${weapon.id}-damage`,
option: `item:${weapon.id}:boosted`,
} as RollOptionRuleElement,
];
data.system.description.value += `\n@UUID[Actor.${actor.id}.Item.${weapon.id}]{${weapon.name}}`;
await actor.createEmbeddedDocuments("Item", [data]);
}
} else if (this.action === "raise-a-shield") {
// Apply Effect: Raise a Shield
const alreadyRaised = actor.itemTypes.effect.some((e) => e.slug === "raise-a-shield");
Expand Down
6 changes: 6 additions & 0 deletions src/module/actor/character/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,12 @@ function getWeaponAuxiliaryActions(weapon: WeaponPF2e<CharacterPF2e>): WeaponAux
}
}

if (weapon.system.traits.config.boost) {
auxiliaryActions.push(
new WeaponAuxiliaryAction({ weapon, action: "interact", annotation: "boost" }),
);
}

if (weapon.handsHeld === 2) {
auxiliaryActions.push(
new WeaponAuxiliaryAction({ weapon, action: "release", annotation: "grip", hands: 1 }),
Expand Down
23 changes: 23 additions & 0 deletions src/module/system/damage/weapon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,29 @@ class WeaponDamagePF2e {
modifiers.push(modifier);
}

// Boost trait
if (weapon.system.traits.config.boost) {
const boostConfig = weapon.system.traits.config.boost;
const slug = `boost-${boostConfig}`;

const dieSize = boostConfig.substring(boostConfig.indexOf("d")) as DamageDieSize;
const baseNumber = Number(/(\d)d\d{1,2}$/.exec(boostConfig)?.at(1)) || 1;
const diceNumber = strikingDice > 0 ? baseNumber + strikingDice : baseNumber;

const isBoosted = options.has(`item:${weapon.id}:boosted`) || options.has("item:weapon:boosted");
Copy link
Copy Markdown
Collaborator

@CarlosFdez CarlosFdez May 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can move this to the predicate field of the lower damage die object. [{ or: [] }] if you need both.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing that will also allow a disabled boost row to exist in the damage roll as well in the same way deadly does on non-crits, allowing it to work with npcs as well if you remove the weapon check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand exactly. It was showing boost toggle even when there were no effect present and now after removing weapon check it works for npc as well

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No you're right, I misread. Preferable use predicate because its cleaner but not to fix any bug or anything.

damageDice.push(
new DamageDicePF2e({
selector: `${weapon.id}-damage`,
slug,
label: traitLabels[slug],
diceNumber: diceNumber,
dieSize,
critical: false,
enabled: isBoosted,
}),
);
}

// Add roll notes to the context
const runeNotes = propertyRunes.flatMap((r) => {
const data = RUNE_DATA.weapon.property[r].damage?.notes ?? [];
Expand Down
4 changes: 4 additions & 0 deletions static/lang/action-en.json
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,10 @@
"Description": "{actor} sheathes their {weapon}.",
"Title": "Sheathe"
},
"Boost": {
"Description": "{actor} boosts their {weapon}.",
"Title": "Boost"
},
"Title": "Interact"
},
"Leap": {
Expand Down
Loading