Advertisement
Bolodefchoco_LUAXML

[Game] Chess (Beta)

Feb 10th, 2018
688
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.29 KB | None | 0 0
  1. string.split = function(value, pattern, f)
  2.     local out = {}
  3.     for v in string.gmatch(value, pattern) do
  4.         out[#out + 1] = (not f and v or f(v))
  5.     end
  6.     return out
  7. end
  8. table.copy = function(list)
  9.     local out = {}
  10.     for k,v in next, list do
  11.         out[k] = (type(v) == "table" and table.copy(v) or v)
  12.     end
  13.     return out
  14. end
  15.  
  16. -- Board
  17. local setBoard = function()
  18.     return
  19.     {
  20.         {'♜', '♞', '♝', '♛', '♚', '♝', '♞', '♜'},
  21.         {'♟', '♟', '♟', '♟', '♟', '♟', '♟', '♟'},
  22.         {'', '', '', '', '', '', '', ''},
  23.         {'', '', '', '', '', '', '', ''},
  24.         {'', '', '', '', '', '', '', ''},
  25.         {'', '', '', '', '', '', '', ''},
  26.         {'♙', '♙', '♙', '♙', '♙', '♙', '♙', '♙'},
  27.         {'♖', '♘', '♗', '♕', '♔', '♗', '♘', '♖'}
  28.     }
  29. end
  30. local board = setBoard()
  31. local colors = {
  32.     background = 0x2F363F,
  33.     whiteSquare = 0xFFCE9E,
  34.     whitePiece = 'FFFFFF',
  35.     blackSquare = 0xD18B47,
  36.     blackPiece = '1',
  37.     specialMove = 0xB300EF,
  38.     emptyMove = 0x2ECF73,
  39.     captureMove = 0xAF2A2A,
  40.     lastMove = 0xFFCF5F,
  41.     selectedPiece = '<PT>',
  42. }
  43. local pieces = {
  44.     king = 1,
  45.     queen = 2,
  46.     rook = 3,
  47.     bishop = 4,
  48.     knight = 5,
  49.     pawn = 6
  50. }
  51.  
  52. -- Info
  53. local playerInfo = function()
  54.     return
  55.     {
  56.         [1] = { name = "", pieces = 16, castling = true, lastMove = "" },
  57.         [2] = { name = "", pieces = 16, castling = true, lastMove = "" },
  58.     }
  59. end
  60. local players = playerInfo()
  61. local moveTimer = 0
  62. local canStart = false
  63. local currentPlayer = 2
  64. local currentPlayerColor = ""
  65. local lastMove = {}
  66.  
  67. -- StringReference
  68. local stringReference = {}
  69. stringReference.emptySquare = "<textformat leftmargin='30' rightmargin='30' leading='30'>"
  70. stringReference.HREF_select = "<a href='event:select_%s_%s_%s_%s'>"
  71. stringReference.squareFormat = "<font size='25'><B>"
  72.  
  73. stringReference.select = stringReference.emptySquare .. stringReference.HREF_select .. "\n"
  74. stringReference.piece = stringReference.squareFormat .. stringReference.HREF_select .. "%s"
  75. stringReference.castling = stringReference.emptySquare .. "<a href='event:kingpass_%s_%s_%s'>\n"
  76.  
  77. -- System
  78. local isWhitePiece = function(p)
  79.     p = string.byte(p, 3, 3)
  80.     return p > 147 and p < 154
  81. end
  82. local existSquare = function(row, column)
  83.     return board[row] and board[row][column]
  84. end
  85. local isPieceSquare = function(row, column)
  86.     return existSquare(row, column) and board[row][column] ~= ''
  87. end
  88. local pieceDifColor = function(p1, p2)
  89.     return isWhitePiece(p1) ~= isWhitePiece(p2)
  90. end
  91. local pieceID = function(p)
  92.     return (string.byte(p, 3, 3) - 148) % 6 + 1
  93. end
  94. local checkCapture = function(n, row, column, newRow, newColumn, boolCapture, boolEmpty)
  95.     boolCapture = boolCapture == nil or boolCapture
  96.     boolEmpty = boolEmpty == nil or boolEmpty
  97.  
  98.     if isPieceSquare(newRow, newColumn) then
  99.         if boolCapture and pieceDifColor(board[row][column], board[newRow][newColumn]) then
  100.             uiupdateSquare(newRow, newColumn, n, colors.captureMove, string.format(stringReference.piece, row, column, newRow, newColumn, board[newRow][newColumn]))
  101.         end
  102.         return true
  103.     end
  104.     if boolEmpty then
  105.         uiupdateSquare(newRow, newColumn, n, colors.emptyMove, string.format(stringReference.select, row, column, newRow, newColumn))
  106.     end
  107.     return false
  108. end
  109.  
  110. local border = function(text)
  111.     ui.addTextArea(-4, "<font color='#1'>" .. text, nil, 5, 367, 792, nil, 1, 1, 0, true)
  112.     ui.addTextArea(-5, "<PS>" .. text, nil, 5, 365, 790, nil, 1, 1, 0, true)
  113. end
  114. local changeTurn = function()
  115.     currentPlayer = (currentPlayer == 1 and 2 or 1)
  116.     currentPlayerColor = ({"White", "Black"})[currentPlayer]
  117.    
  118.     local text = "<B><p align='center'><font size='18'>" .. currentPlayerColor .. " turn!"
  119.     border(text)
  120. end
  121. local restart = function()
  122.     canStart = false
  123.  
  124.     uiclearColoredSquares()
  125.    
  126.     for k, v in next, players do
  127.         tfm.exec.movePlayer(v.name, 400, 375)
  128.     end
  129.    
  130.     board = setBoard()
  131.     players = playerInfo()
  132.  
  133.     currentPlayer = 2
  134.     for i = 3, 5 do
  135.         ui.removeTextArea(-i)
  136.     end
  137.    
  138.     for i = 1, 2 do
  139.         ui.addTextArea(-i, "<font color='#" .. ({"White", "Black"})[i] .. "'><p align='center'><font size='20'>[Space]", nil, 5 + (i - 1) * 595, 180, 200, nil, 1, 1, 0, true)
  140.     end
  141.    
  142.     uiboard()
  143. end
  144.  
  145. -- UI
  146. local coloredSquares = {}
  147. uiclearColoredSquares = function()
  148.     for k, v in next, table.copy(coloredSquares) do
  149.         if v then
  150.             ui.removeTextArea(k)
  151.             coloredSquares[k] = nil
  152.         end
  153.     end
  154. end
  155.  
  156. uiupdateSquare = function(row, column, n, color, href, notNeg)
  157.     if existSquare(row, column) then
  158.         local isNeg = false
  159.         if not notNeg then
  160.             isNeg = not not (color or href)
  161.         end
  162.  
  163.         local squareText = href or board[row][column] == '' and '' or string.format("%s%s<a href='event:square_%s_%s'>%s", stringReference.squareFormat, "<font color='#" .. colors[(isWhitePiece(board[row][column]) and "white" or "black") .. "Piece"] .. "'>", row, column, board[row][column])
  164.        
  165.         ui.addTextArea((row..column) * (isNeg and -1 or 1), squareText, n, 252 + (column - 1) * 38, 50 + (row - 1) * 38, 30, 30, color or (((row + column) % 2 == 0) and colors.whiteSquare or colors.blackSquare), 1, 1, true)
  166.        
  167.         ui.setShamanName(string.format("-   <G>|   <S>%s x %s", players[1].pieces, players[2].pieces))
  168.         if isNeg then
  169.             coloredSquares[-(row..column)] = true
  170.         end
  171.     end
  172. end
  173.  
  174. local uiupdateLastMove = function(...)
  175.     if lastMove[1] and lastMove[2] then
  176.         uiupdateSquare(lastMove[1], lastMove[2])
  177.     end
  178.     lastMove = {...}
  179. end
  180.  
  181. uiboard = function(n)
  182.     --[[
  183.         [11:88] -> Squares
  184.         [-88:-11] -> Effects
  185.         [-10:0] -> Others
  186.     ]]
  187.     ui.addTextArea(0, "", nil, 247, 45, 306, 306, colors.background, colors.background, 1, true)
  188.     for row = 1, 8 do
  189.         for column = 1, 8 do
  190.             uiupdateSquare(row, column)
  191.         end
  192.     end
  193. end
  194.  
  195. -- Callbacks
  196. eventTextAreaCallback = function(i, n, c)
  197.     if players[currentPlayer].name == n and os.time() > moveTimer then
  198.         moveTimer = os.time() + 100
  199.    
  200.         c = string.split(c, "[^_]+", function(value)
  201.             return tonumber(value) or value
  202.         end)
  203.        
  204.         local row, column = c[2], c[3]
  205.        
  206.         uiclearColoredSquares()
  207.         if c[1] == "transform" then
  208.             ui.removeTextArea(-3, n)
  209.             board[row][column] = string.char(226, 153, (c[4] == 2 and c[5] + 6 or c[5]))
  210.            
  211.             uiupdateSquare(row, column, nil, colors.lastMove, nil, true)
  212.            
  213.             changeTurn()
  214.         elseif c[1] == "kingpass" then
  215.             local initialSquare = (c[4] == "left" and -1 or 1)
  216.             local finalSquare = column + (c[4] == "right" and 3 or -4)
  217.            
  218.             local iniTwo = column + (2 * initialSquare)
  219.             local iniSig = column + (1 * initialSquare)
  220.            
  221.             board[row][iniTwo] = board[row][column]
  222.             board[row][column] = ''
  223.            
  224.             board[row][iniSig] = board[row][finalSquare]
  225.             board[row][finalSquare] = ''
  226.            
  227.             players[currentPlayer].castling = false
  228.             players[currentPlayer].lastMove = ''
  229.            
  230.             uiupdateLastMove(row, iniTwo)
  231.            
  232.             uiupdateSquare(row, iniTwo, nil, colors.lastMove, nil, true)
  233.             uiupdateSquare(row, column)
  234.             uiupdateSquare(row, iniSig)
  235.             uiupdateSquare(row, finalSquare)
  236.            
  237.             changeTurn()
  238.         else
  239.             local piece = pieceID(board[row][column])
  240.        
  241.             if c[1] == "square" then
  242.                 local whitePiece = isWhitePiece(board[row][column])
  243.                 if (currentPlayer == 1 and not whitePiece) or (currentPlayer == 2 and whitePiece) then
  244.                     tfm.exec.chatMessage("<S>[#Chess] You can move only the " .. currentPlayerColor .. " pieces!", n)
  245.                     return
  246.                 end
  247.  
  248.                 -- Highlights the piece you've selected
  249.                 uiupdateSquare(row, column, n, nil, stringReference.squareFormat .. colors.selectedPiece .. board[row][column])
  250.                
  251.                 local dir = whitePiece and -1 or 1
  252.                 if piece == pieces.pawn then
  253.                     -- In front, 1 or 2 squares
  254.                     for i = 1, ((row == 2 or row == 7) and 2 or 1) do
  255.                         local newRow = row + i * dir
  256.                        
  257.                         if isPieceSquare(newRow, column) then
  258.                             break
  259.                         end
  260.                        
  261.                         uiupdateSquare(newRow, column, n, ((newRow == 1 or newRow == 8) and colors.specialMove or colors.emptyMove), string.format(stringReference.select, row, column, newRow, column))
  262.                     end
  263.                    
  264.                     -- En passant
  265.                     if players[3 - currentPlayer].lastMove ~= "" then
  266.                         local grid = string.split(players[3 - currentPlayer].lastMove, "[^_]+", tonumber)
  267.                         if grid[1] and grid[2] then
  268.                             for i = -1, 1, 2 do
  269.                                 if grid[1] == row and grid[2] + i == column then
  270.                                     uiupdateSquare(grid[1] + dir, grid[2], n, colors.specialMove, string.format(stringReference.piece, row, column, grid[1], grid[2] .. "_" .. (grid[1] + dir), "\n"))
  271.                                     break
  272.                                 end
  273.                             end
  274.                         end
  275.                     end
  276.                 end
  277.                 if piece == pieces.rook or piece == pieces.queen or piece == pieces.king then
  278.                     local range = (piece == pieces.king and 1 or 8)
  279.                    
  280.                     -- Horizontal and Vertical
  281.                     local coord = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}}
  282.                     for i = 1, 4 do
  283.                         for j = 1, range do
  284.                             local newRow = row + j * coord[i][1]
  285.                             local newColumn = column + j * coord[i][2]
  286.                            
  287.                             if checkCapture(n, row, column, newRow, newColumn) then
  288.                                 break
  289.                             end
  290.                         end
  291.                     end
  292.                 end
  293.                 if piece == pieces.knight then
  294.                     -- L Shape
  295.                     local coord = {{-2, -1}, {-1, -2}, {-2, 1}, {-1, 2}, {1, -2}, {2, -1}, {1, 2}, {2, 1}}
  296.                     for i = 1, 8 do
  297.                         local newRow = row + coord[i][1]
  298.                         local newColumn = column + coord[i][2]
  299.                        
  300.                         checkCapture(n, row, column, newRow, newColumn)
  301.                     end
  302.                 end
  303.                 if piece == pieces.bishop or piece == pieces.queen or piece == pieces.king or piece == pieces.pawn then
  304.                     local isPawn = piece == pieces.pawn
  305.                     local range = ((piece == pieces.king or isPawn) and 1 or 8)
  306.                    
  307.                     -- Diagonal
  308.                     local coord = {{-1, -1}, {-1, 1}, {1, -1}, {1, 1}}
  309.                     for i = 1, 4 do
  310.                         for j = 1, range do
  311.                             local newRow = row + j * coord[i][1]
  312.                             local newColumn = column + j * coord[i][2]
  313.                            
  314.                             local check = checkCapture(n, row, column, newRow, newColumn, (not isPawn or coord[i][1] == dir), not isPawn)
  315.                             if check then
  316.                                 break
  317.                             end
  318.                         end
  319.                     end
  320.                 end
  321.                 if piece == pieces.king then
  322.                     -- Castling
  323.                     if players[currentPlayer].castling then
  324.                         local d = 1
  325.                         for i = 1, 2 do
  326.                             if not isPieceSquare(row, column + d) and not isPieceSquare(row, column + (d * 2)) then
  327.                                 if d > 0 or not isPieceSquare(row, column - 3) then
  328.                                     uiupdateSquare(row, column + (d > 0 and 2 or -3), n, colors.specialMove, string.format(stringReference.castling, row, column, (d > 0 and "right" or "left")))
  329.                                 end
  330.                             end
  331.                             d = -d
  332.                         end
  333.                     end
  334.                 end
  335.             elseif c[1] == "select" then
  336.                 local newRow, newColumn = c[4], c[5]
  337.            
  338.                 uiupdateLastMove(c[6] or newRow, newColumn)
  339.                
  340.                 -- Updates the squares
  341.                 board[c[6] or newRow][newColumn] = board[row][column]
  342.                 if c[6] then
  343.                     board[newRow][newColumn] = ''
  344.                     uiupdateSquare(c[6], newColumn, nil, colors.lastMove, nil, true)
  345.                 end
  346.                 uiupdateSquare(newRow, newColumn, nil, (not c[6] and colors.lastMove or nil), nil, true)
  347.                
  348.                 board[row][column] = ''
  349.                 uiupdateSquare(row, column)
  350.                
  351.                 -- Checks the attack
  352.                 if isPieceSquare(row, column) and isPieceSquare(newRow, newColumn) and pieceDifColor(board[row][column], board[newRow][newColumn]) then
  353.                     players[3 - currentPlayer].pieces = players[3 - currentPlayer].pieces - 1
  354.                    
  355.                     -- Checkmate
  356.                     if pieceID(board[newRow][newColumn]) == pieces.king then
  357.                         tfm.exec.chatMessage("<S>[#Chess] " .. currentPlayerColor .. " pieces won!")
  358.                         tfm.exec.setPlayerScore(n, 10, true)
  359.                         restart()
  360.                         return
  361.                     end
  362.                 end
  363.                
  364.                 -- Sets the lastMove
  365.                 players[currentPlayer].lastMove = ((piece == pieces.pawn and math.abs(newRow - row) == 2) and (newRow .. "_" .. newColumn) or '')
  366.  
  367.                 -- Pawn promotion
  368.                 if piece == pieces.pawn then
  369.                     if newRow == 1 or newRow == 8 then
  370.                         local text = "<textformat leading='40'><p align='center'><font size='25'>PAWN PROMOTION<font size='15'>\n<B>"
  371.                         for k, v in next, {{'<ROSE>Queen', 149}, {'<J>Rook', 150}, {'<PT>Bishop', 151}, {'<BV>Knight', 152}} do
  372.                             text = text .. string.format("<a href='event:transform_%s_%s_%s_%s'>%s\n", newRow, newColumn, currentPlayer, v[2], "<CH>" .. string.char(226, 153, v[2]) .. " " .. v[1] .. " <CH>" .. string.char(226, 153, v[2] + 6))
  373.                         end
  374.                         ui.addTextArea(-3, text, n, 247, 45, 306, 306, nil, nil, .9, true)
  375.                         border("<B><p align='center'><font size='18'>" .. currentPlayerColor .. " Pawn promotion!")
  376.                         return
  377.                     end
  378.                 -- Disable Castling
  379.                 elseif piece == pieces.king or piece == pieces.rook then
  380.                     players[currentPlayer].castling = false
  381.                 end
  382.                
  383.                 changeTurn()
  384.             end
  385.         end
  386.     end
  387. end
  388.  
  389. -- Loop
  390. eventLoop = function()
  391.     if not canStart then
  392.         local totalPlayers = 0
  393.         for i = 1, 2 do
  394.             if players[i].name == "" then
  395.                 tfm.exec.addShamanObject(0, 40 + 720 * (i - 1), 200)
  396.             else
  397.                 totalPlayers = totalPlayers + 1
  398.             end
  399.         end
  400.        
  401.         if totalPlayers == 2 then
  402.             canStart = true
  403.             changeTurn()
  404.         end
  405.     end
  406. end
  407.  
  408. -- New Game
  409. eventNewPlayer = function(n)
  410.     uiboard(n)
  411.     tfm.exec.respawnPlayer(n)
  412.     system.bindKeyboard(n, 32, true, true)
  413.     tfm.exec.chatMessage("<S>[#Chess] Welcome to the module! Choose an armchair and enjoy the game with a friend!\n\tYou, chess lord, report any bug to Bolodefchoco!", n)
  414. end
  415.  
  416. -- Keyboard & Emote
  417. eventKeyboard = function(n, k, d, x)
  418.     for k, v in next, players do
  419.         if v.name == n then
  420.             return
  421.         end
  422.     end
  423.    
  424.     local id = x < 76 and 1 or x > 724 and 2 or 0
  425.     if id > 0 then
  426.         if players[id].name == "" then
  427.             players[id].name = n
  428.             local color = ({"White", "Black"})[id]
  429.             ui.addTextArea(-id, "<font color='#" .. colors[string.lower(color) .. "Piece"] .. "' size='20'><p align='center'>" .. n .. "\n«" .. color .. "»", nil, 5 + (id - 1) * 595, 180, 200, nil, 1, 1, 0, true)
  430.             tfm.exec.playEmote(n, 8)
  431.             tfm.exec.chatMessage("<S>[#Chess] " .. n .. " is in the " .. color .. " team!")
  432.         end
  433.     end
  434. end
  435. eventEmotePlayed = function(n, t)
  436.     if t == 8 then
  437.         eventKeyboard(n, 32, nil, tfm.get.room.playerList[n].x)
  438.     end
  439. end
  440.  
  441. -- Player left
  442. eventPlayerLeft = function(n)
  443.     for i = 1, 2 do
  444.         if players[i].name == n then
  445.             tfm.exec.chatMessage("<S>[#Chess] " .. n .. " left the game :(")
  446.             restart()
  447.             break
  448.         end
  449.     end
  450. end
  451.  
  452. -- Respawn
  453. eventPlayerDied = tfm.exec.respawnPlayer
  454.  
  455. -- Init
  456. for k, v in next, {"AutoShaman", "AfkDeath", "AutoNewGame", "AutoScore"} do
  457.     tfm.exec["disable" .. v]()
  458. end
  459.  
  460. tfm.exec.newGame(1995980)
  461. restart()
  462. table.foreach(tfm.get.room.playerList, eventNewPlayer)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement