Advertisement
nitrogenfingers

Solitaire

Apr 20th, 2015
5,604
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 54.46 KB | None | 0 0
  1. --[[
  2.     Solitare
  3.     A card game by Nitrogen Fingers
  4. ]]--
  5.  
  6.  
  7. --[[ Cards.lua API
  8.     Currently in the same source file but might separate out
  9.     Everything below are the features usable by this engine to make a
  10.     simple card game. It creates cards and displays them, as well as
  11.     helpers to make interaction with other cards easier.
  12.     You implement the mechanics, and you have a card game on your hands!
  13. ]]--
  14.  
  15. --The layout on each card (except aces, which vary from suit to suit)
  16. --Numbered values are the front, named styles are backs
  17. --Values: 2-10 as read, 1 == ace, 11 = jack, 12 = queen, 13 = king
  18. local styles = {
  19.     [0]  = { "|   "; "|   "; "|   "; "|___" };
  20.     [2]  = { "2  ;"; "  ; "; "    "; "  ; " };
  21.     [3]  = { "3  ;"; " ; ;"; "    "; "  ; " };
  22.     [4]  = { "4  ;"; " ; ;"; "    "; " ; ;" };
  23.     [5]  = { "5  ;"; " ; ;"; "  ; "; " ; ;" };
  24.     [6]  = { "6  ;"; " ; ;"; " ; ;"; " ; ;" };
  25.     [7]  = { "7  ;"; " ; ;"; " ;;;"; " ; ;" };
  26.     [8]  = { "8  ;"; " ; ;"; " ;;;"; " ;;;" };
  27.     [9]  = { "9  ;"; " ;;;"; " ;;;"; " ;;;" };
  28.     [10] = { "10 ;"; " ;;;"; ";;;;"; " ;;;" };
  29.     [11] = { "J  ;"; " (>|"; " ** "; "|<) " };
  30.     [12] = { "Q  ;"; " (>|"; " -- "; "|<) " };
  31.     [13] = { "K  ;"; " (>|"; " ## "; "|<) " };
  32.    
  33.     --Styles of the back of the card
  34.     backs = {
  35.         alligator = { ">##<"; ">##<"; ">##<"; ">##<" };
  36.         rounded = { "/  \\"; " || "; " || "; "\\  /" };
  37.         royal = { " oo "; "-/\\-"; "-\\/-"; " oo " };
  38.         frame = { "/--\\"; "|  |"; "|  |"; "\\--/" };
  39.         spooky = { "\\  /"; "-()-"; "-()-"; "/  \\" };
  40.     };
  41.     --The style regex. Replace this character with the suit.char
  42.     --Don't use this as part of card styling (change if necessary)
  43.     styleregex = ";";
  44.     --Width and height of the cards
  45.     width = 4; height = 4;
  46. }
  47. --The style the back of the card uses
  48. local backStyle = styles.backs.rounded
  49. --The colours the card back uses
  50. local backbg = colours.blue
  51. local backfg = colours.white
  52.  
  53. --The colour of the table
  54. local tablebg = colours.green
  55. --The colour of the face of the cards (should probably be white)
  56. local facecol = colours.white
  57. --The colour the face changes when a card is selected
  58. local selcol = colours.yellow
  59. --The colour of the outline of a 'space' where cards can be placed
  60. local emptycol = colours.grey
  61. --The X and Y offset of the screen. You can change this to allow
  62. --more cards than would otherwise appear (use wisely)
  63. local xoff, yoff = 0,0
  64.  
  65. --The suits a card can have and how they look
  66. local suits = {
  67.     spades = {
  68.         colour = colours.black;
  69.         char = "^";
  70.         ace = { "A  ".."^"; " /\\ "; "(__)"; " /\\ " }
  71.     };
  72.     diamonds = {
  73.         colour = colours.red;
  74.         char = "*";
  75.         ace = { "A  *"; " /\\ "; "<  >"; " \\/ " }
  76.     };
  77.     clubs = {
  78.         colour = colours.black;
  79.         char = "+";
  80.         ace = { "A  +"; " () "; "()()"; " /\\ " }
  81.     };
  82.     hearts = {
  83.         colour = colours.red;
  84.         char = "v";
  85.         ace = { "A  v"; "/\\/\\"; "\\  /"; " \\/ " }
  86.     };
  87. }
  88.  
  89. --Changes the numerical code of the card value to a printable string
  90. local function valToDisplay(_val)
  91.     if _val == 1 then return "A "
  92.     elseif _val == 10 then return "10"
  93.     elseif _val == 11 then return "J "
  94.     elseif _val == 12 then return "Q "
  95.     elseif _val == 13 then return "K "
  96.     else return _val.." " end
  97. end
  98.  
  99. --A singly linked list prototype for containing collections of cards
  100. --Card games often layer cards on one another so this is a good way to
  101. --keep track of them and make moving lots of cards around easier.
  102. local linkedCardP = {
  103.     --Head of the list
  104.     head = nil,
  105.     --Tail of the list
  106.     tail = nil,
  107.    
  108.     display = function(self)
  109.         if self.head then self.head:display() end
  110.     end;
  111.    
  112.     reverse = function(self)
  113.         if not self.head and self.head.tail then return end
  114.         local _head = self.head
  115.         local function recRev(_head)
  116.             local _rest = _head.tail
  117.             if _rest then
  118.                 recRev(_rest)
  119.                 _rest.tail = _head
  120.             else
  121.                 self.head = _head
  122.             end
  123.         end
  124.         recRev(_head)
  125.         _head.tail = nil
  126.     end;
  127. }
  128.  
  129. --Constructs a
  130. function linkedCardP:new(o)
  131.     o = o or { }
  132.     setmetatable(o, self)
  133.     self.__index = self
  134.     return o
  135. end;
  136.  
  137. --The card prototype
  138. local cardP = {
  139.     --The value on the face of the card (2-A)
  140.     val = 0,
  141.     --The suit of the card, from the suits table
  142.     suit = suits.spades,
  143.     --Whether or not the card is turned face-up
  144.     visible = false,
  145.     --Whether or not the card is selected
  146.     selected = false,
  147.     --The card directly on top of this card, if any
  148.     tail = nil,
  149.     --Whether or not the card runs a display call at all. This is used
  150.     --when the cards would otherwise clutter the display area
  151.     hidden = false,
  152.    
  153.     --Used for the coordinates of the card, as X-Y
  154.     x = 0, y = 0,
  155.    
  156.     --Displays an outline of the card painted as the table
  157.     --A method to decrease the number of necessary draw calls
  158.     displayTable = function(self)
  159.         for _y = self.y, self.y + styles.height do
  160.             term.setBackgroundColour(tablebg)
  161.             term.setCursorPos(self.x + xoff, _y + yoff)
  162.             term.write(string.rep(" ", styles.width))
  163.         end
  164.     end;
  165.    
  166.     --Displays the face or back of a card, and its children if they
  167.     --are not being overlapped
  168.     display = function(self)
  169.         if self.tail and not (self.tail.x == self.x
  170.                 and self.tail.y == self.y) then
  171.             self.tail:display()
  172.         end
  173.        
  174.         if self.hidden then return end
  175.         local _style = nil
  176.         if self.val == 0 then
  177.             _style = styles[self.val]
  178.             term.setBackgroundColour(tablebg)
  179.             term.setTextColour(emptycol)
  180.         elseif not self.visible then
  181.             _style = backStyle
  182.             term.setBackgroundColour(backbg)
  183.             term.setTextColour(backfg)
  184.         else
  185.             if self.selected then
  186.                 term.setBackgroundColour(selcol)
  187.             else
  188.                 term.setBackgroundColour(facecol)
  189.             end
  190.             term.setTextColour(self.suit.colour)
  191.             if self.val == 1 then _style = self.suit.ace
  192.             else _style = styles[self.val] end
  193.         end
  194.         for i = 1, #_style do
  195.             term.setCursorPos(self.x + xoff, self.y + i - 1 + yoff)
  196.             term.write(string.gsub(_style[i], ";", self.suit.char))
  197.         end
  198.     end;
  199.    
  200.     --Move this card (and all cards on top of it) to a new position
  201.     --ChildMove will move all cards in the tail
  202.     move = function(self, newx, newy, childMove)
  203.         local _xdiff,_ydiff = newx - self.x, newy - self.y
  204.         if childMove and self.tail then self.tail:move(
  205.             self.tail.x + _xdiff, self.tail.y + _ydiff, true) end
  206.         self.x = newx
  207.         self.y = newy
  208.     end;
  209.    
  210.     --Determine whether or not an xy point lies on the body of the card
  211.     clicked = function(self, mousex, mousey)
  212.         return mousex >= self.x + xoff and mousex < self.x + styles.width + xoff and
  213.                 mousey >= self.y + yoff and mousey < self.y + styles.height + yoff and not self.hidden
  214.     end;
  215.    
  216.     --Determines whether or not two cards are overlapping
  217.     overlapping = function(self, ocard)
  218.         return self.x >= ocard.x - styles.width and
  219.             self.x <= ocard.x + styles.width  and
  220.             self.y >= ocard.y - styles.height and
  221.             self.y <= ocard.y + styles.height  and not ocard.hidden and not self.hidden
  222.     end;
  223.    
  224.     __tostring = function(self)
  225.         return self.val.." of "..self.suit.char
  226.     end
  227. }
  228.  
  229. --Constructs a new card
  230. function cardP:new (o)
  231.     o = o or {}
  232.     setmetatable(o, self)
  233.     self.__index = self
  234.     return o
  235. end;
  236.  
  237. --The main deck, from which you should draw all cards
  238. local deck = {}
  239.  
  240. --Creates a fresh deck of 52 cards in suit and number order
  241. --Count is the number of decks you wish to include
  242. local function createDeck(_count)
  243.     deck = {}
  244.     for i = 1, _count do
  245.         for _,suitval in pairs(suits) do
  246.             for _val = 1,13 do
  247.                 table.insert(deck, cardP:new({
  248.                     val = _val;
  249.                     suit = suitval;
  250.                 }))
  251.             end
  252.         end
  253.     end
  254. end
  255.  
  256. --Shuffles the deck. A close-to-optimal shuffle
  257. local function shuffleDeck()
  258.     for i=#deck,2,-1 do
  259.         local _card = table.remove(deck, math.random(1, i))
  260.         table.insert(deck, i, _card)
  261.     end
  262. end
  263.     --[[ Overmenu Facilities
  264.          The glue that ties each of the games together
  265.     ]]--
  266.  
  267. --Screen Size
  268. local w,h = term.getSize()
  269. --The function to call to draw the entire game again as needed
  270. local currOverDraw = nil
  271. --Whether or not the user has just quit
  272. local quit = false
  273. --The next game to be played
  274. local nextGame = nil
  275.  
  276. --The options displayed in the menu
  277. local menuOptions = { name = "Games", x = 3, y = 1 }
  278. --The title at the top of the screen
  279. local title = "Card Games"
  280.  
  281. --Draws the menu bar. Should be the last thing in every overdraw call
  282. local function displayOverMenuBar()
  283.     term.setCursorPos(3,1)
  284.     term.setBackgroundColour(colours.lightGrey)
  285.     term.clearLine()
  286.     term.setTextColour(colours.black)
  287.     term.write("Games")
  288.     term.setTextColour(colours.grey)
  289.     term.setCursorPos(w/2 - #title/2, 1)
  290.     term.write(title)
  291. end
  292.  
  293. --[[Produces a nice dropdown menu based on a table of strings. Depending on the position, this will auto-adjust the position
  294.         of the menu drawn, and allows nesting of menus and sub menus. Clicking anywhere outside the menu will cancel and return nothing
  295.         Params: x:int = the x position the menu should be displayed at
  296.                 y:int = the y position the menu should be displayed at
  297.                 options:table = the list of options available to the user, as strings or submenus (tables of strings, with a name parameter)
  298.         Returns:string the selected menu option.
  299. ]]--
  300. local function displayDropDown(x, y, options, noTitle)
  301.     inDropDown = true
  302.     if noTitle then y = y - 1 end
  303.     --Figures out the dimensions of our thing
  304.     local longestX = #options.name
  305.     for i=1,#options do
  306.         local currVal = options[i]
  307.         if type(currVal) == "table" then currVal = currVal.name end
  308.         longestX = math.max(longestX, #currVal)
  309.     end
  310.     local xOffset = math.max(0, longestX - ((w-2) - x) + 1)
  311.     local yOffset = math.max(0, #options - ((h-1) - y))
  312.    
  313.     local clickTimes = 0
  314.     local tid = nil
  315.     local selection = nil
  316.     while clickTimes < 4 do
  317.         if not noTitle then
  318.             term.setCursorPos(x-xOffset,y-yOffset)
  319.             term.setBackgroundColour(colours.blue)
  320.             term.setTextColour(colours.white)
  321.             term.write(options.name.." ")
  322.         end
  323.  
  324.         for i=1,#options do
  325.             term.setCursorPos(x-xOffset, y-yOffset+i)
  326.             local currVal = options[i]
  327.             if type(currVal.value) == "table" then
  328.                 currVal.enabled = #currVal.value > 0
  329.             end
  330.            
  331.             if i==selection and clickTimes % 2 == 0 then
  332.                 term.setBackgroundColour(colours.blue)
  333.                 if options[selection].enabled then term.setTextColour(colours.white)
  334.                 else term.setTextColour(colours.grey) end
  335.             else
  336.                 term.setBackgroundColour(colours.lightGrey)
  337.                 local _tcol = colours.black
  338.                 if not currVal.enabled then _tcol = colours.grey end
  339.                 term.setTextColour(_tcol)
  340.             end
  341.             if type(currVal.value) == "table" then
  342.                 term.write(currVal.name..string.rep(" ", longestX-#currVal.name))
  343.                 term.setBackgroundColour(colours.blue)
  344.                 term.setTextColour(colours.white)
  345.                 term.write(">")
  346.             else
  347.                 term.write(currVal.name..string.rep(" ", longestX-#currVal.name + 1))
  348.             end
  349.            
  350.             if (i~= selection or clickTimes %2 == 1) and currVal.key and currVal.enabled then
  351.                 term.setTextColour(colours.blue)
  352.                 term.setBackgroundColour(colours.lightGrey)
  353.                 local co = currVal.name:find(currVal.key)
  354.                 if not co then co = longestX else co = co - 1 end
  355.                 term.setCursorPos(x-xOffset+co, y-yOffset + i)
  356.                 term.write(currVal.key)
  357.             end
  358.         end
  359.        
  360.         local id, p1, p2, p3 = os.pullEvent()
  361.         if id == "timer" then
  362.             if p1 == tid then
  363.                 clickTimes = clickTimes + 1
  364.                 if clickTimes > 2 then
  365.                     break
  366.                 else
  367.                     tid = os.startTimer(0.1)
  368.                 end
  369.             elseif p1 == bTimer then saveDocument(bPath) end
  370.         elseif id == "key" and not tid then
  371.             if p1 == keys.leftCtrl then
  372.                 selection = ""
  373.                 break
  374.             elseif p1 == keys.down and (not selection or selection < #options) then
  375.                 selection = selection or 0
  376.                 _os = selection
  377.                 repeat selection = selection + 1
  378.                 until selection == #options + 1 or options[selection].enabled
  379.                 --if selection == #options + 1 then selection = _os end
  380.             elseif p1 == keys.up and (not selection or selection > 1) then
  381.                 selection = selection or #options + 1
  382.                 _os = selection
  383.                 repeat selection = selection - 1
  384.                 until selection == 0 or options[selection].enabled
  385.                 if selection == 0 then selection = _os end
  386.             elseif p1 == keys.enter and selection and options[selection].enabled then
  387.                 tid = os.startTimer(0.1)
  388.                 clickTimes = clickTimes - 1
  389.             end
  390.         elseif id == "mouse_click" and not tid then
  391.             local _xp, _yp = x - xOffset, y - yOffset
  392.             if p2 >= _xp and p2 <= _xp + longestX + 1 and
  393.             p3 >= _yp+1 and p3 <= _yp+#options then
  394.                 if options[p3 - _yp].enabled then
  395.                     selection = p3-(_yp)
  396.                     tid = os.startTimer(0.1)
  397.                 end
  398.             else
  399.                 selection = ""
  400.                 break
  401.             end
  402.         elseif id == "char" and not tid then
  403.             for k,v in ipairs(options) do
  404.                 if v.key and v.key:lower() == p1:lower() and options[k].enabled then
  405.                     selection = k
  406.                     tid = os.startTimer(0.1)
  407.                     break
  408.                 end
  409.             end
  410.         end
  411.     end
  412.    
  413.     local _val = selection
  414.     if type(selection) == "number" then
  415.         selection = options[selection].value
  416.     end
  417.    
  418.     if type(selection) == "string" then
  419.         inDropDown = false
  420.         return selection
  421.     elseif type(selection) == "table" then
  422.         return displayDropDown(x + longestX + 1, y + _val, selection, true)
  423.     elseif type(selection) == "function" then
  424.         local _rval = selection()
  425.         if not _rval then return "" else return _rval end
  426.     end
  427. end
  428.  
  429. --Handles mouse events for the menu, returns true or false if something happens
  430. local function manageMenuMouseEvents(_id, _x, _y)
  431.     if _id == "mouse_click" and _y == menuOptions.y and _x >= menuOptions.x and
  432.             _x < menuOptions.x + #menuOptions.name then
  433.         local _rval = displayDropDown(menuOptions.x, menuOptions.y, menuOptions)
  434.         if currOverDraw then currOverDraw()
  435.         else
  436.             term.setBackgroundColour(tablebg)
  437.             term.clear()
  438.             displayOverMenuBar()
  439.         end
  440.     end
  441.     return nextGame ~= nil or quit
  442. end
  443.  
  444.  
  445.     --[[ Game Variant: Klondike
  446.         The classic game of solitare. Seven columns of cards, try to
  447.         sort your deck by suit and number.
  448.     ]]--
  449.    
  450. --The selected card, and the pile it belongs to
  451. local selCard, selDeck, selSpace = nil, nil, nil
  452. --The space, waste and tableau decks
  453. local spaces, waste, tableaus = {}, linkedCardP:new(), {}
  454. --The deck's default position
  455. local deckX,deckY = 0,0
  456. --An empty card representing where the deck should be
  457. local deckSpace = nil
  458. --The last position of a mouse click not intercepting a card
  459. local lmX,lmY = 0,0
  460. --And a temporary offset value so we don't keep reapplying
  461. local txoff, tyoff = 0,0
  462. --The player's score at Klondike
  463. local klondikeScore = 0
  464.  
  465. --Shows the score at the bottom of the screen
  466. local function displayScore()
  467.     term.setCursorPos(1,h)
  468.     term.setBackgroundColour(tablebg)
  469.     term.setTextColour(colours.black)
  470.     term.write(" Score: "..klondikeScore)
  471. end
  472.  
  473. --Draws every element in Klondike. There's not much redraw in this game
  474. --so I haven't bothered to optimize too heavily.
  475. local function drawKlondike()
  476.     term.setBackgroundColour(tablebg)
  477.     term.clear()
  478.  
  479.     for i=1,7 do
  480.         if spaces[i] then spaces[i]:display() end
  481.     end
  482.     waste:display()
  483.     for i=1,4 do
  484.         if tableaus[i] then tableaus[i]:display() end
  485.     end
  486.     if deckSpace then deckSpace:display() end
  487.     displayScore()
  488.     displayOverMenuBar()
  489. end
  490.  
  491. --Sets up a new game of Klondike, organizing the deck.
  492. local function makeKlondikeSetup()
  493.     createDeck(1)
  494.     shuffleDeck()
  495.     spaces = {}
  496.    
  497.     --Cleanup from last game
  498.     if deckSpace then deckSpace.val = 1 end
  499.     if waste then waste.head = nil end
  500.     for i=1,4 do
  501.         if tableaus[i] then tableaus[i].head = cardP:new({
  502.             x = tableaus[i].head.x;
  503.             y = tableaus[i].head.y;
  504.             val = 0;
  505.         })
  506.         end
  507.     end
  508.     for i=1,7 do spaces[i] = nil end
  509.    
  510.     --The main play area
  511.     for i=1,7 do
  512.         for j=i,7 do
  513.             --Our (silly) little card animation :D
  514.             drawKlondike()
  515.             sleep(0.1)
  516.            
  517.             if i == 1 then spaces[j] = linkedCardP:new() end
  518.            
  519.             local _card = table.remove(deck, 1)
  520.             _card.x = 1 + 1 * j + styles.width * (j - 1)
  521.             _card.y = i + 2
  522.             if spaces[j].head then _card.tail = spaces[j].head
  523.             else spaces[j].tail = _card end
  524.             spaces[j].head = _card
  525.             if i == j then spaces[j].head.visible = true end
  526.         end
  527.     end
  528.    
  529.     --The waste pile and remaining deck
  530.     deckX = spaces[#spaces].head.x + 2 + styles.width
  531.     deckY = 2
  532.     for i=1,#deck do
  533.         deck[i].x = deckX
  534.         deck[i].y = deckY
  535.     end
  536.     deckSpace = cardP:new({ x = deckX; y = deckY; val = 1})
  537.    
  538.     --The tableau piles
  539.     for i=1,4 do
  540.         local _ecard = cardP:new()
  541.         _ecard.val = 0
  542.         if i % 2 == 0 then _ecard.x = deckX
  543.         else _ecard.x = deckX + styles.width + 2 end
  544.         if i <= 2 then _ecard.y = deckY + styles.height * 2
  545.         else _ecard.y = deckY + styles.height * 3 + 1 end
  546.         tableaus[i] = linkedCardP:new()
  547.         tableaus[i].head = _ecard
  548.     end
  549. end
  550.  
  551. --Determines whether or not the game is won
  552. local function checkWinState()
  553.     local _won = true
  554.     for i=1,#tableaus do
  555.         _won = tableaus[i].head and tableaus[i].head.val == 13
  556.         if not _won then break end
  557.     end
  558.     return _won
  559. end
  560.  
  561. --Selects a given card
  562. local function select(_card, _deck, _space)
  563.     if selCard then selCard.selected = false end
  564.     selCard = _card
  565.     selDeck = _deck
  566.     selSpace = _space
  567.     if selCard then selCard.selected = true end
  568. end
  569.  
  570. --Determines how many points were scored (or lost) for making a specific move. Uses Windows Solitare conventions
  571. local function evaluateScore(initDeck, finalDeck)
  572.     if finalDeck == tableaus then
  573.         klondikeScore = klondikeScore + 10
  574.     elseif initDeck == waste then
  575.         klondikeScore = klondikeScore + 5
  576.     elseif initDeck == tableaus then
  577.         klondikeScore = klondikeScore - 15
  578.     end
  579.     displayScore()
  580. end
  581.  
  582. --Adds a card to the selected tableau. Returns true if the check was successful
  583. local function addKlondikeTableau(_card, _deck)
  584.     if selCard == selDeck.head and selCard.val == _card.val + 1 and
  585.             (_card.val == 0 or _card.suit == selCard.suit) then
  586.         selDeck.head = selCard.tail
  587.         if selSpace == spaces and selDeck.head == nil then
  588.             selDeck.head = cardP:new( { x = selCard.x; y = selCard.y; val = 0; } )
  589.         end
  590.         selCard.x = _deck.head.x
  591.         selCard.y = _deck.head.y
  592.         if _deck.head.val == 0 then _deck.head = nil end
  593.         selCard.tail = _deck.head
  594.         _deck.head = selCard
  595.         evaluateScore(_deck, tableaus)
  596.     else
  597.         return false
  598.     end
  599.     select()
  600.     return true
  601. end
  602.  
  603. --Moves one card and it's peers to be on top of another card in the play area. Implements
  604. --rules associated with this kind of move
  605. local function shiftKlondikeCard(_card, _deck)
  606.     --Ensuring the move is legal. If it isn't we just select the new card
  607.     local isLegal = (_card.suit.colour ~= selCard.suit.colour and _card.val == selCard.val + 1 and
  608.             _card == _deck.head) or (_card.val == 0 and selCard.val == 13)
  609.     if not isLegal then
  610.         local _cDeck = selDeck
  611.         select(_card, _deck, spaces)
  612.         _cDeck:display()
  613.         _deck:display()
  614.         return
  615.     end
  616.    
  617.     --Moving a card from the waste pile into the play area
  618.     if selSpace == waste then
  619.         selCard:displayTable()
  620.         selCard:move(_card.x, _card.y + 1)
  621.         _deck.head = selCard
  622.         selDeck.head = selCard.tail
  623.         selDeck:display()
  624.     --Moving a card from one part of the play field to the other
  625.     elseif selSpace == spaces then
  626.         local _top = selDeck.head
  627.         _deck.head = _top
  628.         local _ydiff = 1
  629.         _top:displayTable()
  630.         while _top ~= selCard do
  631.             _top = _top.tail
  632.             _ydiff = _ydiff + 1
  633.             _top:displayTable()
  634.         end
  635.         selDeck.head = selCard.tail
  636.         if selDeck.head == nil then
  637.             selDeck.head = cardP:new({ val = 0, x = selCard.x, y = selCard.y })
  638.         end
  639.         selDeck:display()
  640.         selCard.tail = nil
  641.         _deck.head:move(_card.x, _card.y + _ydiff, true)
  642.     --Moving a card from the tableau onto the play area
  643.     elseif selSpace == tableaus then
  644.         selDeck.head = selCard.tail
  645.         if selDeck.head == nil then
  646.             selDeck.head = cardP:new({ val = 0, x = selCard.x, y = selCard.y })
  647.         end
  648.         selDeck:display()
  649.         selCard:move(_card.x, _card.y + 1)
  650.         _deck.head = selCard
  651.     end
  652.     selCard.tail = _card
  653.     evaluateScore(selSpace, spaces)
  654.    
  655.     if _card.val == 0 then
  656.         selCard.tail = nil
  657.         _deck.head:move(_deck.head.x, _deck.head.y - 1, true)
  658.     end
  659.     select()
  660.     _deck:display()
  661. end
  662.  
  663. --Completes the game for us, when all cards are revealed and in the play area
  664. local function autoCompleteKlondike()
  665.     local _lowestVal = nil
  666.     repeat
  667.         _lowestVal = math.huge
  668.         for i = 1, #spaces do
  669.             if spaces[i].head.val > 0 then
  670.                 _lowestVal = math.min(_lowestVal, spaces[i].head.val)
  671.             end
  672.         end
  673.         for i = 1, #spaces do
  674.             if spaces[i].head.val == _lowestVal then
  675.                 select(spaces[i].head, spaces[i], spaces)
  676.                 for j = 1, #tableaus do
  677.                     if addKlondikeTableau(tableaus[j].head, tableaus[j]) then break end
  678.                 end
  679.             end
  680.         end
  681.         drawKlondike()
  682.         sleep(0.2)
  683.     until _lowestVal >= 13
  684. end
  685.  
  686. --Handles all input for Klondike
  687. local function handleKlondikeInput()
  688.     gameOver, gameWon = false, false
  689.     while not gameOver do
  690.         local id,p1,p2,p3 = os.pullEvent()
  691.         if manageMenuMouseEvents(id,p2,p3) then return end
  692.    
  693.         if id == "mouse_click" then
  694.             local complete = false
  695.             lmX, lmY = 0,0
  696.            
  697.             for i=1,#spaces do
  698.                 local _c = spaces[i].head
  699.                 while _c do
  700.                     --We've clicked a card in the main hand
  701.                     if _c:clicked(p2,p3) then
  702.                         --Performing a doubleclick
  703.                         if selCard == _c then
  704.                             local _cDeck = selDeck
  705.                             select()
  706.                             _cDeck:display()
  707.                             complete = true
  708.                             break
  709.                         --Revealing a newly freed card
  710.                         elseif _c == spaces[i].head and _c.visible == false and _c.val > 0 then
  711.                             _c.visible = true
  712.                             local _cDeck = selDeck
  713.                             select()
  714.                             if _cDeck then _cDeck:display() end
  715.                             klondikeScore = klondikeScore + 5
  716.                             displayScore()
  717.                             _c:display()
  718.                             complete = true
  719.                             break
  720.                         --Selecing a card with no other selection
  721.                         elseif selCard == nil and _c.visible == true and _c.val > 0 then
  722.                             select(_c, spaces[i], spaces)
  723.                             spaces[i]:display()
  724.                             complete = true
  725.                             break
  726.                         --Attempting to move a previously selected card onto this one
  727.                         elseif selCard then
  728.                             shiftKlondikeCard(_c, spaces[i])
  729.                             drawKlondike()
  730.                             complete = true
  731.                             break
  732.                         end
  733.                     end
  734.                     _c = _c.tail
  735.                 end
  736.                 if complete then break end
  737.             end
  738.            
  739.             for i=1,#tableaus do
  740.                 local _c = tableaus[i].head
  741.                 if _c:clicked(p2,p3) then
  742.                     --Attempting to add a card to the tableau
  743.                     if selCard and addKlondikeTableau(_c, tableaus[i]) then
  744.                         gameWon = checkWinState()
  745.                         gameOver = gameWon
  746.                         drawKlondike()
  747.                     --Selecting a card already on the tableau
  748.                     elseif _c.val > 0 then
  749.                         local _cDeck = selDeck
  750.                         select(_c, tableaus[i], tableaus)
  751.                         tableaus[i]:display()
  752.                         if _cDeck then _cDeck:display() end
  753.                     end
  754.                     complete = true
  755.                     break
  756.                 end
  757.             end
  758.            
  759.             if deckSpace:clicked(p2,p3) then
  760.                 if waste.head and waste.head.selected then select() end
  761.                 --Refreshing the deck
  762.                 if deckSpace.val == 0 then
  763.                     while waste.head do
  764.                         if not waste.head.hidden then waste.head:displayTable() end
  765.                         table.insert(deck, 1, waste.head)
  766.                         waste.head = deck[1].tail
  767.                         deck[1].visible = false
  768.                         deck[1].hidden = false
  769.                         deck[1].tail = nil
  770.                     end
  771.                     deckSpace.val = #deck
  772.                     deckSpace:display()
  773.                 --Dealing another 3 cards to the waste deck
  774.                 else
  775.                     local _h = waste.head
  776.                     while _h and not _h.hidden do
  777.                         _h.hidden = true
  778.                         _h:displayTable()
  779.                         _h = _h.tail
  780.                     end
  781.                    
  782.                     for i = 1, math.min(#deck, 3) do
  783.                         local _c = table.remove(deck,1)
  784.                         _c.tail = waste.head
  785.                         _c:move(deckSpace.x + styles.width + 2, deckSpace.y + i - 1)
  786.                         _c.visible = true
  787.                         waste.head = _c
  788.                         deckSpace.val = #deck
  789.                         --More animations!
  790.                         waste:display()
  791.                         displayOverMenuBar()
  792.                         sleep(0.1)
  793.                     end
  794.                     deckSpace:display()
  795.                 end
  796.             end
  797.            
  798.             if waste.head and waste.head:clicked(p2,p3) then
  799.                 --Selecting a card in the waste deck
  800.                 if waste.head.selected then
  801.                     select()
  802.                 else
  803.                     local _d = selDeck
  804.                     select(waste.head, waste, waste)
  805.                     if _d then _d:display() end
  806.                 end
  807.                 waste.head:display()
  808.                 complete = true
  809.             end
  810.            
  811.             --Deselecting a card by clicking in empty space
  812.             if selCard ~= nil and not complete then
  813.                 local _cDeck = selDeck
  814.                 select()
  815.                 if _cDeck then _cDeck:display() end
  816.             end
  817.             lmX, lmY = p2, p3
  818.             txoff, tyoff = xoff, yoff
  819.             displayOverMenuBar()
  820.            
  821.             --Determining if the player can autocomplete the game
  822.             if complete and deckSpace.val == 0 and waste.head == nil and not checkWinState() then
  823.                 local _autoComplete = true
  824.                
  825.                 for i=#spaces,1,-1 do
  826.                     local _h = spaces[i].head
  827.                     while _h do
  828.                         if _h.val > 0 then
  829.                             _autoComplete = _h.visible
  830.                             if not _autoComplete then break end
  831.                         end
  832.                         _h = _h.tail
  833.                     end
  834.                     if not _autoComplete then break end
  835.                 end
  836.                
  837.                 if _autoComplete then
  838.                     autoCompleteKlondike()
  839.                     gameWon = true
  840.                     gameOver = true
  841.                 end
  842.             end
  843.         elseif id == "mouse_drag" then
  844.             if lmX > 0 and lmY > 0 then
  845.                 local yDiff = p3 - lmY
  846.                 --Mouse drag events seem to be pretty overzealous. Or is that a version issue...
  847.                 if tyoff + yDiff ~= yoff then
  848.                     yoff = math.min(tyoff + yDiff, 0)
  849.                     --h-21 is the maximum unrevealed column (6) plus the max revealed column (13)
  850.                     --plus 3 to reveal the face of the card and 4 more for whitespace
  851.                     yoff = math.max(yoff, h - 26)
  852.                     drawKlondike()
  853.                 end
  854.             end
  855.         elseif id == "mouse_scroll" then
  856.             yoff = math.min(yoff - p1, 0)
  857.             yoff = math.max(yoff, h - 26)
  858.             drawKlondike()
  859.         elseif id == "key" then
  860.             if p1 == keys.down then
  861.                 yoff = math.min(yoff + 1, 0)
  862.                 drawKlondike()
  863.             elseif p1 == keys.up then
  864.                 yoff = math.max(yoff - 1, h - 26)
  865.                 drawKlondike()
  866.             end
  867.         end
  868.     end
  869.     if gameWon then
  870.         --One last silly win animation
  871.         local _spread = {}
  872.         for i=1,#tableaus do
  873.             tableaus[i]:reverse()
  874.             tableaus[i].head:move(w/4 + styles.width/2 + 13, 2 + styles.height * (i - 1), true)
  875.             local _c = tableaus[i].head.tail
  876.             _spread[i] = _c
  877.             while _c do
  878.                 _c:move(_c.x - 2 + xoff, _c.y + yoff, true)
  879.                 _c.hidden = true
  880.                 _c = _c.tail
  881.             end
  882.         end
  883.        
  884.         while _spread[1] do
  885.             drawKlondike()
  886.             sleep(0.1)
  887.             for i=1,#_spread do
  888.                 _spread[i].hidden = false
  889.                 _spread[i] = _spread[i].tail
  890.             end
  891.         end
  892.         drawKlondike()
  893.     end
  894. end
  895.  
  896. --Runs a game of Klondike
  897. local function playKlondike()
  898.     backStyle = styles.backs.rounded
  899.     backbg = colours.blue
  900.     backfg = colours.white
  901.     title = "Klondike Solitaire"
  902.     xoff = 0
  903.     yoff = 0
  904.  
  905.     makeKlondikeSetup()
  906.     drawKlondike()
  907.     handleKlondikeInput()
  908. end
  909.  
  910.     --[[ Game Variant: Blackjack
  911.         Play against a dealer, bet on your dealout and try to have a
  912.         greater score than the dealer without going over 21
  913.     ]]--
  914.    
  915. --The player's funds
  916. local bank = 200
  917. --The table minimum and maximum
  918. local tableMin, tableMax = 20, math.huge
  919. --The current bet, the split bet and any insurance the player has bought
  920. local currBet,splitBet,insurance = 0,0,0
  921. --The player's hand
  922. local hand = linkedCardP:new()
  923. local splitHand = nil
  924. --The dealer's hand
  925. local dealerHand = linkedCardP:new()
  926. --The position of the betting squares
  927. local _bx1, _bx2, _by = 14, w - 21, 10
  928. --The empty 'deck' card, symbolizing the deck to click for a deal
  929. local _bjDeck = cardP:new( { val = 1; visible = false; x = w - 8; y = 3; } )
  930. --The footer message and colour
  931. local _footermsg, _footercolor = "",colours.white
  932.  
  933. --Prepares a new game of blackjack
  934. local function startBlackjack()
  935.     createDeck(1)
  936.     bank = 200
  937.     hand = linkedCardP:new()
  938.     dealerHand = linkedCardP:new()
  939.     currBet = 0
  940.     insurance = 0
  941.     splitBet = 0
  942.     _footermsg, _footercolor = "",colours.white
  943. end
  944.  
  945. --Displays the bets and bank at the bottom of the screen
  946. local function displayBlackjackBets()
  947.     term.setCursorPos(1,h-1)
  948.     term.setBackgroundColour(tablebg)
  949.     term.setTextColour(colours.black)
  950.     term.clearLine()
  951.     term.write("  Bank: $"..bank)
  952.     term.setCursorPos(20, h-1)
  953.     term.setTextColour(_footercolor)
  954.     term.write(_footermsg)
  955.    
  956.     term.setCursorPos(_bx1 + 1, _by + 1)
  957.     term.write(string.rep(" ", 5))
  958.     if currBet > 0 then
  959.         term.setCursorPos(_bx1 + 1, _by + 1)
  960.         term.write("$"..currBet.." ")
  961.     end
  962.    
  963.     term.setCursorPos(_bx2 + 1, _by + 1)
  964.     term.write(string.rep(" ", 5))
  965.     if splitBet > 0 then
  966.         term.setCursorPos(_bx2 + 1, _by + 1)
  967.         term.write("$"..splitBet.." ")
  968.     end
  969. end
  970.  
  971. --Displays all elements in a game of blackjack
  972. local function displayBlackjack()
  973.     term.setBackgroundColour(tablebg)
  974.     term.clear()
  975.     --The table
  976.     term.setTextColour(colours.orange)
  977.     local _tableMsg = "Blackjack pays 3 to 2"
  978.     term.setCursorPos(w/2-#_tableMsg/2, 8)
  979.     term.write(_tableMsg)
  980.     term.setTextColour(colours.white)
  981.     _tableMsg = "Insurance pays 2 to 1"
  982.     term.setCursorPos(w/2-#_tableMsg/2, 9)
  983.     term.write(_tableMsg)
  984.    
  985.     term.setTextColour(colours.white)
  986.     for i=1,3,2 do
  987.         term.setCursorPos(_bx1 + 1, _by - 1 + i)
  988.         term.write(string.rep("-", 5))
  989.         term.setCursorPos(_bx2 + 1, _by - 1+ i)
  990.         term.write(string.rep("-", 5))
  991.     end
  992.     term.setCursorPos(_bx1, _by + 1)
  993.     term.write("|"..string.rep(" ",5).."|")
  994.     term.setCursorPos(_bx2, _by + 1)
  995.     term.write("|"..string.rep(" ",5).."|")
  996.    
  997.     --Hands
  998.     hand:display()
  999.     if splitHand then splitHand:display() end
  1000.     dealerHand:display()
  1001.     displayBlackjackBets()
  1002.     _bjDeck:display()
  1003.     displayOverMenuBar()
  1004. end
  1005.  
  1006. --Prompts the user to put in how much money they will bet before the next draw
  1007. local function placeBlackjackBet()
  1008.     _footermsg = ""
  1009.     displayBlackjack()
  1010.     term.setBackgroundColour(tablebg)
  1011.     term.setTextColour(colours.black)
  1012.     local _x = 20
  1013.     local _prompt = "Place bet: "
  1014.     while currBet == nil or currBet < tableMin or currBet > tableMax or currBet > bank do
  1015.         term.setCursorPos(_x,h-1)
  1016.         term.write(_prompt)
  1017.         term.setTextColour(colours.black)
  1018.         currBet = read()
  1019.         term.setCursorPos(_x + #_prompt, h-1)
  1020.         term.write(string.rep(" ", #currBet))
  1021.         currBet = tonumber(currBet)
  1022.         term.setTextColour(colours.red)
  1023.     end
  1024.     bank = bank - currBet
  1025.     displayBlackjackBets()
  1026. end
  1027.  
  1028. --Deal a hand of blackjack
  1029. local function dealBlackjack()
  1030.     createDeck(1)
  1031.     local _c = hand.head
  1032.     while _c do
  1033.         _c:displayTable()
  1034.         _c = _c.tail
  1035.     end
  1036.     local _c = dealerHand.head
  1037.     while _c do
  1038.         _c:displayTable()
  1039.         _c = _c.tail
  1040.     end
  1041.     hand.head = nil
  1042.     dealerHand.head = nil
  1043.     splitHand = nil
  1044.     shuffleDeck()
  1045.     displayBlackjackBets()
  1046.     placeBlackjackBet()
  1047.    
  1048.     --Deal the cards
  1049.     for i=1,4 do
  1050.         local _c = table.remove(deck,1)
  1051.         if i % 2 == 1 then
  1052.             if hand.head then _c.x = hand.head.x + styles.width + 1
  1053.             else _c.x = _bx1 - 4  end
  1054.             _c.y = h - styles.height - 2
  1055.             _c.tail = hand.head
  1056.             _c.visible = true
  1057.             hand.head = _c
  1058.         else
  1059.             if dealerHand.head then _c.x = dealerHand.head.x + styles.width + 1
  1060.             else _c.x = _bx1 + 4  end
  1061.             _c.y = 3
  1062.             _c.tail = dealerHand.head
  1063.             _c.visible = dealerHand.head ~= nil
  1064.             dealerHand.head = _c
  1065.         end
  1066.         _c:display()
  1067.         sleep(0.2)
  1068.     end
  1069. end
  1070.  
  1071. --Returns a point value for how much the hand is worth
  1072. local function calculateHandValue(_hand)
  1073.     local _score, _c = 0, _hand.head
  1074.     local _firstAce = false
  1075.     while _c do
  1076.         if _c.val == 1 and not _firstAce then
  1077.             _score = _score + 11
  1078.             _firstAce = true
  1079.         elseif _c.val > 10 then
  1080.             _score = _score + 10
  1081.         else
  1082.             _score = _score + _c.val
  1083.         end
  1084.         _c = _c.tail
  1085.     end
  1086.     if _score > 21 and _firstAce then
  1087.         _firstAce = false
  1088.         _score = _score - 10
  1089.     end
  1090.     return _score, _firstAce
  1091. end
  1092.  
  1093. local function drawHandValue(_x,_y,_value,_soft)
  1094.     term.setBackgroundColour(colours.blue)
  1095.     term.setTextColour(colours.white)
  1096.     term.setCursorPos(_x,_y)
  1097.     term.write(" ".._value..string.rep(" ", 2 - math.floor(math.log10(_value))))
  1098.     term.setCursorPos(_x,_y+1)
  1099.     if _soft then term.write("soft") else term.write("hard") end
  1100. end
  1101.  
  1102. --Handles events for insurace
  1103. local function handleBlackjackInsurance()
  1104.     if dealerHand.head.val == 1 then
  1105.         local _insuranceCost = math.floor(currBet / 2)
  1106.         _footermsg, _footercolor = "Buy insurance? Y/N", colours.white
  1107.         displayBlackjackBets()
  1108.        
  1109.         local id,_c,p2,p3 = os.pullEvent()
  1110.         while string.lower(_c) ~= 'y' and string.lower(_c) ~= 'n' do
  1111.             if manageMenuMouseEvents(id,p2,p3) then return end
  1112.             id,_c,p2,p3 = os.pullEvent("char")
  1113.         end
  1114.         if string.lower(_c) == 'y' then
  1115.             insurance = currBet / 2
  1116.         end
  1117.     end
  1118. end
  1119.  
  1120. --Displays a little message in the betting box
  1121. local function displayBetMessage(_msg, _col)
  1122.     term.setCursorPos(_bx1 + 1, _by + 1)
  1123.     term.setBackgroundColour(tablebg)
  1124.     term.setTextColour(_col)
  1125.     term.write(_msg)
  1126. end
  1127.  
  1128. --Handles the input for the basic game of blackjack
  1129. local function handleBlackjackInput()
  1130.     handleBlackjackInsurance()
  1131.     local _takings = 0
  1132.     if calculateHandValue(dealerHand) == 21 then
  1133.         sleep(0.2)
  1134.         _c = dealerHand.head
  1135.         while _c do
  1136.             _c.visible = true
  1137.             _c = _c.tail
  1138.         end
  1139.         dealerHand:display()
  1140.         _takings = _takings - currBet + (insurance * 2)
  1141.         bank = bank + math.max(_takings, 0)
  1142.         currBet = 0
  1143.         _footermsg, _footercolor = "Dealer wins! Takings: ".._takings, colours.black
  1144.         displayBlackjackBets()
  1145.         displayBetMessage("LOSE!", colours.red)
  1146.     elseif calculateHandValue(hand) == 21 then
  1147.         _takings = _takings + math.floor(currBet * 2.5) - insurance
  1148.         bank = bank + _takings
  1149.         currBet = 0
  1150.         _footermsg, _footercolor = "Blackjack! Takings: ".._takings, colours.blue
  1151.         displayBlackjackBets()
  1152.         displayBetMessage(" BJ! ", colours.blue)
  1153.     else
  1154.         --The insurance bet, if taken, was lost
  1155.         _takings = _takings - insurance
  1156.         local _handValue, _handSoft = calculateHandValue(hand)
  1157.         drawHandValue(_bx1 - 9, _by + 4, _handValue, _handSoft)
  1158.         local _doubledDown = false
  1159.        
  1160.         --Double down
  1161.         if hand.head.val == hand.head.tail.val then
  1162.             _footermsg, _footercolor = "Double Down? Y/N", colours.white
  1163.             displayBlackjackBets()
  1164.             while true do
  1165.                 local id,p1,p2,p3 = os.pullEvent()
  1166.                 if manageMenuMouseEvents(id,p2,p3) then return end
  1167.                 if id == "key" and p1 == keys.y then
  1168.                     _doubledDown = true
  1169.                     bank = bank - currBet
  1170.                     currBet = currBet + currBet
  1171.                     displayBlackjackBets()
  1172.                     local _c = table.remove(deck, 1)
  1173.                     _c.x = hand.head.x + styles.width + 1
  1174.                     _c.y = hand.head.y
  1175.                     _c.visible = true
  1176.                     _c. tail = hand.head
  1177.                     hand.head = _c
  1178.                     hand:display()
  1179.                     sleep(0.2)
  1180.                     break
  1181.                 elseif id == "key" and p1 == keys.n then
  1182.                     break
  1183.                 end
  1184.             end
  1185.         end
  1186.        
  1187.         if not _doubledDown then
  1188.             --The player chooses to hit or stay
  1189.             local _hitCount = 0
  1190.             local _spaceDiff = styles.width + 1
  1191.             while true do
  1192.                 _footermsg, _footercolor = "(H)it or (S)tand? H/S", colours.white
  1193.                 displayBlackjackBets()
  1194.                
  1195.                 local id,p1,p2,p3 = os.pullEvent()
  1196.                 if manageMenuMouseEvents(id,p2,p3) then return end
  1197.                 if id == "key" and p1 == keys.h then
  1198.                     local _c = table.remove(deck, 1)
  1199.                     _c.x = hand.head.x + _spaceDiff
  1200.                     _c.y = hand.head.y
  1201.                     _c.tail = hand.head
  1202.                     _c.visible = true
  1203.                     hand.head = _c
  1204.                     _hitCount = _hitCount + 1
  1205.                     if _hitCount > 1 and _hitCount < 5 then
  1206.                         _c = hand.head
  1207.                         local _shift = _hitCount + 1
  1208.                         while _c.tail do
  1209.                             _c:displayTable()
  1210.                             _c:move(_c.x - _shift, _c.y)
  1211.                             _shift = _shift - 1
  1212.                             _c = _c.tail
  1213.                         end
  1214.                         _spaceDiff = _spaceDiff - 1
  1215.                     end
  1216.                    
  1217.                     hand:display()
  1218.                     _handValue, _handSoft = calculateHandValue(hand)
  1219.                     drawHandValue(_bx1 - 9, _by + 4, _handValue, _handSoft)
  1220.                     if _handValue >= 21 then
  1221.                         sleep(0.2)
  1222.                         break
  1223.                     end
  1224.                 elseif id == "key" and p1 == keys.s then
  1225.                     sleep(0.2)
  1226.                     break
  1227.                 end
  1228.             end
  1229.         end
  1230.         _footermsg = ""
  1231.        
  1232.         local _hitCount = 0
  1233.         local _spaceDiff = styles.width + 1
  1234.         if _handValue <= 21 then
  1235.             --The dealer takes his turn to hit or stay
  1236.             local _dhandValue, _dhandSoft = calculateHandValue(dealerHand)
  1237.             local _c = dealerHand.head
  1238.             while _c do _c.visible = true _c = _c.tail end
  1239.             dealerHand:display()
  1240.             drawHandValue(13, 4, _dhandValue, _dhandSoft)
  1241.             sleep(0.2)
  1242.            
  1243.             while _dhandValue < 17 and _dhandValue < _handValue do
  1244.                 local _c = table.remove(deck, 1)
  1245.                 _c.x = dealerHand.head.x + _spaceDiff
  1246.                 _c.y = dealerHand.head.y
  1247.                 _c.visible = true
  1248.                 _c.tail = dealerHand.head
  1249.                 dealerHand.head = _c
  1250.                
  1251.                 _hitCount = _hitCount + 1
  1252.                 if _hitCount > 1 and _hitCount < 5 then
  1253.                     _c = dealerHand.head
  1254.                     local _shift = _hitCount + 1
  1255.                     while _c.tail do
  1256.                         _c:displayTable()
  1257.                         _c:move(_c.x - _shift, _c.y)
  1258.                         _shift = _shift - 1
  1259.                         _c = _c.tail
  1260.                     end
  1261.                     _spaceDiff = _spaceDiff - 1
  1262.                 end
  1263.                
  1264.                 _dhandValue = calculateHandValue(dealerHand)
  1265.                 dealerHand:display()
  1266.                 drawHandValue(13, 4, _dhandValue, _dhandSoft)
  1267.                 sleep(0.4)
  1268.             end
  1269.            
  1270.             local _betmsg, _betcol = nil, nil
  1271.             term.setBackgroundColour(tablebg)
  1272.             if _dhandValue > 21 then
  1273.                 term.setCursorPos(_bx1 + 1, _by + 1)
  1274.                 _betmsg, _betcol = " WIN!", colours.blue
  1275.                 _takings = _takings + currBet + currBet - insurance
  1276.                 _footermsg, _footercolor =  "Dealer Bust! Takings: ".._takings, colours.white
  1277.             elseif _dhandValue > _handValue then
  1278.                 term.setCursorPos(_bx1 + 1, _by + 1)
  1279.                 _betmsg, _betcol = "LOSE!", colours.red
  1280.                 _takings = _takings - currBet
  1281.                 _footermsg, _footercolor =  "Dealer Wins! Takings: ".._takings, colours.red
  1282.             elseif _dhandValue == _handValue then
  1283.                 term.setCursorPos(_bx1 + 1, _by + 1)
  1284.                 _takings = currBet
  1285.                 _betmsg, _betcol = "PUSH!", colours.orange
  1286.                 _footermsg, _footercolor =  "Push! Takings: ".._takings, colours.orange
  1287.             else
  1288.                 term.setCursorPos(_bx1 + 1, _by + 1)
  1289.                 _takings = _takings + currBet * 2
  1290.                 _betmsg, _betcol = " WIN!", colours.blue
  1291.                 _footermsg, _footercolor =  "Player Wins! Takings: ".._takings, colours.white
  1292.             end
  1293.             currBet = 0
  1294.             bank = bank + math.max(_takings, 0)
  1295.             displayBlackjackBets()
  1296.             displayBetMessage(_betmsg,_betcol)
  1297.         else
  1298.             _takings = _takings - currBet
  1299.             currBet = 0
  1300.             displayBetMessage("BUST!", colours.red)
  1301.             _footermsg, _footercolor =  "Player Bust! Takings: ".._takings, colours.red
  1302.             displayBlackjackBets()
  1303.         end
  1304.     end
  1305.     --Cleanup
  1306.     currBet = 0
  1307.     insurance = 0
  1308.     splitBet = 0
  1309. end
  1310.  
  1311. --Plays blackjack
  1312. local function playBlackjack()
  1313.     xoff = 0
  1314.     yoff = 0
  1315.     backStyle = styles.backs.alligator
  1316.     backbg = colours.red
  1317.     backfg = colours.white
  1318.     title = "Casino Blackjack"
  1319.    
  1320.     startBlackjack()
  1321.     local playing = true
  1322.     displayBlackjack()
  1323.     while playing do
  1324.         local id,p1,p2,p3 = os.pullEvent()
  1325.         if manageMenuMouseEvents(id,p2,p3) then return end
  1326.         if (id == 'key' and p1 == keys.enter) or
  1327.                 (id == 'mouse_click' and _bjDeck:clicked(p2,p3)) then
  1328.             if bank < tableMin then
  1329.                 _footermsg, _footercolor = "No money left...", colours.red
  1330.                 displayBlackjack()
  1331.             else
  1332.                 dealBlackjack()
  1333.                 handleBlackjackInput()
  1334.             end
  1335.         end
  1336.         playing = not quit and nextGame == nil
  1337.     end
  1338. end
  1339.  
  1340.     --[[
  1341.         Spider Solitaire
  1342.         The windows vista classic. Think freecel but more random and harder
  1343.     ]]--
  1344.  
  1345. --We use 'spaces' from Klondike in the same fashion
  1346. --The decks of cards that have been completed
  1347. local finishedDecks = {}
  1348. --Difficulty, and the (one or two) suits allowed for use in the game.
  1349. local spiderLevel = 1
  1350. local _suit1, _suit2  = nil, nil
  1351. local _settings = {
  1352.     { name = "Easy", decks = "one"; colour = colours.lime; val = 1, y = 4 };
  1353.     { name = "Medium", decks = "two"; colour = colours.orange; val = 2, y = 6};
  1354.     { name = "Hard", decks = "four", colour = colours.red; val = 3, y = 8};
  1355. }
  1356. --The spider draw deck
  1357. local _spdeck = cardP:new( { x = w - styles.width, y = 2, val = #deck } )
  1358.  
  1359. --Displays the game board for spider
  1360. local function displaySpider()
  1361.     term.setBackgroundColour(tablebg)
  1362.     term.clear()
  1363.     for i=1,#spaces do spaces[i]:display() end
  1364.     for i=1,#finishedDecks do finishedDecks[i]:display() end
  1365.     _spdeck:display()
  1366.     displayOverMenuBar()
  1367. end
  1368.  
  1369. --Performs the initial deal (animated as is now the standard)
  1370. local function dealSpider()
  1371.     createDeck(2)
  1372.     shuffleDeck()
  1373.     _spdeck.val = #deck
  1374.     _spdeck:display()
  1375.     _suit1, _suit2 = nil, nil
  1376.     displaySpider()
  1377.     --Changing the suits per difficulty. Standard spider is all/reds/suits but this is a computer!
  1378.     if spiderLevel < 3 then
  1379.         for i=1,#deck do
  1380.             local _c = deck[i]
  1381.             if not _suit1 then _suit1 = deck[i].suit
  1382.             elseif not _suit2 and spiderLevel == 2 and deck[i].suit.colour ~= _suit1.colour then
  1383.                 _suit2 = deck[i].suit
  1384.             elseif spiderLevel == 1 and deck[i].suit ~= _suit1 then
  1385.                 deck[i].suit = _suit1
  1386.             elseif spiderLevel == 2 and (deck[i].suit ~= _suit1 or deck[i].suit ~= _suit2) then
  1387.                 if deck[i].suit.colour == _suit1.colour then deck[i].suit = _suit1
  1388.                 else deck[i].suit = _suit2 end
  1389.             end
  1390.         end
  1391.     end
  1392.     --Constructing the 10 spaces
  1393.     local _cspace = 1
  1394.     for i=1,54 do
  1395.         local _c = table.remove(deck, 1)
  1396.         _c.x = _cspace + styles.width * (_cspace - 1) + 1
  1397.         _c.y = math.ceil(i * 0.1) + 6
  1398.         _c.visible = i > 44
  1399.        
  1400.         if not spaces[_cspace] then
  1401.             spaces[_cspace] = linkedCardP:new()
  1402.             spaces[_cspace].head = _c
  1403.         else
  1404.             _c.tail = spaces[_cspace].head
  1405.             spaces[_cspace].head = _c
  1406.         end
  1407.         _cspace = (_cspace % 10) + 1
  1408.         _c:display()
  1409.         sleep(0.05)
  1410.     end
  1411. end
  1412.  
  1413. --Check to see if a set was made
  1414. local function checkForSet(_deck)
  1415.     --We can assume a set can ONLY be made from the head of the deck
  1416.     local _val,_topSuit = 1, _deck.head.suit
  1417.     local _c = _deck.head
  1418.     while _c and _c.val == _val and _c.suit == _topSuit do
  1419.         _val = _val + 1
  1420.         _c = _c.tail
  1421.     end
  1422.    
  1423.     --All 13 cards are accounted for
  1424.     if _val == 14 then
  1425.         table.insert(finishedDecks,linkedCardP:new())
  1426.         _c = _deck.head
  1427.         _val = 1
  1428.         while _c and _c.val == _val and _c.suit == _topSuit do
  1429.             _deck.head = _c.tail
  1430.             _c.tail = finishedDecks[#finishedDecks].head
  1431.             finishedDecks[#finishedDecks].head = _c
  1432.            
  1433.             if not _deck.head then
  1434.                 _deck.head = cardP:new( { x = _c.x, y = _c.y, visible = true, val = 0 } )
  1435.                 _c:displayTable()
  1436.                 _c:move(#finishedDecks * 2 + 2, 2)
  1437.                 _c:display()
  1438.                 displayOverMenuBar()
  1439.                 _deck.head:display()
  1440.                 break
  1441.             end
  1442.             _c:displayTable()
  1443.             _c:move(#finishedDecks * 2 + 2, 2)
  1444.             _c = _deck.head
  1445.             finishedDecks[#finishedDecks]:display()
  1446.             _c:display()
  1447.             displayOverMenuBar()
  1448.             _val = _val + 1
  1449.             sleep(0.2)
  1450.         end
  1451.         assert(_deck.head ~= nil)
  1452.     end
  1453. end
  1454.  
  1455. --Attempts to move one list of cards onto another list of cards
  1456. local function performSpiderMove(_card, _deck)
  1457.     --We assume a selection is impossible if wrong-suited cards lie above this one
  1458.     if ((selCard.val == _card.val - 1 and _deck.head == _card) or _card.val == 0)
  1459.             and selDeck ~= _deck then
  1460.         local _top = selDeck.head
  1461.         _deck.head = _top
  1462.         local _ydiff = 1
  1463.         _top:displayTable()
  1464.         while _top ~= selCard do
  1465.             _top = _top.tail
  1466.             _ydiff = _ydiff + 1
  1467.             _top:displayTable()
  1468.         end
  1469.    
  1470.         selDeck.head = selCard.tail
  1471.         if selDeck.head == nil then
  1472.             selDeck.head = cardP:new( { val = 0; x = selCard.x; y = selCard.y; } )
  1473.         end
  1474.         selDeck:display()
  1475.         if _card.val == 0 then
  1476.             selCard.tail = nil
  1477.             _deck.head:move(_card.x, _card.y + _ydiff - 1, true)
  1478.         else
  1479.             selCard.tail = nil
  1480.             _deck.head:move(_card.x, _card.y + _ydiff, true)
  1481.             selCard.tail = _card
  1482.         end
  1483.    
  1484.         select()
  1485.         _deck:display()
  1486.         checkForSet(_deck)
  1487.     else
  1488.         local _c = selDeck
  1489.         select(_card, _deck)
  1490.         _c:display()
  1491.         _deck:display()
  1492.     end
  1493. end
  1494.  
  1495. --Draws 10 more cards from the deck
  1496. local function dealSpiderDeck()
  1497.     local _canSkip, _shouldSkip = false, false
  1498.     for i=1,#spaces do
  1499.         if spaces[i].head.tail then _canSkip = true end
  1500.         if spaces[i].head.val == 0 then _shouldSkip = true end
  1501.     end
  1502.     if _canSkip and _shouldSkip then return end
  1503.    
  1504.     for i=1,#spaces do
  1505.         local _c = table.remove(deck, 1)
  1506.         _spdeck.val = #deck
  1507.         _c.visible = true
  1508.         _c.tail = spaces[i].head
  1509.         _c.x = spaces[i].head.x
  1510.         _c.y = spaces[i].head.y + 1
  1511.         spaces[i].head = _c
  1512.         spaces[i]:display()
  1513.         _spdeck:display()
  1514.         displayOverMenuBar()
  1515.         sleep(0.1)
  1516.     end
  1517.    
  1518.     for i=1,#spaces do checkForSet(spaces[i]) end
  1519. end
  1520.  
  1521. --Handles basic spider input and events
  1522. local function handleSpiderInput()
  1523.     local gameWon = false
  1524.     while not gameWon do
  1525.         local id,p1,p2,p3 = os.pullEvent()
  1526.         if manageMenuMouseEvents(id,p2,p3) then
  1527.             return
  1528.         end
  1529.         if id == "mouse_click" then
  1530.             --Check if the deck was clicked
  1531.             if _spdeck:clicked(p2,p3) and _spdeck.val > 0 then
  1532.                 dealSpiderDeck()
  1533.             else
  1534.                 local _complete = false
  1535.                 for i=1,#spaces do
  1536.                     local _c = spaces[i].head
  1537.                     local _topSuit = _c.suit
  1538.                     while _c do
  1539.                         if _c:clicked(p2,p3) then
  1540.                             if _c.val == 0 and selCard then
  1541.                                 performSpiderMove(_c, spaces[i])
  1542.                             elseif _c.visible then
  1543.                                 if not selCard or selDeck == spaces[i] then
  1544.                                     local _d = selDeck
  1545.                                     select(_c, spaces[i])
  1546.                                     if _d then _d:display() end
  1547.                                     selDeck:display()
  1548.                                 elseif _c == selCard then
  1549.                                     break;
  1550.                                 elseif _c == spaces[i].head then
  1551.                                     performSpiderMove(_c, spaces[i])
  1552.                                 end
  1553.                             elseif not _c.visible and _c == spaces[i].head then
  1554.                                 _c.visible = true
  1555.                                 _c:display()
  1556.                                 local _d = selDeck
  1557.                                 select()
  1558.                                 if _d then _d:display() end
  1559.                             else
  1560.                                 local _d = selDeck
  1561.                                 select()
  1562.                                 if _d then _d:display() end
  1563.                             end
  1564.                             _complete = true
  1565.                             break
  1566.                         end
  1567.                         if not _c.tail or _c.tail.suit ~= _topSuit or _c.tail.val ~= _c.val + 1 then
  1568.                             break
  1569.                         end
  1570.                         _c = _c.tail
  1571.                     end
  1572.                     if _complete then break end
  1573.                 end
  1574.                
  1575.                 if not _complete then
  1576.                     local _d = selDeck
  1577.                     select()
  1578.                     if _d then _d:display() end
  1579.                 end
  1580.                
  1581.                 lmX, lmY = p2, p3
  1582.                 txoff, tyoff = xoff, yoff
  1583.                 displayOverMenuBar()
  1584.                
  1585.                 gameWon = #finishedDecks == 8
  1586.             end
  1587.         elseif id == "mouse_drag" then
  1588.             if lmX > 0 and lmY > 0 then
  1589.                 local yDiff = p3 - lmY
  1590.                 --Mouse drag events seem to be pretty overzealous. Or is that a version issue...
  1591.                 if tyoff + yDiff ~= yoff then
  1592.                     yoff = math.min(tyoff + yDiff, 0)
  1593.                     --h-21 is the maximum unrevealed column (6) plus the max revealed column (13)
  1594.                     --plus 3 to reveal the face of the card and 4 more for whitespace
  1595.                     yoff = math.max(yoff, h - 30)
  1596.                     displaySpider()
  1597.                 end
  1598.             end
  1599.         elseif id == "mouse_scroll" then
  1600.             yoff = math.min(yoff - p1, 0)
  1601.             yoff = math.max(yoff, h - 30)
  1602.             displaySpider()
  1603.             --Check each space on the board
  1604.         elseif id == "key" then
  1605.             if p1 == keys.down then
  1606.                 yoff = math.min(yoff + 1, 0)
  1607.                 displaySpider()
  1608.             elseif p1 == keys.up then
  1609.                 yoff = math.max(yoff - 1, h - 30)
  1610.                 displaySpider()
  1611.             end
  1612.         end
  1613.     end
  1614.    
  1615.     --A final win animation
  1616.     local _t = {
  1617.         { x = math.floor(w/2); y = math.floor(h/2); xdir = -1; ydir = -1; };
  1618.         { x = math.floor(w/2) + 1; y = math.floor(h/2); xdir = 1; ydir = -1; };
  1619.         { x = math.floor(w/2); y = math.floor(h/2) + 1; xdir = -1; ydir = -0.25; };
  1620.         { x = math.floor(w/2) + 1; y = math.floor(h/2) + 1; xdir = 1; ydir = -0.25; };
  1621.         { x = math.floor(w/2); y = math.floor(h/2) + 2;  xdir = -1; ydir = 0.25; };
  1622.         { x = math.floor(w/2) + 1; y = math.floor(h/2) + 2; xdir = 1; ydir = 0.25; };
  1623.         { x = math.floor(w/2); y = math.floor(h/2) + 3; xdir = -1; ydir = 1; };
  1624.         { x = math.floor(w/2) + 1; y = math.floor(h/2) + 3; xdir = 1; ydir = 1; };
  1625.     }
  1626.     for i = 1, #finishedDecks do
  1627.         for j = 1, #_t do
  1628.             term.setCursorPos(_t[j].x, _t[j].y)
  1629.             term.setBackgroundColour(tablebg)
  1630.             term.setTextColour(finishedDecks[i].head.suit.colour)
  1631.             term.write(finishedDecks[i].head.suit.char)
  1632.             _t[j].x = _t[j].x + _t[j].xdir
  1633.             _t[j].y = _t[j].y + _t[j].ydir
  1634.         end
  1635.         displayOverMenuBar()
  1636.         sleep(0.2)
  1637.     end
  1638. end
  1639.  
  1640. --Chooses easy medium or hard
  1641. local function chooseDifficuly()
  1642.     for i=1,#_settings do
  1643.         local _s = _settings[i]
  1644.         term.setCursorPos(10, _s.y)
  1645.         term.setBackgroundColour(colours.grey)
  1646.         term.setTextColour(_s.colour)
  1647.         term.write(" ".._s.name.." ")
  1648.         term.setBackgroundColour(tablebg)
  1649.         term.setTextColour(colours.white)
  1650.         term.setCursorPos(20, _s.y)
  1651.         term.write(_s.decks.." suit(s)")
  1652.     end
  1653.    
  1654.     while true do
  1655.         local id,p1,p2,p3 = os.pullEvent()
  1656.         if manageMenuMouseEvents(id,p2,p3) then return false end
  1657.         if id == "mouse_click" then
  1658.             for i=1,#_settings do
  1659.                 if p2 >= 10 and p2 <= 25 and _settings[i].y == p3 then
  1660.                     spiderLevel = _settings[i].val
  1661.                     return true
  1662.                 end
  1663.             end
  1664.         end
  1665.     end
  1666. end
  1667.  
  1668. --Deals up a good old fashion game of spider
  1669. local function playSpider()
  1670.     xoff = 0
  1671.     yoff = 0
  1672.     backbg = colours.purple
  1673.     backfg = colours.black
  1674.     backStyle = styles.backs.spooky
  1675.     title = "Spider Solitaire"
  1676.     spaces = {}
  1677.     finishedDecks = {}
  1678.     _spdeck.val = 1
  1679.    
  1680.     displaySpider()
  1681.     if not chooseDifficuly() then return end
  1682.     displaySpider()
  1683.     dealSpider()
  1684.     handleSpiderInput()
  1685. end
  1686.    
  1687.     --[[
  1688.         Golf
  1689.         Because apparently I'm enjoying making these card games
  1690.     ]]--
  1691.  
  1692. --Like spider and klondike, this uses the spaces deck (7 slots like klondike
  1693.  
  1694. --The card clicked to draw another card to the tableau
  1695. local _gfcard = cardP:new( {
  1696.     x = w/2 - styles.width / 2 - styles.width + 1;
  1697.     y = h - styles.height - 1;
  1698.     visible = false;
  1699.     val = 1;
  1700. } )
  1701. --The foundation
  1702. local foundation = linkedCardP:new()
  1703.  
  1704. --Makes sure golf is ready for the next game
  1705. local function setupGolf()
  1706.     createDeck(1)
  1707.     shuffleDeck()
  1708.     _gfcard.val = #deck
  1709.     foundaction = linkedCardP:new()
  1710.     foundation.head = cardP:new({
  1711.         x = _gfcard.x + 2 + styles.width;
  1712.         y = _gfcard.y;
  1713.         visible = false;
  1714.         val = 0;
  1715.     })
  1716.     local _extraSpace = (w - (styles.width * 7)) / 8
  1717.     for i=1,7 do
  1718.         spaces[i] = linkedCardP:new()
  1719.         spaces[i].head = cardP:new({
  1720.             x = _extraSpace * i + styles.width * (i - 1) + 1;
  1721.             y = 3;
  1722.             visible = false;
  1723.             val = 0;
  1724.         })
  1725.     end
  1726. end
  1727.  
  1728. --Gets the score of a game of golf
  1729. local function getGolfScore()
  1730.     local _score = 0
  1731.     for i=1,#spaces do
  1732.         local _c = spaces[i].head
  1733.         while _c and _c.val ~= 0 do
  1734.             _c = _c.tail
  1735.             _score = _score + 1
  1736.         end
  1737.     end
  1738.     if _score == 0 then _score = -#deck end
  1739.     return _score
  1740. end
  1741.  
  1742. --Displays golf
  1743. local function displayGolf()
  1744.     term.setBackgroundColour(tablebg)
  1745.     term.clear()
  1746.     for i=1,#spaces do if spaces[i] then spaces[i]:display() else break end end
  1747.     _gfcard:display()
  1748.     foundation:display()
  1749.     displayOverMenuBar()
  1750.     term.setCursorPos(3,h)
  1751.     term.setBackgroundColour(tablebg)
  1752.     term.setTextColour(colours.black)
  1753.     local _score = getGolfScore()
  1754.     if _score < -15 then _score = 0 end
  1755.     term.write("Score: ".._score.."  ")
  1756. end
  1757.  
  1758. --Deals up a hand of golf
  1759. local function dealGolf()
  1760.     local _index = 1
  1761.     for i=1,35 do
  1762.         local _c = table.remove(deck, 1)
  1763.         _c.visible = true
  1764.         _c.x = spaces[_index].head.x
  1765.        
  1766.         if spaces[_index].head.val == 0 then
  1767.             _c.y = spaces[_index].head.y
  1768.         else
  1769.             _c.y = spaces[_index].head.y + 1
  1770.         end
  1771.         _c.tail = spaces[_index].head
  1772.         spaces[_index].head = _c
  1773.         _c:display()
  1774.         sleep(0.1)
  1775.        
  1776.         _index = _index % 7 + 1
  1777.     end
  1778.    
  1779.     displayGolf()
  1780. end
  1781.  
  1782. --Attempts to move a card from the tabluea to the foundation
  1783. local function tryGolfMove(_deck)
  1784.     if foundation.head.val == 13 or _deck.head.val == 0 or foundation.head.val == 0 then
  1785.         return false
  1786.     end
  1787.     local scoreDiff = foundation.head.val - _deck.head.val
  1788.     if math.abs(scoreDiff) == 1 then
  1789.         local _c = _deck.head
  1790.         _deck.head = _c.tail
  1791.         _c:displayTable()
  1792.         _c:move(foundation.head.x, foundation.head.y)
  1793.         _c.tail = foundation.head
  1794.         foundation.head = _c
  1795.         _deck:display()
  1796.         foundation:display()
  1797.         return true
  1798.     else return false end
  1799. end
  1800.  
  1801. --Handles all that golfing you'll be doing
  1802. local function handleGolfInput()
  1803.     local _currScore = getGolfScore()
  1804.     while _currScore > 0 do
  1805.         local id,p1,p2,p3 = os.pullEvent()
  1806.         if manageMenuMouseEvents(id,p2,p3) then return end
  1807.        
  1808.         if id == "mouse_click" then
  1809.             if _gfcard.val > 0 and _gfcard:clicked(p2,p3) then
  1810.                 _c = table.remove(deck, 1)
  1811.                 _c.x = foundation.head.x
  1812.                 _c.y = foundation.head.y
  1813.                 _c.visible = true
  1814.                 _c.tail = foundation.head
  1815.                 foundation.head = _c
  1816.                 _gfcard.val = #deck
  1817.                 foundation:display()
  1818.                 _gfcard:display()
  1819.             else
  1820.                 for i=1,#spaces do
  1821.                     local _c = spaces[i].head
  1822.                     --Moving from space to the foundation
  1823.                     if _c:clicked(p2,p3) then
  1824.                         if tryGolfMove(spaces[i]) then
  1825.                             _currScore = getGolfScore()
  1826.                             term.setCursorPos(3,h)
  1827.                             term.setBackgroundColour(tablebg)
  1828.                             term.setTextColour(colours.black)
  1829.                             term.write("Score: "..getGolfScore().."  ")
  1830.                         end
  1831.                     end
  1832.                 end
  1833.             end
  1834.         end
  1835.     end
  1836.     displayGolf()
  1837.     term.setBackgroundColour(tablebg)
  1838.     term.setTextColour(colours.black)
  1839.     term.setCursorPos(_gfcard.x + 2, _gfcard.y - 3)
  1840.     term.write("/'")
  1841.     term.setCursorPos(_gfcard.x, _gfcard.y - 2)
  1842.     term.write("o/")
  1843. end
  1844.    
  1845.  
  1846. local function playGolf()
  1847.     xoff = 0
  1848.     yoff = 0
  1849.     backbg = colours.yellow
  1850.     backfg = colours.blue
  1851.     backStyle = styles.backs.royal
  1852.     title = "Golf"
  1853.    
  1854.     setupGolf()
  1855.     displayGolf()
  1856.     dealGolf()
  1857.     handleGolfInput()
  1858. end
  1859.  
  1860.     --[[
  1861.         Game Management Stuff
  1862.     ]]--
  1863.    
  1864. table.insert(menuOptions, { name = "Klondike", key = "K", enabled = true, value = function()
  1865.     currOverDraw = drawKlondike
  1866.     nextGame = playKlondike
  1867. end })
  1868. table.insert(menuOptions, { name = "Blackjack", key = "B", enabled = true, value = function()
  1869.     currOverDraw = displayBlackjack
  1870.     nextGame = playBlackjack
  1871. end })
  1872. table.insert(menuOptions, { name = "Spider", key = "S", enabled = true, value = function()
  1873.     currOverDraw = displaySpider
  1874.     nextGame = playSpider
  1875. end })
  1876. table.insert(menuOptions, { name = "Golf", key = "G", enabled = true, value = function()
  1877.     currOverDraw = displayGolf
  1878.     nextGame = playGolf
  1879. end })
  1880. table.insert(menuOptions, { name = "--------", enabled = false, value = nil })
  1881. table.insert(menuOptions, { name = "Quit", key = "Q", enabled = true, value = function()
  1882.     currOverDraw = nil
  1883.     nextGame = nil
  1884.     quit = true
  1885. end })
  1886.  
  1887. if not term.isColor() then print("For advanced computers only") return end
  1888.  
  1889. local function displayNitrosoftTitle()
  1890.     shell.run("clear")
  1891.     local _w,_h = term.getSize()
  1892.     local _t1,_t2 = "nitrosoft", "games"
  1893.     term.setCursorPos(math.floor(_w/2-#_t1), math.floor(_h/2))
  1894.     if term.isColour() then term.setTextColour(colours.blue) end
  1895.     term.write(_t1)
  1896.     term.setCursorPos(math.floor(_w/2-#_t2/2),math.floor(_h/2)+1)
  1897.     term.setTextColour(colours.white)
  1898.     term.write(_t2)
  1899.     term.setCursorPos(math.floor(_w/2-#_t1), math.floor(_h/2)+2)
  1900.     if term.isColour() then term.setTextColour(colours.red) end
  1901.     term.write(string.rep("-",#_t1*2))
  1902.     if term.isColour() then
  1903.         term.setBackgroundColour(colours.green)
  1904.         term.setCursorPos(_w/2+#_t1-4, math.floor(_h/2)-2)
  1905.         term.write("  ")
  1906.         term.setCursorPos(_w/2+#_t1-4, math.floor(_h/2)-1)
  1907.         term.write("  ")
  1908.         term.setBackgroundColour(colours.white)
  1909.         term.setTextColour(colours.red)
  1910.         term.setCursorPos(_w/2+#_t1-3, math.floor(_h/2)-1)
  1911.         term.write("4 ")
  1912.         term.setCursorPos(_w/2+#_t1-3, math.floor(_h/2))
  1913.         term.write(" v")
  1914.     end
  1915.     term.setBackgroundColour(colours.black)
  1916.     term.setTextColour(colours.white)
  1917.     term.setCursorPos(1,_h)
  1918.     os.pullEvent("key")
  1919. end
  1920. displayNitrosoftTitle()
  1921.  
  1922. --The over menu game fnction
  1923. local function overMenuInput()
  1924.     term.setBackgroundColour(tablebg)
  1925.     term.clear()
  1926.     displayOverMenuBar()
  1927.     while not quit do
  1928.         if nextGame then
  1929.             local _game = nextGame
  1930.             nextGame = nil
  1931.             _game()
  1932.         else
  1933.             local id,p1,p2,p3 = os.pullEvent()
  1934.             manageMenuMouseEvents(id,p2,p3)
  1935.         end
  1936.     end
  1937. end
  1938.  
  1939. overMenuInput()
  1940.    
  1941. term.setBackgroundColour(colours.black)
  1942. shell.run("clear")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement