Anyway, once things got out of beta (by which I mean we got to 1.63) it struck me that the new window API would be fun to shoe-horn into it and things started moving along. Those references have since been removed, but they were interesting to play with.
So what we have here is part card game and part game-API. The point is to make it easy for other coders to produce card games of their own without having to worry too much about all the underlying mechanics involved, other than those specific to the game they have in mind - well that's the plan, anyway. The API lets you define cells you can place cards in, deal them out, move them around and so on. I guess you could call it a super-charged button API.
Truth of the matter is that it's still somewhat unfinished, so both games and API are (somewhat) subject to change - however, it's still quite workable, so here it is together with Solitaire and FreeCell:
Screenshots
Thanks to Zambonie for the beach image, and to Requiem for some of the others. :)/>/>
I'm not aware of any bugs at present, so please let me know if you can get it to mess up in some way. At this time I'm not considering lack of polish to be a "bug", but please speak up if you feel something is amiss anyways. ;)/>/> You'll want a 4x3 colour monitor attached in order to play.
BBCards (games):
pastebin get dhWZ7kJU bbcards
Card API (required by games):
pastebin get A8kCA8Zc card
Card API documentation
Constants:card.spade / card.spades
card.heart / card.hearts
card.club / card.clubs
card.diamond / card.diamonds
card.straight / card.up / card.left / card.down / card.right
card.victoryPile / card.drawPile / card.discardPile / card.temporary
Functions:
card.defineCell(num xPos, num yPos [, num stackDirection, num cellType, num param1, num param2])
Defines a cell - an area of the screen where players may place / collect cards. xPos/yPos should represent the top-left corner, bearing in mind a cell is typically 7x7.
Cells are "straight" by default - that is to say, every card placed in them will obscure those underneath. If a stack direction of card.left or card.down is specified, then the cards will cascade that way as they're dealt to the cell. No, they can't go up or to the right, the coding for that would've been… tedious.
Setting a cell type allows you to flag a cell as "special". card.victoryPile / card.drawPile / card.discardPile / card.temporary (numbers one to four) are some acceptable values here, though you can use others if you need to track more types of cells. Make up some numbers.
If a cell type of "card.drawPile" is used, you may also specify additional parameters - the cell upturned cards are to be placed in, and the amount of cards each click of the draw pile will reveal at once. It's up to you to actually act on this data - it's just stored against the cell's record for convenience, and can be accessed later via card.getTarget() and card.getFlipAmount() respectively.
Cards in a "victoryPile" are animated when card.victoryAnimation() is called. "temporary" cells are invisible by default.
Every cell defined is automatically added to a table of cells which isn't cleared until your script unloads the API. Generally you should only need to define cells once, then you can clear their contents later if you need to via card.shuffle(). It's up to you to keep track of which cells you want to use for which purposes, but the cell type flags can be used to assist with this.
Cells are automatically rendered in their empty state when defined (unless flagged as "temporary").
card.shuffle()
Shuffles the deck. All cards are removed from any cells they've been dealt to. Ordering is more or less random; after shuffling, card 1 in the deck could be any of 52 possibilities. The deck does not exist until shuffled at least once.
card.reset()
Deletes all cells and shuffles the deck.
card.dealCard(num cell, bool faceDown)
Deals whatever card happens to be at the top of the deck to the specified cell.
card.getRemainingDeckSize()
Returns the number of cards remaining in the deck.
card.checkClick(num xPos, num yPos)
Checks whether a given click to the screen was on a given cell (and perhaps card), and returns their IDs. Returns "cardID, cellID". cardID may be nil if the clicked cell contained no cards, or both will be nil if the click didn't intercept anything.
card.redraw([num x1, num y1, num x2, num y2, bool ignoreSelected])
Re-renders any cells that exist within the specified area of the screen (a rectangle defined between points x1/y1 to x2/y2). If no screen area is specified, all cells are re-rendered. Will also re-render the card selection outline unless otherwise specified.
You should generally only need to call this if you're manually drawing to the screen on top of cells / cards and want to re-reveal them (or if there was a monitor resize, etc).
card.straightenCell(num cell)
If a cell contains a stack of cards spreading across the display, this function can straighten it up so only the top-most one is visible.
card.moveTo(num cardToMove, num cellToMoveTo [, faceDown] [, skipAnimation])
Moves a given card (and currently, all cards on top of that card, always!) to the specified cell, stacking them on top of that cell's current top card.
They'll still face up / down as they were before unless specifically specified.
card.select(targetCard [, hidden])
Marks a given card as selected, and unless it's requested that the action be hidden, draws a selection rectangle around it.
Currently selecting a given card also selects all cards on top of it.
card.getSelected()
Returns the currently selected card ID.
card.deselect()
De-selects the current card, and clears the selection rectangle from the screen.
card.getSpecial(num cell)
Returns the special type value of the specified cell. Can typically be compared to card.victoryPile / card.drawPile / card.discardPile.
card.getTopCard(num cell)
Returns the ID of the card currently on the top of the cell's stack (or nil if there's nothing there).
card.getTarget(num cell)
Assuming the cell is a draw pile, this returns the ID of the cell where its cards should be moved to.
card.getFlipAmount(num cell)
Assuming the cell is a draw pile, this returns the number of cards that should be revealed per click.
card.getValue(num card)
Returns the value of the specified card ID. 1 is an Ace, 13 is a King.
card.getSuit(num card)
Returns the suit of the specified card ID. 1 is a Spade, 2 a Heart, 3 a Club and 4 a Diamond. Can generally be compared to card.spade / card.heart / card.club / card.diamond.
card.isFaceDown(num card)
Returns whether the given card ID is lying face down.
card.setFaceDown(num card, bool faceDown)
Sets a given card ID's facing.
card.getHigherCard(num card)
If the specified card is under another, returns the ID of that card (or nil if it's not). Note that this information is NOT tracked for cards that are in the deck and haven't been dealt yet.
card.getLowerCard(num card)
If the specified card is on top of another, returns the ID of that card (or nil if it's not). Note that this information is NOT tracked for cards that are in the deck and haven't been dealt yet.
card.save(string gameType)
Saves the state of the game (the deck contents, cell locations and their contents) into "bbcards.sav". Currently overwrites the previous save. "GameType" can be anything - it's used to determine which game rules should be used with a loaded save (eg, Solitaire, FreeCell, Poker, etc).
card.load()
Restores cell / card data per the info saved into "bbcards.sav" by card.save(). Returns a string containing the name of the game being played.
card.displayCell(num cell, bool visible)
Enables / disables rendering of the specified cell. It's recommended to disable rendering if you intend to move a lot of cards in / out of it using separate calls to card.moveTo(). If you're moving a pile in one go, you need not bother. Re-enabling rendering automatically draws the contents of the cell.
card.renderCard(num cardValue, num cardSuit, num xPos, num yPos [, bool cardFaceDown])
Renders a card of a given value / suit at the specified location. When dealing with cards assigned to cells, this function need not be manually called (as cards are automatically rendered when dealt / moved / etc), but you may wish to occasionally show specific card types without worrying about where they are in the playing field.
card.victoryAnimation([string monitorSide])
Plays an animation where cards bounce out of "victoryPile" cells. Click or press a key to interupt it, though it'll ignore clicks to monitors unless they're attached to the "side" specified by "monitorSide".
Version History
2014/05/05Alpha 0.1.0
Initial release.
2014/06/08
Alpha 0.1.1
Removed ComputerCraft 1.6 dependencies; should now work in CC 1.5 up (at least).
Moved "victoryAnimation" function to API.
Fixed a "bug" or two, such as the spelling of "Solitaire"…
Broke old save game support.
2014/06/14
Alpha 0.2.0
Added FreeCell.
Added card.reset().
card.moveTo() now animates the cards it moves (and accepts an additional argument to disable the effect).
Various bug fixes.
Broke old save game support (again).
2014/12/09
Alpha 0.2.1
Added more card-back sprites to the API.
2015/12/12
Alpha 0.2.2
Under ComputerCraft 1.76 or later, shows proper symbols for cards.
2015/12/16
Alpha 0.3.0
All relevant art updated for CC 1.76.