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

Changeable patrons?? Help

So I am still new to APIs, I have utilized a few that I've found here and have been able to modify somewhat for various effects. I am looking for help building a specific routine that seems like it would be a combination of a few different scripts and I am hoping for help from some of you experienced API masters. So what I am looking for is a combination of the shuffle effect and changing of the token face from rollable tokens. Imagine a pub... There are 20 spots people could occupy. In each space is a token. Each token has 5 different options built into them including a blank image to give the appearance of no one in that space. When you click the macro button, the 20 tokens each randomize which image they use then shuffle positions. This would be a quick way to change the patronage of the pub/market/whatever on the fly. It seems like it would take building the 20 rollable tokens (Patron A, Patron B, etc.) and placing them on the map. Then building the script and macro to random the image for each named token and the shuffle to use these tokens. Like I said, it seems like a combination of a few effects that exist, can you guys help?
1553896700

Edited 1553896729
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
This can all be done with the Token Mod script (available in the API dropdown). Let's say you have 5 different faces on a token, and 20 copies of the token. Select them all and run: !token-mod --set currentside|[[1d5]]
1553896785
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
You can also you it to change positions on a token, but there's a lot of logic in there to avoid overlaps and not putting anyone in a wall or off the edge of the map.
1553898306

Edited 1553898940
I loaded Token Mod from the dropdown. I created a Rollable Token with 5 images. I created a macro using the script you showed above. I drop the token on the board from the rollable table and named it Patron-A. I selected the token, clicked the macro, nothing happens.. what am I missing? I also tried it without the Macro, Just pasting the code into chat. Still Nothing.  Do you have a simple test I can run to verify the Token-Mod script is responding?
1553900288

Edited 1553962803
The Aaron
Roll20 Production Team
API Scripter
If I were writing a script for this, I would create a selection of tokens on the GM layer for the patrons.&nbsp; I would denote them in some way, like putting the word "patron" in one of the bars.&nbsp; I would then place on the GM layer, a token with the name "seat".&nbsp; The script, when executed would find all the seats on the current page (player.get('lastpage') for GM's "current" page), then find all the patrons.&nbsp; It would move all the patrons to the GM Layer, then choose one randomly for each seat (possibly with a decision about if the seat should be empty, then skip it), then move them to the position, and rotation of the seat, and place them on the Objects layer.&nbsp; I'd then move all the unplaced patrons to some holding area on the GMLayer, possibly just lined up along the top edge. This has the benefit that the concept of a seat is separated from the person that occupies it.&nbsp; Adding more seats is as easy as copy/pasting the token on the GM layer that represents a seat.&nbsp; Having individual patrons means you never have the same patron more than once, unless you make duplicates, and then you could flip it, shade it, etc to make it appear slightly different.&nbsp; Adding more patrons is an easy task and you can mix in more patrons easily (even NPCs or Monsters, which themselves might have multiple sides, such as a druid or werewolf).&nbsp; Additionally, you can use Marketplace content freely, as the API is never creating those tokens. ... Like this: Run the command: !take-a-seat By default there's a 75% chance each seat gets filled (calculated individually).&nbsp; You can specify the chance either explicitly as a number: !take-a-seat 50 or with an inline roll: !take-a-seat [[@{Game|base_seat_chance}+1d30-15]] Put 'patron' in bar1's value slot to mark a patron token.&nbsp; You can modify that in the code at the top. Code: Expanded and Bug-fixed below: &nbsp;<a href="https://app.roll20.net/forum/permalink/7337250/" rel="nofollow">https://app.roll20.net/forum/permalink/7337250/</a>
That worked great! You are awesome.
1553903360
The Aaron
Roll20 Production Team
API Scripter
=D&nbsp; Good deal!
1553903611
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
showoff. ;)
1553904060
The Aaron
Roll20 Production Team
API Scripter
I just gotta be me... =D
That is awesome! Now I am going to create a few variants for staff (waitresses, bartenders, etc) maybe one for merchants or merchant tents in the market, maybe for guards to vary content of guards or thugs for encounters... the possibilities are endless.&nbsp;
1553906268
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
@{Game|base_seat_chance} Aaron, does your game have a character named "Game" that has a lot of custom attributes?
1553917680
GiGs
Pro
Sheet Author
API Scripter
The Aaron said: If I were writing a script for this, *proceeds to write script* The word "If" clearly does not belong in Aaron's vocabulary - and we are all better for it :)
1553926066
The Aaron
Roll20 Production Team
API Scripter
Ha! &nbsp;By the time I wrote those first paragraphs, I figured it would have been faster to just write the script. =D There’s a bug in it I’ll fix in tomorrow.&nbsp;
1553927424

