From 1ef7eb8e57d52fd0a63e5e6b3e4f7e63e4e1fe07 Mon Sep 17 00:00:00 2001 From: Paul Liverman Date: Tue, 10 Feb 2015 16:52:25 -0800 Subject: [PATCH] woo more stuff - custom button support WIP - logging --- src/conf.lua | 6 +- src/gamestates/game.lua | 46 ++++++++------- src/gamestates/menu.lua | 79 ++++++++++++++++++++++++-- src/lib/ser.lua | 122 ++++++++++++++++++++++++++++++++++++++++ src/main.lua | 61 ++++++++++++++++---- src/util/input.lua | 10 ++++ 6 files changed, 290 insertions(+), 34 deletions(-) create mode 100644 src/lib/ser.lua create mode 100644 src/util/input.lua diff --git a/src/conf.lua b/src/conf.lua index 5638368..84dae93 100644 --- a/src/conf.lua +++ b/src/conf.lua @@ -1,8 +1,10 @@ +local debug = true + function love.conf(t) t.identity = "rgb" t.version = "0.9.1" --t.author = "Guard13007" - --t.console = true + if debug then t.console = true end t.window = {} t.window.title = "RGB - The Color Chooser" @@ -16,3 +18,5 @@ function love.conf(t) t.modules.joystick = false t.modules.physics = false end + +return debug diff --git a/src/gamestates/game.lua b/src/gamestates/game.lua index 0dd76a3..7d3f0fd 100644 --- a/src/gamestates/game.lua +++ b/src/gamestates/game.lua @@ -1,5 +1,7 @@ love.math.setRandomSeed(os.time()) +local input = require "util.input" + -- Gamestates --local won = require "gamestates.won" --TODO MAKE THIS local lost = require "gamestates.lost" @@ -12,7 +14,7 @@ local game = {} local boxes = {} local score, totalScore = 0, 0 local level, time, startingTime = 0, 0, 0 -local previousState, gameSettings +local previousState, gameSettings, controls --these are defined on each entry to this gamestate local screenWidth, screenHeight --defines where things are rendered local boxColumns, boxRows --defines how many boxes @@ -20,6 +22,8 @@ local boxColumns, boxRows --defines how many boxes local boxSize, colorStep, timeLimit = 20, 80, 60 --default values just in case local function nextLevel() + log("Creating the next level!") + totalScore = totalScore + score score = 0 level = level + 1 @@ -43,6 +47,8 @@ local function nextLevel() boxes[x][y][2] = boxes[x][y][2] - boxes[x][y][2] % colorStep boxes[x][y][3] = boxes[x][y][3] - boxes[x][y][3] % colorStep end + + log("Done!") end local function colorsEqual(A, B) @@ -56,7 +62,8 @@ local function copyColor(A) return {A[1], A[2], A[3]} end -function game:enter(previous, settings) +function game:enter(previous, settings, gameControls) + log("Entering game...") -- save the state we came from previousState = previous -- set locals based on screen size @@ -66,6 +73,7 @@ function game:enter(previous, settings) boxRows = math.floor(screenHeight / boxSize) - 5 -- save the settings for later use gameSettings = settings or gameSettings + controls = gameControls or controls -- set how to play the game based on settings boxSize = gameSettings.boxSize colorStep = gameSettings.colorStep @@ -165,19 +173,19 @@ function game:mousepressed(x, y, button) -- check if we are actually over a box first if boxes[nx][ny] then -- left, red - if button == "l" then + if input(button, controls.red) then boxes[nx][ny][1] = boxes[nx][ny][1] + colorStep if boxes[nx][ny][1] > 255 then boxes[nx][ny][1] = 0 end -- middle, green - elseif button == "m" or button == "wu" or button == "wd" then + elseif input(button, controls.green) then boxes[nx][ny][2] = boxes[nx][ny][2] + colorStep if boxes[nx][ny][2] > 255 then boxes[nx][ny][2] = 0 end -- right, blue - elseif button == "r" then + elseif input(button, controls.blue) then boxes[nx][ny][3] = boxes[nx][ny][3] + colorStep if boxes[nx][ny][3] > 255 then boxes[nx][ny][3] = 0 @@ -186,6 +194,20 @@ function game:mousepressed(x, y, button) end end +function game:keypressed(key, unicode) + if input(key, controls.back) then + Gamestate.switch(previousState) + elseif input(key, controls.pause) then + Gamestate.push(paused, love.graphics.newScreenshot()) + end +end + +function game:focus(isFocused) + if not isFocused then + Gamestate.push(paused, love.graphics.newScreenshot()) + end +end + function game:leave() --double check the correctness of this level = 0 @@ -195,18 +217,4 @@ function game:leave() startingTime = 0 end -function game:keypressed(key, unicode) - if key == " " then - Gamestate.push(paused, love.graphics.newScreenshot()) - elseif key == "escape" then - Gamestate.switch(previousState) - end -end - -function game:focus(isFocused) - if not isFocused then - Gamestate.push(paused, love.graphics.newScreenshot()) - end -end - return game diff --git a/src/gamestates/menu.lua b/src/gamestates/menu.lua index 61e2720..b240f40 100644 --- a/src/gamestates/menu.lua +++ b/src/gamestates/menu.lua @@ -1,11 +1,82 @@ +local ser = require "lib.ser" +local input = require "util.input" + local Gamestate = require "lib.gamestate" local game = require "gamestates.game" local menu = {} local screenWidth, screenHeight +local settings, controls + +function menu:init() + log("Initializing menu...") + -- load or create settings + if love.filesystem.isFile("settings.ini") then + log("Loading settings (again)...") + settings = inifile.parse("settings.ini") + else + log("Creating settings...") + settings = { + display = { + width = love.graphics.getWidth(), + height = love.graphics.getHeight(), + fullscreen = false, + borderless = true, + }, + gamejolt = { + username = false, + usertoken = false + }, + sound = { + music = 0, + sfx = 0 + }, + difficulty = { + preset = "normal", + timeLimit = 60, + colorStep = 80, + boxSize = 20 + } + } + end + -- load or create controls + if love.filesystem.isFile("controls.lua") then + log("Loading controls...") + controls = require "controls" + else + log("Creating controls...") + controls = { + select = { + clicks = {"l"}, + buttons = {} + }, + back = { + clicks = {}, + buttons = {"escape"} + }, + pause = { + clicks = {}, + buttons = {" ", "escape"} + }, + red = { + clicks = {"l"}, + buttons = {} + }, + green = { + clicks = {"wd", "wu", "m"}, + buttons = {} + }, + blue = { + clicks = {"r"}, + buttons = {} + } + } + end +end function menu:enter() + log("Entering menu...") screenWidth = love.graphics.getWidth() screenHeight = love.graphics.getHeight() end @@ -22,14 +93,14 @@ function menu:draw() end function menu:mousepressed(x, y, button) - if button == "l" then - -- TODO replace constructed settings object with actual loaded settings - Gamestate.switch(game, {boxSize = 20, colorStep = 80, timeLimit = 10}) + if input(button, controls.select) then + Gamestate.switch(game, {boxSize = settings.difficulty.boxSize, colorStep = settings.difficulty.colorStep, timeLimit = settings.difficulty.timeLimit}, controls) end end function menu:keypressed(key, unicode) - if key == "escape" then + if input(key, controls.back) then + log("Quitting.") love.event.quit() end end diff --git a/src/lib/ser.lua b/src/lib/ser.lua new file mode 100644 index 0000000..1583968 --- /dev/null +++ b/src/lib/ser.lua @@ -0,0 +1,122 @@ +local pairs, ipairs, tostring, type, concat, dump, floor = pairs, ipairs, tostring, type, table.concat, string.dump, math.floor + +local function getchr(c) + return "\\" .. c:byte() +end + +local function make_safe(text) + return ("%q"):format(text):gsub('\n', 'n'):gsub("[\128-\255]", getchr) +end + +local oddvals = {[tostring(1/0)] = '1/0', [tostring(-1/0)] = '-1/0', [tostring(0/0)] = '0/0'} +local function write(t, memo, rev_memo) + local ty = type(t) + if ty == 'number' or ty == 'boolean' or ty == 'nil' then + t = tostring(t) + return oddvals[t] or t + elseif ty == 'string' then + return make_safe(t) + elseif ty == 'table' or ty == 'function' then + if not memo[t] then + local index = #rev_memo + 1 + memo[t] = index + rev_memo[index] = t + end + return '_[' .. memo[t] .. ']' + else + error("Trying to serialize unsupported type " .. ty) + end +end + +local kw = {['and'] = true, ['break'] = true, ['do'] = true, ['else'] = true, + ['elseif'] = true, ['end'] = true, ['false'] = true, ['for'] = true, + ['function'] = true, ['goto'] = true, ['if'] = true, ['in'] = true, + ['local'] = true, ['nil'] = true, ['not'] = true, ['or'] = true, + ['repeat'] = true, ['return'] = true, ['then'] = true, ['true'] = true, + ['until'] = true, ['while'] = true} +local function write_key_value_pair(k, v, memo, rev_memo, name) + if type(k) == 'string' and k:match '^[_%a][_%w]*$' and not kw[k] then + return (name and name .. '.' or '') .. k ..' = ' .. write(v, memo, rev_memo) + else + return (name or '') .. '[' .. write(k, memo, rev_memo) .. '] = ' .. write(v, memo, rev_memo) + end +end + +-- fun fact: this function is not perfect +-- it has a few false positives sometimes +-- but no false negatives, so that's good +local function is_cyclic(memo, sub, super) + local m = memo[sub] + local p = memo[super] + return m and p and m < p +end + +local function write_table_ex(t, memo, rev_memo, srefs, name) + if type(t) == 'function' then + return '_[' .. name .. '] = loadstring ' .. make_safe(dump(t)) + end + local m = {'_[', name, '] = {'} + local mi = 3 + for i = 1, #t do -- don't use ipairs here, we need the gaps + local v = t[i] + if v == t or is_cyclic(memo, v, t) then + srefs[#srefs + 1] = {name, i, v} + m[mi + 1] = 'nil, ' + mi = mi + 1 + else + m[mi + 1] = write(v, memo, rev_memo) + m[mi + 2] = ', ' + mi = mi + 2 + end + end + for k,v in pairs(t) do + if type(k) ~= 'number' or floor(k) ~= k or k < 1 or k > #t then + if v == t or k == t or is_cyclic(memo, v, t) or is_cyclic(memo, k, t) then + srefs[#srefs + 1] = {name, k, v} + else + m[mi + 1] = write_key_value_pair(k, v, memo, rev_memo) + m[mi + 2] = ', ' + mi = mi + 2 + end + end + end + m[mi > 3 and mi or mi + 1] = '}' + return concat(m) +end + +return function(t) + local memo = {[t] = 0} + local rev_memo = {[0] = t} + local srefs = {} + local result = {} + + -- phase 1: recursively descend the table structure + local n = 0 + while rev_memo[n] do + result[n + 1] = write_table_ex(rev_memo[n], memo, rev_memo, srefs, n) + n = n + 1 + end + + -- phase 2: reverse order + for i = 1, n*.5 do + local j = n - i + 1 + result[i], result[j] = result[j], result[i] + end + + -- phase 3: add all the tricky cyclic stuff + for i, v in ipairs(srefs) do + n = n + 1 + result[n] = write_key_value_pair(v[2], v[3], memo, rev_memo, '_[' .. v[1] .. ']') + end + + -- phase 4: add something about returning the main table + if result[n]:sub(1, 5) == '_[0] ' then + result[n] = 'return' .. result[n]:sub(7) + else + result[n + 1] = 'return _[0]' + end + + -- phase 5: just concatenate everything + result = concat(result, '\n') + return n > 1 and 'local _ = {}\n' .. result or result +end diff --git a/src/main.lua b/src/main.lua index 5693de5..dc0eb33 100644 --- a/src/main.lua +++ b/src/main.lua @@ -1,49 +1,90 @@ Gamestate = require "lib.gamestate" -Gamejolt = require "lib.gamejolt" +GameJolt = require "lib.gamejolt" +debug = require "conf" -- a bit redundant but makes it obvious what is global + +local startDate = os.date("*t", os.time()) +local logFile = "logs/" .. startDate.year .. "." .. startDate.month .. "." .. startDate.day .. "-" .. startDate.hour .. "." .. startDate.min .. ".log" +function log(...) + --[[ + local strings = "" + if type(arg) == "table" then + for _,v in pairs(arg) do + strings = strings .. v + end + else + strings = arg + end + if love.filesystem.exists("logs") then + if not love.filesystem.isDirectory("logs") then + love.filesystem.remove() + love.filesystem.createDirectory("logs") + end + else + love.filesystem.createDirectory("logs") + end + local success, errorMsg = love.filesystem.append(logFile, strings) + if not success then + print("Failed to write to log file.", errorMsg) + end + --]] + if debug then print(...) end +end local inifile = require "lib.inifile" local menu = require "gamestates.menu" function love.load() + log("Loading...") -- set custom window icon local icon = love.image.newImageData("icon.png") love.window.setIcon(icon) + log("Window icon set.") -- initialize Game Jolt - Gamejolt.init(48728, "b8e4a0eae1509d3edef3d8451bae1842") + local initSuccess = GameJolt.init(48728, "b8e4a0eae1509d3edef3d8451bae1842") + if initSuccess then log("Game Jolt initialized.") end -- load settings and change if needed + local gamejoltSessionOpen = false --set true if we get a session open if love.filesystem.isFile("settings.ini") then + log("Loading settings...") local settings = inifile.parse("settings.ini") love.window.setMode(settings.display.width, settings.display.height, {fullscreen = settings.display.fullscreen, borderless = settings.display.borderless}) -- login if we have the data to do so if settings.gamejolt.username and settings.gamejolt.usertoken then - local authSuccess = Gamejolt.authUser(settings.gamejolt.username, settings.gamejolt.usertoken) + log("Logging in to Game Jolt.") + local authSuccess = GameJolt.authUser(settings.gamejolt.username, settings.gamejolt.usertoken) if authSuccess then -- check if the player has been banned - local userInfo = Gamejolt.fetchUserByName(settings.gamejolt.username) + local userInfo = GameJolt.fetchUserByName(settings.gamejolt.username) if userInfo.status == "Banned" then + log("Player has been banned from Game Jolt.") settings.gamejolt.username = false settings.gamejolt.usertoken = false inifile.save("settings.ini", settings) error("You have been banned from Game Jolt. Your login data has been deleted, re-open RGB to continue playing without Game Jolt account integration.") end - local sessionSuccess = Gamejolt.openSession() -- tell Game Jolt the user is playing + gamejoltSessionOpen = GameJolt.openSession() -- tell Game Jolt the user is playing if sessionSuccess then - local idleSuccess = Gamejolt.pingSession(false) + log("Game Jolt session opened.") + local idleSuccess = GameJolt.pingSession(false) if not idleSuccess then - print("Couldn't ping Gamejolt session. Session may close.") --this is lazy but I don't care + -- TODO make a better system for checking this + log("Couldn't ping Game Jolt session. Session may close.") --this is lazy but I don't care end else - print("Couldn't open a session with Game Jolt.") + -- TODO make this known to user + log("Couldn't open a session with Game Jolt.") end else - print("Failed to log into Game Jolt. Please report this error (with a screenshot) to: paul.liverman.iii@gmail.com") + -- TODO make this better, also detect if online somehow + log("Failed to log into Game Jolt. Please report this error (with a screenshot) to: paul.liverman.iii@gmail.com") end end end Gamestate.registerEvents() - Gamestate.switch(menu) + log("Loaded, switching to main menu...") + Gamestate.switch(menu, gamejoltSessionOpen) end diff --git a/src/util/input.lua b/src/util/input.lua new file mode 100644 index 0000000..cc29486 --- /dev/null +++ b/src/util/input.lua @@ -0,0 +1,10 @@ +return function(inValue, acceptableValues) + local isValid = false + for i=1,#acceptableValues.clicks do + if inValue == acceptableValues.clicks[i] then isValid = true end + end + for i=1,#acceptableValues.buttons do + if inValue == acceptableValues.buttons[i] then isValid = true end + end + return isValid +end