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

Manipulating Multiple Cards or Decks at Once

1586366609

Edited 1586366665
I recently set up a board game on Roll20, and it would be super helpful if I could automate a few of the routine tasks that occur during play or setup.  1. First, and most importantly, I would like a function that: (1) looks for all tokens on the token layer; (2) determines whether they came from one of several named decks; and, (3) if they did, flips them face-up (until they are recalled back into the players' hands). For example: Cards "1" "4" and "7" of the deck "Baratheon - Order Tokens" have been played face-down onto the tokens layer by "Player1" and cards "4" "5" and "13" of the deck "Stark - Order Tokens" have been played face-down onto the tokens layer by "Player2." Each token (potentially) has a different image on its face-up side. I want to have a button or command that will cause all of these tokens to show their face-up side at once. However, this should not change the fact that they initially show their face-down side the next time they are played. 2. Second, I would like a function that: (1) looks for all tokens on the GM layer; (2) determines whether they came from one of several named decks; and (3) if they did, moves them to the tokens layer. For example: Cards 1 through 14 of the "Forts - 3 player version" deck have been placed on the GM layer. During setup, I want to move them all to the same position on the map, but on the tokens layer. However, the GM layer also includes all the cards in the "Forts - 4 player version" deck, which I do NOT want to move onto the tokens layer. Tokens from the different decks will overlap in space, meaning that it is hard to group-select them. Currently all these tokens are put into decks, but I could change them to ordinary tokens if that would make things easier. 3. Third, I would like a function that: (1) takes a player name as an input; (2) takes a role as an input; and then (3) deals that player all cards from each of several named decks associated with that role. For example: "Player1" will be playing "Baratheon." I want to deal "Player1" 7 cards from the "Baratheon - Character Cards" deck, 15 cards from the "Baratheon - Order Tokens" deck, and 20 cards from the "Baratheon - Power Tokens" deck. I then want to do something similar for "Player2" and "Stark." Etc. 4. Fourth, I would like a function that: (1) looks for all tokens on the token layer; (2) determines whether they came from one of several named decks; (3) associates a specific player with the named decks; and (4) has that player pick up all the appropriate cards.  For example: Cards "1" "4" and "7" of the deck "Baratheon - Order Tokens" were played by "Player1" and cards "4" "5" and "13" of the deck "Stark - Order Tokens" were played by "Player2." After manually resolving the effects of those cards, I want to recall c ards "1" "4" and "7" of the deck "Baratheon - Order Tokens" to the hand of "Player1" and recall  cards "4" "5" and "13" of the deck "Stark - Order Tokens" to the hand of "Player2." Does anyone know whether these are tasks that the API is capable of performing? And, if so, can you point me in the right direction as far as examples, or documentation of the appropriate functions to call?  Thanks so much for your help!
1586371145
The Aaron
Roll20 Production Team
API Scripter
You should be able to do all of those things.&nbsp; I have a few scripts that do things with cards and I can likely help you write any or all of those functions if you need the help, time permitting.&nbsp; Here's the post about Card functions, which I don't think are well documented in the wiki/helpdesk right now:&nbsp;&nbsp;<a href="https://app.roll20.net/forum/post/6223396/slug%7D" rel="nofollow">https://app.roll20.net/forum/post/6223396/slug%7D</a>
1586371572
The Aaron
Roll20 Production Team
API Scripter
For most of this, you'll mainly be dealing with Graphic objects.&nbsp; The important details will be that cards have a subtype of "card": 'card' === obj.get('subtype') If they are cards, they'll have a "_cardid" with the unique id of the card they represent: let mycard = getObj('card',obj.get('cardid')); Card objects have a "_deckid" property that represents the deck they belong to: let mydeck = getObj('deck',mycard.get('deckid')); That should get you started on how to find out which graphics are cards from which decks.&nbsp; The rest is probably going to be manipulating those (setting the "currentside" property to flip the graphic—cards are basically a RollableTable Token with a sides of the face and the back, switching the "currentside" sets which one is shown... you might have to set the imgsrc also based on the entry in "sides", I can't recall off hand.), and passing some of the ids to the card functions.
Thanks so much!
Just in case someone has the same issue and finds this on google five years from now, I thought I would document my results. The cards don't have a "deckid" property at the moment, so that needs to be worked around. In addition, as The Aaron surmised, the "imgsrc" property must be set as well. Finally, there seems to be a glitch in the API whereby many of the functions don't work unless the deck has been manually shuffled once, which is a weird problem, but easily overcome. Anyway, the final code for my main question ended up looking like this: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; flip: function (args, msg) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var tlist = "" ; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _.each( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; findObjs({_type: "deck" }), &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; function (deck) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (deck. get ( "name" ).toLowerCase().includes( "order token" )) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (args.length) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (deck. get ( "name" ).toLowerCase().includes(args[ 0 ].toLowerCase())) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tlist += deck. get ( "currentDeck" ); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else tlist += deck. get ( "currentDeck" ); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _.each( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; findObjs({_pageid: Campaign(). get ( "playerpageid" ), _subtype: "card" }), &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; function (card) { &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (tlist.includes(card. get ( "cardid" ))) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var parts = decodeURIComponent(card. get ( "sides" ).split( "|" )[ 0 ]).match( /(.*\/images\/.*)(thumb|med|original|max)([^?]*)(\?[^?]+)?$/ ); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; card. set ({currentSide: 0 , imgsrc: parts[ 1 ]+ 'thumb' +parts[ 3 ]+parts[ 4 ]}); &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp;
1586418688
The Aaron
Roll20 Production Team
API Scripter
The Graphic Object with subtype "card" doesn't have a deck id, it has a card id.&nbsp; The Card Object that card id corresponds to had a deck id.&nbsp;
1586730187

Edited 1586730220
@ The Aaron, thanks for the clarification. As I reread your original response, I see that you said that, but I misunderstood. With your assistance I have gotten all of the functions required to manipulate cards already on the table to work. However, I still can't seem to get the function for moving cards from the deck into play to work. Here is my code: _.each( &nbsp; &nbsp;findObjs({_type: "deck" }), &nbsp; &nbsp; function (deck) { &nbsp; &nbsp; &nbsp;&nbsp; if (/* logic to figure out if this is the right deck */ true) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var card = drawCard(deck. get ( "id" )); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log(card); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; playCardToTable(card); &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; } ); This code causes the cardid of an actual card to be logged. But then it logs the following error and halts: TypeError: Cannot read property 'set' of undefined &nbsp; &nbsp; at playCardToTable (/home/node/d20-api-server/api.js:2492:8) &nbsp; &nbsp; at apiscript.js:107:33 &nbsp; &nbsp; at Function._.each._.forEach (/home/node/d20-api-server/node_modules/underscore/underscore.js:186:9) &nbsp; &nbsp; at Object.place (apiscript.js:96:23) &nbsp; &nbsp; at handleInput (apiscript.js:465:38) &nbsp; &nbsp; at eval (eval at &lt;anonymous&gt; (/home/node/d20-api-server/api.js:154:1), &lt;anonymous&gt;:65:16) &nbsp; &nbsp; at Object.publish (eval at &lt;anonymous&gt; (/home/node/d20-api-server/api.js:154:1), &lt;anonymous&gt;:70:8) &nbsp; &nbsp; at /home/node/d20-api-server/api.js:1648:12 &nbsp; &nbsp; at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560 &nbsp; &nbsp; at hc (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:39:147) I get the same error if I try to place a card directly from the deck: _.each( &nbsp; &nbsp;findObjs({_type: "deck" }), &nbsp; &nbsp; function (deck) { &nbsp; &nbsp; &nbsp;&nbsp; if (/* logic to figure out if this is the right deck */ true) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var card = deck. get ( "currentDeck" ).split( "," )[ 0 ]; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log(card); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; playCardToTable(card); &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; } ); Substantially similar code works to&nbsp;giveCardToPlayer(), but not to playCardToTable(). Any idea what I am missing?
1586736565
The Aaron
Roll20 Production Team
API Scripter
It is entirely possible that the functions are broken. I have a vague recollection of reporting this sometime last fall... ...yup, September 1st, 2019. Basically exactly what you've run into. :(
1586736601
The Aaron
Roll20 Production Team
API Scripter
It only happens with user decks, apparently.&nbsp;
Drat. Looks like I will have to work around that by doing a createObj(). Any idea if it is possible to create an object with _type: 'graphic' and _subtype: 'card'? Or am I stuck only making _subtype: 'token'?
1586783107
The Aaron
Roll20 Production Team
API Scripter
I would just have to try it.&nbsp; I think it's possible...