-- pls set tabs to width of 4 spaces class = require "lib/middleclass" wind = require "lib/windfield" stalker = require "lib/STALKER-X" bitser = require "lib/bitser" sock = require "lib/sock" SWORDLENGTH = 40; KNIFELENGTH = 10 SWORDWIDTH = 3 SHIELDWIDTH = 16 SHIELDHEIGHT = 5 MP_PORT = 13371 CHATLOG = {} -- GAME STATES -------------------------------------------------------------------------------- -- LOVE ---------------------------------------- function love.load() math.randomseed(os.time()) bgm = nil newBgm() logMsg(nil, "Starting up...") love.graphics.setDefaultFilter("nearest", "nearest") a_ttf = love.graphics.newFont("art/font/alagard.ttf", nil, "none") r_ttf = love.graphics.newFont("art/font/romulus.ttf", nil, "none") love.graphics.setBackgroundColor(0, 152/255, 255/255, 1) love.resize() menu_load(makeMainMenu()) end function love.update(dt) if (bgm.isPlaying == false) then newBgm() end updateFunction(dt) camera:update(dt) end function love.draw() camera:attach() drawFunction() drawLogMsgs() camera:detach() camera:draw() end function love.resize() local width,height = love.window.getMode() logMsg("[Window]", width .. "x" .. height) newCamera() end function love.keypressed(key) keypressedFunction(key) end function love.keyreleased (key) keyreleasedFunction(key) end -- MENUS ---------------------------------------- function menu_load(menu) menu:install() end function makeMainMenu() return Menu:new(100, 100, 30, 50, 3, { {love.graphics.newText(a_ttf, "Local"), function () lobby_load(LocalLobby) end}, {love.graphics.newText(a_ttf, "Net"), function () menu_load(makeNetMenu()) end}, {love.graphics.newText(a_ttf, "Quit"), function () love.event.quit(0) end }}) end function makeNetMenu() return Menu:new(100, 100, 30, 50, 3, { {love.graphics.newText(a_ttf, "Join"), function () local addressBox = TextBox:new(100, 100, 3, 99, "192.168.254.51", "Address/Host: ", function (text) lobby_load(ClientLobby, text) end) addressBox:install() end}, {love.graphics.newText(a_ttf, "Host"), function () lobby_load(HostLobby) end}, {love.graphics.newText(a_ttf, "Back"), function () menu_load(makeMainMenu()) end}}) end -- GAME LOBBY ---------------------------------------- function lobby_load(lobbyClass, arg) lobby = lobbyClass:new(arg) lobby:install() end -- IN-GAME ---------------------------------------- function game_load(game) game:install() end -- CLASSES -------------------------------------------------------------------------------- -- Fighter player class ---------------------------------------- Player = class('Fighter') function Player:initialize(game, x, y, character, swordType, name) self.game = game self.name = name self.swordType = 'normal' self.character = character or math.random(1, table.maxn(CHARACTERS)) self.lives = 5 self.directionals = {} self.deadPieces = {} self:initBody(x, y) self:initSword() self:initShield() self.id = math.random(1, 20000) end function Player:update(dt) local dir = self.directionals self:movement() self:glueSwordAndShield() if (self.body:getX() < 0) then self.body:setX(800) elseif (self.body:getX() > 800) then self.body:setX(0) end if (self.body:getY() < 0) then self.body:setY(800) elseif (self.body:getY() > 800) then self.body:setY(0) end if (dir['left'] == 2 and dir['right'] == 0) then dir['left'] = 1; end if (dir['right'] == 2 and dir['left'] == 0) then dir['right'] = 1; end end function Player:draw() local x,y = self.body:getWorldPoints(self.body.shape:getPoints()) love.graphics.draw(CHARACTERS[self.character], x, y, self.body:getAngle(), 1, 1) love.graphics.polygon("fill", self.sword:getWorldPoints(self.sword.shape:getPoints())) love.graphics.polygon("fill", self.shield:getWorldPoints(self.shield.shape:getPoints())) end function Player:movement() end function Player:toTable() local bx1,by1, bx2,by2, bx3,by3, bx4,by4 = self.body.shape:getPoints() local bodyVertices = {bx1,by1, bx2,by2, bx3,by3, bx4,by4} local sx1,sy1, sx2,sy2, sx3,sy3, sx4,sy4 = self.sword.shape:getPoints() local swordVertices = {sx1,sy1, sy2,sy2, sx3,sy3, sx4,sy4} local mx1,my1, mx2,my2, mx3,my3, mx4,my4 = self.shield.shape:getPoints() local shieldVertices = {mx1,my1, my2,my2, mx3,my3, mx4,my4} return {["bodyBox"] = bodyVertices, ["bodyAngle"] = self.body:getAngle(), ["swordBox"] = swordVertices, ["swordAngle"] = self.sword:getAngle(), ["shieldBox"] = shieldVertices, ["shieldAngle"] = self.shield:getAngle(), ["bodyX"] = self.body:getX(), ["bodyY"] = self.body:getY(), ["swordX"] = self.sword:getX(), ["swordY"] = self.sword:getY(), ["shieldX"] = self.shield:getX(), ["shieldY"] = self.shield:getY(), ["character"] = self.character, ["name"] = self.name, ["id"] = self.id} end function Player:applyTable(pTable) self.body.shape = love.physics.newPolygonShape(pTable["bodyBox"]) self.body:setAngle(pTable["bodyAngle"]) self.body:setX(pTable["bodyX"]) self.body:setY(pTable["bodyY"]) self.sword.shape = love.physics.newPolygonShape(pTable["swordBox"]) self.sword:setAngle(pTable["swordAngle"]) self.sword:setX(pTable["swordX"]) self.sword:setY(pTable["swordY"]) self.shield.shape = love.physics.newPolygonShape(pTable["shieldBox"]) self.shield:setAngle(pTable["shieldAngle"]) self.shield:setX(pTable["shieldX"]) self.shield:setY(pTable["shieldY"]) self.character = pTable["character"] self.id = pTable["id"] self.name = pTable["name"] end function Player:initBody(x, y) self.body = self.game.world:newRectangleCollider(x, y, 16, 16); self.body:setCollisionClass('Player') self.body:setObject(self) self.body:setAngularDamping(2) self.body:setLinearDamping(.5) self.body:setPostSolve(self.makePostSolve()) end function Player:initShield() self.shield = self.game.world:newRectangleCollider(0, 0, 20, 5); self.shield:setCollisionClass('Shield') self.shield:setObject(self) end function Player:initSword() self.swordLength = SWORDLENGTH if (self.swordType == 'normal') then self.sword = self.game.world:newRectangleCollider(0, 0, 3, self.swordLength); else self.sword = self.game.world:newRectangleCollider(0, 0, 3, KNIFELENGTH); end self.sword:setCollisionClass('Sword') self.sword:setObject(self) self.sword:setPostSolve(self:makeSwordPostSolve()) end function Player:glueSwordAndShield() local x, y = self.body:getPosition() local angle = self.body:getAngle() self.shield:setAngle(angle) self.shield:setPosition(x - (math.sin(angle) * 16), y + (math.cos(angle) * 16)) if (self.swordType == 'normal') then local offset = self.swordLength - 10 self.sword:setAngle(angle) self.sword:setPosition(x + (math.sin(angle) * offset), y - (math.cos(angle) * offset)) elseif (self.swordType == 'knife') then local offset = self.swordLength * 2 self.sword:setAngle(angle) self.sword:setPosition(x + (math.sin(angle) * 4.5 * offset), y - (math.cos(angle) * 1.5 * offset)) end end function Player:makePostSolve() return function(col1, col2, contact) if (col1.collision_class == "Player" and col2.collision_class == "Sword") then -- col1.object.game:sendChat(self.name .. " lost a life! " .. self.lives .. " left!") -- print(col2.shape) -- print("THEY DEEED, dude") end end end function Player:makeSwordPostSolve() return function(col1, col2, contact) if (col1.collision_class == "Sword" and col2.collision_class == "Shield") then end end end -- LocalPlayer for local players (ofc) ---------------------------------------- LocalPlayer = class("LocalPlayer", Player) function LocalPlayer:initialize(game, x, y, keymap, character, swordType, name) self.keymap = keymap or KEYMAPS[1] Player.initialize(self, game, x, y, character, swordType, name) end function LocalPlayer:movement() local x, y = self.body:getPosition() local dir = self.directionals local angle = self.body:getAngle() if (dir['left'] == 1) then self.body:applyAngularImpulse(-.5, 1) elseif (dir['right'] == 1) then self.body:applyAngularImpulse(.5, 1) end if (dir['up'] == 1) then self.body:applyLinearImpulse(math.sin(angle) * 0.5, math.cos(angle) * -0.5) elseif (dir['down'] == 1) then self.body:setAngle(angle - (math.pi * .70)) self.body:applyAngularImpulse(-45, 1) dir['down'] = 0 end end function LocalPlayer:keypressed(key) local dir = self.directionals if (key == self.keymap["right"]) then dir['right'] = 1 if (dir['left'] == 1) then dir['left'] = 2; end elseif (key == self.keymap["left"]) then dir['left'] = 1 if (dir['right'] == 1) then dir['right'] = 2; end elseif (key == self.keymap["accel"]) then dir['up'] = 1 if (dir['down'] == 1) then dir['down'] = 2; end elseif (key == self.keymap["flip"]) then dir['down'] = 1 if (dir['up'] == 1) then dir['up'] = 2; end end end function LocalPlayer:keyreleased(key) local dir = self.directionals if (key == self.keymap["right"]) then dir['right'] = 0 elseif (key == self.keymap["left"]) then dir['left'] = 0 elseif (key == self.keymap["accel"]) then dir['up'] = 0 elseif (key == self.keymap["flip"]) then dir['down'] = 0 end end -- NetPlayer for network players ---------------------------------------- NetPlayer = class("NetPlayer", Player) function NetPlayer:initialize(ptable, game) Player.initialize(self, game, 0, 0, 1, 'normal', "sldkfj") self:applyTable(ptable) end -- HostPlayer for from-server players ---------------------------------------- HostPlayer = class("HostPlayer", NetPlayer) function HostPlayer:intialize(ptable, game) NetPlayer.initialize(self, ptable, game) end -- ClientPlayer for from-client players ---------------------------------------- ClientPlayer = class("ClientPlayer", NetPlayer) function ClientPlayer:intialize(ptable, game) NetPlayer.initialize(self, ptable, game) end -- GAME superclass for matches ---------------------------------------- Game = class("Game") function Game:initialize(lobbiests) self.world = wind.newWorld(0, 0, true) self.world:addCollisionClass('Player') self.world:addCollisionClass('Shield') self.world:addCollisionClass('Sword') self.localPlayers = {} self.localPlayersN = 0 self:addLobbiests(lobbiests) end function Game:install(update, draw, press, release) hookInstall(function (dt) self:update(dt) end, function () self:draw() end, function (key) self:keypressed(key) end, function (key) self:keyreleased(key) end, update, draw, press, release) end function Game:update(dt) self.world:update(dt) for k,player in pairs(self:players()) do player:update(dt) end end function Game:draw() -- self.world:draw() for k,player in pairs(self:players()) do player:draw() end end function Game:keypressed(key) local dir = self.localPlayers[1].directionals -- if a player presses the left key, then holds the right key, they should -- go right until they let go, then they should go left. if (key == "=" and camera.scale < 10) then camera.scale = camera.scale + .5 elseif (key == "-" and camera.scale > .5) then camera.scale = camera.scale - .5 elseif (key == "t") then local chatbox = TextBox:new(10,770, 2, 99, nil, nil, function (text) self:sendChat(text) self:install() end) chatbox:install(false, drawFunction, nil, false) elseif (key == "escape") then menu_load(makeMainMenu()) else for i, player in pairs(self.localPlayers) do player:keypressed(key) end end end function Game:keyreleased (key) for i, player in pairs(self.localPlayers) do player:keyreleased(key) end end function Game:players() return self.localPlayers end function Game:sendChat(message) local author = "AGhost" if (self.localPlayersN > 0) then author = self.localPlayers[1].name end logMsg(author, message) return author,message end function Game:addLobbiests(localLobbiests) for k,lobbiest in pairs(localLobbiests) do local i = self.localPlayersN + 1 self.localPlayers[i] = LocalPlayer:new(self, 0 + i * 50, 0 + i * 50, KEYMAPS[i], lobbiest.character, lobbiest.swordType, lobbiest.name) self.localPlayersN = i end end -- NETGAME superclass for online matches ---------------------------------------- NetGame = class("NetGame", Game) function NetGame:initialize(localLobbiests, sock) self.remotePlayers = {} self.remotePlayersN = 0 self.sock = sock Game.initialize(self, localLobbiests) self:sockCallbacks() end function NetGame:sockCallbacks() self.sock:on("newPlayers", function(playerTables, client) self:addNewPlayers(playerTables, client) end) self.sock:on("playerPing", function(playerTables, client) self:receivePlayers(playerTables, client) end) end function NetGame:update(dt) Game.update(self, dt) self:sendPlayers() self.sock:update() end function NetGame:players() local players = {} table.foreach(self.localPlayers, function(k, v) table.insert(players, v) end) table.foreach(self.remotePlayers, function(k, v) table.insert(players, v) end) return players end function NetGame:receivePlayers(playerTables, client) for i,ptable in pairs(playerTables) do local id = ptable["id"] if (self.remotePlayers[id] == nil) then self:addNewPlayer(ptable) end self.remotePlayers[id]:applyTable(ptable) end end -- HOSTGAME for server matches ---------------------------------------- HostGame = class("HostGame", NetGame) function HostGame:initialize(localLobbiests, server) NetGame.initialize(self, localLobbiests, server) self.sock:sendToAll("newGame", nil) end function HostGame:sockCallbacks() NetGame.sockCallbacks(self) end function HostGame:sendChat(message) local author,text = Game.sendChat(self, message) self.sock:sendToAll("chat", {["author"] = author, ["text"] = text}) end function HostGame:addNewPlayer(ptable) self.remotePlayersN = self.remotePlayersN + 1 self.remotePlayers[ptable["id"]] = ClientPlayer:new(ptable, self) end function HostGame:sendPlayers() local ptables = {} for i,player in pairs(self.localPlayers) do table.insert(ptables, player:toTable()) end self.sock:sendToAll("playerPing", ptables) end function HostGame:receivePlayers(playerTables, client) NetGame.receivePlayers(self, playerTables) self.sock:sendToAllBut(client, "playerPing", playerTables) end -- CLIENTGAME for client-side matches ---------------------------------------- ClientGame = class("ClientGame", NetGame) function ClientGame:initialize(localLobbiests, client) NetGame.initialize(self, localLobbiests, client) end function ClientGame:sendChat(message) local author,text = Game.sendChat(self, message) self.sock:send("chat", {["author"] = author, ["text"] = text}) end function ClientGame:sendPlayers() local ptables = {} for i,player in pairs(self.localPlayers) do table.insert(ptables, player:toTable()) end self.sock:send("playerPing", ptables) end function ClientGame:addNewPlayer(ptable) self.remotePlayersN = self.remotePlayersN + 1 self.remotePlayers[ptable["id"]] = HostPlayer:new(ptable, self) end -- LOBBY superclass for pre-matches ---------------------------------------- Lobby = class("Lobby") function Lobby:initialize() self.localLobbiests = {} self.localLobbiestsN = 0 self.remoteLobbiests = {} self.remoteLobbiestsN = 0 self.ttf = r_ttf self.scale = 3 end function Lobby:draw() love.graphics.draw(love.graphics.newText(self.ttf, self.class.name), 10, 10, 0, self.scale) love.graphics.draw(love.graphics.newText(self.ttf, self:lobbiestsN() .. " players"), 500, 10, 0, self.scale) for i,lobbiest in pairs(self:lobbiests()) do local rowX = 10 local rowY = (25 * i) + 50 love.graphics.draw(CHARACTERS[lobbiest.character], rowX, rowY, 0, 1, 1) if (lobbiest.swordType == "normal") then love.graphics.rectangle("fill", rowX + 18, rowY + SWORDWIDTH, SWORDLENGTH, SWORDWIDTH) else love.graphics.rectangle("fill", rowX + 18, rowY + SWORDWIDTH, KNIFELENGTH, SWORDWIDTH) end love.graphics.draw(love.graphics.newText(self.ttf, lobbiest.name), rowX + SWORDLENGTH + 30, rowY, 0, self.scale) love.graphics.draw(love.graphics.newText(self.ttf, lobbiest.class.name), rowX + 550, rowY, 0, self.scale) if (lobbiest.class.name == "LocalLobbiest") then local keymap = lobbiest.keymap local text = keymap["accel"] .. " " .. keymap["left"] .. " " .. keymap["flip"] .. " " .. keymap["right"] love.graphics.draw(love.graphics.newText(self.ttf, text), rowX + 350, rowY + 5, 0, self.scale * (2/3)) end end local rowX = 470 local rowY = 500 love.graphics.draw(love.graphics.newText(self.ttf, "SPACE: Add player"), rowX, rowY + (40 * 1), 0, self.scale) love.graphics.draw(love.graphics.newText(self.ttf, "DELETE: Del player"), rowX, rowY + (40 * 2), 0, self.scale) rowY = 560 love.graphics.draw(love.graphics.newText(self.ttf, "LEFT: Edit name"), rowX, rowY + (40 * 2), 0, self.scale) love.graphics.draw(love.graphics.newText(self.ttf, "RIGHT: Change sprite"), rowX, rowY + (40 * 3), 0, self.scale) love.graphics.draw(love.graphics.newText(self.ttf, "ACCEL: Change sword"), rowX, rowY + (40 * 4), 0, self.scale) end function Lobby:install(update, draw, press, release) hookInstall(function (dt) self:update(dt) end, function () self:draw() end, function (key) self:keypressed(key) end, function (key) self:keyreleased(key) end, update, draw, press, release) end function Lobby:update(dt) end function Lobby:keypressed(key) if (key == "space" and self.localLobbiestsN < table.maxn(KEYMAPS)) then self:newLocalLobbiest() elseif (key == "t") then local chatbox = TextBox:new(10,770, 2, 99, nil, nil, function (text) self:sendChat(text) self:install() end) chatbox:install(false, drawFunction, nil, false) elseif (key == "escape") then self:toMainMenu() else for i,lobbiest in pairs(self.localLobbiests) do lobbiest:keypressed(key, self) end end end function Lobby:keyreleased(key) end function Lobby:toMainMenu() menu_load(makeMainMenu()) end function Lobby:sendChat(message) local author = "AGhost" if (self.localLobbiestsN > 0) then author = self.localLobbiests[1].name end logMsg(author, message) return author,message end function Lobby:newLocalLobbiest() local i = self.localLobbiestsN + 1 self.localLobbiestsN = i self.localLobbiests[i] = LocalLobbiest:new(self, nil, KEYMAPS[i]) end function Lobby:lobbiests() local lobbiests = {} table.foreach(self.localLobbiests, function(k, v) table.insert(lobbiests, v) end) table.foreach(self.remoteLobbiests, function(k, v) table.insert(lobbiests, v) end) return lobbiests end function Lobby:lobbiestsN() return self.remoteLobbiestsN + self.localLobbiestsN end function Lobby:localLobbiestTables() local lobbiests = {} table.foreach(self.localLobbiests, function (k, lobbiest) table.insert(lobbiests, lobbiest:toTable()) end) return lobbiests end -- LOCAL LOBBY ---------------------------------------- LocalLobby = class("LocalLobby", Lobby) function LocalLobby:initialize() Lobby.initialize(self) end function LocalLobby:keypressed(key) if (key == "return" and self:lobbiestsN() > 1) then game_load(Game:new(self:lobbiests())) else Lobby.keypressed(self, key) end end -- NET - NET LOBBY ---------------------------------------- NetLobby = class("NetLobby", Lobby) function NetLobby:initialize() Lobby.initialize(self) end function NetLobby:install() Lobby.install(self) self:sendLobbiests() end function NetLobby:update(dt) self.sock:update() end function NetLobby:keypressed(key) Lobby.keypressed(self, key) self:sendLobbiests() end function NetLobby:sockCallbacks() self.sock:on("chat", function (chatData, client) self:chatReceived(chatData, client) end) self.sock:on("lobbiests", function (localLobbiests, client) self:receiveLobbiests(localLobbiests, client) end) end function NetLobby:chatReceived(chatData, client) logMsg(chatData["author"], chatData["text"]) end -- NET - HOST LOBBY ---------------------------------------- HostLobby = class("HostLobby", NetLobby) function HostLobby:initialize() NetLobby.initialize(self) self.sock = sock.newServer("*", MP_PORT) self.sock:setSerialization(bitser.dumps, bitser.loads) self:sockCallbacks() end function HostLobby:sockCallbacks() NetLobby.sockCallbacks(self) self.sock:on("connect", function (data, client) -- self:sendLobbiests() -- st end) self.sock:on("disconnect", function (data, client) self:removeLobbiestsOfClient(client) end) end function HostLobby:keypressed(key) if (key == "return" and self:lobbiestsN() > 1) then game_load(HostGame:new(self.localLobbiests, self.sock)) else Lobby.keypressed(self, key) end end function HostLobby:toMainMenu() -- self.sock:destroy() -- Lobby.toMainMenu(self) end function HostLobby:sendChat(message) local author,text = Lobby.sendChat(self, message) self.sock:sendToAll("chat", {["author"] = author, ["text"] = text}) end function HostLobby:chatReceived(chatData, client) NetLobby.chatReceived(self, chatData) self.sock:sendToAllBut(client, "chat", chatData) end function HostLobby:sendLobbiests() for k,client in pairs(self.sock:getClients()) do client:send("lobbiests", self:lobbiestTables(client)) end end function HostLobby:receiveLobbiests(localLobbiestTables, client) self:removeLobbiestsOfClient(client) for k,lobbiestTable in pairs(localLobbiestTables) do table.insert(self.remoteLobbiests, ClientLobbiest:new(self, client, lobbiestTable)) self.remoteLobbiestsN = self.remoteLobbiestsN + 1 end self:sendLobbiests() end function HostLobby:newLocalLobbiest() Lobby.newLocalLobbiest(self) self:sendLobbiests() end function HostLobby:removeLobbiestsOfClient(client) local lobbiests = {} local n = 0 for k,lobbiest in pairs(self.remoteLobbiests) do if not (lobbiest.client == client) then table.insert(lobbiests, lobbiest) n = n + 1 end end self.remoteLobbiests = lobbiests self.remoteLobbiestsN = n end function HostLobby:remoteLobbiestTables(client) local lobbiests = {} table.foreach(self.remoteLobbiests, function (k, lobbiest) if not (lobbiest.client == client) then table.insert(lobbiests, lobbiest:toTable()) end end) return lobbiests end function HostLobby:lobbiestTables(client) local lobbiests = {} table.foreach(self:localLobbiestTables(), function(k, v) table.insert(lobbiests, v) end) table.foreach(self:remoteLobbiestTables(client), function(k, v) table.insert(lobbiests, v) end) return lobbiests end -- NET - CLIENT LOBBY ---------------------------------------- ClientLobby = class("ClientLobby", NetLobby) function ClientLobby:initialize(address) NetLobby.initialize(self) self.status = "Connecting..." self.sock = sock.newClient(address, MP_PORT) self.sock:setSerialization(bitser.dumps, bitser.loads) self:sockCallbacks() self.sock:connect() end function ClientLobby:sockCallbacks() NetLobby.sockCallbacks(self) self.sock:on("connect", function (ignoredData) self.status = "Connected!" self.sock:send("lobbiests", self:localLobbiestTables()) end) self.sock:on("disconnect", function (ignoredData) self.status = "Disconnected" end) self.sock:on("newGame", function (data, client) game_load(ClientGame:new(self.localLobbiests, self.sock)) end) end function ClientLobby:update(dt) self.sock:update() end function ClientLobby:draw() Lobby.draw(self) love.graphics.draw(love.graphics.newText(self.ttf, self.status), 200, 10, 0, self.scale) end function ClientLobby:toMainMenu() self.sock:disconnect() Lobby.toMainMenu(self) end function ClientLobby:sendChat(message) local author,text = Lobby.sendChat(self, message) self.sock:send("chat", {["author"] = author, ["text"] = text}) end function ClientLobby:sendLobbiests() self.sock:send("lobbiests", self:localLobbiestTables()) end function ClientLobby:receiveLobbiests(remoteLobbiestTables) self.remoteLobbiests = {} self.remoteLobbiestsN = 0 for i,lobbiestTable in pairs(remoteLobbiestTables) do table.insert(self.remoteLobbiests, HostLobbiest:new(nil, lobbiestTable)) self.remoteLobbiestsN = self.remoteLobbiestsN + 1 end end function ClientLobby:newLocalLobbiest() Lobby.newLocalLobbiest(self) self:sendLobbiests() end -- LOBBIEST proposed fighter ---------------------------------------- Lobbiest = class("Lobbiest") function Lobbiest:initialize(lobby, name) self.name = name or NAMES[math.random(1, table.maxn(NAMES))] self.character = math.random(1, table.maxn(CHARACTERS)) self.swordType = "normal" end function Lobbiest:toTable() return {["name"] = self.name, ["character"] = self.character, ["swordType"] = self.swordType} end -- LOCAL LOBBIEST ---------------------------------------- LocalLobbiest = class("LocalLobbiest", Lobbiest) function LocalLobbiest:initialize(lobby, name, keymap) Lobbiest.initialize(self, lobby, name) self.keymap = keymap or KEYMAPS[math.random(1, table.maxn(KEYMAPS))] end function LocalLobbiest:keypressed(key, lobby) if (key == self.keymap["accel"]) then if (self.swordType == "normal") then self.swordType = "knife" elseif (self.swordType == "knife") then self.swordType = "normal" end elseif (key == self.keymap["left"]) then local textBox = TextBox:new(20, 400, 3, 10, self.name, "Name: ", function (text) self.name = text lobby:install() end) textBox:install(false, drawFunction, nil, false) elseif (key == self.keymap["right"]) then if (self.character == table.maxn(CHARACTERS)) then self.character = 1 else self.character = self.character + 1 end end end function LocalLobbiest:toTable() local tablo = Lobbiest.toTable(self) tablo["keymap"] = self.keymap return tablo end -- CLIENT LOBBIEST used by HostLobby ---------------------------------------- ClientLobbiest = class("ClientLobbiest", Lobbiest) function ClientLobbiest:initialize(lobby, client, lobbiestTable) self.client = client self.name = lobbiestTable["name"] self.keymap = lobbiestTable["keymap"] self.swordType = lobbiestTable["swordType"] self.character = lobbiestTable["character"] end -- HOST LOBBIEST used by ClientLobby ---------------------------------------- HostLobbiest = class("HostLobbiest", Lobbiest) function HostLobbiest:initialize(lobby, lobbiestTable) self.name = lobbiestTable["name"] self.swordType = lobbiestTable["swordType"] self.character = lobbiestTable["character"] end -- MENU used for creating menus (lol) ---------------------------------------- Menu = class("Menu") function Menu:initialize(x, y, offset_x, offset_y, scale, menuItems) self.x,self.y = x,y self.offset_x,self.offset_y = offset_x,offset_y self.options = menuItems self.selected = 1 self.scale = scale self.keys = {} self.keys['up'] = false self.keys['down'] = false self.keys['enter'] = false self.ttf = r_ttf end function Menu:install(update, draw, press, release) hookInstall(function (dt) self:update(dt) end, function () self:draw() end, function (key) self:keypressed(key) end, function (key) self:keyreleased(key) end, update, draw, press, release) end function Menu:update() end function Menu:draw() for i=1,table.maxn(self.options) do local this_y = self.y + (self.offset_y * i) love.graphics.draw(self.options[i][1], self.x, this_y, 0, self.scale, self.scale) if (i == self.selected) then love.graphics.draw(love.graphics.newText(self.ttf, ">>"), self.x - self.offset_x, this_y, 0, self.scale, self.scale) end end end function Menu:keypressed(key) maxn = table.maxn(self.options) if (key == "return" or key == "space") then self.keys['enter'] = true if(self.options[self.selected][2]) then self.options[self.selected][2]() end elseif (key == "up" and self.selected > 1 and self.keys['up'] == false) then self.keys['up'] = true self.selected = self.selected - 1 elseif (key == "up" and self.keys['up'] == false) then self.keys['up'] = true self.selected = maxn elseif (key == "down" and self.selected < maxn and self.keys['down'] == false) then self.keys['down'] = true self.selected = self.selected + 1 elseif (key == "down" and self.keys['down'] == false) then self.keys['down'] = true self.selected = 1 end end function Menu:keyreleased(key) if (key == "return" or key == "space") then self.keys['enter'] = false elseif (key == "up") then self.keys['up'] = false elseif (key == "down") then self.keys['down'] = false end end -- TEXT ENTRY ---------------------------------------- TextBox = class("TextBox") function TextBox:initialize(x, y, scale, max, initialText, label, onEnter) self.x,self.y = x,y self.scale = scale self.onEnter = onEnter self.text = initialText or "" self.label = label or "" self.max = max or 999 self.ttf = r_ttf end function TextBox:install(update, draw, press, release) hookInstall(function (dt) self:update(dt) end, function () self:draw() end, function (key) self:keypressed(key) end, function (key) self:keyreleased(key) end, update, draw, press, release) end function TextBox:update() end function TextBox:draw() love.graphics.draw(love.graphics.newText(self.ttf, self.label .. self.text .. "_"), self.x, self.y, 0, self.scale, self.scale) end function TextBox:keypressed(key) if (key == "return") then self.onEnter(self.text) elseif (key == "backspace") then self.text = self.text:sub(1, string.len(self.text) - 1) elseif (string.len(self.text) > self.max) then return elseif (key == "space") then self.text = self.text .. " " elseif (string.len(key) == 1) then self.text = self.text .. key end end function TextBox:keyreleased(key) end -- CHAT/LOGGING -------------------------------------------------------------------------------- function logMsg(source, text) local string = text if not (source == nil) then string = source .. ": " .. text end print(string) table.remove(CHATLOG, 5) table.insert(CHATLOG, 1, string) end function drawLogMsgs() local x,y = 10,600 local offset_y = 30 local scale = 1.7 local chatCount = table.maxn(CHATLOG) for i=1,chatCount do local this_y = y + (offset_y * (chatCount - i)) love.graphics.draw(love.graphics.newText(a_ttf, CHATLOG[i]), x, this_y, 0, scale, scale) end end -- UTIL -------------------------------------------------------------------------------- -- Install the important 'hook' functions (draw, update, keypressed/released) -- If any of the 'old' functions passed are not nil, then both the new and -- old will be added into the new corresponding hook function -- This function is too god damn long and it makes me want to cry -- Could be pretty easily shortened, now that I think about it function hookInstall(newUpdate, newDraw, newPress, newRelease, oldUpdate, oldDraw, oldPress, oldRelease) local ignored = 1 if (oldUpdate == false) then elseif (oldUpdate == nil and not (newUpdate == nil)) then updateFunction = function (dt) newUpdate(dt) end elseif not (newUpdate == nil) then updateFunction = function (dt) oldUpdate(dt) newUpdate(dt) end end if (oldDraw == false) then elseif (oldDraw == nil and not (newDraw == nil)) then drawFunction = function () newDraw() end elseif not (newDraw == nil) then drawFunction = function () oldDraw() newDraw() end end if (oldPress == false) then elseif (oldPress == nil and not (newPress == nil)) then keypressedFunction = function (key) newPress(key) end elseif not (newPress == nil) then keypressedFunction = function (key) oldPress(key) newPress(key) end end if (oldRelease == false) then elseif (oldRelease == nil and not (newRelease == nil)) then keyreleasedFunction = function (key) newRelease(key) end elseif not (newPress == nil) then keyreleasedFunction = function (key) oldRelease(key) newRelease(key) end end end function newCamera() local width,height = love.window.getMode() local scale = height / 800 logMsg("[Camera]", "Scale: " .. scale) camera = stalker() camera.scale = scale camera:setFollowStyle('NO_DEADZONE') camera:follow(400, 400) end function newBgm() bgm = love.audio.newSource(MUSIC[math.random(1,table.maxn(MUSIC))], "stream") bgm:play() end -- MISC DATA -------------------------------------------------------------------------------- -- CHARACTERS ------------------------------------------ CHARACTERS = {} -- Lion Jellyfish by rapidpunches, CC-BY-SA 4.0 CHARACTERS[1] = love.graphics.newImage("art/sprites/jellyfish-lion.png") -- N Jellyfish by rapidpunches, CC-BY-SA 4.0 CHARACTERS[2] = love.graphics.newImage("art/sprites/jellyfish-n.png") -- Octopus by rapidpunches, CC-BY-SA 4.0 CHARACTERS[3] = love.graphics.newImage("art/sprites/octopus.png") -- Something Indecipherable by my little brother (<3<3), CC-BY-SA 4.0 --CHARACTERS[4] = love.graphics.newImage("art/sprites/shark-unicorn.png") -- MUSIC ------------------------------------------ MUSIC = {} MUSIC[1] = "art/music/Cephalopod.ogg" MUSIC[2] = "art/music/Go Cart.ogg" MUSIC[3] = "art/music/Latin Industries.ogg" MUSIC[4] = "art/music/Ouroboros.ogg" MUSIC[5] = "art/music/Pamgaea.ogg" -- DEFAULT NAMES ------------------------------------------ NAMES = {"Ignucius", "Splashers", "Penguin", "Tux", "Puffy", "Doktoro", "Espero", "<3", "