This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Bomb Bloke's profile picture

BBCards

Started by Bomb Bloke, 04 May 2014 - 02:03 PM
Bomb Bloke #1
Posted 04 May 2014 - 04:03 PM
So I've been working on this off and on for quite some time now. Mostly off - I started before the CC 1.6 betas appeared.

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 documentationConstants:

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 History2014/05/05
Alpha 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.
Edited on 10 February 2016 - 10:13 PM
viluon #2
Posted 04 May 2014 - 04:06 PM
Seems nice :)/> (haven't tested yet)
Zambonie #3
Posted 04 May 2014 - 04:57 PM
Seems Nice, I might try it in a while ;)/>
awsmazinggenius #4
Posted 06 May 2014 - 04:02 AM
Looks cool! Definitely not what I guessed when you uploaded your request thread in the Media section.
oeed #5
Posted 06 May 2014 - 07:38 AM
Looks cool! Definitely not what I guessed when you uploaded your request thread in the Media section.

Oh! Right, that explains alot.

Anyway, this looks really, really nice.

Any plans to add multiplayer games? I play cards at lunch when I'm not busy with other things and there's just so many things you can do with them.
Bomb Bloke #6
Posted 06 May 2014 - 07:45 AM
Yes, in fact networking would be the only practical way to handle the likes of Poker, or anything where you've got a hand you're supposed to see while hiding it from other players.
Lyqyd #7
Posted 06 May 2014 - 08:12 AM
For such games, the Pocket Computers might be worth looking in to.
sEi #8
Posted 30 May 2014 - 05:28 PM
Very nice game

Beautiful code. Helps me a lot getting into CC and LUA.

Thank you - Have a nice day

/sEi
Bomb Bloke #9
Posted 31 May 2014 - 08:03 AM
Glad you like it - though I sorta get the impression you're the first to try it! :lol:/> :(/>

I'd gone with the new 1.6 functions (eg the window API) on the basis that someone might find it handy to have an example of them in use, but they kinda got swallowed up in a sea of other code and I'm inclined to ditch them (that particular API, for eg, made it faster for me to get my code written but slows the execution of my code down compared to what I otherwise would've done). Anyone have any thoughts?
Bomb Bloke #10
Posted 08 June 2014 - 04:13 PM
Well I guess I won that vote - code's been tweaked to run under older CC versions.
cptdeath58 #11
Posted 10 June 2014 - 01:57 AM
Nice game. :D/>
Bomb Bloke #12
Posted 14 June 2014 - 08:42 AM
Thanks. :)/>

Just updated with FreeCell:

Spoiler
cptdeath58 #13
Posted 16 June 2014 - 10:55 PM
Nice Animations dude. :D/>
TheOutcast5 #14
Posted 15 March 2015 - 04:25 AM
Next step, Yu-Gi-Oh!
Bomb Bloke #15
Posted 15 December 2015 - 02:04 PM
CC 1.76 (in beta at the time of writing) offers new font characters which're handy for pixel art; I've updated the script files to take advantage of these:

Spoiler

It should still work fine under older CC builds, albeit without the new imagery.
ExplosiveFerrets #16
Posted 04 February 2016 - 09:23 PM
Seems nice, will try it out :)/>