Macros and API
Everything below lives at game.modules.get("blobs-card-engine").api. In a macro:
const bce = game.modules.get("blobs-card-engine").api;GM-only calls say so. A player's calls act as their own seat.
Starting games
| Call | What it does |
|---|---|
bce.startGame(game, seats, enforcement?) | GM. Starts a match with no dialog. game is a game page's uuid or a built-in id ("holdem", "crazy-eights", "oracle", "initiative"...). seats is [{ userId, actorUuid?, name? }]. A seat with a character takes its name, and linked player values (gold, hit points...) start from the character. |
bce.quickMatch(gameId, userIds, enforcement?) | GM. A built-in game with these users. |
bce.newMatch(gameId?) | GM. The New match dialog. |
bce.openMatches() | The match manager (games, decks, matches). |
bce.openTable(matchId) | Opens a match's table. |
bce.myMatches() | [{ id, name }] of the matches you're seated in. |
// A tavern game with two players, each playing their assigned character.
const page = game.journal.getName("Tavern Games").pages.getName("Tavern Gambit");
const players = game.users.filter((u) => u.active && !u.isGM);
await bce.startGame(page.uuid, players.map((u) => ({ userId: u.id, actorUuid: u.character?.uuid })));Cards
| Call | What it does |
|---|---|
bce.draw(matchId, fromZone = "deck") | Draws a card into your hand. |
bce.dealTo(matchId, userOrSeat, count = 1, fromZone = "deck") | GM. Deals cards into a player's hand. |
bce.sendIntent(matchId, intent) | Sends any intent as you (see src/engine/intent/types.ts), e.g. { seat: "s1", type: "action", action: "draw" }. |
bce.getState(matchId) | The match's full state, as your client sees it. |
Tabletop RPG features
| Call | What it does |
|---|---|
bce.drawOracle(spread = "one") | Deals a tarot reading ("one", "three", "cross") and opens the table. |
bce.drawInitiative(combat?) | GM. Deals Initiative Deck cards to every combatant in the current combat and fills in the tracker. |
bce.placePile(matchId, zoneKey, {x, y}?) | GM. Puts a shared pile on the scene you're viewing as a map pin. Players double-click it to draw. |
bce.rollCheck(actor, checkId, { fast? }) | Rolls a character check with the game system ("skill:dec", "ability:str", "save:dex" in dnd5e). Returns the total, or null if cancelled. |
bce.linkFor(kind, target, label?) / bce.copyLink(text) | Journal link text, e.g. bce.linkFor("game", page.uuid) gives @BlobCards[game:…]. |
Journal links
Type these into any journal page or chat message:
@BlobCards[card:<game page uuid>#<card id>]{label}: the card, small; it enlarges on hover.@BlobCards[game:<game page uuid>]{label}: "start a match" for the GM, "build a deck" for players.@BlobCards[deck:<decklist page uuid>]: opens a deck.@BlobCards[match:<match id>]: opens a match's table.@BlobCards[draw:oracle three]{Ask the fortune teller}: deals a tarot reading.
The game sheet, the decklist sheet and the Library's card inspector have a link button that copies these for you.
Effects for game makers
The builder's Dice & characters group:
- Roll dice (
roll):2d6+1,4d6kh3(keep the best 3),1d20 + {var.self.bonus}. The table posts the dice to chat.asnames the total for the next effects. - Ask for a character check (
check): the player rolls a check with their character (dnd5e opens its own roll dialog), or a d20 without one. They can also type a real-dice total. With a DC,asgivesname.total,name.successandname.dc. - Set initiative (
initiative): puts a seat's character at that place in the current combat. - Change hit points (
actorHp): heals (positive) or damages (negative) a seat's character; damage takes temporary hit points first. - Give or remove a condition (
actorCondition): toggles a status effect (poisoned,prone, …) on a seat's character. - Labels and roll formulas can use
{…}placeholders:label: "{f.name}",formula: "{f.dice}"(a card's2d4+1).
Player values can be linked to the character (Variables tab): "Character's Gold (gp), kept in sync" starts the value from the sheet, writes changes back after every move, and picks up sheet edits made during the match.
Sharing: packs and deck codes
A pack (.bcepack) is a zip with games, decks and every image they use from the world's own files. Export one from the Games tab (a game, with any of its decks) or the Decks tab (a deck, with its game unless it's built in); import from either tab.
pack.json manifest: name, author, description, version, engine, thumbnail, url, games, decks, needs
games/<id>.json { format: "blobs-card-engine/game@1", version, changelog?, definition, cards }
decks/<n>.json { format: "blobs-card-engine/deck@1", name, game: {id, name}, entries, sideboard, commander, customCards, cardBack }
images/<file> bundled art, referenced inside the JSON as "pack:images/<file>"- Images under
icons/,ui/,cards/,sounds/and this module are left as paths (every world has them); other modules' and systems' images are left out and listed underneeds. - Import keeps a game's id: a newer
versionupdates the world's copy, the same or an older one is kept, and decks attach to the world's game with that id. Images are uploaded tobce-packs/<pack name>/. - Games are data and run no code. A definition that mentions
runMacro(reserved, not available yet) is flagged on import.
const api = game.modules.get("blobs-card-engine").api;
await api.exportPack({ name: "My pack", author: "Me", description: "", version: "1.0.0", url: "" }, [gamePageUuid], [deckPageUuid]);
await api.importPack(file); // a File, e.g. from an <input type="file">A deck code (BCE2:…) is a deck as text to paste in chat: its game's id, the lists, its own cards (art only if every world can load it) and its back. Paste it on the Decks tab (Paste a code) or in the deck builder (Load code). Older BCE1: codes still load in the deck builder.
Hooks
| Hook | Arguments |
|---|---|
blobsCardEngine.action | { matchId, intent, v, user } after every committed intent (on the GM's client). |
blobsCardEngine.matchEnd | { matchId, winners } when a match ends (GM's client). |
blobsCardEngine.tableToggled | (matchId, open) when a table window opens or closes (that client). |
Trust
Character checks are rolled on the player's client and the total is reported to the GM. That's fine for a table of friends (the launch "Trust" mode). Sealed mode, a post-launch update, will roll on the GM's side.
