From 20c9ea62ce3e27a1bf04853be34a44269d9b8dfe Mon Sep 17 00:00:00 2001 From: kilbith Date: Tue, 27 Oct 2015 11:26:08 +0100 Subject: [PATCH] Add a Chess Board with game in formspec --- chess.lua | 642 ++++++++++++++++++++++++++++++++++ init.lua | 1 + textures/bishop_black.png | Bin 0 -> 170 bytes textures/bishop_white.png | Bin 0 -> 175 bytes textures/chess_bg.png | Bin 0 -> 848 bytes textures/chessboard_sides.png | Bin 0 -> 195 bytes textures/chessboard_top.png | Bin 0 -> 286 bytes textures/king_black.png | Bin 0 -> 238 bytes textures/king_white.png | Bin 0 -> 188 bytes textures/knight_black.png | Bin 0 -> 231 bytes textures/knight_white.png | Bin 0 -> 235 bytes textures/pawn_black.png | Bin 0 -> 166 bytes textures/pawn_white.png | Bin 0 -> 166 bytes textures/queen_black.png | Bin 0 -> 247 bytes textures/queen_white.png | Bin 0 -> 194 bytes textures/rook_black.png | Bin 0 -> 172 bytes textures/rook_white.png | Bin 0 -> 178 bytes 17 files changed, 643 insertions(+) create mode 100644 chess.lua create mode 100644 textures/bishop_black.png create mode 100644 textures/bishop_white.png create mode 100644 textures/chess_bg.png create mode 100644 textures/chessboard_sides.png create mode 100644 textures/chessboard_top.png create mode 100644 textures/king_black.png create mode 100644 textures/king_white.png create mode 100644 textures/knight_black.png create mode 100644 textures/knight_white.png create mode 100644 textures/pawn_black.png create mode 100644 textures/pawn_white.png create mode 100644 textures/queen_black.png create mode 100644 textures/queen_white.png create mode 100644 textures/rook_black.png create mode 100644 textures/rook_white.png diff --git a/chess.lua b/chess.lua new file mode 100644 index 0000000..3bedaaa --- /dev/null +++ b/chess.lua @@ -0,0 +1,642 @@ +-- See https://github.com/kilbith/realchess for the main repository + +local realchess = {} + +local function index_to_xy(index) + index = index - 1 + local x = index % 8 + local y = (index - x) / 8 + return x, y +end + +local function xy_to_index(x, y) + return x + y * 8 + 1 +end + +function realchess.init(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local slots = "listcolors[#00000000;#00000000;#00000000;#30434C;#FFF]" + local formspec + + inv:set_size("board", 64) + + meta:set_string("formspec", + "size[8,8.6;]".. + "bgcolor[#080808BB;true]".. + "background[0,0;8,8;chess_bg.png]".. + "button[3.1,7.8;2,2;new;New game]".. + "list[context;board;0,0;8,8;]".. + slots) + + meta:set_string("infotext", "Chess Board") + meta:set_string("playerBlack", "") + meta:set_string("playerWhite", "") + meta:set_string("lastMove", "") + meta:set_int("lastMoveTime", 0) + meta:set_string("winner", "") + meta:set_int("castlingBlackL", 1) + meta:set_int("castlingBlackR", 1) + meta:set_int("castlingWhiteL", 1) + meta:set_int("castlingWhiteR", 1) + + inv:set_list("board", { + "realchess:rook_black_1", + "realchess:knight_black_1", + "realchess:bishop_black_1", + "realchess:queen_black", + "realchess:king_black", + "realchess:bishop_black_2", + "realchess:knight_black_2", + "realchess:rook_black_2", + "realchess:pawn_black_1", + "realchess:pawn_black_2", + "realchess:pawn_black_3", + "realchess:pawn_black_4", + "realchess:pawn_black_5", + "realchess:pawn_black_6", + "realchess:pawn_black_7", + "realchess:pawn_black_8", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "realchess:pawn_white_1", + "realchess:pawn_white_2", + "realchess:pawn_white_3", + "realchess:pawn_white_4", + "realchess:pawn_white_5", + "realchess:pawn_white_6", + "realchess:pawn_white_7", + "realchess:pawn_white_8", + "realchess:rook_white_1", + "realchess:knight_white_1", + "realchess:bishop_white_1", + "realchess:queen_white", + "realchess:king_white", + "realchess:bishop_white_2", + "realchess:knight_white_2", + "realchess:rook_white_2" + }) +end + +function realchess.move(pos, from_list, from_index, to_list, to_index, count, player) + if from_list ~= "board" and to_list ~= "board" then + return 0 + end + + local playerName = player:get_player_name() + local meta = minetest.get_meta(pos) + + if meta:get_string("winner") ~= "" then + minetest.chat_send_player(playerName, "This game is over.") + return 0 + end + + local inv = meta:get_inventory() + local pieceFrom = inv:get_stack(from_list, from_index):get_name() + local pieceTo = inv:get_stack(to_list, to_index):get_name() + local lastMove = meta:get_string("lastMove") + local thisMove -- will replace lastMove when move is legal + local playerWhite = meta:get_string("playerWhite") + local playerBlack = meta:get_string("playerBlack") + + if pieceFrom:find("white") then + if playerWhite ~= "" and playerWhite ~= playerName then + minetest.chat_send_player(playerName, "Someone else plays white pieces!") + return 0 + end + if lastMove ~= "" and lastMove ~= "black" then + minetest.chat_send_player(playerName, "It's not your turn, wait for your opponent to play.") + return 0 + end + if pieceTo:find("white") then + -- Don't replace pieces of same color + return 0 + end + playerWhite = playerName + thisMove = "white" + elseif pieceFrom:find("black") then + if playerBlack ~= "" and playerBlack ~= playerName then + minetest.chat_send_player(playerName, "Someone else plays black pieces!") + return 0 + end + if lastMove ~= "" and lastMove ~= "white" then + minetest.chat_send_player(playerName, "It's not your turn, wait for your opponent to play.") + return 0 + end + if pieceTo:find("black") then + -- Don't replace pieces of same color + return 0 + end + playerBlack = playerName + thisMove = "black" + end + + -- DETERMINISTIC MOVING + + local from_x, from_y = index_to_xy(from_index) + local to_x, to_y = index_to_xy(to_index) + + if pieceFrom:find("pawn") then + if thisMove == "white" then + -- white pawns can go up only + if from_y - 1 == to_y then + if from_x == to_x then + if pieceTo ~= "" then + return 0 + elseif to_index >= 1 and to_index <= 8 then + inv:set_stack(from_list, from_index, "realchess:queen_white") + end + elseif from_x - 1 == to_x or from_x + 1 == to_x then + if not pieceTo:find("black") then + return 0 + end + else + return 0 + end + elseif from_y - 2 == to_y then + if pieceTo ~= "" or from_y < 6 or inv:get_stack(from_list, xy_to_index(from_x, from_y - 1)):get_name() ~= "" then + return 0 + end + else + return 0 + end + elseif thisMove == "black" then + -- black pawns can go down only + if from_y + 1 == to_y then + if from_x == to_x then + if pieceTo ~= "" then + return 0 + elseif to_index >= 57 and to_index <= 64 then + inv:set_stack(from_list, from_index, "realchess:queen_black") + end + elseif from_x - 1 == to_x or from_x + 1 == to_x then + if not pieceTo:find("white") then + return 0 + end + else + return 0 + end + elseif from_y + 2 == to_y then + if pieceTo ~= "" or from_y > 1 or inv:get_stack(from_list, xy_to_index(from_x, from_y + 1)):get_name() ~= "" then + return 0 + end + else + return 0 + end + + -- if x not changed, + -- ensure that destination cell is empty + -- elseif x changed one unit left or right + -- ensure the pawn is killing opponent piece + -- else + -- move is not legal - abort + + if from_x == to_x then + if pieceTo ~= "" then + return 0 + end + elseif from_x - 1 == to_x or from_x + 1 == to_x then + if not pieceTo:find("white") then + return 0 + end + else + return 0 + end + else + return 0 + end + + elseif pieceFrom:find("rook") then + if from_x == to_x then + -- moving vertically + if from_y < to_y then + -- moving down + -- ensure that no piece disturbs the way + for i = from_y + 1, to_y - 1 do + if inv:get_stack(from_list, xy_to_index(from_x, i)):get_name() ~= "" then + return 0 + end + end + else + -- mocing up + -- ensure that no piece disturbs the way + for i = to_y + 1, from_y - 1 do + if inv:get_stack(from_list, xy_to_index(from_x, i)):get_name() ~= "" then + return 0 + end + end + end + elseif from_y == to_y then + -- mocing horizontally + if from_x < to_x then + -- mocing right + -- ensure that no piece disturbs the way + for i = from_x + 1, to_x - 1 do + if inv:get_stack(from_list, xy_to_index(i, from_y)):get_name() ~= "" then + return 0 + end + end + else + -- mocing left + -- ensure that no piece disturbs the way + for i = to_x + 1, from_x - 1 do + if inv:get_stack(from_list, xy_to_index(i, from_y)):get_name() ~= "" then + return 0 + end + end + end + else + -- attempt to move arbitrarily -> abort + return 0 + end + + if thisMove == "white" then + if pieceFrom:find("1") then + meta:set_int("castlingWhiteL", 0) + elseif pieceFrom:find("2") then + meta:set_int("castlingWhiteR", 0) + end + elseif thisMove == "black" then + if pieceFrom:find("1") then + meta:set_int("castlingWhiteL", 0) + elseif pieceFrom:find("2") then + meta:set_int("castlingWhiteR", 0) + end + end + + elseif pieceFrom:find("knight") then + -- get relative pos + local dx = from_x - to_x + local dy = from_y - to_y + + -- get absolute values + if dx < 0 then + dx = -dx + end + if dy < 0 then + dy = -dy + end + + -- sort x and y + if dx > dy then + dx, dy = dy, dx + end + + -- ensure that dx == 1 and dy == 2 + if dx ~= 1 or dy ~= 2 then + return 0 + end + -- just ensure that destination cell does not contain friend piece + -- ^ it was done already thus everything ok + + elseif pieceFrom:find("bishop") then + -- get relative pos + local dx = from_x - to_x + local dy = from_y - to_y + + -- get absolute values + if dx < 0 then + dx = -dx + end + if dy < 0 then + dy = -dy + end + + -- ensure dx and dy are equal + if dx ~= dy then + return 0 + end + + if from_x < to_x then + if from_y < to_y then + -- moving right-down + -- ensure that no piece disturbs the way + for i = 1, dx - 1 do + if inv:get_stack(from_list, xy_to_index(from_x + i, from_y + i)):get_name() ~= "" then + return 0 + end + end + else + -- moving right-up + -- ensure that no piece disturbs the way + for i = 1, dx - 1 do + if inv:get_stack(from_list, xy_to_index(from_x + i, from_y - i)):get_name() ~= "" then + return 0 + end + end + end + else + if from_y < to_y then + -- moving left-down + -- ensure that no piece disturbs the way + for i = 1, dx - 1 do + if inv:get_stack(from_list, xy_to_index(from_x - i, from_y + i)):get_name() ~= "" then + return 0 + end + end + else + -- moving left-up + -- ensure that no piece disturbs the way + for i = 1, dx - 1 do + if inv:get_stack(from_list, xy_to_index(from_x - i, from_y - i)):get_name() ~= "" then + return 0 + end + end + end + end + + elseif pieceFrom:find("queen") then + local dx = from_x - to_x + local dy = from_y - to_y + + -- get absolute values + if dx < 0 then + dx = -dx + end + if dy < 0 then + dy = -dy + end + + -- ensure valid relative move + if dx ~= 0 and dy ~= 0 and dx ~= dy then + return 0 + end + + if from_x == to_x then + if from_y < to_y then + -- goes down + -- ensure that no piece disturbs the way + for i = 1, dx - 1 do + if inv:get_stack(from_list, xy_to_index(from_x, from_y + i)):get_name() ~= "" then + return 0 + end + end + else + -- goes up + -- ensure that no piece disturbs the way + for i = 1, dx - 1 do + if inv:get_stack(from_list, xy_to_index(from_x, from_y - i)):get_name() ~= "" then + return 0 + end + end + end + elseif from_x < to_x then + if from_y == to_y then + -- goes right + -- ensure that no piece disturbs the way + for i = 1, dx - 1 do + if inv:get_stack(from_list, xy_to_index(from_x + i, from_y)):get_name() ~= "" then + return 0 + end + end + elseif from_y < to_y then + -- goes right-down + -- ensure that no piece disturbs the way + for i = 1, dx - 1 do + if inv:get_stack(from_list, xy_to_index(from_x + i, from_y + i)):get_name() ~= "" then + return 0 + end + end + else + -- goes right-up + -- ensure that no piece disturbs the way + for i = 1, dx - 1 do + if inv:get_stack(from_list, xy_to_index(from_x + i, from_y - i)):get_name() ~= "" then + return 0 + end + end + end + else + if from_y == to_y then + -- goes left + -- ensure that no piece disturbs the way and destination cell does + for i = 1, dx - 1 do + if inv:get_stack(from_list, xy_to_index(from_x - i, from_y)):get_name() ~= "" then + return 0 + end + end + elseif from_y < to_y then + -- goes left-down + -- ensure that no piece disturbs the way + for i = 1, dx - 1 do + if inv:get_stack(from_list, xy_to_index(from_x - i, from_y + i)):get_name() ~= "" then + return 0 + end + end + else + -- goes left-up + -- ensure that no piece disturbs the way + for i = 1, dx - 1 do + if inv:get_stack(from_list, xy_to_index(from_x - i, from_y - i)):get_name() ~= "" then + return 0 + end + end + end + end + + elseif pieceFrom:find("king") then + local dx = from_x - to_x + local dy = from_y - to_y + local check = true + + if thisMove == "white" then + if from_y == 7 and to_y == 7 then + if to_x == 1 then + if meta:get_int("castlingWhiteL") == 1 and inv:get_stack(from_list, 57):get_name() == "realchess:rook_white_1" then + for i = 58, from_index - 1 do + if inv:get_stack(from_list, i):get_name() ~= "" then + return 0 + end + end + inv:set_stack(from_list, 57, "") + inv:set_stack(from_list, 59, "realchess:rook_white_1") + check = false + end + elseif to_x == 6 then + if meta:get_int("castlingWhiteR") == 1 and inv:get_stack(from_list, 64):get_name() == "realchess:rook_white_2" then + for i = from_index + 1, 63 do + if inv:get_stack(from_list, i):get_name() ~= "" then + return 0 + end + end + inv:set_stack(from_list, 62, "realchess:rook_white_2") + inv:set_stack(from_list, 64, "") + check = false + end + end + end + elseif thisMove == "black" then + if from_y == 0 and to_y == 0 then + if to_x == 1 then + if meta:get_int("castlingBlackL") == 1 and inv:get_stack(from_list, 1):get_name() == "realchess:rook_black_1" then + for i = 2, from_index - 1 do + if inv:get_stack(from_list, i):get_name() ~= "" then + return 0 + end + end + inv:set_stack(from_list, 1, "") + inv:set_stack(from_list, 3, "realchess:rook_black_1") + check = false + end + elseif to_x == 6 then + if meta:get_int("castlingBlackR") == 1 and inv:get_stack(from_list, 8):get_name() == "realchess:rook_black_2" then + for i = from_index + 1, 7 do + if inv:get_stack(from_list, i):get_name() ~= "" then + return 0 + end + end + inv:set_stack(from_list, 6, "realchess:rook_black_2") + inv:set_stack(from_list, 8, "") + check = false + end + end + end + end + + if check then + if dx < 0 then + dx = -dx + end + if dy < 0 then + dy = -dy + end + + if dx > 1 or dy > 1 then + return 0 + end + end + + if thisMove == "white" then + meta:set_int("castlingWhiteL", 0) + meta:set_int("castlingWhiteR", 0) + elseif thisMove == "black" then + meta:set_int("castlingBlackL", 0) + meta:set_int("castlingBlackR", 0) + end + end + + meta:set_string("playerWhite", playerWhite) + meta:set_string("playerBlack", playerBlack) + meta:set_string("lastMove", thisMove) + meta:set_int("lastMoveTime", minetest.get_gametime()) + + if meta:get_string("lastMove") == "black" then + minetest.chat_send_player(playerWhite, playerName.." has moved a "..pieceFrom:match("%a+:(%a+)")..", it's now your turn.") + elseif meta:get_string("lastMove") == "white" then + minetest.chat_send_player(playerBlack, playerName.." has moved a "..pieceFrom:match("%a+:(%a+)")..", it's now your turn.") + end + + if pieceTo:find("king") then + minetest.chat_send_player(playerBlack, playerName.." won the game.") + minetest.chat_send_player(playerWhite, playerName.." won the game.") + meta:set_string("winner", thisMove) + end + + return 1 +end + +function realchess.fields(pos, formname, fields, sender) + local playerName = sender:get_player_name() + local meta = minetest.get_meta(pos) + + if fields.quit then return end + + -- the chess can't be reset during a started game unless if nobody has played during a while (~5 min. by default) + if fields.new and (meta:get_string("playerWhite") == playerName or + meta:get_string("playerBlack") == playerName) then + realchess.init(pos) + elseif fields.new and meta:get_int("lastMoveTime") ~= 0 and + minetest.get_gametime() >= meta:get_int("lastMoveTime") + 250 and + (meta:get_string("playerWhite") ~= playerName or + meta:get_string("playerBlack") ~= playerName) then + realchess.init(pos) + else + minetest.chat_send_player(playerName, "You can't reset the chessboard, a game has been started.\nIf you are not a current player, try again after a while.") + end +end + +function realchess.dig(pos, player) + local meta = minetest.get_meta(pos) + local playerName = player:get_player_name() + + -- the chess can't be dug during a started game unless if nobody has played during a while (~5 min. by default) + if meta:get_int("lastMoveTime") ~= 0 and + minetest.get_gametime() <= meta:get_int("lastMoveTime") + 250 then + minetest.chat_send_player(playerName, "You can't dig the chessboard, a game has been started.\nReset it first if you're a current player, or try digging again after a while.") + return false + end + + return true +end + +function realchess.on_move(pos, from_list, from_index, to_list, to_index, count, player) + local inv = minetest.get_meta(pos):get_inventory() + inv:set_stack(from_list, from_index, '') + return false +end + +function realchess.take(pos, listname, index, stack, player) + return 0 +end + +minetest.register_node(":realchess:chessboard", { + description = "Chess Board", + drawtype = "nodebox", + paramtype = "light", + paramtype2 = "facedir", + inventory_image = "chessboard_top.png", + wield_image = "chessboard_top.png", + tiles = {"chessboard_top.png", "chessboard_top.png", + "chessboard_sides.png", "chessboard_sides.png", + "chessboard_top.png", "chessboard_top.png"}, + groups = {choppy=3, flammable=3}, + sounds = default.node_sound_wood_defaults(), + node_box = {type = "fixed", fixed = {-0.5, -0.5, -0.5, 0.5, -0.4375, 0.5}}, + sunlight_propagates = true, + can_dig = realchess.dig, + on_construct = realchess.init, + on_receive_fields = realchess.fields, + allow_metadata_inventory_move = realchess.move, + on_metadata_inventory_move = realchess.on_move, + allow_metadata_inventory_take = realchess.take +}) + +local function register_piece(name, count) + for _, color in pairs({"black", "white"}) do + if not count then + minetest.register_craftitem(":realchess:"..name.."_"..color, { + description = color:gsub("^%l", string.upper).." "..name:gsub("^%l", string.upper), + inventory_image = name.."_"..color..".png", + stack_max = 1, + groups = {not_in_creative_inventory=1} + }) + else + for i = 1, count do + minetest.register_craftitem(":realchess:"..name.."_"..color.."_"..i, { + description = color:gsub("^%l", string.upper).." "..name:gsub("^%l", string.upper), + inventory_image = name.."_"..color..".png", + stack_max = 1, + groups = {not_in_creative_inventory=1} + }) + end + end + end +end + +register_piece("pawn", 8) +register_piece("rook", 2) +register_piece("knight", 2) +register_piece("bishop", 2) +register_piece("queen") +register_piece("king") + +minetest.register_craft({ + output = "realchess:chessboard", + recipe = { + {"dye:black", "dye:white", "dye:black"}, + {"stairs:slab_wood", "stairs:slab_wood", "stairs:slab_wood"} + } +}) + diff --git a/init.lua b/init.lua index 1f703e2..34198da 100644 --- a/init.lua +++ b/init.lua @@ -4,6 +4,7 @@ local modpath = minetest.get_modpath("xdecor") dofile(modpath.."/handlers/nodeboxes.lua") dofile(modpath.."/handlers/registration.lua") dofile(modpath.."/aliases.lua") +dofile(modpath.."/chess.lua") dofile(modpath.."/crafts.lua") dofile(modpath.."/enchanting.lua") dofile(modpath.."/hive.lua") diff --git a/textures/bishop_black.png b/textures/bishop_black.png new file mode 100644 index 0000000000000000000000000000000000000000..b9d0670f9754bfa39060a363bc41a4cb8c3743b8 GIT binary patch literal 170 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa2=EDU1=37ROj1%(0s;cAuCBVe zx=Be%ii(QUAH|#k$}yG%`2{mLJiCzwmkLu3KZR)-Z1T?-hdD6%9P z>|%42;91lfaI~pOVAf4t38keONgRSkf+8&%LdCr1Eh`LJBs(}6=GL=WpJgo;1)9a+ M>FVdQ&MBb@0Ov?6i~s-t literal 0 HcmV?d00001 diff --git a/textures/bishop_white.png b/textures/bishop_white.png new file mode 100644 index 0000000000000000000000000000000000000000..c474e7edcfcf288d1a2f0e2dfc10d71f0ef8c420 GIT binary patch literal 175 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa4)6(a1=3|@Wyg;npE+}8Z*OmF zYwPXXw>NCquypCtm!}q{0HqmAg8YIR9G=}s19F@^T^vI=t|uShieO&QW8k{NVbTJI zmWg^ii3Y30oh5i4wFMk)Y7&?gxt3KaHR}q8pb?iy35)R^lPCoqG4~0LGZ+|7e`lAi TecJmKXc~j3tDnm{r-UW|Gc7w5 literal 0 HcmV?d00001 diff --git a/textures/chess_bg.png b/textures/chess_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..3a2eb057091a4b42d6a7a79193c26ed072c695ba GIT binary patch literal 848 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&wFLNtxE|ixZ!W`WD9(0t$AmrW zI!vV4bwyeEnHhyy7!GXimEmIAx1sCk?gcwnx2~I8ZY|HPCCqYc=fr3Wxo}h2Z7Z55 z)rR+1hpG#)s0c8h*th7=&Uve67F)@2Nw70+UQ)ktVa>A1*^0bOL55N*rselk1a+4O zSS#?vTPvQ}J$YeY>hYbECe=qKAN}|d=pM!-Z+91l4pvzYAcwQSBeIx*fm;}a85w5H zkpK#^mw5WRvft;D;$#zV_^|050|Qf#r;B4q#jUq9j!$}`Ai&Da!lC&7s*&#HytHrs z|L1q#lrG)D4tUsMfnp5h?Vcw=)!f6%GY)TgIr%!;}%Gtc$kX`wd? z1+8tyCnYDp|GrD>@{eZ*GMOS*88UO_@5*FH-dex-o@#QP#uOgge%ieK--(Sj1woTkCUnidCOUc5A*qQ%>Sp^azqm%#*FNOC`7OWyp7!&n z`N7M+p8Y5%;4w*lgYS*vRbIz_N^gI;-K)0PhL!2Vj0cV@Uu)>+Z47*>wR4MbO6uwx z`t6AaMX!}Lzj57o|55L4(IUN#;pvZOJMUkg& z?_OH*=Kk+Mo36)w&#&a9SwFtK?`y@+XBYOjEqoupeqsHi2mZ^GWs?uLAA5MLwwPn? zf4%k#Ki?No$WX9%sB8Gc@RRWq^Aq+H{1fD9An@mV-2?rjhKYJQKkifk6C8u5tDnm{ Hr-UW|N>YcB literal 0 HcmV?d00001 diff --git a/textures/chessboard_sides.png b/textures/chessboard_sides.png new file mode 100644 index 0000000000000000000000000000000000000000..14d1a69974f2e26ef87bf41ea721c71bdf421120 GIT binary patch literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP~mjoA!uO$lEhN4_=FDIdQ=PK{qpK`>c ke~-P=jq6=13}<@S7r*0H+7+AT?@lVHp#fRC! k9&`2g>_F>mL%K)j58U+y*|rx^dH?_b07*qoM6N<$g5Z6A`v3p{ literal 0 HcmV?d00001 diff --git a/textures/king_black.png b/textures/king_black.png new file mode 100644 index 0000000000000000000000000000000000000000..d9a80d610c5e1d97d53af88cc8dbb3cb10aba1a5 GIT binary patch literal 238 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa2=EDUO)OwwVqy{y5KvT9bai#r z)zwW(N|KhA_TSm`0H}tsB*-tA!Qt7BG!Q4r+uensgH_f8$l)yTh%9Dc;1&j9Muu5) zB!GhKC7!;n?Dx4O`Pi*apG%tv6!Q0UaSY+Oo}A#orP#r!%R~ zDM4{+K(gxwDMtkcV~OBi7KsH;0dMmh1tvO)x^_(HTChNIhT=0Ro{Q&}XlNX0U}a!1 XKE>|wd$;ghpwSGTu6{1-oD!MNCquypBCYmN3xKxxL3AirP+hi5m^fE<5M7sn8e>&XsmUQGhCGysbzJMo!W7XWFYebbEJ-NdnSQIA0!(x0$CrXj$ gnuFs4DIW%g_8**_YCOw0fkrcUy85}Sb4q9e08&*uZ~y=R literal 0 HcmV?d00001 diff --git a/textures/knight_black.png b/textures/knight_black.png new file mode 100644 index 0000000000000000000000000000000000000000..db229aa012c3d6c0736df6c0f3b803d6145f1f90 GIT binary patch literal 231 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa2=EDUO)OwwVqy{y5YW}tRa8`T zb#+ZjN|KhA{<^DQ6{v=>B*-tA!Qt7BG!Q4r+uensgH_f8$l)yTh%9Dc;1&j9Muu5) zB!GhKC7!;n?Dx4O`8X7h8E@VM6!P$NaSY+Oo}A#oto0+U@k-We!&cr0ACNWo?L0tJ_i5gRx|dKWEVU>0LwxERPbA>g;) Qd7zmLp00i_>zopr06FzL?*IS* literal 0 HcmV?d00001 diff --git a/textures/knight_white.png b/textures/knight_white.png new file mode 100644 index 0000000000000000000000000000000000000000..d6c01a1f54da3a62e4090a6190563d0094e1978d GIT binary patch literal 235 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa4)6(aHDq8YD=V8hbLR2m$2V-) z(A(SF+SC)S`Z@*u@gb%2Uu_VYZn8D%MjWiG^$=lt9p@UV{1IXbl@Q5sCVBi)8 zVMc~ob0mO*>?NMQuI%@@B>6bx*@M8#f5Mw47WdqO@pPj0VTWsTvX-X)ZISJ4vi*Y+~YxU|c(&YqlY6hHzX@P5^?Sga(FCca7#ihEoD<9U6w5np_-B zAuCo$S!p$eNU$#FXbk1-vgC3yk>qmR%IU-+F~euFf>P_LE&;_&XmEZj5Xk0>Ld8I0O?r zI=H(REND=e@K8-9ZN&?Ypu{P6RG7k4H5O`cTuk8*V&LX<%23-J)X~vZr0C*tGtfZb l42Q9Pt3d=aE2{+1UH|(z?AKHm?+04I;OXk;vd$@?2>|c6JwFIvE0Hk)yQ6r1oHw`^^o OX$+pOelF{r5}E*x;4fqV literal 0 HcmV?d00001 diff --git a/textures/rook_white.png b/textures/rook_white.png new file mode 100644 index 0000000000000000000000000000000000000000..e76ff59019931f92f8e025642d7d06c29dbee993 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa4)6(a1=3|@Wiw~aY;A2le*AcE zZ|{Z;8*bmey>#i)d&`Z_0i_vBg8YIR9G=}s19DtFT^vI=t|uShl3-OZ*&LwMlA5Qp zf+KCl3>7Ddw0E8YY{j#LLbfhYXh|!|Z|%@nZQ|4t!o$jZu&1CujHB5!Ab?@^SqAYU W4pZho{~iMkWbkzLb6Mw<&;$UtfIH^^ literal 0 HcmV?d00001