Edited 1553927450
GiGs
Pro
Sheet Author
API Scripter
keithcurtis said: @{Game|base_seat_chance} Aaron, does your game have a character named "Game" that has a lot of custom attributes? That seems like a clever way to handle game- or scene-specific parameters like these.&nbsp;
1553960890
The Aaron
Roll20 Production Team
API Scripter
I got that from Al e, I thought it was on the stupid tricks thread already.
1553962729

Edited 1553962873
The Aaron
Roll20 Production Team
API Scripter
Upgraded and bug fixed version. There was a crash bug where if you didn't have enough patrons for the number of seats, it would try to dereference and undefined value, fixed. Additionally, since the ordering of tokens returned from findObj() is deterministic, it was always filling seats in the same order, it now randomizes which seat is attempted to fill next. Finally, I added a -- argument to tell it to seat in a different list: !take-a-seat --staff|cook That will find all the markers on the current page gm layer with the name "staff" (case insensitive) and randomly assign tokens with "cook" in their bar1 (case insensitive) in them.&nbsp; If you omit the |cook part, it will try to find tokens with the same value in their bar1 as the place you want to stick them, for example: !take-a-seat --staff is equivalent to: !take-a-seat --staff|staff You can still specify a likelihood that any given seat is filled: !take-a-seat 53 --staff You can use the same token on the GM layer, it doesn't matter.&nbsp; I just tinted them differently for contrast: Code: on('ready', ()=&gt;{ const PATRON_LOCATION = 'bar1_value'; const getPageForPlayer = (playerid) =&gt; { let player = getObj('player',playerid); if(playerIsGM(playerid)){ return player.get('lastpage'); } let psp = Campaign().get('playerspecificpages'); if(psp[playerid]){ return psp[playerid]; } return Campaign().get('playerpageid'); }; const processInlinerolls = (msg) =&gt; { if(_.has(msg,'inlinerolls')){ return _.chain(msg.inlinerolls) .reduce(function(m,v,k){ let ti=_.reduce(v.results.rolls,function(m2,v2){ if(_.has(v2,'table')){ m2.push(_.reduce(v2.results,function(m3,v3){ m3.push(v3.tableItem.name); return m3; },[]).join(', ')); } return m2; },[]).join(', '); m['$[['+k+']]']= (ti.length &amp;&amp; ti) || v.results.total || 0; return m; },{}) .reduce(function(m,v,k){ return m.replace(k,v); },msg.content) .value(); } else { return msg.content; } }; const esRE = (s) =&gt; s.replace(/(\\|\/|\[|\]|\(|\)|\{|\}|\?|\+|\*|\||\.|\^|\$)/g,'\\$1'); const matcher = (t) =&gt; new RegExp(`^\\s*${esRE(t)}\\s*$`,'i'); on('chat:message', (msg)=&gt;{ if('api' === msg.type &amp;&amp; /^!take-a-seat\b/i.test(msg.content) &amp;&amp; playerIsGM(msg.playerid)){ let pageid = getPageForPlayer(msg.playerid); let content = processInlinerolls(msg); let where = 'seat'; let whom = 'patron'; let which = content.split(/\s+--/).slice(1); let args = content.split(/\s+/); let fill = parseInt(args[1],10)||75; if(which.length){ let w = which.shift().split(/\|/); where = w[0]; whom = w[1]||where; } let whereM = matcher(where); let whomM = matcher(whom); let seats = findObjs({ type: 'graphic', layer: 'gmlayer', pageid: pageid }).filter((o)=&gt;whereM.test(o.get('name'))); let patrons = findObjs({ type: 'graphic', pageid: pageid }).filter((o)=&gt;whomM.test(o.get(PATRON_LOCATION))); patrons.forEach((o)=&gt;{ o.set({layer: 'gmlayer'}); }); const getRandomPatron = ()=&gt;{ let e = randomInteger(patrons.length)-1; let p = patrons[e]; patrons = [...patrons.slice(0,e),...patrons.slice(e+1)]; return p; }; const getRandomSeat = ()=&gt;{ let e = randomInteger(seats.length)-1; let p = seats[e]; seats = [...seats.slice(0,e),...seats.slice(e+1)]; return p; }; sendChat('TakeASeat',`/w gm Filling ${seats.length} seat(s) with a ${fill}% chance.`); let s; while(undefined != (s = getRandomSeat())){ if(randomInteger(100) &lt;= fill){ let p = getRandomPatron(); if(p){ p.set({ layer: 'objects', top: s.get('top'), left: s.get('left'), rotation: s.get('rotation') }); } } } let pos = { top: 35, left: 35 }; patrons.forEach(p=&gt;{ p.set(pos); pos.left+=70; }); } }); });
1553966027
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
The Aaron said: I got that from Al e, I thought it was on the stupid tricks thread already. I have several utility characters, like the Macro Sheet, a Jukebox control Sheet, and my NPC directory, but hadn't done a lot with custom attributes. Mostly each holds a library of related Abilities