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"