Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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"
}
23 changes: 22 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,24 @@ class WeaponAuxiliaryAction {
selected: Number(selection),
});
if (!updated) return;
} else if (this.annotation === "boost") {
const alreadyBoosted = actor.itemTypes.effect.some((e) => e.slug === "effect-boost");
if (alreadyBoosted) 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
17 changes: 17 additions & 0 deletions src/module/actor/character/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,23 @@ function getWeaponAuxiliaryActions(weapon: WeaponPF2e<CharacterPF2e>): WeaponAux
}
}

if (
traitsArray.includes("boost-1d4") ||
traitsArray.includes("boost-1d6") ||
traitsArray.includes("boost-1d8") ||
traitsArray.includes("boost-1d10") ||
traitsArray.includes("boost-1d12")
) {
Comment thread
Geliogabalus marked this conversation as resolved.
Outdated
const isBoosted = actor.itemTypes.effect.some(
(e) => e.slug === "effect-boost" && e.flags.sf2e.grantedBy?.id === weapon.id,
Comment thread
Geliogabalus marked this conversation as resolved.
Outdated
);
if (!isBoosted) {
Comment thread
Geliogabalus marked this conversation as resolved.
Outdated
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
18 changes: 18 additions & 0 deletions src/module/system/damage/weapon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,24 @@ class WeaponDamagePF2e {
modifiers.push(modifier);
}

// Boost trait, ignore invalid boost traits
for (const trait of weaponTraits.filter((t) => t.startsWith("boost-1d"))) {
Comment thread
Geliogabalus marked this conversation as resolved.
Outdated
if (!weapon.isOfType("weapon")) continue;
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.

This should work on npcs as well. Bo-Shek for example has 2d10 boost. You can more or less copy what deadly does for the diceNumber. While npcs don't support aux actions yet, the existance of the effect as well as the toggle in the damage roll should be handy.

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.

Made it work for npc and tested it. It is working as intended when the effect is applied from the compendium and user otherwise can toggle it manually. We can make checkbox in the sheet since it is controlled by roll option right now.

const dieSize = trait.substring(trait.indexOf("-") + 2) as DamageDieSize;
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.

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.

We can construct a choice set that works for both PCs and NPCs and provides the weapon flag in question. So we can use the effect to choose the weapon and just rely on a single roll option that will contain the ID, making the code itself simpler. This would auto set item:boosted:{item|id}.

{
  "choices": {
    "ownedItems": true,
    "predicate": [
      {
        "or": [
          {
            "and": [
              "self:type:npc",
              "item:type:melee"
            ]
          },
          {
            "and": [
              "self:type:character",
              "item:type:weapon"
            ]
          }
        ]
      }
    ],
    "types": [
      "melee",
      "weapon"
    ]
  },
  "flag": "weapon",
  "rollOption": "item:boosted",
  "key": "ChoiceSet",
  "prompt": "PF2E.SpecificRule.Prompt.Weapon",
  "predicate": [
    {
      "or": [
        "self:type:npc",
        "self:type:character"
      ]
    }
  ]
}

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.

might need an item:trait:boost in the predicate but yeah that might work better. Then the code would basically pre-set the value.

damageDice.push(
new DamageDicePF2e({
selector: `${weapon.id}-damage`,
slug: trait,
label: traitLabels[trait],
diceNumber: weapon.system.damage.dice,
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