I used ai to write a script to put all arcane and divine spells into chat buttons for easy use without having to open the character sheet. This is especially useful for GMs that are managing multiple spell casting monsters in a combat. The script only lists the spells favored in the abilities section of the Mythras sheet. Command What it does !cfspells Lists all Arcane & Divine spells as clickable buttons (select token first) !cfcast SpellName Shows full spell description, traits and rank in chat !cfspells-debug Lists all repeating field names (troubleshooting) !cfspells-row Dumps a spell row's raw data (troubleshooting) Here is the script: var CFS={}; on('chat:message',function(msg){ if(msg.type!=='api')return; var d=msg.content.startsWith('!cfspells-debug'); var r1=msg.content.startsWith('!cfspells-row'); var sc=msg.content.startsWith('!cfcast '); if(!msg.content.startsWith('!cfspells')&&!sc)return; var cid,tk,ch,cn,aa,rw={},sp=[],ar=[],dv=[],gn=[],out; if(sc){ var sid=msg.content.replace('!cfcast ','').trim(); var s=CFS[sid]; if(!s){sendChat('CFS','/w gm Spell not found. Run !cfspells first.');return;} out='&{template:default} {{name='+s.name+'}}'; if(s.rank)out+=' {{Rank='+s.rank+'}}'; if(s.traits)out+=' {{Traits='+s.traits+'}}'; if(s.desc)out+=' {{notes='+s.desc+'}}'; sendChat(msg.who,out); return; } if(msg.selected&&msg.selected.length){tk=getObj('graphic',msg.selected[0]._id);if(tk)cid=tk.get('represents');} if(!cid){sendChat('CFS','/w gm No token.');return;} ch=getObj('character',cid); if(!ch){sendChat('CFS','/w gm No character.');return;} cn=ch.get('name'); aa=findObjs({type:'attribute',characterid:cid}); if(d){var fn=[];aa.forEach(function(a){var n=a.get('name'),m=n.match(/^repeating_[^_]+_[^_]+_(.+)$/);if(m&&fn.indexOf(m[1])===-1)fn.push(m[1]);});sendChat('CFS','/w gm '+fn.sort().join(', '));return;} aa.forEach(function(a){var n=a.get('name'),m=n.match(/^(repeating_[^_]+_[^_]+)_(.+)$/);if(!m)return;var id=m[1],f=m[2],v=a.get('current')||'';if(!rw[id])rw[id]={name:'',type:'',rank:'',desc:'',traits:'',favored:''};if(f==='name')rw[id].name=v;if(f==='type')rw[id].type=v;if(f==='rank')rw[id].rank=v;if(f==='description')rw[id].desc=v;if(f==='traits')rw[id].traits=v;if(f==='favored')rw[id].favored=v;}); if(r1){var found=null;Object.keys(rw).forEach(function(id){if(!found&&(rw[id].type==='arcane_magic'||rw[id].type==='divine_magic'||rw[id].type==='magic'))found=id;});if(!found){sendChat('CFS','/w gm No spell row found.');return;}var dump=[];aa.forEach(function(a){var n=a.get('name');if(n.indexOf(found)!==-1)dump.push(n.replace(found+'_','')+'='+a.get('current'));});sendChat('CFS','/w gm '+dump.join(', '));return;} Object.keys(rw).forEach(function(id){var r=rw[id];if(r.name&&(r.type==='arcane_magic'||r.type==='divine_magic'||r.type==='magic')&&r.favored==='1')sp.push(r);}); if(!sp.length){sendChat('CFS','/w gm No favored CF spells found.');return;} sp.sort(function(a,b){var o={arcane_magic:0,magic:1,divine_magic:2},tA=o[a.type]||0,tB=o[b.type]||0;if(tA!==tB)return tA-tB;if((parseInt(a.rank)||0)!==(parseInt(b.rank)||0))return(parseInt(a.rank)||0)-(parseInt(b.rank)||0);return a.name.localeCompare(b.name);}); CFS={}; sp.forEach(function(s){ var sid=s.name.replace(/\s+/g,'_').replace(/[^a-zA-Z0-9_]/g,''); CFS[sid]={name:s.name,rank:s.rank,desc:s.desc,traits:s.traits}; var label=s.name+(s.rank&&s.rank!='0'?' R'+s.rank:''); var e='['+label+'](!cfcast '+sid+')'; if(s.type==='arcane_magic')ar.push(e); else if(s.type==='divine_magic')dv.push(e); else gn.push(e); }); var wt=playerIsGM(msg.playerid)?'gm':msg.who.replace(/[\s.]/g,''); var w='/w "'+wt+'" '; sendChat('CFS',w+'**'+cn+' CF Spells**'); if(ar.length)sendChat('CFS',w+'**Arcane** '+ar.join(' ')); if(gn.length)sendChat('CFS',w+'**Magic** '+gn.join(' ')); if(dv.length)sendChat('CFS',w+'**Divine** '+dv.join(' ')); });