SC - Conditional Activities
Adds a Condition tab to every dnd5e activity sheet in Foundry VTT.
The condition is a JavaScript snippet that must return true for the activity to be usable. If the condition returns false, the activity shows a Not available label and is blocked when a user tries to use it.
This also applies to activity types added by More Activities.
Report an issue or request a feature
Official Wiki
Preview
Locked Activity Choice
When an item has multiple activities, locked activities remain visible in the choice dialog with a clear Not available label.
Activity List Label
The same label is shown in the item sheet activity list, so users can see which activity is currently blocked before trying to use it.
Condition Tab
Each activity sheet gets a Condition tab with a JavaScript editor and direct wiki access. This example checks whether the item has an occupied Simple Sockets socket.
What It Does
- Adds a Condition tab to dnd5e activities.
- Stores the condition on the activity at
flags.sc-conditional-activities.condition. - Evaluates the condition before
activity.use(). - Shows a visible Not available label when an activity is locked.
- Works with native dnd5e activities.
- Works with activities registered by More Activities.
- Supports English and Brazilian Portuguese.
Requirements
- Foundry VTT: v13 and v14
- System: dnd5e
Installation
- In Foundry, open Add-on Modules > Install Module.
- Paste this manifest URL:
https://github.com/Shattered-Codex/sc-conditional-activities/releases/latest/download/module.json
- Install the module.
- Enable SC - Conditional Activities in your world.
Condition Context
Available variables in the condition script:
activityactivityTypeitemactoruserusagedialogmessagerollDatasourcegetPropertyhasPropertydeepClonegame
You can write either a complete script:
return actor?.system?.attributes?.hp?.value > 0;
Or a simple expression. This only works when the entire condition is one expression:
actor?.system?.attributes?.hp?.value > 0
If your condition uses statements like const, let, if, or await, finish with return.
This works:
const hp = actor?.system?.attributes?.hp?.value ?? 0;
return hp > 0;
This does not work:
const hp = actor?.system?.attributes?.hp?.value ?? 0;
hp > 0;
Example Conditions
Actor must be alive
return actor?.system?.attributes?.hp?.value > 0;
Only the GM can use this activity
return user?.isGM === true;
Item must be equipped
return item?.system?.equipped === true;
Item must be attuned
return item?.system?.attuned === true;
Item must be identified
return item?.system?.identified === true;
Actor must have at least 10 HP
return actor?.system?.attributes?.hp?.value >= 10;
Actor must have a specific flag
return getProperty(actor, "flags.world.canUseAncientPower") === true;
Activity must be an attack activity
return activityType === "attack";
Item name must include a word
return item?.name?.toLowerCase().includes("flame");
Actor must have a minimum Strength score
return actor?.system?.abilities?.str?.value >= 16;
Actor must have a resource available
return actor?.system?.resources?.primary?.value > 0;
Require at least one target selected
return game.user?.targets?.size > 0;
Require exactly one target selected
return game.user?.targets?.size === 1;
Require combat to be active
return Boolean(game.combat?.started);
SC - Simple Sockets Examples
These examples are useful when the activity belongs to an item that also uses SC - Simple Sockets.
Item must have at least one occupied socket
Recommended version using the Simple Sockets API:
const socketsApi = game.modules.get("sc-simple-sockets")?.api?.sockets;
if (!socketsApi) return false;
const slots = await socketsApi.getItemSlots(item);
return slots.some((entry) => entry.hasGem);
First socket must be occupied
const socketsApi = game.modules.get("sc-simple-sockets")?.api?.sockets;
if (!socketsApi) return false;
const slots = await socketsApi.getItemSlots(item);
return slots[0]?.hasGem === true;
Item must have at least two occupied sockets
const socketsApi = game.modules.get("sc-simple-sockets")?.api?.sockets;
if (!socketsApi) return false;
const slots = await socketsApi.getItemSlots(item);
return slots.filter((entry) => entry.hasGem).length >= 2;
Item must have a gem with a specific name
const socketsApi = game.modules.get("sc-simple-sockets")?.api?.sockets;
if (!socketsApi) return false;
const gems = await socketsApi.getItemGems(item);
return gems.some((gem) => gem.name?.toLowerCase().includes("ruby"));
Direct flag check for an occupied socket
Use this only if you want a simple direct read and do not need the Simple Sockets API helpers.
const sockets = item?.getFlag?.("sc-simple-sockets", "sockets") ?? [];
return sockets.some((slot) => Boolean(slot?.gem));
Notes
- Empty conditions always allow the activity.
- If a condition throws an error, the activity is treated as unavailable.
- Conditions can use
await. - Conditions run when the UI checks availability and again when the activity is used.