Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local wdir = shell and shell.dir() or ""
- if term.current().setTextScale then
- term.current().setTextScale(0.5)
- end
- local json = require("json")
- local wapi = require("w")
- local rapi = require("r")
- local kapi = require("k")
- local jua = require("jua")
- -- Load local config
- local configHandle = fs.open(wdir .. "/config.lua", "r")
- if not configHandle then
- configHandle = fs.open(wdir .. "/.config", "r")
- if not configHandle then
- error("No config file found at 'config.lua', please create one")
- end
- end
- local config
- local configData = configHandle.readAll()
- if not configData:match("^return") then
- configData = "return " .. configData
- end
- local configFunc, err = loadstring(configData)
- if not configFunc then
- error("Invalid config: Line " .. (err:match(":(%d+:.+)") or err))
- else
- config = configFunc()
- end
- configHandle.close()
- local Surface = dofile(wdir .. "/surface.lua")
- local display = Surface.create(term.getSize())
- local buffer = Surface.create(display.width * 2, display.height * 3, colors.black)
- local function loadRF(name)
- local ims = Surface.load(wdir .. "/res/" .. name .. ".rif")
- ims:toRGB(Surface.palette.riko4)
- ims:toPalette(Surface.palette.cc)
- return ims
- end
- local fontMapping = {
- [" "] = 32,
- ["0"] = 33,
- ["1"] = 34,
- ["2"] = 35,
- ["3"] = 36,
- ["4"] = 37,
- ["5"] = 38,
- ["6"] = 39,
- ["7"] = 40,
- ["8"] = 41,
- ["9"] = 42,
- ["A"] = 43,
- ["J"] = 44,
- ["Q"] = 45,
- ["K"] = 46
- }
- local sleepTime = 0 -- 0.1
- local function gChar(char)
- return string.char(fontMapping[char])
- end
- local bigFontSurf = Surface.load(wdir .. "/res/font.bmp")
- local bigFont = Surface.loadFont(bigFontSurf)
- local fontSurf = loadRF("font")
- local font = Surface.loadFont(fontSurf)
- local cardFirst = loadRF("card")
- local cardMost = loadRF("card2")
- local cardLast = loadRF("card-s")
- local heart = loadRF("heart")
- local diamond = loadRF("diamond")
- local spade = loadRF("spade")
- local club = loadRF("club")
- local cardBack = loadRF("cardfill")
- local function checkBounds(surf, x, y, cx, cy)
- local w, h = surf.width / 2, surf.height / 3
- return cx >= x and cx < x + w and cy >= y and cy < y + h
- end
- local function writeCenter(surf, text, y, b, t)
- surf:drawString(text, math.floor((surf.width - #text) / 2), y, b, t)
- end
- local function writeBigCenter(surf, text, y, b, t, ns)
- local fw, fh = Surface.getTextSize(text, bigFont)
- local oSurf = Surface.create(math.ceil(fw / 2) * 2, math.ceil(fh / 3) * 3, b or colors.black)
- oSurf:drawText(text, bigFont, 0, 0, t or colors.white)
- if ns then
- surf:drawSurface(oSurf, math.floor((surf.width - oSurf.width) / 2), y)
- else
- surf:drawSurfaceSmall(oSurf, math.floor((surf.width - (oSurf.width / 2)) / 2), y)
- end
- end
- local function getDeckDims(deckCnt)
- if deckCnt == 0 then
- return 0
- end
- return cardFirst.width + (deckCnt - 1) * cardMost.width + cardLast.width, cardFirst.height
- end
- local function drawDeck(surf, deck, x, y, firstOver)
- if #deck == 0 then
- return x
- end
- if not surf then
- surf = setmetatable({}, {__index = function() return function() end end})
- end
- local suits = {hearts=heart,diamonds=diamond,spades=spade,clubs=club}
- local colors = {hearts=colors.red,diamonds=colors.red,spades=colors.black,clubs=colors.black}
- local function drawFaceValue(v, c, x, y)
- if v == "10" then
- surf:drawText(gChar("1") .. gChar("0"), font, x - 2, y, c)
- else
- surf:drawText(gChar(v), font, x, y, c)
- end
- end
- local firstCard = deck[1]
- surf:drawSurface(firstOver and cardMost or cardFirst, x, y)
- if firstOver then
- x = x + 1
- end
- if firstCard.hidden then
- surf:drawSurface(cardBack, x + 2, y + 2)
- surf:drawSurface(cardBack, x + 2, y + 10)
- surf:drawSurface(cardBack, x + 2, y + 18)
- else
- surf:drawSurface(suits[firstCard.suit], x + 2, y + 2)
- drawFaceValue(firstCard.value, colors[firstCard.suit], x + 4, y + 19)
- end
- x = x + 10
- for i = 2, #deck do
- local thisCard = deck[i]
- surf:drawSurface(cardMost, x, y)
- if thisCard.hidden then
- surf:drawSurface(cardBack, x + 3, y + 2)
- surf:drawSurface(cardBack, x + 3, y + 10)
- surf:drawSurface(cardBack, x + 3, y + 18)
- else
- surf:drawSurface(suits[thisCard.suit], x + 3, y + 2)
- drawFaceValue(thisCard.value, colors[thisCard.suit], x + 5, y + 19)
- end
- x = x + 11
- end
- local lastCard = deck[#deck]
- surf:drawSurface(cardLast, x, y)
- if lastCard.hidden then
- surf:drawSurface(cardBack, x, y + 2)
- surf:drawSurface(cardBack, x, y + 10)
- surf:drawSurface(cardBack, x, y + 18)
- else
- surf:drawSurfaceRotated(suits[lastCard.suit], x, y + 18, 7, 7, math.pi)
- drawFaceValue(lastCard.value, colors[lastCard.suit], x + 2, y + 3)
- end
- return x
- end
- local hitBox = Surface.create(50, 24, colors.black)
- hitBox:drawRect(0, 0, 50, 24, colors.green)
- writeBigCenter(hitBox, "HIT", 10, nil, colors.green, true)
- local standBox = Surface.create(50, 24, colors.black)
- standBox:drawRect(0, 0, 50, 24, colors.red)
- writeBigCenter(standBox, "STAND", 10, nil, colors.red, true)
- local function outputBanner(text, color)
- display:fillRect(0, 16, display.width, 6, color)
- writeBigCenter(display, text, 18, color, colors.white)
- writeCenter(display, "Click Anywhere to Finish...", 20, color, colors.white)
- display:output()
- end
- local suitMap = {"hearts", "spades", "diamonds", "clubs"}
- local valueMap = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"}
- local baseValue = {
- ["2"] = 2,
- ["3"] = 3,
- ["4"] = 4,
- ["5"] = 5,
- ["6"] = 6,
- ["7"] = 7,
- ["8"] = 8,
- ["9"] = 9,
- ["J"] = 10,
- ["Q"] = 10,
- ["K"] = 10,
- ["10"] = 10
- }
- -- GAME STATE
- local totalDeck = {}
- local playerHand, playerY = {}, 83
- local houseHand, houseY = {}, 4
- local wager = 0
- local account = {}
- local function getHandValue(hand, trueValue)
- local aces = 0
- local value = 0
- -- First add up all non-aces
- for i = 1, #hand do
- if trueValue or not hand[i].hidden then
- if hand[i].value == "A" then
- aces = aces + 1
- else
- value = value + baseValue[hand[i].value]
- end
- end
- end
- -- Now find the least number of aces that need to count as 1 for it to not be a bust
- local finalValue
- for i = aces, 0, -1 do
- finalValue = value + (i * 11) + (aces - i)
- if finalValue <= 21 then
- break
- end
- end
- return finalValue
- end
- local function drawGame(extraCard, ex, ey, flag)
- buffer:clear(colors.black)
- display:clear()
- drawDeck(buffer, houseHand, math.floor(houseHand.x or 0), houseY)
- drawDeck(buffer, playerHand, math.floor(playerHand.x or 0), playerY)
- if extraCard then
- drawDeck(buffer, {extraCard}, math.floor(ex), math.floor(ey), flag)
- end
- writeBigCenter(buffer, "House: " .. getHandValue(houseHand), houseY + 28, nil, nil, true)
- writeBigCenter(buffer, "You: " .. getHandValue(playerHand), playerY - 6, nil, nil, true)
- display:drawSurfaceSmall(buffer, 0, 0)
- display:output()
- end
- local function resetDeck()
- totalDeck = {}
- playerHand = {}
- houseHand = {}
- for suit = 1, 4 do
- for v = 1, 13 do
- totalDeck[#totalDeck + 1] = {suit = suitMap[suit], value = valueMap[v]}
- end
- end
- -- Shuffle the deck
- for i = #totalDeck, 1, -1 do
- local j = math.random(1, i)
- totalDeck[i], totalDeck[j] = totalDeck[j], totalDeck[i]
- end
- end
- local function tween(x, d)
- local val = x + (d - x) / 2
- return val, math.abs(val - x) <= 1
- end
- local function dealTo(hand, startY, handY, hidden)
- local card = totalDeck[#totalDeck]
- card.hidden = hidden
- totalDeck[#totalDeck] = nil
- -- local cardX
- -- Animate in
- local done = false
- -- Move deck over
- local deckXDst = math.floor((buffer.width - getDeckDims(#hand + 1)) / 2)
- if #hand == 0 then
- hand.x = deckXDst
- end
- repeat
- hand.x, done = tween(hand.x, deckXDst)
- drawGame()
- sleep(sleepTime)
- until done
- -- Slide card in
- local cx, cy = drawDeck(nil, hand, math.floor(hand.x), handY), startY
- --deckXDst + getDeckDims(#hand) - cardLast.width, startY
- repeat
- cy, done = tween(cy, handY)
- drawGame(card, cx, cy, #hand > 0)
- sleep(sleepTime)
- until done
- hand[#hand + 1] = card
- drawGame()
- end
- local deck21 = {
- {value = "J", suit = "spades"},
- {value = "A", suit = "diamonds"}
- }
- local d21Surf = Surface.create(getDeckDims(#deck21))
- drawDeck(d21Surf, deck21, 0, 0)
- local titleSurf
- do
- local fw, fh = Surface.getTextSize(config.title, bigFont)
- titleSurf = Surface.create(math.ceil(fw / 2) * 2, math.ceil(fh / 3) * 3, colors.green)
- titleSurf:drawText(config.title, bigFont, 0, 0, colors.white)
- end
- local function makePayout()
- os.queueEvent("mktx", math.floor(wager * config.payout[1] / config.payout[2]), account[1], account[2], "message=Congratulations! Here are your winnings.")
- wager = 0
- end
- local state = "pregame"
- local function gameThread()
- while state ~= "quit" do
- if state == "pregame" then
- display:clear(colors.black)
- display:fillRect(0, 0, display.width, 5, colors.green)
- display:drawSurfaceSmall(titleSurf, math.floor((display.width - titleSurf.width / 2) / 2), 2)
- display:drawSurfaceSmall(d21Surf, math.floor((display.width - d21Surf.width / 2) / 2), 10)
- writeBigCenter(display, config.payout[1] .. ":" .. config.payout[2] .. " Payout", 21)
- writeCenter(display, "To play, send your wager to:", 26)
- writeBigCenter(display, config.kristName .. ".kst", 28)
- writeCenter(display, "Push is considered a loss, house wins. Dealer stops at 17.", 37)
- display:output()
- while true do
- local e = os.pullEvent()
- if e == "payment" and wager > 0 then
- state = "gameInit"
- break
- end
- end
- elseif state == "gameInit" then
- resetDeck()
- dealTo(houseHand, -40, houseY)
- dealTo(playerHand, 120, playerY)
- dealTo(houseHand, -40, houseY, true)
- dealTo(playerHand, 120, playerY)
- if getHandValue(playerHand) == 21 then
- state = "reveal-stand"
- -- outputBanner("BlackJack!", colors.green)
- -- os.pullEvent("mouse_click")
- -- state = "quit"
- else
- state = "game"
- end
- elseif state == "game" then
- local hbx, hby = 5, 15
- local sbx, sby = display.width - standBox.width / 2 - 5, 15
- local function drawBoxes()
- display:drawSurfaceSmall(hitBox, hbx, hby)
- display:drawSurfaceSmall(standBox, sbx, sby)
- display:output()
- end
- while true do
- drawBoxes()
- local e, b, mx, my = os.pullEvent("mouse_click")
- if checkBounds(hitBox, hbx, hby, mx, my) then
- dealTo(playerHand, 120, playerY)
- if getHandValue(playerHand) > 21 then
- state = "bust-player"
- break
- end
- elseif checkBounds(standBox, sbx, sby, mx, my) then
- state = "reveal-stand"
- break
- end
- end
- elseif state == "reveal-stand" then
- -- Reveal the starter for the house
- houseHand[#houseHand].hidden = false
- drawGame()
- sleep(0.1)
- while getHandValue(houseHand) < 17 do
- dealTo(houseHand, -40, houseY)
- end
- if getHandValue(houseHand) > 21 then
- state = "bust-house"
- else
- state = "checkwin"
- end
- elseif state == "bust-player" then
- outputBanner("Bust!", colors.red)
- os.pullEvent("mouse_click")
- state = "quit"
- elseif state == "bust-house" then
- outputBanner("House Bust!", colors.green)
- makePayout()
- os.pullEvent("mouse_click")
- state = "quit"
- elseif state == "checkwin" then
- local player = getHandValue(playerHand)
- local house = getHandValue(houseHand)
- if player > house then
- if player == 21 then
- outputBanner("BlackJack!", colors.green)
- else
- outputBanner("You Win!", colors.green)
- end
- makePayout()
- elseif player == house then
- outputBanner("Push, House Wins", colors.red)
- else
- if house == 21 then
- outputBanner("BlackJack, House Wins", colors.red)
- else
- outputBanner("House Wins", colors.red)
- end
- end
- os.pullEvent("mouse_click")
- state = "quit"
- end
- if state == "quit" then
- state = "pregame"
- wager = 0
- elseif state == "fatal" then
- state = "quit"
- end
- end
- end
- local function kristThread()
- --== Krist Interface Setup ==--
- rapi.init(jua)
- wapi.init(jua)
- kapi.init(jua, json, wapi, rapi)
- jua.on("mktx", function(e, amount, tx, meta, msg)
- if meta.meta and meta.meta["return"] then
- jua.await(kapi.makeTransaction, config.pkey, meta.meta["return"], amount, msg)
- else
- jua.await(kapi.makeTransaction, config.pkey, tx.from, amount, msg)
- end
- end)
- local seenID = 0
- --== Handlers ==--
- local function handleTransaction(data)
- local tx = data.transaction
- if tx.to == config.host then
- if tx.metadata then
- local meta = kapi.parseMeta(tx.metadata)
- if tx.id > seenID then
- seenID = tx.id
- if meta.domain == config.kristName then
- -- print("Received " .. tx.value .. "kst from " .. tx.from .. " (Meta: " .. tx.metadata .. ")")
- -- for k, v in pairs(tx) do
- -- print(k, v)
- -- end
- -- processPayment(tx, meta)
- if wager == 0 then
- wager = tx.value
- account = {tx, meta}
- os.queueEvent("payment")
- else
- os.queueEvent("mktx", tx.value, account[1], account[2], "error=A game is currently underway, please wait your turn..")
- end
- end
- end
- end
- end
- end
- --== Main Loop ==--
- jua.go(function()
- local success
- if not config.pkey then
- state = "fatal"
- jua.stop()
- error("No pkey configured")
- end
- if config.pkeyFormat == "kwallet" then
- config.pkey = kapi.toKristWalletFormat(config.pkey)
- end
- success, ws = await(kapi.connect, config.pkey or "no-pkey")
- if success then
- ws.on("hello", function(helloData)
- local subscribeSuccess = await(ws.subscribe, "transactions", handleTransaction)
- if not subscribeSuccess then
- state = "fatal"
- jua.stop()
- error("Failed to subscribe to Krist transactions")
- end
- end)
- ws.on("closed", function()
- os.reboot()
- end)
- else
- state = "fatal"
- jua.stop()
- error("Failed to request a websocket url")
- end
- end)
- end
- parallel.waitForAny(kristThread, gameThread)
Add Comment
Please, Sign In to add comment