-
-
Notifications
You must be signed in to change notification settings - Fork 52
Cool Macros
Use this page to share any cool macros you've created for NaN's GURPS 4th Ed. Game Aid for Foundry.
Type: Script
Description: Clears all effects on the selected token.
let effect = async function() {
const effect = _token.actor.effects.contents;
for (let i = 0; i < effect.length; i++) {
let condition = effect[i].data.label;
let status = effect[i].data.disabled;
let effect_id = effect[i].data._id;
console.log(`condition: [${condition}] status: [${status}] effect_id: [${effect_id}]`)
if (status === false) {
await _token.actor.deleteEmbeddedDocuments("ActiveEffect", [effect_id]);
}
}
}
effect();
Type: Script
Description: Shows the use of the GURPS.lastTargetedRoll
variable and how to get information such as margin of success from it.
let lastactor = GURPS.LastActor;
let data = GURPS.lastTargetedRolls[lastactor.id];
console.log(`check: [${data.thing}], modified target: [${data.finaltarget}], roll total: [${data.rtotal}], margin of success: [${data.margin}]`)
Type: script
Description: Make a Fright Check for every selected token, using the current Modifier Bucket modifier. If there is a failure, set the token to have the "Stunned" status effect.
async function check() {
// Add Rule of 14 modifier
await GURPS.executeOTF("[+0 Rule of 14 *Max:13]")
// save the list of modifiers (including Rule of 14)
let modifiers = GURPS.ModifierBucket.modifierStack.modifierList
// get a list of all selected tokens
let selected = canvas.tokens.controlled
// save the original actor
const originalActor = GURPS.LastActor
// for each token
for (let token of selected) {
// select the current token
GURPS.SetLastActor(token.actor)
// execute the Fright Check
await GURPS.executeOTF(`[/if ![Fright Check] [/st + stun]]`)
// reset the modifiers
for (let mod of modifiers) {
GURPS.ModifierBucket.addModifier(mod.modint, mod.desc)
}
}
// clear the modifier bucket
GURPS.ModifierBucket.clear()
//restore last actor
GURPS.SetLastActor(originalActor)
}
check()
Type: Script
Description: Prompts the user for how much energy he is putting into the Fireball, then generates and rolls the OTF for damage. For example, if the user enters '5' into the dialog, the following OTF is rolled: /r [5d burn *Costs 5FP]
.
function fireballDamage(energy) {
GURPS.executeOTF(`/r [${energy}d burn *Costs ${energy}FP]`)
}
new Dialog({
title: `Fireball Damage`,
content: `<div><label for="energy">Energy</label><input id="energy" type="text" /></div>`,
buttons: {
confirm: {
label: "Confirm",
callback: async (html) => fireballDamage(html.find('#energy').val())
}
}
}).render(true);
Type: Script
Contributor: Iconat20 (Discord)
Description: It scales all the lights' dim and bright values by dividing them by three. Which is the factor needed when you change the grid size from 140 to 84 and grid units from 5ft to 1yd. Specific I know but it's useful when downloading pre-made foundry scenes from someone who made it for D&D.
canvas.lighting.updateAll(light => ({"config.bright": light.data.config.bright / 3, "config.dim": light.data.config.dim / 3 }))
Type: Script
Contributor: danielrab (Discord)
Description: add selected tokens to the combat, roll initiative for each of them, then start the combat.
async function quickCombat() {
await _token.toggleCombat();
await game.combat.rollAll();
await game.combat.startCombat();
}
quickCombat();
Type: Script
Contributor: danielrab (Discord)
Description: opens a dialog that asks for damage value (for example 2d6+2) and damage type (for example cr) and rolls the damage.
function manualDamage(damage, type) {
GURPS.executeOTF(`/r [${damage} ${type}]`);
}
new Dialog({
title: `Manual Damage`,
content: `<div><label for="damageAmount">damage</label><input id="damageAmount" type="text" /></div>
<div><label for="damageType">type</label><input id="damageType" type="text" /></div>`,
buttons: {
confirm: {
label: "Confirm",
callback: async (html) => {
manualDamage(html.find('#damageAmount').val(), html.find('#damageType').val());
}
}
}
}, {
width: 400
}).render(true);
Type: Script
Contributor: Nick Coffin, PI
Description: Roll for a Quick Draw and if successful, roll a ranged attack applying the current Modifier Bucket modifiers.
async function fastDrawAndShoot() {
// Save the current list of modifiers.
let modifiers = GURPS.ModifierBucket.modifierStack.modifierList
// Clear the Modifier Bucket.
GURPS.ModifierBucket.clear()
// Execute the fast-draw portion and give the user feedback.
await GURPS.executeOTF(`[S:Fast*Draw*Arrow ? "You rapidly draw an arrow and shoot!", "You fiddle with the bow for a second."]`)
// Get success or failure of the Fast-Draw roll.
let roll = GURPS.lastTargetedRolls[GURPS.LastActor.id]
// If Fast-Draw roll is successful:
if (!roll.failure) {
// Restore the list of modifiers to the Modifier Bucket.
for (let mod of modifiers) {
GURPS.ModifierBucket.addModifier(mod.modint, mod.desc)
}
// Roll the attack.
await GURPS.executeOTF(`[A:Longbow*]`)
}
}
fastDrawAndShoot()
Deprecated -- just select the tokens and run the appropriate chat command: /st t reeling
or /st t exhausted
.
Type: Script
Contributor: Nick Coffin, PI
Description: For all selected tokens, flip the status of Reeling -- i.e., if reeling is currently on, turn it off; if off, turn it on.
let effect = 'reeling' // change 'reeling' to 'exhausted' if needed
// for each selected token
for (let token of canvas.tokens.controlled) {
let flag = token.actor.data.data.conditions[effect]
// flip the effect
token.actor.toggleEffectByName(effect, !flag)
}
Type: Script
Contributor: Nick Coffin, PI (for Nose)
Description: Just what the title says.
// Attack with Rapier
GURPS.executeOTF('A:Rapier')
// if the attack roll was a Critical Success...
if (GURPS.lastTargetedRoll.isCritSuccess) {
// Find a roll table with name 'Critical Hit'
let tname = 'Critical Hit'
let tables = game.tables.contents.filter(t => t.name.match(tname))
// if found, roll on the table and display to the chat
if (tables.length == 1) {
let table = tables[0]
let r = await table.roll()
table.draw(r)
}
}
Type: Script
Contributor: Nick Coffin, PI (for Nose)
Description: Demonstrates creating a new Active Effect and applying it to selected tokens. This example only adds effect modifiers. Toggling turns the effect on if it is currently off, or turning it off if currently on.
// get selected tokens
let tokens = canvas.tokens.controlled
if (tokens && tokens.length > 0) {
// create a new effect
let effect = {
icon: 'systems/gurps/icons/statuses/number-3.webp',
id: 'distraction',
label: 'Distraction',
changes: [{
key: 'data.conditions.target.modifiers',
value: '-3 for Distraction',
mode: 2 // ADD
}]
}
// toggle the effect for all selected tokens
for (let token of tokens) {
token.toggleEffect(effect)
}
}
Type: Script
Contributor: Nick Coffin, PI
Description: GURPS Magic (the standard system) usually handles damaging spells by making the dice of damage directly proportional to the amount of mana/energy that the mage puts into it -- Fireballs doing 1d burn per point of energy is an example. This macro is intended to be used with the Advanced Macros module in Foundry to generically handle this type of spell. Import this macro, but don't call it directly -- instead create another macro or OTF to call this one with the necessary parameters filled in. Look below this macro's source code for examples of how to call it from OTF.
Calling the macro pops up a dialog asking the player where the energy should come from, FP or another source (in this case, a resource tracker named 'EnergyReserve'). To add a different source, find where 'Energy Reserve' and 'EnergyReserve' are used in the macro and change accordingly.
// Usage: SpellDamage <title> <dice> <adds> <type> <adjust>
// Title - name to display on dialog
// Dice - dice of damage per energy point; may be a fraction
// Adds - modifier to each die of damage, zero if none
// Type - Damage type (cr, cut, burn, etc...)
// Adjust - Adjust the energy cost by this number
// Examples:
// Fireball 1 1 burn 0 -- 1d+1 burn damage per energy point
// Concussion 0.5 0 cr -1 -- 1d cr per 2 points of energy; reduce total cost by 1
console.log(args[0])
let title = args[0][1]
let dice = parseFloat(args[0][2])
let adds = args[0].length > 3 ? parseInt(args[0][3]) : 0
let type = args[0].length > 4 ? args[0][4] : 'dmg'
let adjust = args[0].length > 5 ? parseInt(args[0][5]) : 0
console.log(`title:${title}; dice:${dice}; adds:${adds}; type:${type}; adjust:${adjust}`)
function damage(energy, source) {
let limit = 0 - energy; // cost cannot be less than 0
if (adjust < 0 && adjust < limit ) adjust = 0 - energy;
let cost = `${energy + adjust}FP`
if (source === 'HP') cost = `${energy + adjust}HP`
if (source === 'Energy Reserve') cost = `${energy + adjust} tr(EnergyReserve)`
let d = dice * energy
let a = adds * energy
if (a === 0) a = ''
else if (a > 0) a = `+${a}`
let formula = `[${d}d${a} ${type} *Costs ${cost}]`
console.log(formula)
GURPS.executeOTF(`/r ` + formula)
}
new Dialog({
title: title,
content: `
<div style='padding: 4px;'>
<label for="energy">Energy</label>
<input id="energy" type="text" />
</div>
<div style='padding: 4px;'>
<label for="source">Source</label>
<select id="source">
<option value='Energy Reserve'>Energy Reserve</option>
<option value='FP'>FP</option>
<option value='HP' style='color: darkred;'>HP</option>
</select>
</div>
`,
buttons: {
confirm: {
label: "Confirm",
callback: async (html) => damage(
parseInt(html.find('#energy').val()),
html.find('#source').val())
}
}
}).render(true)
Example of use:
["Damage" /:SpellDamage Fireball 1 0 burn -1]
["Damage" /:SpellDamage Concussion 0.5 0 cr]
The first one creates an OTF button that does 1d burn per point of energy, and costs the caster 1 energy point less -- i.e., a 1d burn fireball would not subtract any energy from the caster's reserves, while a 2d burn would cost the caster 1 point.
The second creates an OTF button that does 1d cr damage per 2 points of energy.
Type: Script
Contributor: devakm
OtF to trigger it: ["Major Healing"/:majorHealing]
This takes inspiration from SpellDamage to let you specify the energy source. It also handles crits, which don't cost any energy, and gives a bonus on the heal when you crit. You can easily alter the crit bonus formula by editing critHeal. You can change which animation to play by altering anim, or remove the animation altogether by changing anim=''.
// Usage: /:majorHealing
function majorHealing(energy, source) {
let cost = `/fp -${energy}`;
if (source === 'HP') cost = `/hp -${energy}`;
if (source === 'EnergyReserve') cost = `/tr(EnergyReserve) -${energy}`;
let heal=energy*2;
let critHeal=(energy*2)+energy;
let anim = '\\\\!/anim HealingAbility*Blue c *0.2';
let OtF = '[/if [Sp:"Major Healing"] cs:{/hp +'+critHeal+' @target '+anim+'} s:{/hp +'+heal+' @target '+anim+' \\\\'+cost+' }]';
console.log(OtF);
GURPS.executeOTF(OtF);
}
new Dialog({
title: `Major Healing`,
content: `
<div style='padding: 4px;'>
<label for="energy">Energy</label>
<input id="energy" type="text" />
</div>
<div style='padding: 4px;'>
<label for="source">Source</label>
<select id="source">
<option value='FP'>FP</option>
<option value='EnergyReserve'>Energy Reserve</option>
<option value='HP' style='color: darkred;'>HP</option>
</select>
</div>
`,
buttons: {
confirm: {
label: "Confirm",
callback: async (html) => majorHealing(
parseInt(html.find('#energy').val()),
html.find('#source').val())
}
}
}).render(true)
Type: Script
Contributor: devakm
The objective for this macro is to provide a template for reducing complex OtF commands into easy-to-use macros, such as /:fireball
OtF to trigger it: ["Fireball"/:fireball]
/* Usage: /:fireball
* copy this macro and rename it to match other spells, then reference it in an OtF like this: [/:spellname]
* then fill in the values below to match the name of the spell, the ranged attack, the animations, and outcomes.
* the example success formulas use the SpellDamage macro
*/
// OtF action setup:
let SpellName ='Fireball'; // Spell Name, i.e. [Sp:Fireball]
let RangedAttackName ='Fireball'; // Ranged Attack Name, i.e. [R:Fireball]
let PrimaryCheck = '[Sp:'+SpellName+']'; // alter the OtF type used for primary check
let SecondaryCheck = '[R:'+RangedAttackName+']'; // alter the OtF type used for secondary check
// Outcomes for critical success, critical failure, regular success, and regular failure
// each of these settings can be tested individually as an OtF or chat command.
// outcome animations:
let sanim = '!/anim FireBolt*Regular_Orange -0.3 +1.5'; // success animation
let csanim = '!/anim FireBolt*Regular_Orange -0.3 +1.5'; // critical success animation
let fanim = '!/anim FireBolt*Regular_Orange -0.3 -3'; // failure animation
let cfanim = '!/anim FireballExplosion*Orange c *0.1 @self'; // critical failure animation
// outcome formulas:
let csformula ='/:SpellDamage Fireball 1 +2 burn -4'; // critical success formula
let cfformula ='/hp -1d-3!'; // critical failure formula
let sformula ='/:SpellDamage Fireball 1 0 burn 0'; //success formula
let fformula ='/fp -1'; // failure formula
let OtF = '[/if '+PrimaryCheck+' cs:{/if '+SecondaryCheck+' {'+csanim+' \\\\'+csformula+' }} cf:{'+cfanim+' \\\\'+cfformula+'} s:{/if '+SecondaryCheck+' {'+sanim+' \\\\'+sformula+'}} f:{'+fanim+' \\\\'+fformula+'} ]';
console.log(OtF);
GURPS.executeOTF(OtF);
Type: Script
Contributor: devakm
This is a variant of the Spell Handler Template designed to handle melee attacks with a Wizard's Staff or similar attack combined with Burning Touch, Shocking Touch, Deathtouch, etc. Modify as needed.
OtF to trigger it: ["Burning Smash"/:BurningSmash]
/* Usage: /:BurningSmash
* copy this macro and rename it to match other spell attacks, then reference it in an OtF like this: [/:spellname]
* Fill in the values below to match the name of the spell, the melee attack, the animations, and outcomes.
* the example success formulas roll melee strike damage first and then use the SpellDamage macro
*/
// OtF action setup:
let SpellName ='Burning*Touch'; // Spell Name, i.e. [Sp:Burning*Touch]
let AttackName ='Wizard*Swung'; // Attack Name, i.e. [R:Burning*Touch]
let PrimaryCheck = '[Sp:'+SpellName+']'; // alter the OtF type used for primary check
let SecondaryCheck = '[M:'+AttackName+']'; // alter the OtF type used for secondary check
let StrikeDamage = '/r [D:'+AttackName+']'; // strike damage OtF. If this penetrates DR, then apply SpellDamage
// Outcomes for critical success, critical failure, regular success, and regular failure
// each of these settings can be tested individually as an OtF or chat command.
// outcome animations:
let sanim = '!/anim Quarterstaff03*Regular_Purple *0.3 -0.2 +1 \\\\!/wait 1500 \\\\!/anim Impact_01_Regular_Yellow c *0.7 \\\\!/anim Flames_01_Regular_Orange c *0.5'; // success animation
let csanim = '!/anim Quarterstaff03*Regular_Purple *0.3 -0.2 +1 \\\\!/wait 1500 \\\\!/anim Impact_01_Regular_Yellow c \\\\!/anim Flames_01_Regular_Orange c *0.8'; // critical success animation
let fanim = '!/anim Quarterstaff03*Regular_Purple *0.3 -0.2 -0.1'; // failure animation
let cfanim = '!/anim Impact_01_Regular_Yellow c *0.8 @self \\\\!/anim Flames_01_Regular_Orange c *0.4 @self'; // critical failure animation
// outcome formulas:
let csformula = StrikeDamage+' \\\\/:SpellDamage BurningTouch 1 +2 burn -8'; // critical success formula
let cfformula ='/hp -1d-3!'; // critical failure formula
let sformula = StrikeDamage+' \\\\/:SpellDamage BurningTouch 1 0 burn 0'; //success formula
let fformula ='/fp -1'; // failure formula
let OtF = '[/if '+PrimaryCheck+' cs:{/if '+SecondaryCheck+' {'+csanim+' \\\\'+csformula+' }} cf:{'+cfanim+' \\\\'+cfformula+'} s:{/if '+SecondaryCheck+' {'+sanim+' \\\\'+sformula+'}} f:{'+fanim+' \\\\'+fformula+'} ]';
console.log(OtF);
GURPS.executeOTF(OtF);
Type: Script
Contributor: LordHelmet (Discord)
Description: Replaces a selected Token completely with a different Token, from different Actors, while playing an animation. Suitable for characters with Alternate Form, such as werewolves or superheroes who transform from Normals to Supers (such as DC's Shazam).
const {x,y} = token.document;
// in the quotes the path for the animation to be played, easy to get via Sequencer Database
// const file = "modules/jb2a_patreon/Library/Generic/Particles/ParticlesSwirl01_01_Regular_Blue_400x400.webm";
// in the quotes the ID of the actor that should be there at the end of the transformation.
// get it in the console via "game.actors.getName('name of the actor').id
const tokenData = await game.actors.get("ID of the actor").getTokenDocument({x,y});
await new Sequence()
.effect()
.file("path for the first animation")
.atLocation(token)
.scale(0.3, 0.3)
.playbackRate(2)
.waitUntilFinished(-1000)
.effect()
.file("path for the second animation")
.atLocation(token)
.scale(0.6, 0.6)
.scaleIn(0.2, 2000)
.randomRotation()
.fadeIn(2000)
.scaleOut(3, 1500, { ease: "easeInExpo", delay: -400})
.fadeOut(1500)
.wait(2000)
.thenDo(async function(){
await canvas.scene.createEmbeddedDocuments("Token", [tokenData]);
token.document.delete();
})
.play()
- Home
- Getting Started
- Modifiers and the Modifier Bucket
- Combat Tracker
- Foundry Items
-
Cool Macros
- Clear All Active Effects
- Last Targeted Roll demo and margin of success
- Fright Check
- Fireball Damage
- Scale Lighting
- Quick Combat
- Manual Damage
- Quick-Draw and Shoot
- Toggle Reeling or Exhausted
- Roll Attack and Critical Hit
- Create and Toggle Active Effect
- Bad Footing Active Effect
- Spell Damage
- Major Healing
- Missile Spell Handler Template
- Melee Spell Strike Handler Template
- Alternate Form
- Multiple Quick Contests
- Open/Close Helmet Visor
- Advanced Features
- Useful OTFs
- User Recommended Modules