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

Using Decks

Hi I have a question regarding the decks functionality... I am setting up Torg decks and I need to be able to put the decks back in sequence (i.e. the order I loaded them) after they've been shuffled. I cannot see any way of being able to do this. Am I missing something or is this useful function unavailable? Thanks!
1506695508

Edited 1506718100
The Aaron
Pro
API Scripter
The only way to do this is with the API, and it's very very limited.   You'd need to have all the images for the deck in your User Library so that the API can have access to them.  I wrote a script that will let you reorder a deck.   Here's how it works: Instructions: !deck List cards in the deck, all of these work the same: !deck --Some Deck Name !deck --Some Deck Name --list !deck --SomeDeckName !deck --somedec (assuming there's no other deck with s,o,m,e,d,e,c in that order in it)  Reorder cards in the deck, all of these work the same: !deck --Some Deck Name --stack --Some card first --Some card second --Some card third !deck --Some Deck Name --stack {{ --Some card first --Some card second --Some card third }} !deck --omedec --stack {{ --ard first --cardsec --Somecard third }} Here's the script: (function(){     "use strict";     const numberStyle=`position:absolute;top:3px;right:3px;z-index:100;font-weight:bold;color:white;font-size:2em;text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;`,           cardStyle=`max-width: 5em;max-height:7em;position:relative;display:inline-block;`, //          nameStyle=`position:absolute;bottom:3px;left:3px;z-index:100;font-weight:bold;color:white;font-size:1em;text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;`,                    esRE = function (s) {           var escapeForRegexp = /(\\|\/|\[|\]|\(|\)|\{|\}|\?|\+|\*|\||\.|\^|\$)/g;           return s.replace(escapeForRegexp,"\\$1");         },         HE = (function(){           var entities={                   //' ' : '&'+'nbsp'+';',                   '<' : '&'+'lt'+';',                   '>' : '&'+'gt'+';',                   "'" : '&'+'#39'+';',                   '@' : '&'+'#64'+';',                   '{' : '&'+'#123'+';',                   '|' : '&'+'#124'+';',                   '}' : '&'+'#125'+';',                   '[' : '&'+'#91'+';',                   ']' : '&'+'#93'+';',                   '"' : '&'+'quot'+';'               },               re=new RegExp('('+_.map(_.keys(entities),esRE).join('|')+')','g');           return function(s){             return s.replace(re, function(c){ return entities[c] || c; });           };         }()),         ch = function (c) {             var entities = {                 '<' : 'lt',                 '>' : 'gt',                 "'" : '#39',                 '@' : '#64',                 '{' : '#123',                 '|' : '#124',                 '}' : '#125',                 '[' : '#91',                 ']' : '#93',                 '"' : 'quot',                 '-' : 'mdash',                 ' ' : 'nbsp'             };             if(_.has(entities,c) ){                 return ('&'+entities[c]+';');             }             return '';         },                  keyFormat = (s)=>s.toLowerCase().replace(/[^a-z0-9]/g,''),         showHelp = function(who){             sendChat('',`/w "${who}" `+             `<div>`+                 `<div>`+                     `<code>!deck `+                         `--${ch('<')}Deck name${ch('>')} ${ch('[')}--${ch('<')}Operation${ch('>')} ${ch('[')}--${ch('<')}Option${ch('>')} ...${ch(']')} ${ch(']')}`+                     `</code>`+                 `</div>`+                 `<div>`+                 `<h4>Operations</h4>`+                 `<ul>`+                     `<li><code>list</code> -- The default operation, shows the current stack of cards for the deck.</li>`+                     `<li><code>stack</code> -- Stack the deck with cards.  Each subsequent option is the name of a card in the deck and will be placed on the top of the deck in the order specified.  Cards that are replaced will be moved to where each new card was.</li>`+                 `</ul>`+                 `<h4>Names</h4>`+                 `<p>Wherever you specify a card or deck name, you can use the minimal matching part of the name.  Case is ignored, as are spaces and any punctuation.  ${ch('"')}Bob - the - builder!${ch('"')} would be matched by ${ch('"')}bob${ch('"')} or ${ch('"')}thebui${ch('"')} or a similar substring.</p>`+             `</div>`             );         },                  getDecks = function(name){             let deckKey=keyFormat(name||'');             return deckKey ?                 _.filter(findObjs({ type: 'deck' }), (d)=> -1 !== keyFormat(d.get('name')).indexOf(deckKey)) :                 [];         },         getCards = function(deck, cardNames){             let cards = findObjs({                 type: 'card',                 deckid: deck.id             });             return _.chain(cardNames)                 .map(keyFormat)                 .reduce((m,cardKey)=>{                     let match = _.reduce(cards,(m,c) => {                         let cKey = keyFormat(c.get('name'));                         if(-1 !== cKey.indexOf(cardKey)){                             if(cKey===cardKey){                                 return {                                     card: c,                                     exact: true                                 };                             } else if(!m.card){                                 return {                                     card: c,                                     exact: false                                 };                             }                         }                         return m;                     },{card:false, exact:false});                     m.push(match.card);                     return m;                 },[])                 .value();         },         showDeckOptions = function(who,msg,decks,deckName){             let notFound = (decks.length ? '' : `<div style="color:red;font-weight:bold;">No deck found for <code>${deckName}</code></div>`),                 deckOpt = (decks.length ? decks : findObjs({type:'deck'}));             sendChat('',`/w "${who}" `+                 `<div>`+                     notFound+                     `<div><div>Possible options:</div><ul>`+                         _.map(deckOpt,(d)=>{                             return `<li><a href="${HE(msg.replace(`--${deckName}`,`--${keyFormat(d.get('name'))}`))}">${d.get('name')}</a></li>`;                         }).join('')+                     `</ul></div>`+                 `</div>`             );                      },         showCardOptions = function(who,deck, cardNames){             sendChat('',`/w "${who}" `+                 `<div>`+                     `<div style="color:red;font-weight:bold;">No card found in <code>${deck.get('name')}</code> for <code>${cardNames.join('</code>, <code>')}</code></div>`+                     `<div>Possible options:</div>`+                     `<div>${getDeckCardList(deck)}</div>`+                 `</div>`             );         },         getDeckCardList = function(deck){             let cards=_.chain(deck.get('currentDeck').split(/\s*,\s*/))                 .map((id)=>getObj('card',id))                 .reject(_.isUndefined)                 .value();             let disp = _.map(cards,(o,idx)=>{                 return `<div style="${cardStyle}">`+                     `<span `+                         `style="${numberStyle}min-width:.1em;" `+                         `class="tipsy showtip" `+                         `title="${HE(HE(o.get('name')))}">`+                             (idx+1)+                         `</span>`+                     `<img src="${o.get('avatar')}">`+                 `</div>`;             }).join('');             return disp;         },         moveCardToPosition = function(deck,cardData,idx){             let card = findObjs({                 type: 'card',                 deckid: deck.id,                 name: cardData.name,                 avatar: cardData.avatar             })[0];             if(card){                 let cardPos=deck.get('currentDeck').split(/\s*,\s*/),                     currentIdx=cardPos[idx];                 if(currentIdx){                     let cardCur=getObj('card',currentIdx);                     card.set({                         name: cardCur.get('name'),                         avatar: cardCur.get('avatar')                     });                     cardCur.set(cardData);                 }             }         }         ;     on('ready',function(){                  on('chat:message',function(msg){             if(msg.type !== 'api' || !playerIsGM(msg.playerid)){                 return;             }             if(msg.content.match(/^!deck/)){                 let args = msg.content                         .replace(/<br\/>\n/g, ' ')                         .replace(/(\{\{(.*?)\}\})/g," $2 ")                         .trim()                         .split(/\s+--/),                     who=(getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname'),                     operation = (args[2] || 'list').toLowerCase(),                     decks = getDecks(args[1]);                 if(1 === args.length){                     showHelp(who);                     return;                 }                 if(1 !== decks.length){                     showDeckOptions(who,msg.content,decks,args[1]);                     return;                 }                 switch(operation){                     case 'list':                         // show                         _.each(decks, (d)=>{                             sendChat('',`/w "${who}" `+                                 `<div><h3>Current ordering of cards</h3>`+                                 `<div>${getDeckCardList(d)}</div>`+                                 `</div>`                                 );                         });                         break;                     case 'stack': {                             let deck = _.first(decks),                                 cardNames = _.rest(args, 3),                                 stack=getCards(deck, cardNames),                                 unmatched=[];                             _.each(stack,(c,i)=>{                                 if(c===false){                                     unmatched.push(cardNames[i]);                                 }                             });                             if(unmatched.length){                                 showCardOptions(who,deck, unmatched);                                 return;                             }                             let stackData=_.map(stack,(o)=>({name: o.get('name'),avatar: o.get('avatar')}));                             _.each(stackData,(o,idx)=>{                                 moveCardToPosition(deck,o,idx);                             });                                                          sendChat('',`/w "${who}" `+                                 `<div><h3>New ordering of cards</h3>`+                                 `<div>${getDeckCardList(deck)}</div>`+                                 `</div>`                                 );                         }                         break;                                          }             }         });     }); })();
1506700383
Finderski
Pro
Sheet Author
Compendium Curator
This could be weird, but could you use the Transmogrifier? Create a deck in one game that has the order you want them in.  Then transmogrify that deck to the game you're actually playing in.  When you need to reload the deck, just delete the deck from the game and reload it from the "storage" game?
1506700586
The Aaron
Pro
API Scripter
Hey Finderski, that's a really clever solution!
Now that is a thought... might need to re-order during the game though... will have to noodle on it.
Aaron, I've got this in the APIs and it works fine for --List *but* it does not like spaces in the name (i.e. it'll find Living but fails when I use Living Land). I set my deck up just using numbers as the "name" - so 1 through 10 - but when I try and --stack I get the error "No card found in Living for 10". What am I doing wrong?
1506714257
The Aaron
Pro
API Scripter
Hmmm.. wanna PM me an invite?  Might be easiest to look at it there.
1506718123
The Aaron
Pro
API Scripter
(Fixed several bugs and updated the script above.)
I play Torg, why do you need a deck in a certain order? Both Drama  and Destiny deck have no particular order they should be in.
Greg C. said: I play Torg, why do you need a deck in a certain order? Both Drama  and Destiny deck have no particular order they should be in. I have a split group with one playing on Roll20 and the other five in person... I'll use the Drama deck on Roll20 but, in order to avoid duplication, I'll deal Destiny/Cosm physically... If the decks are in order in Roll20, it's easy for me to give my remote player the cards she "drew"... 
wow gotcha...good luck!
1506731010
The Aaron
Pro
API Scripter
With that script, you don't actually need to put in order, just put the ones she drew at the top of the deck. =D
The Aaron said: With that script, you don't actually need to put in order, just put the ones she drew at the top of the deck. =D you do... if I'm drawing a physical card at the table for her, I need to be able to quickly find that car (Destiny and Cosm only) so I can 'deal' it to her virtually...
1506874553
The Aaron
Pro
API Scripter
I was just thinking if you know the card, you can put it on the top and deal get the top card. 
Why not use a different thing to say what cards someone has...?
Josef E. said: Why not use a different thing to say what cards someone has...? Because a) I might end up running a fully online game at some time in the future; b) the player needs to see the card content; and c) it looks damn good!