Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- +---------------------+------------+---------------------+
- -- | | | |
- -- | | BBCards | |
- -- | | | |
- -- +---------------------+------------+---------------------+
- local version = "Version 0.3.0"
- -- Card games for ComputerCraft, by Jeffrey Alexander (aka Bomb Bloke).
- -- Currently offers Solitaire and FreeCell.
- -- http://www.computercraft.info/forums2/index.php?/topic/18480-bbcards
- ---------------------------------------------
- ------------Variable Declarations------------
- ---------------------------------------------
- local myEvent, clickTimer, mon
- local game = "Solitaire"
- local kingHead
- if _HOST then
- kingHead = {{{{32,146,143,158,32},{32,129,133,133,32},{32,144,129,133,132},{32,136,130,131,32},{32,32,139,32,32}},
- {"dde4d","dd88d","dd7f6","d966d","de11d"},{"d44dd","d777d","d766d","dfffd","de31d"}},
- {{{32,146,143,158,32},{32,138,138,130,32},{136,138,130,159,32},{32,131,129,132,32},{32,32,135,32,32}},
- {"dde4d","d88dd","6f77d","d669d","d11ed"},{"d44dd","d777d","d66dd","dfffd","d13ed"}}}
- for j = 1, #kingHead do
- local rows = kingHead[j][1]
- for i = 1, 5 do rows[i] = string.char(unpack(rows[i])) end
- end
- else kingHead = {{4,4,4},{7,7,7},{6,6,6},{15,15,15},{14,3,14}} end
- ---------------------------------------------
- ------------Function Declarations------------
- ---------------------------------------------
- os.loadAPI("card")
- if not card then error("Unable to initialise card API - ensure it's present on the root of your drive.") end
- -- Returns true if the current event represents a mouse click we should listen to.
- local function touchedMe()
- if myEvent[1] == "mouse_click" then return true
- elseif myEvent[1] ~= "monitor_touch" or not mon then return false
- else return mon.side == myEvent[2] end
- end
- -- Returns true if the current event represents one of the passed keys being pressed.
- local function pressedKey(...)
- if myEvent[1] ~= "key" then return false end
- local args = {...}
- for i = 1, #args do if args[i] == myEvent[2] then return true end end
- return false
- end
- -- Draws the watching king:
- local function drawKingHead()
- if _HOST then
- local kingHead = kingHead[myEvent[3] < 35 and 2 or 1]
- for y = 1, 5 do
- term.setCursorPos(33, y + 2)
- term.blit(kingHead[1][y], kingHead[2][y], kingHead[3][y])
- end
- else
- for y = 1, 5 do
- term.setCursorPos(34, y + 2)
- for x = 1, 3 do
- term.setBackgroundColor(bit.blshift(1,kingHead[y][x]))
- term.write(" ")
- end
- end
- term.setCursorPos(34 + (myEvent[3] < 35 and 2 or 0), 5)
- term.setBackgroundColor(colours.grey)
- term.write(" ")
- end
- end
- -- Sets up the layout of the play area.
- local prepareBoard = {["Solitaire"] = function()
- for i = 0, 3 do card.defineCell(8 * i + 26, 2, card.straight, card.victoryPile) end -- Cells 1-4, targets.
- for i = 0, 6 do card.defineCell(8 * i + 2, 10, card.down) end -- Cells 5-11, the main play area.
- card.defineCell(2, 2, card.straight, card.drawPile, 13, 3) -- Cells 12-13, draw piles.
- card.defineCell(10, 2, card.left, card.discardPile)
- end,
- ["FreeCell"] = function()
- for i = 0, 3 do card.defineCell(8 * i + 38, 2, card.straight, card.victoryPile) end -- Cells 1-4, targets.
- for i = 0, 7 do card.defineCell(8 * i + 4, 10, card.down) end -- Cells 5-12, the main play area.
- for i = 0, 3 do card.defineCell(8 * i + 2, 2, card.straight, card.discardPile) end -- Cells 13-16, additional free cells.
- end}
- -- Deals out a new game.
- local deal = {["Solitaire"] = function()
- card.shuffle()
- for i = 6, 11 do card.displayCell(i,false) end
- for i = 1, 7 do
- for j = 7, i + 1, -1 do card.dealCard(j+4,true) end
- card.dealCard(i+4,false)
- end
- for i = 6, 11 do card.displayCell(i,true) end
- -- And the rest of the cards can go in the face-down draw pile.
- card.displayCell(12,false)
- for i = 1, card.getRemainingDeckSize() do card.dealCard(12,true) end
- card.displayCell(12,true)
- end,
- ["FreeCell"] = function()
- card.shuffle()
- for i = 5, 12 do card.displayCell(i,false) end
- local curCell = 5
- for i = 1, 52 do
- card.dealCard(curCell,false)
- curCell = curCell == 12 and 5 or (curCell + 1)
- end
- for i = 5, 12 do card.displayCell(i,true) end
- myEvent = {0, 0, 40}
- drawKingHead()
- end}
- -- Handle gameplay.
- local function handleClick()
- thisCard, thisCell = card.checkClick(myEvent[3],myEvent[4])
- local selected = card.getSelected()
- card.deselect()
- if not thisCell then return end
- -- At this point, we have determined which cell was clicked ("thisCell"), and
- -- if any cards were in that cell, which specific one was clicked ("thisCard").
- -- React according to the cell's type and the card's placement:
- if selected then
- -- Attempt to place pre-selected cards elsewhere.
- -- Moving to a victory pile:
- if (card.getSpecial(thisCell) == card.victoryPile and (not card.getHigherCard(selected)) and
- ((card.getValue(selected) == 1 and not thisCard) or
- (thisCard and card.getValue(selected) == card.getValue(thisCard) + 1 and card.getSuit(selected) == card.getSuit(thisCard)))) or
- -- Moving to a FreeCell upper-free cell:
- (game == "FreeCell" and card.getSpecial(thisCell) == card.discardPile and
- not (card.getHigherCard(selected) or card.getTopCard(thisCell))) then
- card.moveTo(selected,thisCell)
- return
- -- Moving to a regular pile:
- elseif ((not card.getSpecial(thisCell)) and
- (((card.getValue(selected) == 13 or game == "FreeCell") and not thisCard) or
- (thisCard and (not card.getHigherCard(thisCard)) and card.getValue(thisCard) == card.getValue(selected) + 1 and bit.band(card.getSuit(selected),1) ~= bit.band(card.getSuit(thisCard),1)))) then
- if game == "FreeCell" then
- local moving, freeCells, temp = 1, 1, selected
- while card.getHigherCard(temp) do
- temp = card.getHigherCard(temp)
- moving = moving + 1
- end
- for i = 5, 16 do if i ~= thisCell and not card.getTopCard(i) then freeCells = freeCells + 1 end end
- if moving > freeCells then return end
- end
- card.moveTo(selected,thisCell)
- return
- -- Quick-move to victory pile:
- elseif clickTimer and thisCard == selected and (not card.getHigherCard(thisCard)) and card.getSpecial(thisCell) ~= card.victoryPile then
- for i = 1, 4 do
- if (card.getTopCard(i) and card.getValue(card.getTopCard(i)) + 1 == card.getValue(selected) and card.getSuit(selected) == card.getSuit(card.getTopCard(i))) or
- (card.getValue(selected) == 1 and not card.getTopCard(i)) then
- card.moveTo(selected,i)
- return
- end
- end
- if game == "FreeCell" and card.getSpecial(thisCell) ~= card.discardPile then for i=13,16 do if not card.getTopCard(i) then
- card.moveTo(selected,i)
- return
- end end end
- end
- end
- if thisCard and (card.getSpecial(thisCell) == card.victoryPile or card.getSpecial(thisCell) == card.discardPile or not card.getSpecial(thisCell)) then
- -- Standard play cell.
- -- Select cards for movement elsewhere, or flip upside-down cards to reveal them.
- if card.isFaceDown(thisCard) then
- -- Attempt to reveal a card.
- if not card.getHigherCard(thisCard) then card.setFaceDown(thisCard, false) end
- else
- -- Attempt to select a card.
- if (card.getSpecial(thisCell) == card.discardPile and card.getTopCard(thisCell) ~= thisCard) or (game == "FreeCell" and card.getSpecial(thisCell) == card.victoryPile) then return end
- selected = thisCard
- while card.getHigherCard(selected) do
- if card.getValue(selected) ~= card.getValue(card.getHigherCard(selected)) + 1 or bit.band(card.getSuit(selected),1) == bit.band(card.getSuit(card.getHigherCard(selected)),1) then return end
- selected = card.getHigherCard(selected)
- end
- card.select(thisCard)
- end
- elseif card.getSpecial(thisCell) == card.drawPile then
- card.displayCell(thisCell,false)
- card.displayCell(card.getTarget(thisCell),false)
- if thisCard then
- -- Flip cards to the target pile.
- card.moveTo(card.getTopCard(thisCell),card.getTarget(thisCell),false)
- card.straightenCell(card.getTarget(thisCell))
- for i=1,card.getFlipAmount(thisCell)-1 do
- if not card.getTopCard(thisCell) then break end
- card.moveTo(card.getTopCard(thisCell),card.getTarget(thisCell),false)
- end
- else
- -- Flip cards back from the target pile.
- while card.getTopCard(card.getTarget(thisCell)) do
- card.moveTo(card.getTopCard(card.getTarget(thisCell)),thisCell,true,true)
- end
- end
- card.displayCell(thisCell,true)
- card.displayCell(card.getTarget(thisCell),true)
- end
- end
- -- Automatically moves cards up to the target cells, if it's appropriate to do so.
- local function autoMove()
- local moving = true
- while moving do
- local least = 13
- for i = 1, 4 do
- if card.getTopCard(i) then
- if card.getValue(card.getTopCard(i)) < least then least = card.getValue(card.getTopCard(i)) end
- else least = 0 end
- end
- moving = false
- for i = 5, 16 do if card.getTopCard(i) and card.getValue(card.getTopCard(i)) <= least + 2 then
- for j = 1, 4 do if (card.getValue(card.getTopCard(i)) == 1 and not card.getTopCard(j)) or
- (card.getTopCard(j) and card.getSuit(card.getTopCard(i)) == card.getSuit(card.getTopCard(j)) and
- card.getValue(card.getTopCard(i)) == card.getValue(card.getTopCard(j)) + 1) then
- moving = true
- if card.getSelected() == card.getTopCard(i) then card.deselect() end
- card.moveTo(card.getTopCard(i),j)
- break
- end end
- end end
- end
- end
- ---------------------------------------------
- ------------ Init ------------
- ---------------------------------------------
- term.clear()
- term.setCursorPos(1,1)
- do
- local temp = peripheral.getNames()
- for i=1,#temp do if peripheral.getType(temp[i]) == "monitor" and peripheral.call(temp[i],"isColor") then
- mon = peripheral.wrap(temp[i])
- mon.side = temp[i]
- if not term.restore then mon.restoreTo = term.current() end
- break
- end end
- end
- if not mon then
- print("Sorry, BBCards requires access to an advanced monitor.")
- print("At least 4x3 blocks is recommended.")
- error()
- end
- print("BBCards is running.")
- print("")
- print("Keys:")
- print("G - Change game (Solitaire / FreeCell)")
- print("S / L - Save / Load")
- print("R - Redeal")
- print("Q / X - Exit")
- print("")
- print("Play commencing on attached monitor \""..mon.side.."\". Recommended size is 4x3.")
- mon.setTextScale(0.5)
- term.redirect(mon)
- prepareBoard[game]()
- deal[game]()
- term.setCursorPos(1,1)
- ---------------------------------------------
- ------------ Main Program ------------
- ---------------------------------------------
- local function main()
- while true do
- myEvent = {os.pullEvent()}
- if touchedMe() then
- handleClick()
- os.queueEvent("startTimer")
- if game == "FreeCell" then
- autoMove()
- drawKingHead()
- end
- myEvent = true
- for i = 1, 4 do if not card.getTopCard(i) or card.getValue(card.getTopCard(i)) ~= 13 then
- myEvent = false
- break
- end end
- if myEvent then
- card.victoryAnimation(mon.side)
- deal[game]()
- end
- elseif pressedKey(keys.q,keys.x) then
- os.pullEvent("char")
- return
- elseif pressedKey(keys.r) then
- deal[game]()
- elseif pressedKey(keys.s) then
- card.save("Solitaire")
- elseif pressedKey(keys.l) then
- game = card.load()
- elseif pressedKey(keys.g) then
- game = game == "FreeCell" and "Solitaire" or "FreeCell"
- card.reset()
- prepareBoard[game]()
- deal[game]()
- elseif myEvent[1] == "monitor_resize" then
- card.redraw()
- end
- end
- end
- local function timerCheck()
- local timerEvent
- while true do
- timerEvent = {os.pullEvent()}
- if timerEvent[1] == "timer" and timerEvent[2] == clickTimer then
- clickTimer = nil
- elseif timerEvent[1] == "startTimer" then clickTimer = os.startTimer(0.5) end
- end
- end
- parallel.waitForAny(main, timerCheck)
- ---------------------------------------------
- ------------ Termination ------------
- ---------------------------------------------
- os.unloadAPI("card")
- if term.restore then term.restore() else term.redirect(mon.restoreTo) end
- term.clear()
- term.setCursorPos(1,1)
- print("Thanks for playing!")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement