Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

[Script] Pathfinder Actions Chat Menu generator

1558204535

Edited 1558577900
GiGs
Pro
Sheet Author
API Scripter
Pathfinder Action Menu. For the Pathfinder by Roll20 Sheet . This script generates a chat menu for a character of attacks, spells, spell-like abilities, or any combination of them, and whispers that chat menu so it doesnt clutter up the chat. You must be using the Pathfinder by Roll20 sheet (haven't tested with others, but i expect it won't work). It can be used by players and GMs.  Here's a good way to call it: !pfactionmenu @{selected|character_id} ?{Menu Type?|Attacks|Spells|Spell-like|All} You can also use any of the following to launch it: !pfactionmenu @{selected|character_id} All !pfactionmenu @{selected|character_id} Attacks Spell-like !pfactionmenu @{selected|character_id} Spells !pfactionmenu @{selected|character_id} Spell-like Spells The chat menu will leave out any sections you dont have, so if you select All, but dont have any spell-like abilities, or spells above 4th level, those sections won't be printed. Edit: Update Sheet now has the option to show only prepared spells. Add the word 'prepared' anywhere after character_id, like so: !pfactionmenu @{selected|character_id} Attacks Spells prepared !pfactionmenu @{selected|character_id} prepared Spells Spell-like !pfactionmenu @{selected|character_id} prepared Spells It uses the pf rolltemplate and roll20's standard API menu buttoms, so its output looks like this Paste the following into your scripts page: /* Pathfinder !pfactionmenu @{selected|character_id} ?{Menu Type?|Attacks|Spells|Spell-like|All} !pfactionmenu @{target|character_id} Attacks !pfactionmenu @{name|character_id} Spells !pfactionmenu @{selected|character_id} Attacks Spell-like !pfactionmenu @{selected|character_id} All if you want to show only prepared spells, add 'prepared' anywhere after character_id, like so: !pfactionmenu @{selected|character_id} Attacks Spell-like prepared !pfactionmenu @{selected|character_id} Attacks prepared Spell-like */ on('ready',function(){ "use strict"; const ch = function (c) { var entities = { '@' : '#64', '{' : '#123', '|' : '#124', '}' : '#125', '#' : '#13' }; if(_.has(entities,c) ){ return ('&'+entities[c]+';'); } return ''; }; const field = (section, id, field) => `repeating_${section}_${id}_${field}`; const repIDs = (cid, section, display) => { const repeating = findObjs({ _type: "attribute", _characterid: cid }) .filter((obj)=> { return obj.get('name').startsWith('repeating_' + section) && obj.get('name').endsWith(display); }) .map(obj => obj.get('name').replace(`repeating_${section}_`,'').replace('_' + display,'').trim()); return repeating; }; const getPrepared = (cid, section, spellid, suffix = '_spellprepared') => { const found = findObjs({ _type: "attribute", _characterid: cid }) .filter((obj)=> { return obj.get('name').startsWith(`repeating_${section}_${spellid}`) && obj.get('name').endsWith(suffix); })[0]; let prepared = 0; if(found) { prepared = found.get('current'); } return prepared; }; on('chat:message',function(msg){ if('api' === msg.type && msg.content.startsWith('!pfactionmenu') ){ let args = msg.content.split(/\s+/);; const parameters = { 'attacks': {section: 'attacks', display: 'atkname', macro: 'rollbase', title: 'Attacks'}, 'spell-like': {section: 'spell-like', display: 'spelldisplay', macro: 'rollcontent', title: 'Spell-Like Abilities'}, 'spell-0': {section: 'spell-0', display: 'spelldisplay', macro: 'rollcontent', title: 'Level 0 Spells'}, 'spell-1': {section: 'spell-1', display: 'spelldisplay', macro: 'rollcontent', title: 'Level 1 Spells'}, 'spell-2': {section: 'spell-2', display: 'spelldisplay', macro: 'rollcontent', title: 'Level 2 Spells'}, 'spell-3': {section: 'spell-3', display: 'spelldisplay', macro: 'rollcontent', title: 'Level 3 Spells'}, 'spell-4': {section: 'spell-4', display: 'spelldisplay', macro: 'rollcontent', title: 'Level 4 Spells'}, 'spell-5': {section: 'spell-5', display: 'spelldisplay', macro: 'rollcontent', title: 'Level 5 Spells'}, 'spell-6': {section: 'spell-6', display: 'spelldisplay', macro: 'rollcontent', title: 'Level 6 Spells'}, 'spell-7': {section: 'spell-7', display: 'spelldisplay', macro: 'rollcontent', title: 'Level 7 Spells'}, 'spell-8': {section: 'spell-8', display: 'spelldisplay', macro: 'rollcontent', title: 'Level 8 Spells'}, 'spell-9': {section: 'spell-9', display: 'spelldisplay', macro: 'rollcontent', title: 'Level 9 Spells'}, } const cid = args[1] || 'N/A'; const who = getAttrByName(cid,'character_name'); if(cid === 'N/A' || who === undefined) { sendChat("Action Menu","You need to include a valid character ID."); return; } let controllers = getObj("character", cid).get('controlledby'); if(controllers !== '') controllers = controllers.split(','); // build a list of repeating sections we want to use const allowed = ['all', 'attacks', 'spells', 'spell-like', 'prepared']; let sections = []; // sections is the list of repeating sections this menu will be built from let showPrepOnly = 0; for(let i = 2; i < args.length; i++) { if(allowed.includes(args[i].toLowerCase())) { if(args[i].toLowerCase() === 'all' || args[i].toLowerCase() === 'attacks' ) { sections.push('attacks'); } if(args[i].toLowerCase() === 'all' || args[i].toLowerCase() === 'spell-like' ) { sections.push('spell-like'); } if(args[i].toLowerCase() === 'all' || args[i].toLowerCase() === 'spells' ) { sections.push('spell-0', 'spell-1', 'spell-2', 'spell-3', 'spell-4', 'spell-5', 'spell-6', 'spell-7', 'spell-8', 'spell-9'); } if(args[i].toLowerCase() === 'prepared') { showPrepOnly = 1; } } } if(sections.length === 0) { sendChat("Action Menu","Type not recognised. Enter some combination of Attacks, Spells, Spell-like, or All."); return; } log("prep: " + showPrepOnly); // now we have an array of every section on the sheet we can build the menu. let menuname = (args.length === 3 && args[2].toLowerCase() !== 'all') ? args[2].toUpperCase() : 'ACTIONS'; let icon = (sections.length ===1 && sections[0] === 'attacks') ? 'attack' : (sections.length > 1 && sections.includes('attacks')) ? 'ability' : 'spell'; let output = `&{template:pc} {{showchar=[[1]]}} {{charname=${who}}} {{type=${icon}}} {{smallname=${menuname} MENU}} {{descflag=1}} {{desc=`; sections.forEach(s => { let repeating = repIDs(cid, parameters[s].section, parameters[s].display); let founditems = []; if(repeating.length > 0) { repeating.forEach(id => { let print = true; if(showPrepOnly && s.startsWith('spell-') && !s.endsWith('-like')) { // check if spell is prepared let found = getPrepared(cid, s, id) *1||0; if(found === 0) print = false; } if(print) founditems.push(id); }); if(founditems.length > 0) { if(menuname !== 'ATTACKS' && menuname !== 'SPELL-LIKE') output += `**${parameters[s].title}**\n`; founditems.forEach(id => { output += `[@{${who}|${field(parameters[s].section,id,parameters[s].display)}}]`; output += `(!${ch('#')}${ch('@')}{${who}|${field(parameters[s].section,id,parameters[s].macro)}}) `; }) output += `\n`; } } }); output += `}}`; // time to print it out, after sorting out who needs to see it. const sender = 'character|' + cid; const caller = (getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname'); sendChat(sender,'/w ' + caller + ' ' + output); }; }); });
1558209002
vÍnce
Pro
Sheet Author
Very cool addition for the PF by Roll20 sheet GiGs. Should get lot's of use for this. FYI: The PF Community sheet has chat menus(attacks, skills, spells, abilities, etc.) built into the sheet.
1558209565
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Nice GiGs, you do quick work.
1558211532
GiGs
Pro
Sheet Author
API Scripter
Thanks, both of you. Vince, that's interesting about the community sheet. While writing this, it did occur to me that it would be pretty easy for sheet designers to include such a feature and wondered if any had. 
Turned out incredible, GiGs! Thanks again for building this for me!
1558213266
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
GiGs said: Thanks, both of you. Vince, that's interesting about the community sheet. While writing this, it did occur to me that it would be pretty easy for sheet designers to include such a feature and wondered if any had.  Yep, and similarly the Starfinder by Roll20 and 5e Shaped sheets also have chat menu macros.
1558214889
GiGs
Pro
Sheet Author
API Scripter
You're welcome, Seph. Thanks for giving me the idea!
1558569839
vÍnce
Pro
Sheet Author
How hard would it be to add an option to only show the prepared spells? ;-)
1558571489
GiGs
Pro
Sheet Author
API Scripter
I'm not familiar with the pathfinder sheet, actually. If it uses a checkbox or some other way to mark each spell as prepared or not, on that spell's row, it should be pretty straightforward. I'll check it out later.
1558576299
GiGs
Pro
Sheet Author
API Scripter
Just updated to only show prepared spells, if you add the word 'prepared' to the script command.
1558583121
vÍnce
Pro
Sheet Author
GiGs said: Just updated to only show prepared spells, if you add the word 'prepared' to the script command. I think that will make a lot of spell caster's very happy.  Thanks GiGs
1558643193
Natha
KS Backer
Sheet Author
API Scripter
Great work, Gigs!
1558655608
GiGs
Pro
Sheet Author
API Scripter
Thanks, Natha!
This Script is amazing, Thanks GiGs! I have a question if I may; is it possible to adjust the script so when a prepared spell is cast it removes one from the prepared amount? so, for example, when a caster uses all 3 of their prepared magic missiles it stops showing as a prepared spell? that would be a great help.
1561902443
GiGs
Pro
Sheet Author
API Scripter
I'm glad you like it. I think it is&nbsp;be possible - IIRC I added the feature to my other menu script. I probably wont be able to work on this one for a week or so (probably), so it might be worth checking out my other menu script to see if that does the job in the meantime:&nbsp; <a href="https://app.roll20.net/forum/permalink/7474530/" rel="nofollow">https://app.roll20.net/forum/permalink/7474530/</a> &nbsp;. It takes a little more setup, but is more powerful.