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;
}
}
});
});
})();