diff --git a/sonic-radiance.love/core/debug.lua b/sonic-radiance.love/core/debug.lua index 9a85811..fe6076d 100644 --- a/sonic-radiance.love/core/debug.lua +++ b/sonic-radiance.love/core/debug.lua @@ -23,7 +23,8 @@ local DebugSystem = Object:extend() -local lovebird = require("libs.lovebird") +local cwd = (...):gsub('%.debug$', '') .. "." +local lovebird = require(cwd .. "libs.lovebird") function DebugSystem:new(controller, active) self.controller = controller diff --git a/sonic-radiance.love/core/init.lua b/sonic-radiance.love/core/init.lua index 63bba08..101f49c 100644 --- a/sonic-radiance.love/core/init.lua +++ b/sonic-radiance.love/core/init.lua @@ -23,15 +23,24 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] +local cwd = (...):gsub('%.init$', '') .. "." + +-- GLOBAL UTILS/FUNCTION LOADING +-- Load in the global namespace utilities that'll need to be reusable everywhere +-- in the game + +Object = require(cwd .. "libs.classic") +utils = require(cwd .. "utils") + local CoreSystem = Object:extend() -local DebugSystem = require "core.debug" +local DebugSystem = require(cwd .. "debug") -local Options = require "core.options" -local Input = require "core.input" -local Screen = require "core.screen" -local Lang = require "core.lang" -local SceneManager= require "core.scenemanager" +local Options = require(cwd .. "options") +local Input = require(cwd .. "input") +local Screen = require(cwd .. "screen") +local Lang = require(cwd .. "lang") +local SceneManager = require(cwd .. "scenemanager") function CoreSystem:new() self.debug = DebugSystem(self) diff --git a/sonic-radiance.love/core/input.lua b/sonic-radiance.love/core/input.lua index 7513d25..578c05b 100644 --- a/sonic-radiance.love/core/input.lua +++ b/sonic-radiance.love/core/input.lua @@ -26,7 +26,7 @@ local InputManager = Object:extend() function InputManager:new(controller) self.controller = controller - self.data = self.controller.options.data.input[1] + self.data = self.controller.options:getPlayerInputData(1) self.keys = self:getKeyList() self.fakekeys = self:getKeyList() diff --git a/sonic-radiance.love/core/lang.lua b/sonic-radiance.love/core/lang.lua index 1144806..6c6a69f 100644 --- a/sonic-radiance.love/core/lang.lua +++ b/sonic-radiance.love/core/lang.lua @@ -23,11 +23,22 @@ ]] local LanguageManager = Object:extend() -local langs = require "datas.languages" function LanguageManager:new(controller) self.controller = controller self:setLang(self.controller.options.data.language) + self:getTranslationData() +end + +function LanguageManager:getTranslationData() + local _path = "datas/languages/init.lua" + local fileinfo = love.filesystem.getInfo(_path) + + if fileinfo ~= nil then + self.datas = require "datas.languages" + else + self.datas = nil + end end function LanguageManager:getStringList(library, file) diff --git a/sonic-radiance.love/core/libs/binser.lua b/sonic-radiance.love/core/libs/binser.lua new file mode 100644 index 0000000..5aa1299 --- /dev/null +++ b/sonic-radiance.love/core/libs/binser.lua @@ -0,0 +1,687 @@ +-- binser.lua + +--[[ +Copyright (c) 2016 Calvin Rose + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local assert = assert +local error = error +local select = select +local pairs = pairs +local getmetatable = getmetatable +local setmetatable = setmetatable +local tonumber = tonumber +local type = type +local loadstring = loadstring or load +local concat = table.concat +local char = string.char +local byte = string.byte +local format = string.format +local sub = string.sub +local dump = string.dump +local floor = math.floor +local frexp = math.frexp +local unpack = unpack or table.unpack + +-- Lua 5.3 frexp polyfill +-- From https://github.com/excessive/cpml/blob/master/modules/utils.lua +if not frexp then + local log, abs, floor = math.log, math.abs, math.floor + local log2 = log(2) + frexp = function(x) + if x == 0 then return 0, 0 end + local e = floor(log(abs(x)) / log2 + 1) + return x / 2 ^ e, e + end +end + +-- NIL = 202 +-- FLOAT = 203 +-- TRUE = 204 +-- FALSE = 205 +-- STRING = 206 +-- TABLE = 207 +-- REFERENCE = 208 +-- CONSTRUCTOR = 209 +-- FUNCTION = 210 +-- RESOURCE = 211 +-- INT64 = 212 + +local mts = {} +local ids = {} +local serializers = {} +local deserializers = {} +local resources = {} +local resources_by_name = {} + +local function pack(...) + return {...}, select("#", ...) +end + +local function not_array_index(x, len) + return type(x) ~= "number" or x < 1 or x > len or x ~= floor(x) +end + +local function type_check(x, tp, name) + assert(type(x) == tp, + format("Expected parameter %q to be of type %q.", name, tp)) +end + +local bigIntSupport = false +local isInteger +if math.type then -- Detect Lua 5.3 + local mtype = math.type + bigIntSupport = loadstring[[ + local char = string.char + return function(n) + local nn = n < 0 and -(n + 1) or n + local b1 = nn // 0x100000000000000 + local b2 = nn // 0x1000000000000 % 0x100 + local b3 = nn // 0x10000000000 % 0x100 + local b4 = nn // 0x100000000 % 0x100 + local b5 = nn // 0x1000000 % 0x100 + local b6 = nn // 0x10000 % 0x100 + local b7 = nn // 0x100 % 0x100 + local b8 = nn % 0x100 + if n < 0 then + b1, b2, b3, b4 = 0xFF - b1, 0xFF - b2, 0xFF - b3, 0xFF - b4 + b5, b6, b7, b8 = 0xFF - b5, 0xFF - b6, 0xFF - b7, 0xFF - b8 + end + return char(212, b1, b2, b3, b4, b5, b6, b7, b8) + end]]() + isInteger = function(x) + return mtype(x) == 'integer' + end +else + isInteger = function(x) + return floor(x) == x + end +end + +-- Copyright (C) 2012-2015 Francois Perrad. +-- number serialization code modified from https://github.com/fperrad/lua-MessagePack +-- Encode a number as a big-endian ieee-754 double, big-endian signed 64 bit integer, or a small integer +local function number_to_str(n) + if isInteger(n) then -- int + if n <= 100 and n >= -27 then -- 1 byte, 7 bits of data + return char(n + 27) + elseif n <= 8191 and n >= -8192 then -- 2 bytes, 14 bits of data + n = n + 8192 + return char(128 + (floor(n / 0x100) % 0x100), n % 0x100) + elseif bigIntSupport then + return bigIntSupport(n) + end + end + local sign = 0 + if n < 0.0 then + sign = 0x80 + n = -n + end + local m, e = frexp(n) -- mantissa, exponent + if m ~= m then + return char(203, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + elseif m == 1/0 then + if sign == 0 then + return char(203, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + else + return char(203, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + end + end + e = e + 0x3FE + if e < 1 then -- denormalized numbers + m = m * 2 ^ (52 + e) + e = 0 + else + m = (m * 2 - 1) * 2 ^ 52 + end + return char(203, + sign + floor(e / 0x10), + (e % 0x10) * 0x10 + floor(m / 0x1000000000000), + floor(m / 0x10000000000) % 0x100, + floor(m / 0x100000000) % 0x100, + floor(m / 0x1000000) % 0x100, + floor(m / 0x10000) % 0x100, + floor(m / 0x100) % 0x100, + m % 0x100) +end + +-- Copyright (C) 2012-2015 Francois Perrad. +-- number deserialization code also modified from https://github.com/fperrad/lua-MessagePack +local function number_from_str(str, index) + local b = byte(str, index) + if b < 128 then + return b - 27, index + 1 + elseif b < 192 then + return byte(str, index + 1) + 0x100 * (b - 128) - 8192, index + 2 + end + local b1, b2, b3, b4, b5, b6, b7, b8 = byte(str, index + 1, index + 8) + if b == 212 then + local flip = b1 >= 128 + if flip then -- negative + b1, b2, b3, b4 = 0xFF - b1, 0xFF - b2, 0xFF - b3, 0xFF - b4 + b5, b6, b7, b8 = 0xFF - b5, 0xFF - b6, 0xFF - b7, 0xFF - b8 + end + local n = ((((((b1 * 0x100 + b2) * 0x100 + b3) * 0x100 + b4) * 0x100 + b5) * 0x100 + b6) * 0x100 + b7) * 0x100 + b8 + if flip then + return (-n) - 1, index + 9 + else + return n, index + 9 + end + end + local sign = b1 > 0x7F and -1 or 1 + local e = (b1 % 0x80) * 0x10 + floor(b2 / 0x10) + local m = ((((((b2 % 0x10) * 0x100 + b3) * 0x100 + b4) * 0x100 + b5) * 0x100 + b6) * 0x100 + b7) * 0x100 + b8 + local n + if e == 0 then + if m == 0 then + n = sign * 0.0 + else + n = sign * (m / 2 ^ 52) * 2 ^ -1022 + end + elseif e == 0x7FF then + if m == 0 then + n = sign * (1/0) + else + n = 0.0/0.0 + end + else + n = sign * (1.0 + m / 2 ^ 52) * 2 ^ (e - 0x3FF) + end + return n, index + 9 +end + +local types = {} + +types["nil"] = function(x, visited, accum) + accum[#accum + 1] = "\202" +end + +function types.number(x, visited, accum) + accum[#accum + 1] = number_to_str(x) +end + +function types.boolean(x, visited, accum) + accum[#accum + 1] = x and "\204" or "\205" +end + +function types.string(x, visited, accum) + local alen = #accum + if visited[x] then + accum[alen + 1] = "\208" + accum[alen + 2] = number_to_str(visited[x]) + else + visited[x] = visited.next + visited.next = visited.next + 1 + accum[alen + 1] = "\206" + accum[alen + 2] = number_to_str(#x) + accum[alen + 3] = x + end +end + +local function check_custom_type(x, visited, accum) + local res = resources[x] + if res then + accum[#accum + 1] = "\211" + types[type(res)](res, visited, accum) + return true + end + local mt = getmetatable(x) + local id = mt and ids[mt] + if id then + if x == visited.temp then + error("Infinite loop in constructor.") + end + visited.temp = x + accum[#accum + 1] = "\209" + types[type(id)](id, visited, accum) + local args, len = pack(serializers[id](x)) + accum[#accum + 1] = number_to_str(len) + for i = 1, len do + local arg = args[i] + types[type(arg)](arg, visited, accum) + end + visited[x] = visited.next + visited.next = visited.next + 1 + return true + end +end + +function types.userdata(x, visited, accum) + if visited[x] then + accum[#accum + 1] = "\208" + accum[#accum + 1] = number_to_str(visited[x]) + else + if check_custom_type(x, visited, accum) then return end + error("Cannot serialize this userdata.") + end +end + +function types.table(x, visited, accum) + if visited[x] then + accum[#accum + 1] = "\208" + accum[#accum + 1] = number_to_str(visited[x]) + else + if check_custom_type(x, visited, accum) then return end + visited[x] = visited.next + visited.next = visited.next + 1 + local xlen = #x + accum[#accum + 1] = "\207" + accum[#accum + 1] = number_to_str(xlen) + for i = 1, xlen do + local v = x[i] + types[type(v)](v, visited, accum) + end + local key_count = 0 + for k in pairs(x) do + if not_array_index(k, xlen) then + key_count = key_count + 1 + end + end + accum[#accum + 1] = number_to_str(key_count) + for k, v in pairs(x) do + if not_array_index(k, xlen) then + types[type(k)](k, visited, accum) + types[type(v)](v, visited, accum) + end + end + end +end + +types["function"] = function(x, visited, accum) + if visited[x] then + accum[#accum + 1] = "\208" + accum[#accum + 1] = number_to_str(visited[x]) + else + if check_custom_type(x, visited, accum) then return end + visited[x] = visited.next + visited.next = visited.next + 1 + local str = dump(x) + accum[#accum + 1] = "\210" + accum[#accum + 1] = number_to_str(#str) + accum[#accum + 1] = str + end +end + +types.cdata = function(x, visited, accum) + if visited[x] then + accum[#accum + 1] = "\208" + accum[#accum + 1] = number_to_str(visited[x]) + else + if check_custom_type(x, visited, #accum) then return end + error("Cannot serialize this cdata.") + end +end + +types.thread = function() error("Cannot serialize threads.") end + +local function deserialize_value(str, index, visited) + local t = byte(str, index) + if not t then return end + if t < 128 then + return t - 27, index + 1 + elseif t < 192 then + return byte(str, index + 1) + 0x100 * (t - 128) - 8192, index + 2 + elseif t == 202 then + return nil, index + 1 + elseif t == 203 then + return number_from_str(str, index) + elseif t == 204 then + return true, index + 1 + elseif t == 205 then + return false, index + 1 + elseif t == 206 then + local length, dataindex = deserialize_value(str, index + 1, visited) + local nextindex = dataindex + length + local substr = sub(str, dataindex, nextindex - 1) + visited[#visited + 1] = substr + return substr, nextindex + elseif t == 207 then + local count, nextindex = number_from_str(str, index + 1) + local ret = {} + visited[#visited + 1] = ret + for i = 1, count do + ret[i], nextindex = deserialize_value(str, nextindex, visited) + end + count, nextindex = number_from_str(str, nextindex) + for i = 1, count do + local k, v + k, nextindex = deserialize_value(str, nextindex, visited) + v, nextindex = deserialize_value(str, nextindex, visited) + ret[k] = v + end + return ret, nextindex + elseif t == 208 then + local ref, nextindex = number_from_str(str, index + 1) + return visited[ref], nextindex + elseif t == 209 then + local count + local name, nextindex = deserialize_value(str, index + 1, visited) + count, nextindex = number_from_str(str, nextindex) + local args = {} + for i = 1, count do + args[i], nextindex = deserialize_value(str, nextindex, visited) + end + local ret = deserializers[name](unpack(args)) + visited[#visited + 1] = ret + return ret, nextindex + elseif t == 210 then + local length, dataindex = deserialize_value(str, index + 1, visited) + local nextindex = dataindex + length + local ret = loadstring(sub(str, dataindex, nextindex - 1)) + visited[#visited + 1] = ret + return ret, nextindex + elseif t == 211 then + local res, nextindex = deserialize_value(str, index + 1, visited) + return resources_by_name[res], nextindex + elseif t == 212 then + return number_from_str(str, index) + else + error("Could not deserialize type byte " .. t .. ".") + end +end + +local function serialize(...) + local visited = {next = 1} + local accum = {} + for i = 1, select("#", ...) do + local x = select(i, ...) + types[type(x)](x, visited, accum) + end + return concat(accum) +end + +local function make_file_writer(file) + return setmetatable({}, { + __newindex = function(_, _, v) + file:write(v) + end + }) +end + +local function serialize_to_file(path, mode, ...) + local file, err = io.open(path, mode) + assert(file, err) + local visited = {next = 1} + local accum = make_file_writer(file) + for i = 1, select("#", ...) do + local x = select(i, ...) + types[type(x)](x, visited, accum) + end + -- flush the writer + file:flush() + file:close() +end + +local function writeFile(path, ...) + return serialize_to_file(path, "wb", ...) +end + +local function appendFile(path, ...) + return serialize_to_file(path, "ab", ...) +end + +local function deserialize(str, index) + assert(type(str) == "string", "Expected string to deserialize.") + local vals = {} + index = index or 1 + local visited = {} + local len = 0 + local val + while index do + val, index = deserialize_value(str, index, visited) + if index then + len = len + 1 + vals[len] = val + end + end + return vals, len +end + +local function deserializeN(str, n, index) + assert(type(str) == "string", "Expected string to deserialize.") + n = n or 1 + assert(type(n) == "number", "Expected a number for parameter n.") + assert(n > 0 and floor(n) == n, "N must be a poitive integer.") + local vals = {} + index = index or 1 + local visited = {} + local len = 0 + local val + while index and len < n do + val, index = deserialize_value(str, index, visited) + if index then + len = len + 1 + vals[len] = val + end + end + vals[len + 1] = index + return unpack(vals, 1, n + 1) +end + +local function readFile(path) + local file, err = io.open(path, "rb") + assert(file, err) + local str = file:read("*all") + file:close() + return deserialize(str) +end + +local function default_deserialize(metatable) + return function(...) + local ret = {} + for i = 1, select("#", ...), 2 do + ret[select(i, ...)] = select(i + 1, ...) + end + return setmetatable(ret, metatable) + end +end + +local function default_serialize(x) + assert(type(x) == "table", + "Default serialization for custom types only works for tables.") + local args = {} + local len = 0 + for k, v in pairs(x) do + args[len + 1], args[len + 2] = k, v + len = len + 2 + end + return unpack(args, 1, len) +end + +-- Templating + +local function normalize_template(template) + local ret = {} + for i = 1, #template do + ret[i] = template[i] + end + local non_array_part = {} + -- The non-array part of the template (nested templates) have to be deterministic, so they are sorted. + -- This means that inherently non deterministicly sortable keys (tables, functions) should NOT be used + -- in templates. Looking for way around this. + for k in pairs(template) do + if not_array_index(k, #template) then + non_array_part[#non_array_part + 1] = k + end + end + table.sort(non_array_part) + for i = 1, #non_array_part do + local name = non_array_part[i] + ret[#ret + 1] = {name, normalize_template(template[name])} + end + return ret +end + +local function templatepart_serialize(part, argaccum, x, len) + local extras = {} + local extracount = 0 + for k, v in pairs(x) do + extras[k] = v + extracount = extracount + 1 + end + for i = 1, #part do + extracount = extracount - 1 + if type(part[i]) == "table" then + extras[part[i][1]] = nil + len = templatepart_serialize(part[i][2], argaccum, x[part[i][1]], len) + else + extras[part[i]] = nil + len = len + 1 + argaccum[len] = x[part[i]] + end + end + if extracount > 0 then + argaccum[len + 1] = extras + else + argaccum[len + 1] = nil + end + return len + 1 +end + +local function templatepart_deserialize(ret, part, values, vindex) + for i = 1, #part do + local name = part[i] + if type(name) == "table" then + local newret = {} + ret[name[1]] = newret + vindex = templatepart_deserialize(newret, name[2], values, vindex) + else + ret[name] = values[vindex] + vindex = vindex + 1 + end + end + local extras = values[vindex] + if extras then + for k, v in pairs(extras) do + ret[k] = v + end + end + return vindex + 1 +end + +local function template_serializer_and_deserializer(metatable, template) + return function(x) + argaccum = {} + local len = templatepart_serialize(template, argaccum, x, 0) + return unpack(argaccum, 1, len) + end, function(...) + local ret = {} + local len = select("#", ...) + local args = {...} + templatepart_deserialize(ret, template, args, 1) + return setmetatable(ret, metatable) + end +end + +local function register(metatable, name, serialize, deserialize) + name = name or metatable.name + serialize = serialize or metatable._serialize + deserialize = deserialize or metatable._deserialize + if not serialize then + if metatable._template then + local t = normalize_template(metatable._template) + serialize, deserialize = template_serializer_and_deserializer(metatable, t) + elseif not deserialize then + serialize = default_serialize + deserialize = default_deserialize(metatable) + else + serialize = metatable + end + end + type_check(metatable, "table", "metatable") + type_check(name, "string", "name") + type_check(serialize, "function", "serialize") + type_check(deserialize, "function", "deserialize") + assert(not ids[metatable], "Metatable already registered.") + assert(not mts[name], ("Name %q already registered."):format(name)) + mts[name] = metatable + ids[metatable] = name + serializers[name] = serialize + deserializers[name] = deserialize + return metatable +end + +local function unregister(item) + local name, metatable + if type(item) == "string" then -- assume name + name, metatable = item, mts[item] + else -- assume metatable + name, metatable = ids[item], item + end + type_check(name, "string", "name") + type_check(metatable, "table", "metatable") + mts[name] = nil + ids[metatable] = nil + serializers[name] = nil + deserializers[name] = nil + return metatable +end + +local function registerClass(class, name) + name = name or class.name + if class.__instanceDict then -- middleclass + register(class.__instanceDict, name) + else -- assume 30log or similar library + register(class, name) + end + return class +end + +local function registerResource(resource, name) + type_check(name, "string", "name") + assert(not resources[resource], + "Resource already registered.") + assert(not resources_by_name[name], + format("Resource %q already exists.", name)) + resources_by_name[name] = resource + resources[resource] = name + return resource +end + +local function unregisterResource(name) + type_check(name, "string", "name") + assert(resources_by_name[name], format("Resource %q does not exist.", name)) + local resource = resources_by_name[name] + resources_by_name[name] = nil + resources[resource] = nil + return resource +end + +return { + -- aliases + s = serialize, + d = deserialize, + dn = deserializeN, + r = readFile, + w = writeFile, + a = appendFile, + + serialize = serialize, + deserialize = deserialize, + deserializeN = deserializeN, + readFile = readFile, + writeFile = writeFile, + appendFile = appendFile, + register = register, + unregister = unregister, + registerResource = registerResource, + unregisterResource = unregisterResource, + registerClass = registerClass +} diff --git a/sonic-radiance.love/core/libs/classic.lua b/sonic-radiance.love/core/libs/classic.lua new file mode 100644 index 0000000..cbd6f81 --- /dev/null +++ b/sonic-radiance.love/core/libs/classic.lua @@ -0,0 +1,68 @@ +-- +-- classic +-- +-- Copyright (c) 2014, rxi +-- +-- This module is free software; you can redistribute it and/or modify it under +-- the terms of the MIT license. See LICENSE for details. +-- + + +local Object = {} +Object.__index = Object + + +function Object:new() +end + + +function Object:extend() + local cls = {} + for k, v in pairs(self) do + if k:find("__") == 1 then + cls[k] = v + end + end + cls.__index = cls + cls.super = self + setmetatable(cls, self) + return cls +end + + +function Object:implement(...) + for _, cls in pairs({...}) do + for k, v in pairs(cls) do + if self[k] == nil and type(v) == "function" then + self[k] = v + end + end + end +end + + +function Object:is(T) + local mt = getmetatable(self) + while mt do + if mt == T then + return true + end + mt = getmetatable(mt) + end + return false +end + + +function Object:__tostring() + return "Object" +end + + +function Object:__call(...) + local obj = setmetatable({}, self) + obj:new(...) + return obj +end + + +return Object diff --git a/sonic-radiance.love/core/libs/cscreen.lua b/sonic-radiance.love/core/libs/cscreen.lua new file mode 100644 index 0000000..579ea0d --- /dev/null +++ b/sonic-radiance.love/core/libs/cscreen.lua @@ -0,0 +1,99 @@ +--[[ +CScreen v1.3 by CodeNMore +A simple way to make resolution-independent Love2D games +Tested for LOVE 0.10.1 +See: https://github.com/CodeNMore/CScreen +Zlib License: +Copyright (c) 2016 CodeNMore +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from +the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software in +a product, an acknowledgment in the product documentation would be appreciated +but is not required. +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +--]] + +local CScreen = {} +local rx, ry, ctr = 800, 600, true +local rxv, ryv, fsv, fsvr = 800, 600, 1.0, 1.0 +local tx, ty, rwf, rhf = 0, 0, 800, 600 +local cr, cg, cb, ca = 0, 0, 0, 255 + +-- Initializes CScreen with the initial size values +function CScreen.init(tw, th, cntr) + rx = tw or 800 + ry = th or 600 + ctr = cntr or false + CScreen.update(love.graphics.getWidth(), love.graphics.getHeight()) +end + +-- Draws letterbox borders +function CScreen.cease() + if ctr then + local pr, pg, pb, pa = love.graphics.getColor() + love.graphics.setColor(cr, cg, cb, ca) + love.graphics.scale(fsvr, fsvr) + + if tx ~= 0 then + love.graphics.rectangle("fill", -tx, 0, tx, rhf) + love.graphics.rectangle("fill", rxv, 0, tx, rhf) + elseif ty ~= 0 then + love.graphics.rectangle("fill", 0, -ty, rwf, ty) + love.graphics.rectangle("fill", 0, ryv, rwf, ty) + end + + love.graphics.setColor(pr, pg, pb, pa) + end +end + +-- Scales and centers all graphics properly +function CScreen.apply() + if ctr then + love.graphics.translate(tx, ty) + end + love.graphics.scale(fsv, fsv) +end + +-- Updates CScreen when the window size changes +function CScreen.update(w, h) + local sx = w / rx + local sy = h / ry + fsv = math.min(sx, sy) + fsvr = 1 / fsv + -- Centering + if ctr and fsv == sx then -- Vertically + tx = 0 + ty = (h / 2) - (ry * fsv / 2) + elseif ctr and fsv == sy then -- Horizontally + ty = 0 + tx = (w / 2) - (rx * fsv / 2) + end + -- Variable sets + rwf = w + rhf = h + rxv = rx * fsv + ryv = ry * fsv +end + +-- Convert from window coordinates to target coordinates +function CScreen.project(x, y) + return math.floor((x - tx) / fsv), math.floor((y - ty) / fsv) +end + +-- Change letterbox color +function CScreen.setColor(r, g, b, a) + cr = r + cg = g + cb = b + ca = a +end + +-- Return the table for use +return CScreen diff --git a/sonic-radiance.love/core/libs/lovebird.lua b/sonic-radiance.love/core/libs/lovebird.lua new file mode 100644 index 0000000..8b296eb --- /dev/null +++ b/sonic-radiance.love/core/libs/lovebird.lua @@ -0,0 +1,737 @@ +-- +-- lovebird +-- +-- Copyright (c) 2017 rxi +-- +-- This library is free software; you can redistribute it and/or modify it +-- under the terms of the MIT license. See LICENSE for details. +-- + +local socket = require "socket" + +local lovebird = { _version = "0.4.3" } + +lovebird.loadstring = loadstring or load +lovebird.inited = false +lovebird.host = "*" +lovebird.buffer = "" +lovebird.lines = {} +lovebird.connections = {} +lovebird.pages = {} + +lovebird.wrapprint = true +lovebird.timestamp = true +lovebird.allowhtml = false +lovebird.echoinput = true +lovebird.port = 8000 +lovebird.whitelist = { "127.0.0.1" } +lovebird.maxlines = 200 +lovebird.updateinterval = .5 + + +lovebird.pages["index"] = [[ + + + + + + + + lovebird + + + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + + +]] + + +lovebird.pages["buffer"] = [[ ]] + + +lovebird.pages["env.json"] = [[ + +{ + "valid": true, + "path": "", + "vars": [ + + { + "key": "", + "value": , + "type": "", + }, + + ] +} +]] + + + +function lovebird.init() + -- Init server + lovebird.server = assert(socket.bind(lovebird.host, lovebird.port)) + lovebird.addr, lovebird.port = lovebird.server:getsockname() + lovebird.server:settimeout(0) + -- Wrap print + lovebird.origprint = print + if lovebird.wrapprint then + local oldprint = print + print = function(...) + oldprint(...) + lovebird.print(...) + end + end + -- Compile page templates + for k, page in pairs(lovebird.pages) do + lovebird.pages[k] = lovebird.template(page, "lovebird, req", + "pages." .. k) + end + lovebird.inited = true +end + + +function lovebird.template(str, params, chunkname) + params = params and ("," .. params) or "" + local f = function(x) return string.format(" echo(%q)", x) end + str = ("?>"..str.."(.-)<%?lua", f) + str = "local echo " .. params .. " = ..." .. str + local fn = assert(lovebird.loadstring(str, chunkname)) + return function(...) + local output = {} + local echo = function(str) table.insert(output, str) end + fn(echo, ...) + return table.concat(lovebird.map(output, tostring)) + end +end + + +function lovebird.map(t, fn) + local res = {} + for k, v in pairs(t) do res[k] = fn(v) end + return res +end + + +function lovebird.trace(...) + local str = "[lovebird] " .. table.concat(lovebird.map({...}, tostring), " ") + print(str) + if not lovebird.wrapprint then lovebird.print(str) end +end + + +function lovebird.unescape(str) + local f = function(x) return string.char(tonumber("0x"..x)) end + return (str:gsub("%+", " "):gsub("%%(..)", f)) +end + + +function lovebird.parseurl(url) + local res = {} + res.path, res.search = url:match("/([^%?]*)%??(.*)") + res.query = {} + for k, v in res.search:gmatch("([^&^?]-)=([^&^#]*)") do + res.query[k] = lovebird.unescape(v) + end + return res +end + + +local htmlescapemap = { + ["<"] = "<", + ["&"] = "&", + ['"'] = """, + ["'"] = "'", +} + +function lovebird.htmlescape(str) + return ( str:gsub("[<&\"']", htmlescapemap) ) +end + + +function lovebird.truncate(str, len) + if #str <= len then + return str + end + return str:sub(1, len - 3) .. "..." +end + + +function lovebird.compare(a, b) + local na, nb = tonumber(a), tonumber(b) + if na then + if nb then return na < nb end + return false + elseif nb then + return true + end + return tostring(a) < tostring(b) +end + + +function lovebird.checkwhitelist(addr) + if lovebird.whitelist == nil then return true end + for _, a in pairs(lovebird.whitelist) do + local ptn = "^" .. a:gsub("%.", "%%."):gsub("%*", "%%d*") .. "$" + if addr:match(ptn) then return true end + end + return false +end + + +function lovebird.clear() + lovebird.lines = {} + lovebird.buffer = "" +end + + +function lovebird.pushline(line) + line.time = os.time() + line.count = 1 + table.insert(lovebird.lines, line) + if #lovebird.lines > lovebird.maxlines then + table.remove(lovebird.lines, 1) + end + lovebird.recalcbuffer() +end + + +function lovebird.recalcbuffer() + local function doline(line) + local str = line.str + if not lovebird.allowhtml then + str = lovebird.htmlescape(line.str):gsub("\n", "
") + end + if line.type == "input" then + str = '' .. str .. '' + else + if line.type == "error" then + str = '! ' .. str + str = '' .. str .. '' + end + if line.count > 1 then + str = '' .. line.count .. ' ' .. str + end + if lovebird.timestamp then + str = os.date('%H:%M:%S ', line.time) .. + str + end + end + return str + end + lovebird.buffer = table.concat(lovebird.map(lovebird.lines, doline), "
") +end + + +function lovebird.print(...) + local t = {} + for i = 1, select("#", ...) do + table.insert(t, tostring(select(i, ...))) + end + local str = table.concat(t, " ") + local last = lovebird.lines[#lovebird.lines] + if last and str == last.str then + -- Update last line if this line is a duplicate of it + last.time = os.time() + last.count = last.count + 1 + lovebird.recalcbuffer() + else + -- Create new line + lovebird.pushline({ type = "output", str = str }) + end +end + + +function lovebird.onerror(err) + lovebird.pushline({ type = "error", str = err }) + if lovebird.wrapprint then + lovebird.origprint("[lovebird] ERROR: " .. err) + end +end + + +function lovebird.onrequest(req, client) + local page = req.parsedurl.path + page = page ~= "" and page or "index" + -- Handle "page not found" + if not lovebird.pages[page] then + return "HTTP/1.1 404\r\nContent-Length: 8\r\n\r\nBad page" + end + -- Handle page + local str + xpcall(function() + local data = lovebird.pages[page](lovebird, req) + local contenttype = "text/html" + if string.match(page, "%.json$") then + contenttype = "application/json" + end + str = "HTTP/1.1 200 OK\r\n" .. + "Content-Type: " .. contenttype .. "\r\n" .. + "Content-Length: " .. #data .. "\r\n" .. + "\r\n" .. data + end, lovebird.onerror) + return str +end + + +function lovebird.receive(client, pattern) + while 1 do + local data, msg = client:receive(pattern) + if not data then + if msg == "timeout" then + -- Wait for more data + coroutine.yield(true) + else + -- Disconnected -- yielding nil means we're done + coroutine.yield(nil) + end + else + return data + end + end +end + + +function lovebird.send(client, data) + local idx = 1 + while idx < #data do + local res, msg = client:send(data, idx) + if not res and msg == "closed" then + -- Handle disconnect + coroutine.yield(nil) + else + idx = idx + res + coroutine.yield(true) + end + end +end + + +function lovebird.onconnect(client) + -- Create request table + local requestptn = "(%S*)%s*(%S*)%s*(%S*)" + local req = {} + req.socket = client + req.addr, req.port = client:getsockname() + req.request = lovebird.receive(client, "*l") + req.method, req.url, req.proto = req.request:match(requestptn) + req.headers = {} + while 1 do + local line, msg = lovebird.receive(client, "*l") + if not line or #line == 0 then break end + local k, v = line:match("(.-):%s*(.*)$") + req.headers[k] = v + end + if req.headers["Content-Length"] then + req.body = lovebird.receive(client, req.headers["Content-Length"]) + end + -- Parse body + req.parsedbody = {} + if req.body then + for k, v in req.body:gmatch("([^&]-)=([^&^#]*)") do + req.parsedbody[k] = lovebird.unescape(v) + end + end + -- Parse request line's url + req.parsedurl = lovebird.parseurl(req.url) + -- Handle request; get data to send and send + local data = lovebird.onrequest(req) + lovebird.send(client, data) + -- Clear up + client:close() +end + + +function lovebird.update() + if not lovebird.inited then lovebird.init() end + -- Handle new connections + while 1 do + -- Accept new connections + local client = lovebird.server:accept() + if not client then break end + client:settimeout(0) + local addr = client:getsockname() + if lovebird.checkwhitelist(addr) then + -- Connection okay -- create and add coroutine to set + local conn = coroutine.wrap(function() + xpcall(function() lovebird.onconnect(client) end, function() end) + end) + lovebird.connections[conn] = true + else + -- Reject connection not on whitelist + lovebird.trace("got non-whitelisted connection attempt: ", addr) + client:close() + end + end + -- Handle existing connections + for conn in pairs(lovebird.connections) do + -- Resume coroutine, remove if it has finished + local status = conn() + if status == nil then + lovebird.connections[conn] = nil + end + end +end + + +return lovebird diff --git a/sonic-radiance.love/core/modules/assets/animator.lua b/sonic-radiance.love/core/modules/assets/animator.lua index 7bce90c..716263c 100644 --- a/sonic-radiance.love/core/modules/assets/animator.lua +++ b/sonic-radiance.love/core/modules/assets/animator.lua @@ -77,6 +77,10 @@ function Animator:draw(x, y, r, sx, sy, ox, oy, kx, ky) self.sprite:drawFrame(self.frame, x, y, r, sx, sy, ox, oy, kx, ky) end +function Animator:drawMask(x, y, r, sx, sy, ox, oy, kx, ky) + self.sprite:drawFrameMask(self.frame, x, y, r, sx, sy, ox, oy, kx, ky) +end + function Animator:changeAnimation(name, restart) -- Force restart if animation name is different if (self.currentAnimation ~= name) then diff --git a/sonic-radiance.love/core/modules/assets/autotile.lua b/sonic-radiance.love/core/modules/assets/autotile.lua index 4104303..0cfaf6d 100644 --- a/sonic-radiance.love/core/modules/assets/autotile.lua +++ b/sonic-radiance.love/core/modules/assets/autotile.lua @@ -23,7 +23,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local Tileset = require "core.modules.assets.tileset" +local cwd = (...):gsub('%.autotile$', '') .. "." +local Tileset = require(cwd .. "tileset") local Autotile = Object:extend() function Autotile:new(filepath) diff --git a/sonic-radiance.love/core/modules/assets/imagefonts.lua b/sonic-radiance.love/core/modules/assets/imagefonts.lua index 16e0b7a..3cf2c1b 100644 --- a/sonic-radiance.love/core/modules/assets/imagefonts.lua +++ b/sonic-radiance.love/core/modules/assets/imagefonts.lua @@ -1,4 +1,5 @@ -local Font = require "core.modules.assets.fonts" +local cwd = (...):gsub('%.imagefonts$', '') .. "." +local Font = require(cwd.. "fonts") local ImageFont = Font:extend() function ImageFont:new(filename, extraspacing) diff --git a/sonic-radiance.love/core/modules/assets/init.lua b/sonic-radiance.love/core/modules/assets/init.lua index b6e11dc..5fe379f 100644 --- a/sonic-radiance.love/core/modules/assets/init.lua +++ b/sonic-radiance.love/core/modules/assets/init.lua @@ -24,13 +24,17 @@ local Assets = Object:extend() -local Sprite = require "core.modules.assets.sprites" -local Font = require "core.modules.assets.fonts" -local ImageFont = require "core.modules.assets.imagefonts" +local cwd = (...):gsub('%.init$', '') .. "." -local Tileset = require "core.modules.assets.tileset" -local Autotile = require "core.modules.assets.autotile" -local Background = require "core.modules.assets.background" +local Texture = require(cwd .. "texture") + +local Sprite = require(cwd .. "sprites") +local Font = require(cwd .. "fonts") +local ImageFont = require(cwd .. "imagefonts") + +local Tileset = require(cwd .. "tileset") +local Autotile = require(cwd .. "autotile") +local Background = require(cwd .. "background") function Assets:new() @@ -121,11 +125,11 @@ end -- Background -- function Assets:addImage(name, filename) - self.images[name] = love.graphics.newImage(filename) + self.images[name] = Texture(filename) end function Assets:drawImage(name, x, y, r, sx, sy, ox, oy, kx, ky) - love.graphics.draw(self.images[name], x, y, r, sx, sy, ox, oy, kx, ky) + self.images[name]:draw(x, y, r, sx, sy, ox, oy, kx, ky) end -- Images -- diff --git a/sonic-radiance.love/core/modules/assets/sprites.lua b/sonic-radiance.love/core/modules/assets/sprites.lua index 326db34..0749b63 100644 --- a/sonic-radiance.love/core/modules/assets/sprites.lua +++ b/sonic-radiance.love/core/modules/assets/sprites.lua @@ -24,8 +24,10 @@ ]] local Sprite = Object:extend() -local Animator = require("core.modules.assets.animator") -local Tileset = require("core.modules.assets.tileset") +local cwd = (...):gsub('%.sprites$', '') .. "." + +local Animator = require(cwd .. "animator") +local Tileset = require(cwd .. "tileset") function Sprite:new(filepath) self.tileset = Tileset(filepath) @@ -66,10 +68,18 @@ function Sprite:drawAnimation(x, y, r, sx, sy, ox, oy, kx, ky) self.animator:draw(x, y, r, sx, sy, ox, oy, kx, ky) end +function Sprite:drawAnimationMask(x, y, r, sx, sy, ox, oy, kx, ky) + self.animator:drawMask(x, y, r, sx, sy, ox, oy, kx, ky) +end + function Sprite:drawFrame(frame, x, y, r, sx, sy, ox, oy, kx, ky) self.tileset:drawTile(frame, x, y, r, sx, sy, ox, oy, kx, ky) end +function Sprite:drawFrameMask(frame, x, y, r, sx, sy, ox, oy, kx, ky) + self.tileset:drawTileMask(frame, x, y, r, sx, sy, ox, oy, kx, ky) +end + function Sprite:drawPart(x, y, w, h, r, sx, sy, ox, oy, kx, ky) local w = math.floor(w) local h = math.floor(h) diff --git a/sonic-radiance.love/core/modules/assets/texture.lua b/sonic-radiance.love/core/modules/assets/texture.lua new file mode 100644 index 0000000..63313d9 --- /dev/null +++ b/sonic-radiance.love/core/modules/assets/texture.lua @@ -0,0 +1,65 @@ +-- assets/texture :: the texture object, essentially used to be able to draw easily +-- the mask of the texture (used for stuff like flashing sprite, etc) + +--[[ + Copyright © 2019 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + + +local Texture = Object:extend() + +local function getMask(x, y, r, g, b, a) + -- template for defining your own pixel mapping function + -- perform computations giving the new values for r, g, b and a + -- ... + return 1, 1, 1, a +end + +function Texture:new(filename) + self.imageData = love.image.newImageData(filename) + + local maskData = self.imageData:clone() + maskData:mapPixel( getMask ) + + self.image = love.graphics.newImage( self.imageData ) + self.mask = love.graphics.newImage( maskData ) +end + +function Texture:getDimensions() + return self.image:getDimensions() +end + +function Texture:draw(x, y, r, sx, sy, ox, oy, kx, ky) + love.graphics.draw(self.image, x, y, r, sx, sy, ox, oy, kx, ky) +end + +function Texture:drawQuad(quad, x, y, r, sx, sy, ox, oy, kx, ky) + love.graphics.draw(self.image, quad, x, y, r, sx, sy, ox, oy, kx, ky) +end + +function Texture:drawMask(x, y, r, sx, sy, ox, oy, kx, ky) + love.graphics.draw(self.mask, x, y, r, sx, sy, ox, oy, kx, ky) +end + +function Texture:drawMaskQuad(quad, x, y, r, sx, sy, ox, oy, kx, ky) + love.graphics.draw(self.mask, quad, x, y, r, sx, sy, ox, oy, kx, ky) +end + +return Texture diff --git a/sonic-radiance.love/core/modules/assets/tileset.lua b/sonic-radiance.love/core/modules/assets/tileset.lua index c86aa44..40ae249 100644 --- a/sonic-radiance.love/core/modules/assets/tileset.lua +++ b/sonic-radiance.love/core/modules/assets/tileset.lua @@ -27,9 +27,12 @@ ]] local Tileset = Object:extend() +local cwd = (...):gsub('%.tileset$', '') .. "." + +local Texture = require(cwd .. "texture") function Tileset:new(filepath) - self.texture = love.graphics.newImage(filepath .. ".png") + self.texture = Texture(filepath .. ".png") local data = require(filepath) self.metadata = data.metadata @@ -79,11 +82,21 @@ end function Tileset:drawTile_Grid(i, j, x, y, r, sx, sy, ox, oy, kx, ky) local tileID = self:getTileID_Grid(i, j) - love.graphics.draw(self.texture, self.quads[tileID], x, y, r, sx, sy, ox, oy, kx, ky) + self.texture:drawQuad(self.quads[tileID], x, y, r, sx, sy, ox, oy, kx, ky) end function Tileset:drawTile(id, x, y, r, sx, sy, ox, oy, kx, ky) - love.graphics.draw(self.texture, self.quads[id], x, y, r, sx, sy, ox, oy, kx, ky) + self.texture:drawQuad(self.quads[id], x, y, r, sx, sy, ox, oy, kx, ky) end +function Tileset:drawTileMask_Grid(i, j, x, y, r, sx, sy, ox, oy, kx, ky) + local tileID = self:getTileID_Grid(i, j) + self.texture:drawMaskQuad(self.quads[tileID], x, y, r, sx, sy, ox, oy, kx, ky) +end + +function Tileset:drawTileMask(id, x, y, r, sx, sy, ox, oy, kx, ky) + self.texture:drawMaskQuad(self.quads[id], x, y, r, sx, sy, ox, oy, kx, ky) +end + + return Tileset diff --git a/sonic-radiance.love/core/modules/menusystem/init.lua b/sonic-radiance.love/core/modules/menusystem/init.lua index db5ee4d..6078277 100644 --- a/sonic-radiance.love/core/modules/menusystem/init.lua +++ b/sonic-radiance.love/core/modules/menusystem/init.lua @@ -46,9 +46,22 @@ function MenuSystem:update(dt) end +function MenuSystem:switchMenu(menu) + for k,v in pairs(self.menus) do + if k == menu then + v:getFocus() + v:setVisibility(true) + v.isActive = true + else + v:setVisibility(false) + v.isActive = false + end + end +end + function MenuSystem:setAllMenuVisibility(visibility) for k,v in pairs(self.menus) do - v.isVisible = visibility + v:setVisibility(visibility) end end @@ -93,10 +106,26 @@ function MenuSystem:mousepressed( x, y, button, istouch ) end end -function MenuSystem:draw(dt) -- On dessine les entitées +function MenuSystem:getDrawList() + local drawList = {} for k,v in pairs(self.menus) do - if (v.isVisible) then - v:draw(dt) + local drawObject = {} + drawObject.name = k + drawObject.depth = v.depth + table.insert(drawList, drawObject) + end + table.sort(drawList, function(a,b) return a.depth > b.depth end) + + return drawList +end + +function MenuSystem:draw(dt) -- On dessine les entitées + self.drawList = self:getDrawList() + + for i,v in ipairs(self.drawList) do + local v2 = self.menus[v.name] + if (v2.isVisible) then + v2:draw(dt) end end diff --git a/sonic-radiance.love/core/modules/menusystem/parent.lua b/sonic-radiance.love/core/modules/menusystem/parent.lua index a6bb2a5..b9f6135 100644 --- a/sonic-radiance.love/core/modules/menusystem/parent.lua +++ b/sonic-radiance.love/core/modules/menusystem/parent.lua @@ -19,6 +19,9 @@ function Menu:new(menusystem, name, x, y, w, h) self.isDestroyed = false self.isVisible = true self.isActive = true + self.isLocked = false + + self.depth = 0 self.sound = {} self.sound.asset = nil @@ -27,6 +30,18 @@ function Menu:new(menusystem, name, x, y, w, h) self:register() end +function Menu:setDepth(depth) + self.depth = depth or 0 +end + +function Menu:setVisibility(visibility) + if self.isLocked == false then + self.isVisible = visibility + else + self.isVisible = true + end +end + function Menu:getFocus() self.menusystem.focusedMenu = self.name end diff --git a/sonic-radiance.love/core/modules/scenes.lua b/sonic-radiance.love/core/modules/scenes.lua index c87f29e..60f378c 100644 --- a/sonic-radiance.love/core/modules/scenes.lua +++ b/sonic-radiance.love/core/modules/scenes.lua @@ -22,9 +22,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] +local cwd = (...):gsub('%.scenes$', '') .. "." + local Scene = Object:extend() -local Assets = require "core.modules.assets" -local MenuSystem = require "core.modules.menusystem" +local Assets = require(cwd .. "assets") +local MenuSystem = require(cwd .. "menusystem") function Scene:new() self.mouse = {} @@ -33,10 +35,12 @@ function Scene:new() self.assets = Assets() self.menusystem = MenuSystem() self.keys = core.input:getKeyList() + + self:register() end function Scene:register() - core.scenemanager.currentScene = self + core.scenemanager:setScene(self) end function Scene:update(dt) diff --git a/sonic-radiance.love/core/options.lua b/sonic-radiance.love/core/options.lua index 57111c9..c83a333 100644 --- a/sonic-radiance.love/core/options.lua +++ b/sonic-radiance.love/core/options.lua @@ -24,7 +24,8 @@ local OptionsManager = Object:extend() -local binser = require "libs.binser" +local cwd = (...):gsub('%.options$', '') .. "." +local binser = require(cwd .. "libs.binser") function OptionsManager:new() -- We begin by creating an empty data table before reading the data. @@ -42,7 +43,7 @@ function OptionsManager:reset() self.data.video.fullscreen = false -- We load the default files - self.data.input = require "datas.inputs" + self.data.input = self:getInputDefaultData() -- TODO: have a way to auto-load a language according to the OS ? self.data.language = "en" @@ -66,6 +67,31 @@ function OptionsManager:getFile(absolute) return filepath end +function OptionsManager:getInputDefaultData() + local _path = "datas/inputs.lua" + local datas = {} + local fileinfo = love.filesystem.getInfo(_path) + + if fileinfo ~= nil then + datas = require "datas.inputs" + else + datas = {} + end + + return datas +end + +function OptionsManager:getPlayerInputData(id) + local _playerInputData = self.data.input[id] + + if _playerInputData == nil then + _playerInputData = {} + _playerInputData.keys = {} + end + + return _playerInputData +end + function OptionsManager:write() local data = self:getData() diff --git a/sonic-radiance.love/core/scenemanager.lua b/sonic-radiance.love/core/scenemanager.lua index 5d403ca..008d0a2 100644 --- a/sonic-radiance.love/core/scenemanager.lua +++ b/sonic-radiance.love/core/scenemanager.lua @@ -28,6 +28,28 @@ local SceneManager = Object:extend() function SceneManager:new(controller) self.controller = controller self.currentScene = nil + + self.storage = {} +end + +function SceneManager:setScene(scene) + self.currentScene = scene +end + +function SceneManager:storeCurrentScene(name) + self.storage[name] = self.currentScene +end + +function SceneManager:setStoredScene(name) + local storedScene = self.storage[name] + if storedScene ~= nil then + self.currentScene = storedScene + self.storage[name] = nil + end +end + +function SceneManager:clearStorage() + self.storage = {} end function SceneManager:update(dt) @@ -42,15 +64,19 @@ function SceneManager:update(dt) end function SceneManager:mousemoved(x, y, dx, dy) - self.currentScene.mouse.x, - self.currentScene.mouse.y = x, y - self.currentScene:mousemoved(x, y, dx, dy) - self.currentScene.menusystem:mousemoved(x, y, dx, dy) + if (self.currentScene ~= nil) then + self.currentScene.mouse.x, + self.currentScene.mouse.y = x, y + self.currentScene:mousemoved(x, y, dx, dy) + self.currentScene.menusystem:mousemoved(x, y, dx, dy) + end end function SceneManager:mousepressed( x, y, button, istouch ) - self.currentScene:mousepressed( x, y, button, istouch ) - self.currentScene.menusystem:mousepressed( x, y, button, istouch ) + if (self.currentScene ~= nil) then + self.currentScene:mousepressed( x, y, button, istouch ) + self.currentScene.menusystem:mousepressed( x, y, button, istouch ) + end end function SceneManager:clearScene() diff --git a/sonic-radiance.love/core/screen.lua b/sonic-radiance.love/core/screen.lua index 4e962a8..24a3c4b 100644 --- a/sonic-radiance.love/core/screen.lua +++ b/sonic-radiance.love/core/screen.lua @@ -24,7 +24,8 @@ local ScreenManager = Object:extend() -local CScreen = require "libs.cscreen" +local cwd = (...):gsub('%.screen$', '') .. "." +local CScreen = require(cwd .. "libs.cscreen") function ScreenManager:new(controller) self.controller = controller diff --git a/sonic-radiance.love/core/utils/filesystem.lua b/sonic-radiance.love/core/utils/filesystem.lua new file mode 100644 index 0000000..3d38e27 --- /dev/null +++ b/sonic-radiance.love/core/utils/filesystem.lua @@ -0,0 +1,16 @@ +local Filesystem = {} + +function Filesystem.exists(filepath) + local info = love.filesystem.getInfo( filepath ) + local exists = false + + if (info == nil) then + exists = false + else + exists = true + end + + return exists +end + +return Filesystem diff --git a/sonic-radiance.love/core/utils/graphics.lua b/sonic-radiance.love/core/utils/graphics.lua new file mode 100644 index 0000000..79ad753 --- /dev/null +++ b/sonic-radiance.love/core/utils/graphics.lua @@ -0,0 +1,64 @@ +local Graphics = {} + +function Graphics.resetColor() + love.graphics.setColor(1,1,1,1) +end + +function Graphics.box(x, y, w, h) + local x = math.floor(x) + local y = math.floor(y) + local w = math.floor(w) + local h = math.floor(h) + local a = a or 1 + + local r, g, b, a = love.graphics.getColor( ) + + love.graphics.setColor(r, g, b, 0.3 * a) + love.graphics.rectangle("fill", x, y, w, h) + + love.graphics.setColor(r, g, b, a) + love.graphics.rectangle("line", x, y, w, h) +end + +function Graphics.print(text, x, y, align, r, sx, sy, ox, oy, kx, ky) + local width + local font = love.graphics.getFont() + width = font:getWidth(text) + + if align == "center" then + width = (width/2) + elseif align == "right" then + width = width + else + width = 0 + end + + love.graphics.print(text, x - (width), y, r, sx, sy, ox, oy, kx, ky) +end + +function Graphics.printWithSpacing(text, spacing, align, x, y, r, sx, sy, ox, oy, kx, ky) + -- DO NOT USE THIS FUNCTION IN A "UPDATE" FUNCTION ! + -- it's pretty heavy to use as it use a loop to get every character in a text + local font = love.graphics.getFont() + local xx = 0 + local lenght = string.len(text) + local basewidth = font:getWidth(text) + local width = basewidth + (spacing * lenght) + + if align == "center" then + width = (width/2) + elseif align == "right" then + width = width + else + width = 0 + end + + for i=1, lenght do + local char = string.sub(text, i, i) + pos = math.floor(x + xx - width) + love.graphics.print(char, pos, y) + xx = xx + font:getWidth(char) + spacing + end +end + +return Graphics diff --git a/sonic-radiance.love/core/utils/init.lua b/sonic-radiance.love/core/utils/init.lua new file mode 100644 index 0000000..0f6ea3c --- /dev/null +++ b/sonic-radiance.love/core/utils/init.lua @@ -0,0 +1,7 @@ +local cwd = (...):gsub('%.init$', '') .. "." + +return { + math = require(cwd .. "math"), + graphics = require(cwd .. "graphics"), + filesystem = require(cwd .. "filesystem") +} diff --git a/sonic-radiance.love/core/utils/math.lua b/sonic-radiance.love/core/utils/math.lua new file mode 100644 index 0000000..678720f --- /dev/null +++ b/sonic-radiance.love/core/utils/math.lua @@ -0,0 +1,88 @@ +local Math = {} + +function Math.sign(x) + if (x < 0) then + return -1 + elseif (x > 0) then + return 1 + else + return 0 + end +end + +function Math.round(num) + return math.floor(num + 0.5) +end + +function Math.vector(x1, y1, x2, y2) + local vecx, vecy + + vecx = x2 - x1 + vexy = y2 - y1 + + return vecx, vecy +end + +function Math.getMiddlePoint(x1, y1, x2, y2) + local newx, newy, vecx, vecy + + vecx = math.max(x1, x2) - math.min(x1, x2) + vecy = math.max(y1, y2) - math.min(y1, y2) + + newx = math.min(x1, x2) + (vecx / 2) + newy = math.min(y1, y2) + (vecy / 2) + + return newx, newy +end + +function Math.pointDistance(x1, y1, x2, y2) + local vecx, vecy + + vecx = math.max(x1, x2) - math.min(x1, x2) + vexy = math.max(y1, y2) - math.min(y1, y2) + + return math.sqrt(vecx^2 + vecy^2) + +end + +function Math.pointDirection(x1,y1,x2,y2) + local vecx, vecy, angle + vecy = y2 - y1 + vecx = x2 - x1 + angle = math.atan2(vecy, vecx) + + return angle +end + +function Math.numberToString(x, length) + local length = length or 1 + local string = "" + local x = x + if (x >= math.pow(10, length)) then + x = unitsNumber*10 - 1 + string = string .. x + else + for i=1, (length-1) do + if (x < math.pow(10, length-i)) then + string = string .. "0" + end + end + string = string .. x + end + return string +end + +function Math.floorCoord(x, y) + return math.floor(x), math.floor(y) +end + +function Math.pixeliseCoord(x, y, factor) + x, y = Math.floorCoord(x / factor, y / factor) + + x = x * factor + y = y * factor + + return x, y +end + +return Math diff --git a/sonic-radiance.love/main.lua b/sonic-radiance.love/main.lua index 8837a3a..a565372 100644 --- a/sonic-radiance.love/main.lua +++ b/sonic-radiance.love/main.lua @@ -21,8 +21,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -utils = require "libs.loveutils" -Object = require "libs.classic" Core = require "core" Game = require "game"