diff --git a/src/client/assets/SitkaB.ttc b/src/client/assets/SitkaB.ttc new file mode 100644 index 0000000..a146f09 Binary files /dev/null and b/src/client/assets/SitkaB.ttc differ diff --git a/src/client/assets/strings.lua b/src/client/assets/strings.lua new file mode 100644 index 0000000..3bd8320 --- /dev/null +++ b/src/client/assets/strings.lua @@ -0,0 +1,10 @@ +return setmetatable({ + ["newgame_button"] = "New Game", + ["join_button"] = "Join Server", + ["quit_button"] = "Quit", + ["option_button"] = "Settings", + ["mainmenu_button"] = "Main Menu", + ["option_name"] = "Player Name", + ["option_pron"] = "Player Pronouns", + ["option_tint"] = "Player Colour", +}, {__index = function( t, k ) return k end } ) \ No newline at end of file diff --git a/src/client/browser.lua b/src/client/browser.lua index 1365656..b8e05ae 100644 --- a/src/client/browser.lua +++ b/src/client/browser.lua @@ -14,4 +14,13 @@ function browser.onLoad( ) lg.setColor( 1, 1, 1, 1 ) end -return scene.add( browser, 'browser' ) \ No newline at end of file +function browser.mousepressed() + +end + +function browser.keypressed( key, code, isRepeat ) + if code == "escape" then return scene.mainmenu() end +end + +scene.browser = browser +return browser \ No newline at end of file diff --git a/src/client/button.lua b/src/client/button.lua index e69de29..8161c5f 100644 --- a/src/client/button.lua +++ b/src/client/button.lua @@ -0,0 +1,42 @@ +local button = {} +local lg = assert( love.graphics ) + +function button:new( t, x, y, w, h, text, color, callback ) + --print( t.x, t.y, t.w, t.h, t.text, t.color, t.callback ) + return setmetatable( t or + { + x = 0, y = 0, + w = 100, h = 100, + text = text, color = color, + callback = callback, + selected = false + }, + { + __index = button, + __call = t.callback or callback + } + ) +end + +function button:contains( x, y ) + local mx, my, Mx, My = self.x, self.y, self.x + self.w, self.y + self.h + return (x < Mx and x > mx and y > my and y < My) +end + +function button:draw( ) + lg.setColor( self.color ) + lg.rectangle( "fill", self.x, self.y, self.w, self.h, 10) + + + if self.selected then + lg.setColor( 1, 1, 1, 0.8 ) + lg.rectangle( "fill", self.x + 3, self.y + 3, self.w - 6, self.h - 6, 10 ) + else + lg.setColor( 0, 0, 0, 0.7 ) + end + +lg.setColor( 0, 0, 0, 0.7 ) + lg.print( self.text, self.x + 15, self.y + 10 ) +end + +return setmetatable( button, { __call = button.new } ) \ No newline at end of file diff --git a/src/client/game.lua b/src/client/game.lua index 4bdf48d..716bc29 100644 --- a/src/client/game.lua +++ b/src/client/game.lua @@ -8,26 +8,42 @@ local game = {} local t = 0 local tick = 0 -local currentWorld = shared.NewWorld() function game.draw() + +end +function game.onPacket( data, msg ) + if data then print( data, msg ) end end function game.update( dt ) t = dt + t + game.onPacket( udp:receive() ) if t > 0.1 then t = 0 tick = tick + 1 - local s = string.format("client: %d", tick) - print( s ) - udp:send( s ) + udp:send( tostring(tick) ) end end +function game.newGame( ) + game.curWorld = shared.NewWorld() --Last world state received from server. + game.preWorld = shared.NewWorld() --Current world state predicted by this client. +end + +function game.disconnect( ) + return scene.mainmenu() +end + function game.onLoad( ) udp:settimeout( 0 ) udp:setpeername( "192.168.2.15", 51312 ) end -return scene.add( game, 'game' ) \ No newline at end of file +function game.keypressed( key, code, isRepeat ) + if code == "escape" then return game.disconnect() end +end + +scene.game = game +return game \ No newline at end of file diff --git a/src/client/menu.lua b/src/client/menu.lua index 1fdb83a..a3cec23 100644 --- a/src/client/menu.lua +++ b/src/client/menu.lua @@ -1,40 +1,100 @@ ---Main menu for client. local lg = assert( love.graphics ) +local love = assert( love ) local scene = assert( require 'client.scene' ) -local strings = assert( require 'client.strings' ) +local strings = assert( require 'client.assets.strings' ) +local button = assert( require 'client.button' ) local menu = {} local t = 0 local wWidth = 800 local wHeight = 600 -function menu.onLoad() - lg.setNewFont( 32 ) -end +local selectedButtonIdx = nil + +local canvas = lg.newCanvas() +local buttons = + { + button{ + x = 15, w = 400, h = 50, + y = 115, + text = strings.newgame_button, + color = { 0.3, 0.2, 0.9, 0.5 }, + callback = function() return scene.game() end }, + + button{ + x = 15, w = 400, h = 50, + y = 115 + 55, + text = strings.join_button, + color = { 0.3, 0.2, 0.8, 0.5 }, + callback = function() return scene.browser() end }, + + button{ + x = 15, w = 400, h = 50, + y = 115 + 55 * 2, + text = strings.option_button, + color = { 0.3, 0.2, 0.9, 0.5 }, + callback = function() return scene.options() end }, + + button{ + x = 15, w = 400, h = 50, + y = 115 + 55 * 3, + text = strings.quit_button, + color = { 0.3, 0.2, 1.0, 0.5 }, + callback = love.event.quit }, + } + +local gradientQuad = lg.newMesh{ + { + -- top-left corner (red-tinted) + 0, 0, -- position of the vertex + 0, 0, -- texture coordinate at the vertex position + 0.4, 0.1, 0.4, 0.0 -- color of the vertex + }, + { + -- top-right corner (green-tinted) + 1, 0, + 1, 0, -- texture coordinates are in the range of [0, 1] + 0.8, 0.3, 0.1, 1.0 + }, + { + -- bottom-right corner (blue-tinted) + 1, 1, + 1, 1, + 0.7, 0.4, 0.1, 1.0 + }, + { + -- bottom-left corner (yellow-tinted) + 0, 1, + 0, 1, + 0.4, 0.15, 0.3, 0.0 + }, + } function menu.draw() - local x, y = 10, 10 - do - lg.setColor( 1, 0.8, 0.5, 1 ) - lg.rectangle( "fill", x, y, ( wWidth - 20 ) / 2, 50, 15 ) - lg.setColor( 1, 1, 1, 1 ) - lg.print( strings.newgame_button, x + 15, y + 5 ) - y = y + 100 - end - do - lg.setColor( 1, 0.8, 0.5, 1 ) - lg.rectangle( "fill", x, y, ( wWidth - 20 ) / 2, 50, 15 ) - lg.setColor( 1, 1, 1, 1 ) - lg.print( strings.join_button, x + 15, y + 5 ) - y = y + 100 - end - do - lg.setColor( 1, 0.8, 0.5, 1 ) - lg.rectangle( "fill", x, y, ( wWidth - 20 ) / 2, 50, 15 ) - lg.setColor( 1, 1, 1, 1 ) - lg.print( strings.quit_button, x + 15, y + 5 ) - y = y + 100 - end + lg.setCanvas() + lg.setColor( 1,1,1,1 ) + lg.draw( canvas ) +end + +function menu.paint() + lg.setCanvas( canvas ) + + --bg + lg.setColor( 0.8, 0.6, 0.3, 1 ) + lg.rectangle( "fill", 0, 0, wWidth, wHeight ) + + --buttons + for id, button in pairs( buttons ) do button:draw( ) end + + --gradient + lg.setColor( 1, 1, 1, 1 ) + lg.draw( gradientQuad, 0, 0, 0, wWidth, wHeight ) + lg.setCanvas() +end + +function menu.onLoad() + lg.setNewFont( "client/assets/SitkaB.ttc", 28 ) + return menu.resize( lg.getDimensions() ) end function menu.update( dt ) @@ -43,20 +103,64 @@ end function menu.resize( w, h ) wWidth, wHeight = w, h + canvas = lg.newCanvas() + for id, uiButton in pairs( buttons ) do + uiButton.w = wWidth + end + menu.paint() end function menu.mousemoved( x, y, dx, dy, istouch ) - + if selectedButtonIdx then + buttons[selectedButtonIdx].selected = false + selectedButtonIdx = nil + end + for id, menuButton in ipairs( buttons ) do + if menuButton:contains( x, y ) then + menuButton.selected = true + selectedButtonIdx = id + break + end + end + + return menu.paint() end function menu.mousepressed( x, y, button, istouch, presses ) - if button == 1 then scene.load( 'browser' ) - else scene.load( 'game' ) - end + if not selectedButtonIdx then return end + local uiButton = buttons[selectedButtonIdx] + if uiButton:contains( x, y ) then return uiButton() end + return menu.paint() end function menu.keypressed( key, code, isrepeat ) - + + if code == "escape" then + return love.event.quit() + end + + if code == "return" and selectedButtonIdx then + return buttons[selectedButtonIdx]() + end + + if code == "down" or code == "tab" or code == "up" then + local sbi = (selectedButtonIdx or 1) + buttons[sbi].selected = false + + --Increment / decrement + sbi = sbi + ((code == "up") and -1 or 1) + if sbi > #buttons then sbi = 1 end + if sbi < 1 then sbi = #buttons end + + --Assign + print( "selecting button: ", sbi ) + selectedButtonIdx = sbi + buttons[selectedButtonIdx].selected = true + end + + + return menu.paint() end -return scene.add( menu, 'menu' ) \ No newline at end of file +scene.mainmenu = menu +return menu \ No newline at end of file diff --git a/src/client/options.lua b/src/client/options.lua new file mode 100644 index 0000000..850af7f --- /dev/null +++ b/src/client/options.lua @@ -0,0 +1,108 @@ +local lg = assert( love.graphics ) +local love = assert( love ) +local scene = assert( require 'client.scene' ) +local strings = assert( require 'client.assets.strings' ) +local button = assert( require 'client.button' ) +local menu = {} + +local t = 0 +local wWidth = 800 +local wHeight = 600 + +local selectedButtonIdx = nil + +local buttons = + { + button{ + x = 15, w = 400, h = 50, + y = 115, + text = strings.option_name, + color = { 0.5, 0.7, 0.5, 1 }, + callback = function() print("Adjust Name") end }, + + button{ + x = 15, w = 400, h = 50, + y = 115 + 55, + text = strings.option_pron, + color = { 0.5, 0.7, 0.5, 1 }, + callback = function() print("Adjust Name") end }, + + button{ + x = 15, w = 400, h = 50, + y = 115 + 55 * 2, + text = strings.option_tint, + color = { 0.5, 0.7, 0.5, 1 }, + callback = function() print("Adjust Colour") end }, + + button{ + x = 15, w = 400, h = 50, + y = 115 + 55 * 3, + text = strings.mainmenu_button, + color = { 0.5, 0.7, 0.5, 1 }, + callback = function() print("Adjust Name") return scene.mainmenu() end }, + } + +function menu.onLoad() +end + +function menu.draw() + for id, button in pairs( buttons ) do button:draw( ) end +end + +function menu.update( dt ) + t = t + dt +end + +function menu.resize( w, h ) + wWidth, wHeight = w, h +end + +function menu.mousemoved( x, y, dx, dy, istouch ) + if selectedButtonIdx then + buttons[selectedButtonIdx].selected = false + selectedButtonIdx = nil + end + for id, menuButton in ipairs( buttons ) do + if menuButton:contains( x, y ) then + menuButton.selected = true + selectedButtonIdx = id + break + end + end +end + +function menu.mousepressed( x, y, button, istouch, presses ) + if not selectedButtonIdx then return end + local uiButton = buttons[selectedButtonIdx] + if uiButton:contains( x, y ) then return uiButton() end +end + +function menu.keypressed( key, code, isrepeat ) + + if code == "escape" then + return scene.mainmenu() + end + + if code == "return" and selectedButtonIdx then + return buttons[selectedButtonIdx]() + end + + if code == "down" or code == "tab" or code == "up" then + local sbi = (selectedButtonIdx or 1) + buttons[sbi].selected = false + + --Increment / decrement + sbi = sbi + ((code == "up") and -1 or 1) + if sbi > #buttons then sbi = 1 end + if sbi < 1 then sbi = #buttons end + + --Assign + print( "selecting button: ", sbi ) + selectedButtonIdx = sbi + buttons[selectedButtonIdx].selected = true + end + +end + +scene.options = menu +return menu \ No newline at end of file diff --git a/src/client/scene.lua b/src/client/scene.lua index 7532b5f..09c5927 100644 --- a/src/client/scene.lua +++ b/src/client/scene.lua @@ -2,19 +2,22 @@ local scene = {} local love = assert( love ) local mt = {} -function mt.load( name ) - print( "Loading Scene:", name ) - local scene = assert( scene[name] ) +local function loadScene( scene ) + print( "Loading Scene:", scene.name ) for k, v in pairs( scene ) do love[k] = v end scene.onLoad() end -function mt.add( t, name ) - print( "Adding Scene:", t.name or name ) - scene[name] = t - return t +local function newScene( scenes, name, t ) + t.name = t.name or name + print( "Adding Scene:", t.name ) + setmetatable( t, { __call = function() return loadScene( t ) end } ) + rawset( scenes, name, t ) end -return setmetatable( scene, {__index = mt } ) \ No newline at end of file +return setmetatable( scene, + {__call = loadScene, + __newindex = newScene + } ) \ No newline at end of file diff --git a/src/client/strings.lua b/src/client/strings.lua deleted file mode 100644 index 9e238d4..0000000 --- a/src/client/strings.lua +++ /dev/null @@ -1,5 +0,0 @@ -return { - ["newgame_button"] = "New Game", - ["join_button"] = "Join Server", - ["quit_button"] = "Quit", -} \ No newline at end of file diff --git a/src/main.lua b/src/main.lua index 0829491..1cf3959 100644 --- a/src/main.lua +++ b/src/main.lua @@ -7,5 +7,6 @@ function love.load() assert( require 'client.menu' ) assert( require 'client.browser' ) assert( require 'client.game' ) - scenes.load( 'menu' ) + assert( require 'client.options' ) + scenes.mainmenu() end diff --git a/src/server.lua b/src/server.lua index e4d3bec..1e331fd 100644 --- a/src/server.lua +++ b/src/server.lua @@ -9,6 +9,10 @@ local server = { serverName = "dajjal-server", } +local clients = { + +} + do local _print = print function server.Print(...) @@ -25,9 +29,11 @@ function server.StartLocalClient() os.execute( "start vision.bat" ) end +--Incoming packet. function server.Parse( packet, ip, port ) if not packet then return end - print( packet ) + print( packet, ip, port ) + return server.Parse( udp:receivefrom() ) -- Process any packets we missed. end function server.Start() @@ -38,15 +44,18 @@ function server.Start() repeat server.Parse( udp:receivefrom() ) server.Advance() - until socket.sleep( 0.1 ) + until socket.sleep( 0.1 - (socket.gettime() % 0.1) ) end function server.Advance() server.tick = server.tick + 1 + for id, client in ipairs( clients ) do + udp:sendto( string.format("server: %d client: %d", server.tick, client.tick), client.ip, client.port) + end end function server.NewGame() - + server.tick = 0 end function server.Quit()