diff --git a/src/client/assets/CinzelDecorative-Black.otf b/src/client/assets/CinzelDecorative-Black.otf new file mode 100644 index 0000000..e4aeef4 Binary files /dev/null and b/src/client/assets/CinzelDecorative-Black.otf differ diff --git a/src/client/assets/OFL.txt b/src/client/assets/OFL.txt new file mode 100644 index 0000000..0f1e2d1 --- /dev/null +++ b/src/client/assets/OFL.txt @@ -0,0 +1,92 @@ +Copyright (c) 2012 Natanael Gama (info@ndiscovered.com), with Reserved Font Name 'Cinzel' +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/client/assets/strings.lua b/src/client/assets/strings.lua index dc6ef64..ee18cf0 100644 --- a/src/client/assets/strings.lua +++ b/src/client/assets/strings.lua @@ -1,11 +1,11 @@ return setmetatable({ - ["newgame_button"] = "New Game", - ["join_button"] = "Join Server", + ["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", - ["option_keybinds"] = "Edit Keybindings", + ["mainmenu_button"] = "Main menu", + ["option_name"] = "Player name", + ["option_pron"] = "Player pronouns", + ["option_tint"] = "Player colour", + ["option_keybinds"] = "Edit keybindings", }, {__index = function( t, k ) return k end } ) \ No newline at end of file diff --git a/src/client/scene.lua b/src/client/scene.lua index c14f581..030d208 100644 --- a/src/client/scene.lua +++ b/src/client/scene.lua @@ -1,23 +1,36 @@ local scene = {} local love = assert( love ) + +local callbacks = { + draw = true, + mousepressed = true, + mousemoved = true, + keypressed = true, + update = true, + resize = true, +} + local mt = {} -local function loadScene( scene, params ) - print( "Loading Scene:", scene.name ) - for k, v in pairs( scene ) do - love[k] = v +print( 'scene', scene ) + +function scene.loadScene( scen, params ) + print( "Loading Scene:", scen.name ) + for k, v in pairs( callbacks ) do + if not scen[k] then print( "Warning: scene missing callback.", scen.name, k ) end + love[k] = scen[k] or love[k] end - scene.onLoad( params ) + scen:onLoad( params ) end 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 } ) + setmetatable( t, { __call = function() return scene.loadScene( t ) end } ) rawset( scenes, name, t ) end return setmetatable( scene, - {__call = loadScene, + {__call = scene.loadScene, __newindex = newScene } ) \ No newline at end of file diff --git a/src/client/ui/button.lua b/src/client/ui/button.lua index b142974..b130d5a 100644 --- a/src/client/ui/button.lua +++ b/src/client/ui/button.lua @@ -1,21 +1,34 @@ -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 - } - ) +local lg = assert( love.graphics ) +local button = { + h = lg.getFont():getHeight() + 12, + y = 0, + x = 0, + w = 100, + space = 15, +} +local mt = { __index = button } + +function button:new( t ) + t = t or {} + + if t.y then button.y = t.y end + if t.h then button.h = t.h end + if t.w then button.w = t.w end + if t.x then button.x = t.x end + + t.x = t.x or button.x + t.y = t.y or button.y + t.w = t.w or button.w + t.h = t.h or button.h + t.text = t.text or "" + t.color = t.color or { 0.5, 0.5, 0.5, 0.5 } + t.callback = t.callback or function() print( "Clicked button:", t.text ) end + t.selected = t.selected or false + + button.y = button.y + t.h + button.space + + return setmetatable( t, mt ) end function button:contains( x, y ) @@ -33,8 +46,10 @@ function button:draw( ) lg.rectangle( "fill", self.x + 3, self.y + 3, self.w - 6, self.h - 6, 10 ) end -lg.setColor( 0, 0, 0, 0.7 ) - lg.print( self.text, self.x + 15, self.y + 10 ) + lg.setColor( 0, 0, 0, 0.8 ) + lg.print( self.text, self.x + 15, self.y + 6) + lg.setColor( 0, 0, 0, 0.2 ) + lg.print( self.text, self.x + 18, self.y + 8) end return setmetatable( button, { __call = button.new } ) \ No newline at end of file diff --git a/src/client/ui/mainmenu.lua b/src/client/ui/mainmenu.lua new file mode 100644 index 0000000..0c347a1 --- /dev/null +++ b/src/client/ui/mainmenu.lua @@ -0,0 +1,48 @@ +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.ui.button' ) +local menu = assert( require 'client.ui.menu' ) + +return menu.new( + "mainmenu", + + { + + button{ + x = 15, w = lg.getWidth(), y = 115, + text = strings.newgame_button, + color = { 0.6, 0.6, 0.6, 0.9 }, + callback = function() return scene.game() end }, + + button{ + text = strings.join_button, + color = { 0.6, 0.6, 0.6, 0.9 }, + callback = function() return scene.browser() end }, + + button{ + text = strings.option_button, + color = { 0.6, 0.6, 0.6, 0.9 }, + callback = function() return scene.options() end }, + + button{ + text = strings.quit_button, + color = { 0.6, 0.6, 0.6, 0.9 }, + callback = love.event.quit }, + + }, + + lg.newMesh{ + { 0, 0, 0, 0, 1, 1, 1, 0.01 }, + { 1, 0, 1, 0, 1, 1, 1, 0.1 }, + { 1, 1, 1, 1, 0, 0, 0, 0.1 }, + { 0, 1, 0, 1, 0, 0, 0, 0.01 }, + }, + + lg.newMesh{ + { 0, 0, 0, 0, 0.4, 0.05, 0.0, 0.1 }, + { 1, 0, 1, 0, 0.8, 0.3, 0.1, 0.8 }, + { 1, 1, 1, 1, 0.7, 0.4, 0.1, 0.8 }, + { 0, 1, 0, 1, 0.4, 0.05, 0.05, 0.1 }, + } ) \ No newline at end of file diff --git a/src/client/ui/menu.lua b/src/client/ui/menu.lua index c47eb9d..9615458 100644 --- a/src/client/ui/menu.lua +++ b/src/client/ui/menu.lua @@ -1,74 +1,36 @@ -local lg = assert( love.graphics ) local love = assert( love ) +local lg = assert( love.graphics ) local scene = assert( require 'client.scene' ) -local strings = assert( require 'client.assets.strings' ) -local button = assert( require 'client.ui.button' ) +print( 'scene', scene ) local menu = {} -local t = 0 -local wWidth = 800 -local wHeight = 600 +--Static variables. +local selectedButtonIdx +local canvas +local wWidth, wHeight +local currentMenu -local selectedButtonIdx = nil +function menu.new( name, buttons, fg, bg ) + local t = { buttons = buttons, fg = fg, bg = bg } + scene[name] = t + print( 'scene', scene ) + getmetatable( t ).__index = menu + return t +end -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 }, - } +function menu:onLoad() + print( 'loading:', self.name ) + currentMenu = self + return menu.resize( lg.getDimensions() ) +end -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.update( dt ) end + +function menu.resize( w, h ) + wWidth, wHeight = w, h + canvas = lg.newCanvas() + return currentMenu:paint() +end function menu.draw() lg.setCanvas() @@ -76,89 +38,101 @@ function menu.draw() 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( 28 ) - return menu.resize( lg.getDimensions() ) -end - -function menu.update( dt ) - t = t + dt -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 + if not currentMenu then return end + local buttons = currentMenu.buttons + + local selectedButton = buttons[selectedButtonIdx or 0] for id, menuButton in ipairs( buttons ) do if menuButton:contains( x, y ) then + if selectedButton then selectedButton.selected = false end menuButton.selected = true selectedButtonIdx = id - return menu.paint() + if menuButton ~= selectedButton then + return currentMenu:paint() + else return end end end + + --deselect button + if selectedButton then + selectedButtonIdx = nil + selectedButton.selected = false + return currentMenu:paint() + 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 - return menu.paint() + + if not selectedButtonIdx and currentMenu then return end + local uiButton = currentMenu.buttons[selectedButtonIdx] + if uiButton:contains( x, y ) then + selectedButtonIdx = nil + uiButton.selected = false + return uiButton:callback() + end + return currentMenu:paint() end function menu.keypressed( key, code, isrepeat ) + assert( currentMenu ) + if code == "escape" then return love.event.quit() end + local buttons = currentMenu.buttons + if code == "return" and selectedButtonIdx then - return buttons[selectedButtonIdx]() + local button = buttons[selectedButtonIdx] + selectedButtonIdx = nil + button.selected = false + return button:callback() 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() + + + return currentMenu:paint() end -scene.mainmenu = menu +function menu:paint() + lg.setCanvas( canvas ) + + --bg + lg.setColor( 1, 1, 1, 1 ) + lg.draw( self.bg, 0, 0, 0, wWidth, wHeight ) + + --buttons + for i = #self.buttons, 1, -1 do self.buttons[i]:draw( ) end + + --gradient + lg.setColor( 1, 1, 1, 1 ) + local r = math.random + local v = r() * 0.4 + 0.6 + + local fg = self.fg + fg:setVertexAttribute( 2, 3, v * (0.7 + 0.2 * r()), v * (0.1 + 0.4 * r()), v * (0.1 * r()), 1 ) + fg:setVertexAttribute( 1, 3, 1 - v, 0, 0, 0.1 * (1 - v) ) + fg:setVertexAttribute( 4, 3, 1 - v, 0, 0, 0.1 * (1 - v) ) + fg:setVertexAttribute( 3, 3, v * (0.7 + 0.2 * r()), v * (0.1 + 0.4 * r()), v * (0.1 * r()), 1 ) + lg.draw( fg, 0, 0, 0, wWidth, wHeight ) + lg.setCanvas() +end + + return menu \ No newline at end of file diff --git a/src/client/ui/options.lua b/src/client/ui/options.lua index 4a4bb11..dfd2602 100644 --- a/src/client/ui/options.lua +++ b/src/client/ui/options.lua @@ -3,179 +3,56 @@ local love = assert( love ) local scene = assert( require 'client.scene' ) local strings = assert( require 'client.assets.strings' ) local button = assert( require 'client.ui.button' ) -local textinput = assert( require 'client.ui.textinput' ) -local menu = {} +local menu = assert( require 'client.ui.menu' ) -local t = 0 -local wWidth = 800 -local wHeight = 600 -local canvas = lg.newCanvas() +return menu.new( + "options", -local selectedButtonIdx = nil + { -local gradientQuad = lg.newMesh{ - { 0, 0, 0, 0, 0.4, 0.1, 0.4, 0.0 }, - { 1, 0, 1, 0, 0.8, 0.3, 0.1, 1.0 }, - { 1, 1, 1, 1, 0.7, 0.4, 0.1, 1.0 }, - { 0, 1, 0, 1, 0.4, 0.1, 0.3, 0.0 }, -} + button{ + x = 15, y = 115, w = 800, + text = strings.mainmenu_button, + color = { 0.6, 0.6, 0.6, 0.8 }, + callback = function() return scene.mainmenu() end }, -local buttons = -{ - - button{ - x = 15, w = 400, h = 50, - y = 115, - text = strings.mainmenu_button, - color = { 0.5, 0.2, 0.8, 0.6 }, - callback = function() return scene.mainmenu() end }, - - button{ - x = 15, w = 400, h = 50, - y = 115 + 55, - option = 'name', - text = strings.option_name, - color = { 0.5, 0.2, 0.2, 0.6 }, - callback = menu.textOption }, + button{ + option = 'name', + text = strings.option_name, + color = { 0.6, 0.6, 0.6, 0.8 }, + callback = menu.textOption }, - button{ - x = 15, w = 400, h = 50, - y = 115 + 55 * 2, - option = 'pronoun', - text = strings.option_pron, - color = { 0.5, 0.2, 0.4, 0.6 }, - callback = menu.textOption }, + button{ + option = 'pronoun', + text = strings.option_pron, + color = { 0.6, 0.6, 0.6, 0.8 }, + callback = menu.textOption }, - button{ - x = 15, w = 400, h = 50, - y = 115 + 55 * 3, - option = 'colour', - text = strings.option_tint, - color = { 0.5, 0.2, 0.6, 0.6 }, - callback = menu.colourOption }, + button{ + option = 'colour', + text = strings.option_tint, + color = { 0.6, 0.6, 0.6, 0.8 }, + callback = menu.colourOption }, - - button{ - x = 15, w = 400, h = 50, - y = 115 + 55 * 4, - option = 'keybinds', - text = strings.keybinding_button, - color = { 0.8, 0.0, 0.4, 0.8 }, - callback = menu.editKeybinds, + + button{ + option = 'keybinds', + text = strings.option_keybinds, + color = { 0.6, 0.6, 0.6, 0.8 }, + callback = menu.editKeybinds, } -} - ---[[local keybindButtons = { - button{ - x = wWidth / 2, w = 400, h = 50 - y = 115, - text = options:get( 'forward_key' ), - color = { 0.8, 0.0, 0.4, 0.8 }, - callback = function() options:set( 'forward_key' ) end, }, - - button{ - x = wWidth / 2, w = 400, h = 50 - y = 115, - text = strings.backward_key, - color = { 0.8, 0.0, 0.4, 0.8 }, - callback = function() return setOption( 'backward_key' ) end, - } - -}]] -function menu.onLoad() - lg.setNewFont( 28 ) - return menu.resize( lg.getDimensions() ) -end + lg.newMesh{ + { 0, 0, 0, 0, 0.4, 0.1, 0.05, 0.0 }, + { 1, 0, 1, 0, 0.8, 0.3, 0.1, 0.8 }, + { 1, 1, 1, 1, 0.7, 0.4, 0.1, 0.8 }, + { 0, 1, 0, 1, 0.4, 0.1, 0.03, 0.0 },}, -function menu.draw() - 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.update( dt ) - t = t + dt -end - -function menu.resize( w, h ) - wWidth, wHeight = w, h - canvas = lg.newCanvas() - for id, uiButton in pairs( buttons ) do - uiButton.w = wWidth - end - return 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 - return menu.paint() - 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 - - return menu.paint() -end - -function menu.keypressed( key, code, isrepeat ) - - if code == "escape" then - return scene.mainmenu() - end - - if code == "return" and selectedButtonIdx then - return buttons[selectedButtonIdx].callback() - 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 - -scene.options = menu -return menu \ No newline at end of file + lg.newMesh{ + { 0, 0, 0, 0, 1, 1, 1, 0.01 }, + { 1, 0, 1, 0, 1, 1, 1, 0.1 }, + { 1, 1, 1, 1, 0, 0, 0, 0.1 }, + { 0, 1, 0, 1, 0, 0, 0, 0.01 },} +) \ No newline at end of file diff --git a/src/main.lua b/src/main.lua index c34ffde..65418e6 100644 --- a/src/main.lua +++ b/src/main.lua @@ -3,10 +3,12 @@ local shared = assert( require 'shared' ) local love = assert( love ) function love.load() + love.graphics.setNewFont( "client/assets/CinzelDecorative-Black.otf", 36 ) local scenes = assert( require 'client.scene' ) - assert( require 'client.ui.menu' ) + + assert( require 'client.ui.options' ) assert( require 'client.ui.browser' ) assert( require 'client.game' ) - assert( require 'client.ui.options' ) - scenes.mainmenu() + assert( require 'client.ui.mainmenu' ) + scenes.loadScene( scenes.mainmenu ) end