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

Duplicate Cards in the same deck

January 19 (3 weeks ago)

I can't seem to find a way to make multiple cards of the same type in a deck without remaking each card manually. An example for what I am looking for here is when a player rolls a Herbalism check they get to draw X cards, depending on their roll, but I want a limit to how many of each herb there are in the deck, so that some herbs are rarer than others. So in the deck I want two copies of Sage Root, Ironheart Leaves, and Soul Flower, three copies of Darkshade Lavender, Emerald Saddle, Night bloom, etc.  If I have to add every single card manually I'm looking at having to add around 200 cards manually, please help.  

January 19 (3 weeks ago)
The Aaron
Roll20 Production Team
API Scripter

I have an unreleased script for this, let me see if I can dig it up a little later today. It basically lets you build decks on a dedicated map page, and specify the number of each card, etc. It's very fast for building and rebuilding the deck. I wrote it for my daughter to use in testing various distributions of cards in a deck building game she was designing for a college class. 

January 19 (3 weeks ago)
Gold
Forum Champion

I would test this and want to use it too... For cards for custom potions that our Cleric is brewing at high-levels, which he is able to brew a certain (random) amount of each type, periodically, and then distribute that limited quantity to the fellow PC's. Seems like it might follow the same/similar pattern of Card use as the OP and this API Mod script idea. Looking forward to testing it. 

The Aaron said:

I have an unreleased script for this, let me see if I can dig it up a little later today. It basically lets you build decks on a dedicated map page, and specify the number of each card, etc. It's very fast for building and rebuilding the deck. I wrote it for my daughter to use in testing various distributions of cards in a deck building game she was designing for a college class. 




January 20 (3 weeks ago)


The Aaron said:

I have an unreleased script for this, let me see if I can dig it up a little later today. It basically lets you build decks on a dedicated map page, and specify the number of each card, etc. It's very fast for building and rebuilding the deck. I wrote it for my daughter to use in testing various distributions of cards in a deck building game she was designing for a college class. 


Please! Whenever you are ready, no rush. I just got this really cool mini-expansion for herbalism/alchemy and would love to use it online without spending 3 days adding individual cards :p

January 20 (3 weeks ago)
Gold
Forum Champion

I wonder, what will be the Name of that API Mod script when it comes out?

Also wondering, should we Follow this thread and it would be a code-snippit, or is it a Mod that The Aaron will release into the One-Click?

Following thread with interest to see 

January 20 (3 weeks ago)
The Aaron
Roll20 Production Team
API Scripter

So, after digging back through my 270 games, I found the one I made for my daughter and pulled the script out. (see below)  The copy I have locally is in the middle of a rewrite, and isn't releasable yet, but this copy should work (though it doesn't support card backs yet...).

Here's how it works.

Drop all your cards and card backs on a map page named

  • Deck: <Something>

The <Something> part will be the deck name.  In the bubble for Bar3, place either the letter B (which indicates this is the card back), or a number (representing how many are in the deck).  When ready, run the command:

!db

And it will either construct the deck named <Something> or update it with the cards.

Caveat: This is a simple script and currently, it rebuilds the whole deck by destroying the cards and recreating the proper counts.  This includes removing the cards from the player hands.

The Code:

// By:       The Aaron, Arcane Scriptomancer
// Contact:  https://app.roll20.net/users/104025/the-aaron

const DeckBuilder = (() => { // eslint-disable-line no-unused-vars

  const scriptName = 'DeckBuilder';
  const version = '0.1.0';
  const lastUpdate = 1606881820;
  const schemaVersion = 0.1;

  const checkInstall = () =>  {
    log(`-=> ${scriptName} v${version} <=-  [${new Date(lastUpdate*1000)}]`);

    if( ! state.hasOwnProperty(scriptName) || state[scriptName].version !== schemaVersion) {
      log(`  > Updating Schema to v${schemaVersion} <`);
      switch(state[scriptName] && state[scriptName].version) {

        case 0.1:
          /* break; // intentional dropthrough */ /* falls through */

        case 'UpdateSchemaVersion':
          state[scriptName].version = schemaVersion;
          break;

        default:
          state[scriptName] = {
            version: schemaVersion
          };
          break;
      }
    }
  };


  const getPageForPlayer = (playerid) => {
    let player = getObj('player',playerid);
    if(playerIsGM(playerid)){
      return player.get('lastpage') || Campaign().get('playerpageid');
    }

    let psp = Campaign().get('playerspecificpages');
    if(psp[playerid]){
      return psp[playerid];
    }

    return Campaign().get('playerpageid');
  };

  const times = (n,f)=>Array(n).fill(n).map(f);

  const handleInput = (msg) => {
    if (msg.type !== "api") {
      return;
    }

    let args = msg.content.split(/\s+/);
    switch(args[0]) {
      case '!db': {
          let who = (getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname');
          let pageid = getPageForPlayer(msg.playerid);
          let page = getObj('page',pageid);
          if(page){
            if(/^deck:\s.+$/i.test(page.get('name'))) {
              let deckName = page.get('name').replace(/^deck:\s*/i,'');

                let deck = findObjs({
                  type: 'deck',
                  name: deckName
                })[0] || createObj('deck',{
                  name: deckName
                });
    
                // destroy cards in hands
                findObjs({type:'hand'}).forEach(h=>h.set('currentHand',""));
    
                findObjs({
                  type: 'card',
                  deckid: deck.id
                }).forEach(c=>c.remove());

                findObjs({
                  type: 'graphic',
                  layer: 'objects',
                  pageid
                }).forEach(g=>{
                  let b3 = g.get('bar3_value');

                  if(/^\s*b\s*/i.test(b3)){
                    deck.set({
                      avatar: g.get('imgsrc'),
                      defaultheight: g.get('height'),
                      defaultwidth: g.get('width')
                    });
                  } else {
                    let c = parseInt(b3)||0;
                    let n = g.get('name');
                    let i = g.get('imgsrc');
                    times(c,()=>createObj('card',{
                      name: n,
                      deckid: deck.id,
                      avatar: i
                    }));
                  }
                });

            } else {
              sendChat('DeckBuilder', `/w "${who}" Switch to a Deck page before running DeckBuilder.`);
            }
          }
        }
        break;
    }
  };

  const registerEventHandlers = () => {
    on('chat:message', handleInput);
  };

  on('ready', () => {
    checkInstall();
    registerEventHandlers();
  });

  return {
    // Public interface here
  };

})();
January 20 (3 weeks ago)
The Aaron
Roll20 Production Team
API Scripter

Probably this isn't going to help as much in either of your cases, but I can probably make it less destructive...

January 21 (3 weeks ago)
Gold
Forum Champion

Thanks for sharing what you have at this point!

Right, i probably wouldn't want to destroy cards. But this is all very interesting to me to explore the capability. 

January 21 (3 weeks ago)
keithcurtis
Forum Champion
Marketplace Creator
API Scripter

I used this script several years ago and can attest that it blew the built-in bulk loader out of the water with ease of use and time saved.