From bc8d61728b8697554cf4d5188c7beacab3ebe60e Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Thu, 25 Nov 2021 10:58:06 +0100 Subject: [PATCH] feat: remove libs --- sonic-bluestreak.love/libs/binser.lua | 687 ------------- sonic-bluestreak.love/libs/classic.lua | 68 -- sonic-bluestreak.love/libs/cscreen.lua | 99 -- sonic-bluestreak.love/libs/hump/camera.lua | 216 ---- sonic-bluestreak.love/libs/hump/class.lua | 98 -- sonic-bluestreak.love/libs/hump/gamestate.lua | 108 -- sonic-bluestreak.love/libs/hump/signal.lua | 102 -- sonic-bluestreak.love/libs/hump/timer.lua | 210 ---- .../libs/hump/vector-light.lua | 172 ---- sonic-bluestreak.love/libs/hump/vector.lua | 199 ---- .../libs/level-libs/bump-3dpd.lua | 947 ------------------ .../libs/level-libs/bump.lua | 769 -------------- .../libs/level-libs/tsort.lua | 84 -- sonic-bluestreak.love/libs/lovebird.lua | 737 -------------- .../libs/loveutils/filesystem.lua | 16 - .../libs/loveutils/graphics.lua | 64 -- sonic-bluestreak.love/libs/loveutils/init.lua | 7 - sonic-bluestreak.love/libs/loveutils/math.lua | 104 -- 18 files changed, 4687 deletions(-) delete mode 100644 sonic-bluestreak.love/libs/binser.lua delete mode 100644 sonic-bluestreak.love/libs/classic.lua delete mode 100644 sonic-bluestreak.love/libs/cscreen.lua delete mode 100644 sonic-bluestreak.love/libs/hump/camera.lua delete mode 100644 sonic-bluestreak.love/libs/hump/class.lua delete mode 100644 sonic-bluestreak.love/libs/hump/gamestate.lua delete mode 100644 sonic-bluestreak.love/libs/hump/signal.lua delete mode 100644 sonic-bluestreak.love/libs/hump/timer.lua delete mode 100644 sonic-bluestreak.love/libs/hump/vector-light.lua delete mode 100644 sonic-bluestreak.love/libs/hump/vector.lua delete mode 100644 sonic-bluestreak.love/libs/level-libs/bump-3dpd.lua delete mode 100644 sonic-bluestreak.love/libs/level-libs/bump.lua delete mode 100644 sonic-bluestreak.love/libs/level-libs/tsort.lua delete mode 100644 sonic-bluestreak.love/libs/lovebird.lua delete mode 100644 sonic-bluestreak.love/libs/loveutils/filesystem.lua delete mode 100644 sonic-bluestreak.love/libs/loveutils/graphics.lua delete mode 100644 sonic-bluestreak.love/libs/loveutils/init.lua delete mode 100644 sonic-bluestreak.love/libs/loveutils/math.lua diff --git a/sonic-bluestreak.love/libs/binser.lua b/sonic-bluestreak.love/libs/binser.lua deleted file mode 100644 index 5aa1299..0000000 --- a/sonic-bluestreak.love/libs/binser.lua +++ /dev/null @@ -1,687 +0,0 @@ --- 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-bluestreak.love/libs/classic.lua b/sonic-bluestreak.love/libs/classic.lua deleted file mode 100644 index cbd6f81..0000000 --- a/sonic-bluestreak.love/libs/classic.lua +++ /dev/null @@ -1,68 +0,0 @@ --- --- 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-bluestreak.love/libs/cscreen.lua b/sonic-bluestreak.love/libs/cscreen.lua deleted file mode 100644 index 579ea0d..0000000 --- a/sonic-bluestreak.love/libs/cscreen.lua +++ /dev/null @@ -1,99 +0,0 @@ ---[[ -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-bluestreak.love/libs/hump/camera.lua b/sonic-bluestreak.love/libs/hump/camera.lua deleted file mode 100644 index cb86a79..0000000 --- a/sonic-bluestreak.love/libs/hump/camera.lua +++ /dev/null @@ -1,216 +0,0 @@ ---[[ -Copyright (c) 2010-2015 Matthias Richter - -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. - -Except as contained in this notice, the name(s) of the above copyright holders -shall not be used in advertising or otherwise to promote the sale, use or -other dealings in this Software without prior written authorization. - -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 _PATH = (...):match('^(.*[%./])[^%.%/]+$') or '' -local cos, sin = math.cos, math.sin - -local camera = {} -camera.__index = camera - --- Movement interpolators (for camera locking/windowing) -camera.smooth = {} - -function camera.smooth.none() - return function(dx,dy) return dx,dy end -end - -function camera.smooth.linear(speed) - assert(type(speed) == "number", "Invalid parameter: speed = "..tostring(speed)) - return function(dx,dy, s) - -- normalize direction - local d = math.sqrt(dx*dx+dy*dy) - local dts = math.min((s or speed) * love.timer.getDelta(), d) -- prevent overshooting the goal - if d > 0 then - dx,dy = dx/d, dy/d - end - - return dx*dts, dy*dts - end -end - -function camera.smooth.damped(stiffness) - assert(type(stiffness) == "number", "Invalid parameter: stiffness = "..tostring(stiffness)) - return function(dx,dy, s) - local dts = love.timer.getDelta() * (s or stiffness) - return dx*dts, dy*dts - end -end - - -local function new(x,y, zoom, rot, smoother) - x,y = x or love.graphics.getWidth()/2, y or love.graphics.getHeight()/2 - zoom = zoom or 1 - rot = rot or 0 - smoother = smoother or camera.smooth.none() -- for locking, see below - return setmetatable({x = x, y = y, scale = zoom, rot = rot, smoother = smoother}, camera) -end - -function camera:lookAt(x,y) - self.x, self.y = x, y - return self -end - -function camera:move(dx,dy) - self.x, self.y = self.x + dx, self.y + dy - return self -end - -function camera:position() - return self.x, self.y -end - -function camera:rotate(phi) - self.rot = self.rot + phi - return self -end - -function camera:rotateTo(phi) - self.rot = phi - return self -end - -function camera:zoom(mul) - self.scale = self.scale * mul - return self -end - -function camera:zoomTo(zoom) - self.scale = zoom - return self -end - -function camera:attach(x,y,w,h, noclip) - x,y = x or 0, y or 0 - w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight() - - self._sx,self._sy,self._sw,self._sh = love.graphics.getScissor() - if not noclip then - love.graphics.setScissor(x,y,w,h) - end - - local cx,cy = x+w/2, y+h/2 - love.graphics.push() - love.graphics.translate(cx, cy) - love.graphics.scale(self.scale) - love.graphics.rotate(self.rot) - love.graphics.translate(-self.x, -self.y) -end - -function camera:detach() - love.graphics.pop() - love.graphics.setScissor(self._sx,self._sy,self._sw,self._sh) -end - -function camera:draw(...) - local x,y,w,h,noclip,func - local nargs = select("#", ...) - if nargs == 1 then - func = ... - elseif nargs == 5 then - x,y,w,h,func = ... - elseif nargs == 6 then - x,y,w,h,noclip,func = ... - else - error("Invalid arguments to camera:draw()") - end - - self:attach(x,y,w,h,noclip) - func() - self:detach() -end - --- world coordinates to camera coordinates -function camera:cameraCoords(x,y, ox,oy,w,h) - ox, oy = ox or 0, oy or 0 - w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight() - - -- x,y = ((x,y) - (self.x, self.y)):rotated(self.rot) * self.scale + center - local c,s = cos(self.rot), sin(self.rot) - x,y = x - self.x, y - self.y - x,y = c*x - s*y, s*x + c*y - return x*self.scale + w/2 + ox, y*self.scale + h/2 + oy -end - --- camera coordinates to world coordinates -function camera:worldCoords(x,y, ox,oy,w,h) - ox, oy = ox or 0, oy or 0 - w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight() - - -- x,y = (((x,y) - center) / self.scale):rotated(-self.rot) + (self.x,self.y) - local c,s = cos(-self.rot), sin(-self.rot) - x,y = (x - w/2 - ox) / self.scale, (y - h/2 - oy) / self.scale - x,y = c*x - s*y, s*x + c*y - return x+self.x, y+self.y -end - -function camera:mousePosition(ox,oy,w,h) - local mx,my = love.mouse.getPosition() - return self:worldCoords(mx,my, ox,oy,w,h) -end - --- camera scrolling utilities -function camera:lockX(x, smoother, ...) - local dx, dy = (smoother or self.smoother)(x - self.x, self.y, ...) - self.x = self.x + dx - return self -end - -function camera:lockY(y, smoother, ...) - local dx, dy = (smoother or self.smoother)(self.x, y - self.y, ...) - self.y = self.y + dy - return self -end - -function camera:lockPosition(x,y, smoother, ...) - return self:move((smoother or self.smoother)(x - self.x, y - self.y, ...)) -end - -function camera:lockWindow(x, y, x_min, x_max, y_min, y_max, smoother, ...) - -- figure out displacement in camera coordinates - x,y = self:cameraCoords(x,y) - local dx, dy = 0,0 - if x < x_min then - dx = x - x_min - elseif x > x_max then - dx = x - x_max - end - if y < y_min then - dy = y - y_min - elseif y > y_max then - dy = y - y_max - end - - -- transform displacement to movement in world coordinates - local c,s = cos(-self.rot), sin(-self.rot) - dx,dy = (c*dx - s*dy) / self.scale, (s*dx + c*dy) / self.scale - - -- move - self:move((smoother or self.smoother)(dx,dy,...)) -end - --- the module -return setmetatable({new = new, smooth = camera.smooth}, - {__call = function(_, ...) return new(...) end}) diff --git a/sonic-bluestreak.love/libs/hump/class.lua b/sonic-bluestreak.love/libs/hump/class.lua deleted file mode 100644 index 7d62707..0000000 --- a/sonic-bluestreak.love/libs/hump/class.lua +++ /dev/null @@ -1,98 +0,0 @@ ---[[ -Copyright (c) 2010-2013 Matthias Richter - -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. - -Except as contained in this notice, the name(s) of the above copyright holders -shall not be used in advertising or otherwise to promote the sale, use or -other dealings in this Software without prior written authorization. - -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 function include_helper(to, from, seen) - if from == nil then - return to - elseif type(from) ~= 'table' then - return from - elseif seen[from] then - return seen[from] - end - - seen[from] = to - for k,v in pairs(from) do - k = include_helper({}, k, seen) -- keys might also be tables - if to[k] == nil then - to[k] = include_helper({}, v, seen) - end - end - return to -end - --- deeply copies `other' into `class'. keys in `other' that are already --- defined in `class' are omitted -local function include(class, other) - return include_helper(class, other, {}) -end - --- returns a deep copy of `other' -local function clone(other) - return setmetatable(include({}, other), getmetatable(other)) -end - -local function new(class) - -- mixins - class = class or {} -- class can be nil - local inc = class.__includes or {} - if getmetatable(inc) then inc = {inc} end - - for _, other in ipairs(inc) do - if type(other) == "string" then - other = _G[other] - end - include(class, other) - end - - -- class implementation - class.__index = class - class.init = class.init or class[1] or function() end - class.include = class.include or include - class.clone = class.clone or clone - - -- constructor call - return setmetatable(class, {__call = function(c, ...) - local o = setmetatable({}, c) - o:init(...) - return o - end}) -end - --- interface for cross class-system compatibility (see https://github.com/bartbes/Class-Commons). -if class_commons ~= false and not common then - common = {} - function common.class(name, prototype, parent) - return new{__includes = {prototype, parent}} - end - function common.instance(class, ...) - return class(...) - end -end - - --- the module -return setmetatable({new = new, include = include, clone = clone}, - {__call = function(_,...) return new(...) end}) diff --git a/sonic-bluestreak.love/libs/hump/gamestate.lua b/sonic-bluestreak.love/libs/hump/gamestate.lua deleted file mode 100644 index 4a42205..0000000 --- a/sonic-bluestreak.love/libs/hump/gamestate.lua +++ /dev/null @@ -1,108 +0,0 @@ ---[[ -Copyright (c) 2010-2013 Matthias Richter - -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. - -Except as contained in this notice, the name(s) of the above copyright holders -shall not be used in advertising or otherwise to promote the sale, use or -other dealings in this Software without prior written authorization. - -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 function __NULL__() end - - -- default gamestate produces error on every callback -local state_init = setmetatable({leave = __NULL__}, - {__index = function() error("Gamestate not initialized. Use Gamestate.switch()") end}) -local stack = {state_init} -local initialized_states = setmetatable({}, {__mode = "k"}) -local state_is_dirty = true - -local GS = {} -function GS.new(t) return t or {} end -- constructor - deprecated! - -local function change_state(stack_offset, to, ...) - local pre = stack[#stack] - - -- initialize only on first call - ;(initialized_states[to] or to.init or __NULL__)(to) - initialized_states[to] = __NULL__ - - stack[#stack+stack_offset] = to - state_is_dirty = true - return (to.enter or __NULL__)(to, pre, ...) -end - -function GS.switch(to, ...) - assert(to, "Missing argument: Gamestate to switch to") - assert(to ~= GS, "Can't call switch with colon operator") - ;(stack[#stack].leave or __NULL__)(stack[#stack]) - return change_state(0, to, ...) -end - -function GS.push(to, ...) - assert(to, "Missing argument: Gamestate to switch to") - assert(to ~= GS, "Can't call push with colon operator") - return change_state(1, to, ...) -end - -function GS.pop(...) - assert(#stack > 1, "No more states to pop!") - local pre, to = stack[#stack], stack[#stack-1] - stack[#stack] = nil - ;(pre.leave or __NULL__)(pre) - state_is_dirty = true - return (to.resume or __NULL__)(to, pre, ...) -end - -function GS.current() - return stack[#stack] -end - --- fetch event callbacks from love.handlers -local all_callbacks = { 'draw', 'errhand', 'update' } -for k in pairs(love.handlers) do - all_callbacks[#all_callbacks+1] = k -end - -function GS.registerEvents(callbacks) - local registry = {} - callbacks = callbacks or all_callbacks - for _, f in ipairs(callbacks) do - registry[f] = love[f] or __NULL__ - love[f] = function(...) - registry[f](...) - return GS[f](...) - end - end -end - --- forward any undefined functions -setmetatable(GS, {__index = function(_, func) - -- call function only if at least one 'update' was called beforehand - -- (see issue #46) - if not state_is_dirty or func == 'update' then - state_is_dirty = false - return function(...) - return (stack[#stack][func] or __NULL__)(stack[#stack], ...) - end - end - return __NULL__ -end}) - -return GS diff --git a/sonic-bluestreak.love/libs/hump/signal.lua b/sonic-bluestreak.love/libs/hump/signal.lua deleted file mode 100644 index e204ca0..0000000 --- a/sonic-bluestreak.love/libs/hump/signal.lua +++ /dev/null @@ -1,102 +0,0 @@ ---[[ -Copyright (c) 2012-2013 Matthias Richter - -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. - -Except as contained in this notice, the name(s) of the above copyright holders -shall not be used in advertising or otherwise to promote the sale, use or -other dealings in this Software without prior written authorization. - -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 Registry = {} -Registry.__index = function(self, key) - return Registry[key] or (function() - local t = {} - rawset(self, key, t) - return t - end)() -end - -function Registry:register(s, f) - self[s][f] = f - return f -end - -function Registry:emit(s, ...) - for f in pairs(self[s]) do - f(...) - end -end - -function Registry:remove(s, ...) - local f = {...} - for i = 1,select('#', ...) do - self[s][f[i]] = nil - end -end - -function Registry:clear(...) - local s = {...} - for i = 1,select('#', ...) do - self[s[i]] = {} - end -end - -function Registry:emitPattern(p, ...) - for s in pairs(self) do - if s:match(p) then self:emit(s, ...) end - end -end - -function Registry:registerPattern(p, f) - for s in pairs(self) do - if s:match(p) then self:register(s, f) end - end - return f -end - -function Registry:removePattern(p, ...) - for s in pairs(self) do - if s:match(p) then self:remove(s, ...) end - end -end - -function Registry:clearPattern(p) - for s in pairs(self) do - if s:match(p) then self[s] = {} end - end -end - --- instancing -function Registry.new() - return setmetatable({}, Registry) -end - --- default instance -local default = Registry.new() - --- module forwards calls to default instance -local module = {} -for k in pairs(Registry) do - if k ~= "__index" then - module[k] = function(...) return default[k](default, ...) end - end -end - -return setmetatable(module, {__call = Registry.new}) diff --git a/sonic-bluestreak.love/libs/hump/timer.lua b/sonic-bluestreak.love/libs/hump/timer.lua deleted file mode 100644 index 5b4e515..0000000 --- a/sonic-bluestreak.love/libs/hump/timer.lua +++ /dev/null @@ -1,210 +0,0 @@ ---[[ -Copyright (c) 2010-2013 Matthias Richter - -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. - -Except as contained in this notice, the name(s) of the above copyright holders -shall not be used in advertising or otherwise to promote the sale, use or -other dealings in this Software without prior written authorization. - -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 Timer = {} -Timer.__index = Timer - -local function _nothing_() end - -function Timer:update(dt) - local to_remove = {} - - for handle in pairs(self.functions) do - -- handle: { - -- time = , - -- after = , - -- during = , - -- limit = , - -- count = , - -- } - - handle.time = handle.time + dt - handle.during(dt, math.max(handle.limit - handle.time, 0)) - - while handle.time >= handle.limit and handle.count > 0 do - if handle.after(handle.after) == false then - handle.count = 0 - break - end - handle.time = handle.time - handle.limit - handle.count = handle.count - 1 - end - - if handle.count == 0 then - table.insert(to_remove, handle) - end - end - - for i = 1, #to_remove do - self.functions[to_remove[i]] = nil - end -end - -function Timer:during(delay, during, after) - local handle = { time = 0, during = during, after = after or _nothing_, limit = delay, count = 1 } - self.functions[handle] = true - return handle -end - -function Timer:after(delay, func) - return self:during(delay, _nothing_, func) -end - -function Timer:every(delay, after, count) - local count = count or math.huge -- exploit below: math.huge - 1 = math.huge - local handle = { time = 0, during = _nothing_, after = after, limit = delay, count = count } - self.functions[handle] = true - return handle -end - -function Timer:cancel(handle) - self.functions[handle] = nil -end - -function Timer:clear() - self.functions = {} -end - -function Timer:script(f) - local co = coroutine.wrap(f) - co(function(t) - self:after(t, co) - coroutine.yield() - end) -end - -Timer.tween = setmetatable({ - -- helper functions - out = function(f) -- 'rotates' a function - return function(s, ...) return 1 - f(1-s, ...) end - end, - chain = function(f1, f2) -- concatenates two functions - return function(s, ...) return (s < .5 and f1(2*s, ...) or 1 + f2(2*s-1, ...)) * .5 end - end, - - -- useful tweening functions - linear = function(s) return s end, - quad = function(s) return s*s end, - cubic = function(s) return s*s*s end, - quart = function(s) return s*s*s*s end, - quint = function(s) return s*s*s*s*s end, - sine = function(s) return 1-math.cos(s*math.pi/2) end, - expo = function(s) return 2^(10*(s-1)) end, - circ = function(s) return 1 - math.sqrt(1-s*s) end, - - back = function(s,bounciness) - bounciness = bounciness or 1.70158 - return s*s*((bounciness+1)*s - bounciness) - end, - - bounce = function(s) -- magic numbers ahead - local a,b = 7.5625, 1/2.75 - return math.min(a*s^2, a*(s-1.5*b)^2 + .75, a*(s-2.25*b)^2 + .9375, a*(s-2.625*b)^2 + .984375) - end, - - elastic = function(s, amp, period) - amp, period = amp and math.max(1, amp) or 1, period or .3 - return (-amp * math.sin(2*math.pi/period * (s-1) - math.asin(1/amp))) * 2^(10*(s-1)) - end, -}, { - --- register new tween -__call = function(tween, self, len, subject, target, method, after, ...) - -- recursively collects fields that are defined in both subject and target into a flat list - local function tween_collect_payload(subject, target, out) - for k,v in pairs(target) do - local ref = subject[k] - assert(type(v) == type(ref), 'Type mismatch in field "'..k..'".') - if type(v) == 'table' then - tween_collect_payload(ref, v, out) - else - local ok, delta = pcall(function() return (v-ref)*1 end) - assert(ok, 'Field "'..k..'" does not support arithmetic operations') - out[#out+1] = {subject, k, delta} - end - end - return out - end - - method = tween[method or 'linear'] -- see __index - local payload, t, args = tween_collect_payload(subject, target, {}), 0, {...} - - local last_s = 0 - return self:during(len, function(dt) - t = t + dt - local s = method(math.min(1, t/len), unpack(args)) - local ds = s - last_s - last_s = s - for _, info in ipairs(payload) do - local ref, key, delta = unpack(info) - ref[key] = ref[key] + delta * ds - end - end, after) -end, - --- fetches function and generated compositions for method `key` -__index = function(tweens, key) - if type(key) == 'function' then return key end - - assert(type(key) == 'string', 'Method must be function or string.') - if rawget(tweens, key) then return rawget(tweens, key) end - - local function construct(pattern, f) - local method = rawget(tweens, key:match(pattern)) - if method then return f(method) end - return nil - end - - local out, chain = rawget(tweens,'out'), rawget(tweens,'chain') - return construct('^in%-([^-]+)$', function(...) return ... end) - or construct('^out%-([^-]+)$', out) - or construct('^in%-out%-([^-]+)$', function(f) return chain(f, out(f)) end) - or construct('^out%-in%-([^-]+)$', function(f) return chain(out(f), f) end) - or error('Unknown interpolation method: ' .. key) -end}) - --- Timer instancing -function Timer.new() - return setmetatable({functions = {}, tween = Timer.tween}, Timer) -end - --- default instance -local default = Timer.new() - --- module forwards calls to default instance -local module = {} -for k in pairs(Timer) do - if k ~= "__index" then - module[k] = function(...) return default[k](default, ...) end - end -end -module.tween = setmetatable({}, { - __index = Timer.tween, - __newindex = function(k,v) Timer.tween[k] = v end, - __call = function(t, ...) return default:tween(...) end, -}) - -return setmetatable(module, {__call = Timer.new}) diff --git a/sonic-bluestreak.love/libs/hump/vector-light.lua b/sonic-bluestreak.love/libs/hump/vector-light.lua deleted file mode 100644 index fc47a13..0000000 --- a/sonic-bluestreak.love/libs/hump/vector-light.lua +++ /dev/null @@ -1,172 +0,0 @@ ---[[ -Copyright (c) 2012-2013 Matthias Richter - -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. - -Except as contained in this notice, the name(s) of the above copyright holders -shall not be used in advertising or otherwise to promote the sale, use or -other dealings in this Software without prior written authorization. - -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 sqrt, cos, sin, atan2 = math.sqrt, math.cos, math.sin, math.atan2 - -local function str(x,y) - return "("..tonumber(x)..","..tonumber(y)..")" -end - -local function mul(s, x,y) - return s*x, s*y -end - -local function div(s, x,y) - return x/s, y/s -end - -local function add(x1,y1, x2,y2) - return x1+x2, y1+y2 -end - -local function sub(x1,y1, x2,y2) - return x1-x2, y1-y2 -end - -local function permul(x1,y1, x2,y2) - return x1*x2, y1*y2 -end - -local function dot(x1,y1, x2,y2) - return x1*x2 + y1*y2 -end - -local function det(x1,y1, x2,y2) - return x1*y2 - y1*x2 -end - -local function eq(x1,y1, x2,y2) - return x1 == x2 and y1 == y2 -end - -local function lt(x1,y1, x2,y2) - return x1 < x2 or (x1 == x2 and y1 < y2) -end - -local function le(x1,y1, x2,y2) - return x1 <= x2 and y1 <= y2 -end - -local function len2(x,y) - return x*x + y*y -end - -local function len(x,y) - return sqrt(x*x + y*y) -end - -local function fromPolar(angle, radius) - return cos(angle)*radius, sin(angle)*radius -end - -local function toPolar(x, y) - return atan2(y,x), len(x,y) -end - -local function dist2(x1,y1, x2,y2) - return len2(x1-x2, y1-y2) -end - -local function dist(x1,y1, x2,y2) - return len(x1-x2, y1-y2) -end - -local function normalize(x,y) - local l = len(x,y) - if l > 0 then - return x/l, y/l - end - return x,y -end - -local function rotate(phi, x,y) - local c, s = cos(phi), sin(phi) - return c*x - s*y, s*x + c*y -end - -local function perpendicular(x,y) - return -y, x -end - -local function project(x,y, u,v) - local s = (x*u + y*v) / (u*u + v*v) - return s*u, s*v -end - -local function mirror(x,y, u,v) - local s = 2 * (x*u + y*v) / (u*u + v*v) - return s*u - x, s*v - y -end - --- ref.: http://blog.signalsondisplay.com/?p=336 -local function trim(maxLen, x, y) - local s = maxLen * maxLen / len2(x, y) - s = s > 1 and 1 or math.sqrt(s) - return x * s, y * s -end - -local function angleTo(x,y, u,v) - if u and v then - return atan2(y, x) - atan2(v, u) - end - return atan2(y, x) -end - --- the module -return { - str = str, - - fromPolar = fromPolar, - toPolar = toPolar, - - -- arithmetic - mul = mul, - div = div, - add = add, - sub = sub, - permul = permul, - dot = dot, - det = det, - cross = det, - - -- relation - eq = eq, - lt = lt, - le = le, - - -- misc operations - len2 = len2, - len = len, - dist2 = dist2, - dist = dist, - normalize = normalize, - rotate = rotate, - perpendicular = perpendicular, - project = project, - mirror = mirror, - trim = trim, - angleTo = angleTo, -} diff --git a/sonic-bluestreak.love/libs/hump/vector.lua b/sonic-bluestreak.love/libs/hump/vector.lua deleted file mode 100644 index 14775f3..0000000 --- a/sonic-bluestreak.love/libs/hump/vector.lua +++ /dev/null @@ -1,199 +0,0 @@ ---[[ -Copyright (c) 2010-2013 Matthias Richter - -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. - -Except as contained in this notice, the name(s) of the above copyright holders -shall not be used in advertising or otherwise to promote the sale, use or -other dealings in this Software without prior written authorization. - -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 sqrt, cos, sin, atan2 = math.sqrt, math.cos, math.sin, math.atan2 - -local vector = {} -vector.__index = vector - -local function new(x,y) - return setmetatable({x = x or 0, y = y or 0}, vector) -end -local zero = new(0,0) - -local function fromPolar(angle, radius) - return new(cos(angle) * radius, sin(angle) * radius) -end - -local function isvector(v) - return type(v) == 'table' and type(v.x) == 'number' and type(v.y) == 'number' -end - -function vector:clone() - return new(self.x, self.y) -end - -function vector:unpack() - return self.x, self.y -end - -function vector:__tostring() - return "("..tonumber(self.x)..","..tonumber(self.y)..")" -end - -function vector.__unm(a) - return new(-a.x, -a.y) -end - -function vector.__add(a,b) - assert(isvector(a) and isvector(b), "Add: wrong argument types ( expected)") - return new(a.x+b.x, a.y+b.y) -end - -function vector.__sub(a,b) - assert(isvector(a) and isvector(b), "Sub: wrong argument types ( expected)") - return new(a.x-b.x, a.y-b.y) -end - -function vector.__mul(a,b) - if type(a) == "number" then - return new(a*b.x, a*b.y) - elseif type(b) == "number" then - return new(b*a.x, b*a.y) - else - assert(isvector(a) and isvector(b), "Mul: wrong argument types ( or expected)") - return a.x*b.x + a.y*b.y - end -end - -function vector.__div(a,b) - assert(isvector(a) and type(b) == "number", "wrong argument types (expected / )") - return new(a.x / b, a.y / b) -end - -function vector.__eq(a,b) - return a.x == b.x and a.y == b.y -end - -function vector.__lt(a,b) - return a.x < b.x or (a.x == b.x and a.y < b.y) -end - -function vector.__le(a,b) - return a.x <= b.x and a.y <= b.y -end - -function vector.permul(a,b) - assert(isvector(a) and isvector(b), "permul: wrong argument types ( expected)") - return new(a.x*b.x, a.y*b.y) -end - -function vector:toPolar() - return new(atan2(self.x, self.y), self:len()) -end - -function vector:len2() - return self.x * self.x + self.y * self.y -end - -function vector:len() - return sqrt(self.x * self.x + self.y * self.y) -end - -function vector.dist(a, b) - assert(isvector(a) and isvector(b), "dist: wrong argument types ( expected)") - local dx = a.x - b.x - local dy = a.y - b.y - return sqrt(dx * dx + dy * dy) -end - -function vector.dist2(a, b) - assert(isvector(a) and isvector(b), "dist: wrong argument types ( expected)") - local dx = a.x - b.x - local dy = a.y - b.y - return (dx * dx + dy * dy) -end - -function vector:normalizeInplace() - local l = self:len() - if l > 0 then - self.x, self.y = self.x / l, self.y / l - end - return self -end - -function vector:normalized() - return self:clone():normalizeInplace() -end - -function vector:rotateInplace(phi) - local c, s = cos(phi), sin(phi) - self.x, self.y = c * self.x - s * self.y, s * self.x + c * self.y - return self -end - -function vector:rotated(phi) - local c, s = cos(phi), sin(phi) - return new(c * self.x - s * self.y, s * self.x + c * self.y) -end - -function vector:perpendicular() - return new(-self.y, self.x) -end - -function vector:projectOn(v) - assert(isvector(v), "invalid argument: cannot project vector on " .. type(v)) - -- (self * v) * v / v:len2() - local s = (self.x * v.x + self.y * v.y) / (v.x * v.x + v.y * v.y) - return new(s * v.x, s * v.y) -end - -function vector:mirrorOn(v) - assert(isvector(v), "invalid argument: cannot mirror vector on " .. type(v)) - -- 2 * self:projectOn(v) - self - local s = 2 * (self.x * v.x + self.y * v.y) / (v.x * v.x + v.y * v.y) - return new(s * v.x - self.x, s * v.y - self.y) -end - -function vector:cross(v) - assert(isvector(v), "cross: wrong argument types ( expected)") - return self.x * v.y - self.y * v.x -end - --- ref.: http://blog.signalsondisplay.com/?p=336 -function vector:trimInplace(maxLen) - local s = maxLen * maxLen / self:len2() - s = (s > 1 and 1) or math.sqrt(s) - self.x, self.y = self.x * s, self.y * s - return self -end - -function vector:angleTo(other) - if other then - return atan2(self.y, self.x) - atan2(other.y, other.x) - end - return atan2(self.y, self.x) -end - -function vector:trimmed(maxLen) - return self:clone():trimInplace(maxLen) -end - - --- the module -return setmetatable({new = new, fromPolar = fromPolar, isvector = isvector, zero = zero}, - {__call = function(_, ...) return new(...) end}) diff --git a/sonic-bluestreak.love/libs/level-libs/bump-3dpd.lua b/sonic-bluestreak.love/libs/level-libs/bump-3dpd.lua deleted file mode 100644 index f094f8d..0000000 --- a/sonic-bluestreak.love/libs/level-libs/bump-3dpd.lua +++ /dev/null @@ -1,947 +0,0 @@ -local bump = { - _VERSION = 'bump-3dpd v0.2.0', - _URL = 'https://github.com/oniietzschan/bump-3dpd', - _DESCRIPTION = 'A 3D collision detection library for Lua.', - _LICENSE = [[ - MIT LICENSE - - Copyright (c) 2014 Enrique García Cota - - 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. - ]] -} - ------------------------------------------- --- Auxiliary functions ------------------------------------------- -local DELTA = 1e-10 -- floating-point margin of error - -local abs, floor, ceil, min, max = math.abs, math.floor, math.ceil, math.min, math.max - -local function sign(x) - if x > 0 then return 1 end - if x == 0 then return 0 end - return -1 -end - -local function nearest(x, a, b) - if abs(a - x) < abs(b - x) then return a else return b end -end - -local function assertType(desiredType, value, name) - if type(value) ~= desiredType then - error(name .. ' must be a ' .. desiredType .. ', but was ' .. tostring(value) .. '(a ' .. type(value) .. ')') - end -end - -local function assertIsPositiveNumber(value, name) - if type(value) ~= 'number' or value <= 0 then - error(name .. ' must be a positive integer, but was ' .. tostring(value) .. '(' .. type(value) .. ')') - end -end - -local function assertIsCube(x,y,z,w,h,d) - assertType('number', x, 'x') - assertType('number', y, 'y') - assertType('number', z, 'z') - assertIsPositiveNumber(w, 'w') - assertIsPositiveNumber(h, 'h') - assertIsPositiveNumber(d, 'd') -end - -local defaultFilter = function() - return 'slide' -end - ------------------------------------------- --- Cube functions ------------------------------------------- - -local function cube_getNearestCorner(x,y,z,w,h,d, px, py, pz) - return nearest(px, x, x + w), - nearest(py, y, y + h), - nearest(pz, z, z + d) -end - --- This is a generalized implementation of the liang-barsky algorithm, which also returns --- the normals of the sides where the segment intersects. --- Returns nil if the segment never touches the cube --- Notice that normals are only guaranteed to be accurate when initially ti1, ti2 == -math.huge, math.huge -local function cube_getSegmentIntersectionIndices(x,y,z,w,h,d, x1,y1,z1,x2,y2,z2, ti1,ti2) - ti1, ti2 = ti1 or 0, ti2 or 1 - local dx = x2 - x1 - local dy = y2 - y1 - local dz = z2 - z1 - local nx, ny, nz - local nx1, ny1, nz1, nx2, ny2, nz2 = 0,0,0,0,0,0 - local p, q, r - - for side = 1,6 do - if side == 1 then -- Left - nx,ny,nz,p,q = -1, 0, 0, -dx, x1 - x - elseif side == 2 then -- Right - nx,ny,nz,p,q = 1, 0, 0, dx, x + w - x1 - elseif side == 3 then -- Top - nx,ny,nz,p,q = 0, -1, 0, -dy, y1 - y - elseif side == 4 then -- Bottom - nx,ny,nz,p,q = 0, 1, 0, dy, y + h - y1 - elseif side == 5 then -- Front - nx,ny,nz,p,q = 0, 0, -1, -dz, z1 - z - else -- Back - nx,ny,nz,p,q = 0, 0, 1, dz, z + d - z1 - end - - if p == 0 then - if q <= 0 then - return nil - end - else - r = q / p - if p < 0 then - if r > ti2 then - return nil - elseif r > ti1 then - ti1, nx1,ny1,nz1 = r, nx,ny,nz - end - else -- p > 0 - if r < ti1 then - return nil - elseif r < ti2 then - ti2, nx2,ny2,nz2 = r,nx,ny,nz - end - end - end - end - - return ti1,ti2, nx1,ny1,nz1, nx2,ny2,nz2 -end - --- Calculates the minkowsky difference between 2 cubes, which is another cube -local function cube_getDiff(x1,y1,z1,w1,h1,d1, x2,y2,z2,w2,h2,d2) - return x2 - x1 - w1, - y2 - y1 - h1, - z2 - z1 - d1, - w1 + w2, - h1 + h2, - d1 + d2 -end - -local function cube_containsPoint(x,y,z,w,h,d, px,py,pz) - return px - x > DELTA - and py - y > DELTA - and pz - z > DELTA - and x + w - px > DELTA - and y + h - py > DELTA - and z + d - pz > DELTA -end - -local function cube_isIntersecting(x1,y1,z1,w1,h1,d1, x2,y2,z2,w2,h2,d2) - return x1 < x2 + w2 and x2 < x1 + w1 and - y1 < y2 + h2 and y2 < y1 + h1 and - z1 < z2 + d2 and z2 < z1 + d1 -end - -local function cube_getCubeDistance(x1,y1,z1,w1,h1,d1, x2,y2,z2,w2,h2,d2) - local dx = x1 - x2 + (w1 - w2)/2 - local dy = y1 - y2 + (h1 - h2)/2 - local dz = z1 - z2 + (d1 - d2)/2 - return (dx * dx) + (dy * dy) + (dz * dz) -end - -local function cube_detectCollision(x1,y1,z1,w1,h1,d1, x2,y2,z2,w2,h2,d2, goalX, goalY, goalZ) - goalX = goalX or x1 - goalY = goalY or y1 - goalZ = goalZ or z1 - - local dx = goalX - x1 - local dy = goalY - y1 - local dz = goalZ - z1 - local x,y,z,w,h,d = cube_getDiff(x1,y1,z1,w1,h1,d1, x2,y2,z2,w2,h2,d2) - - local overlaps, ti, nx, ny, nz - - if cube_containsPoint(x,y,z,w,h,d, 0,0,0) then -- item was intersecting other - local px, py, pz = cube_getNearestCorner(x,y,z,w,h,d, 0,0,0) - -- Volume of intersection: - local wi = min(w1, abs(px)) - local hi = min(h1, abs(py)) - local di = min(d1, abs(pz)) - ti = wi * hi * di * -1 -- ti is the negative volume of intersection - overlaps = true - else - local ti1,ti2,nx1,ny1,nz1 = cube_getSegmentIntersectionIndices(x,y,z,w,h,d, 0,0,0,dx,dy,dz, -math.huge, math.huge) - - -- item tunnels into other - if ti1 - and ti1 < 1 - and (abs(ti1 - ti2) >= DELTA) -- special case for cube going through another cube's corner - and (0 < ti1 + DELTA - or 0 == ti1 and ti2 > 0) - then - ti, nx, ny, nz = ti1, nx1, ny1, nz1 - overlaps = false - end - end - - if not ti then - return - end - - local tx, ty, tz - - if overlaps then - if dx == 0 and dy == 0 and dz == 0 then - -- intersecting and not moving - use minimum displacement vector - local px, py, pz = cube_getNearestCorner(x,y,z,w,h,d, 0,0,0) - if abs(px) <= abs(py) and abs(px) <= abs(pz) then - -- X axis has minimum displacement - py, pz = 0, 0 - elseif abs(py) <= abs(pz) then - -- Y axis has minimum displacement - px, pz = 0, 0 - else - -- Z axis has minimum displacement - px, py = 0, 0 - end - nx, ny, nz = sign(px), sign(py), sign(pz) - tx = x1 + px - ty = y1 + py - tz = z1 + pz - else - -- intersecting and moving - move in the opposite direction - local ti1, _ - ti1,_,nx,ny,nz = cube_getSegmentIntersectionIndices(x,y,z,w,h,d, 0,0,0,dx,dy,dz, -math.huge, 1) - if not ti1 then - return - end - tx = x1 + dx * ti1 - ty = y1 + dy * ti1 - tz = z1 + dz * ti1 - end - else -- tunnel - tx = x1 + dx * ti - ty = y1 + dy * ti - tz = z1 + dz * ti - end - - return { - overlaps = overlaps, - ti = ti, - move = {x = dx, y = dy, z = dz}, - normal = {x = nx, y = ny, z = nz}, - touch = {x = tx, y = ty, z = tz}, - itemCube = {x = x1, y = y1, z = z1, w = w1, h = h1, d = d1}, - otherCube = {x = x2, y = y2, z = z2, w = w2, h = h2, d = d2}, - } -end - ------------------------------------------- --- Grid functions ------------------------------------------- - -local function grid_toWorld(cellSize, cx, cy, cz) - return (cx - 1) * cellSize, - (cy - 1) * cellSize, - (cz - 1) * cellSize -end - -local function grid_toCell(cellSize, x, y, z) - return floor(x / cellSize) + 1, - floor(y / cellSize) + 1, - floor(z / cellSize) + 1 -end - --- grid_traverse* functions are based on "A Fast Voxel Traversal Algorithm for Ray Tracing", --- by John Amanides and Andrew Woo - http://www.cse.yorku.ca/~amana/research/grid.pdf --- It has been modified to include both cells when the ray "touches a grid corner", --- and with a different exit condition - -local function grid_traverse_initStep(cellSize, ct, t1, t2) - local v = t2 - t1 - if v > 0 then - return 1, cellSize / v, ((ct + v) * cellSize - t1) / v - elseif v < 0 then - return -1, -cellSize / v, ((ct + v - 1) * cellSize - t1) / v - else - return 0, math.huge, math.huge - end -end - -local function grid_traverse(cellSize, x1,y1,z1,x2,y2,z2, f) - local cx1, cy1, cz1 = grid_toCell(cellSize, x1, y1, z1) - local cx2, cy2, cz2 = grid_toCell(cellSize, x2, y2, z2) - local stepX, dx, tx = grid_traverse_initStep(cellSize, cx1, x1, x2) - local stepY, dy, ty = grid_traverse_initStep(cellSize, cy1, y1, y2) - local stepZ, dz, tz = grid_traverse_initStep(cellSize, cz1, z1, z2) - local cx, cy, cz = cx1, cy1, cz1 - - f(cx, cy, cz) - - -- The default implementation had an infinite loop problem when - -- approaching the last cell in some occassions. We finish iterating - -- when we are *next* to the last cell - while abs(cx - cx2) + abs(cy - cy2) + abs(cz - cz2) > 1 do - if tx < ty and tx < tz then -- tx is smallest - tx = tx + dx - cx = cx + stepX - f(cx, cy, cz) - elseif ty < tz then -- ty is smallest - -- Addition: include both cells when going through corners - if tx == ty then - f(cx + stepX, cy, cz) - end - ty = ty + dy - cy = cy + stepY - f(cx, cy, cz) - else -- tz is smallest - -- Addition: include both cells when going through corners - if tx == tz then - f(cx + stepX, cy, cz) - end - if ty == tz then - f(cx, cy + stepY, cz) - end - tz = tz + dz - cz = cz + stepZ - f(cx, cy, cz) - end - end - - -- If we have not arrived to the last cell, use it - if cx ~= cx2 or cy ~= cy2 or cz ~= cz2 then - f(cx2, cy2, cz2) - end -end - -local function grid_toCellCube(cellSize, x,y,z,w,h,d) - local cx,cy,cz = grid_toCell(cellSize, x, y, z) - local cx2 = ceil((x + w) / cellSize) - local cy2 = ceil((y + h) / cellSize) - local cz2 = ceil((z + d) / cellSize) - - return cx, - cy, - cz, - cx2 - cx + 1, - cy2 - cy + 1, - cz2 - cz + 1 -end - ------------------------------------------- --- Responses ------------------------------------------- - -local touch = function(world, col, x,y,z,w,h,d, goalX, goalY, goalZ, filter) - return col.touch.x, col.touch.y, col.touch.z, {}, 0 -end - -local cross = function(world, col, x,y,z,w,h,d, goalX, goalY, goalZ, filter) - local cols, len = world:project(col.item, x,y,z,w,h,d, goalX, goalY, goalZ, filter) - - return goalX, goalY, goalZ, cols, len -end - -local slide = function(world, col, x,y,z,w,h,d, goalX, goalY, goalZ, filter) - goalX = goalX or x - goalY = goalY or y - goalZ = goalZ or z - - local tch, move = col.touch, col.move - if move.x ~= 0 or move.y ~= 0 or move.z ~= 0 then - if col.normal.x ~= 0 then - goalX = tch.x - end - if col.normal.y ~= 0 then - goalY = tch.y - end - if col.normal.z ~= 0 then - goalZ = tch.z - end - end - - col.slide = {x = goalX, y = goalY, z = goalZ} - - x, y, z = tch.x, tch.y, tch.z - local cols, len = world:project(col.item, x,y,z,w,h,d, goalX, goalY, goalZ, filter) - - return goalX, goalY, goalZ, cols, len -end - -local bounce = function(world, col, x,y,z,w,h,d, goalX, goalY, goalZ, filter) - goalX = goalX or x - goalY = goalY or y - goalZ = goalZ or z - - local tch, move = col.touch, col.move - local tx, ty, tz = tch.x, tch.y, tch.z - local bx, by, bz = tx, ty, tz - - if move.x ~= 0 or move.y ~= 0 or move.z ~= 0 then - local bnx = goalX - tx - local bny = goalY - ty - local bnz = goalZ - tz - - if col.normal.x ~= 0 then - bnx = -bnx - end - if col.normal.y ~= 0 then - bny = -bny - end - if col.normal.z ~= 0 then - bnz = -bnz - end - - bx = tx + bnx - by = ty + bny - bz = tz + bnz - end - - col.bounce = {x = bx, y = by, z = bz} - x, y, z = tch.x, tch.y, tch.z - goalX, goalY, goalZ = bx, by, bz - - local cols, len = world:project(col.item, x,y,z,w,h,d, goalX, goalY, goalZ, filter) - - return goalX, goalY, goalZ, cols, len -end - ------------------------------------------- --- World ------------------------------------------- - -local World = {} -local World_mt = {__index = World} - --- Private functions and methods - -local function sortByWeight(a,b) - return a.weight < b.weight -end - -local function sortByTiAndDistance(a,b) - if a.ti == b.ti then - local ir, ar, br = a.itemCube, a.otherCube, b.otherCube - local ad = cube_getCubeDistance(ir.x,ir.y,ir.z,ir.w,ir.h,ir.d, ar.x,ar.y,ar.z,ar.w,ar.h,ar.d) - local bd = cube_getCubeDistance(ir.x,ir.y,ir.z,ir.w,ir.h,ir.d, br.x,br.y,br.z,br.w,br.h,br.d) - return ad < bd - end - return a.ti < b.ti -end - -local function addItemToCell(self, item, cx, cy, cz) - self.cells[cz] = self.cells[cz] or {} - self.cells[cz][cy] = self.cells[cz][cy] or setmetatable({}, {__mode = 'v'}) - if self.cells[cz][cy][cx] == nil then - self.cells[cz][cy][cx] = { - itemCount = 0, - x = cx, - y = cy, - z = cz, - items = setmetatable({}, {__mode = 'k'}) - } - end - - local cell = self.cells[cz][cy][cx] - self.nonEmptyCells[cell] = true - if not cell.items[item] then - cell.items[item] = true - cell.itemCount = cell.itemCount + 1 - end -end - -local function removeItemFromCell(self, item, cx, cy, cz) - if not self.cells[cz] - or not self.cells[cz][cy] - or not self.cells[cz][cy][cx] - or not self.cells[cz][cy][cx].items[item] - then - return false - end - - local cell = self.cells[cz][cy][cx] - cell.items[item] = nil - - cell.itemCount = cell.itemCount - 1 - if cell.itemCount == 0 then - self.nonEmptyCells[cell] = nil - end - - return true -end - -local function getDictItemsInCellCube(self, cx,cy,cz, cw,ch,cd) - local items_dict = {} - - for z = cz, cz + cd - 1 do - local plane = self.cells[z] - if plane then - for y = cy, cy + ch - 1 do - local row = plane[y] - if row then - for x = cx, cx + cw - 1 do - local cell = row[x] - if cell and cell.itemCount > 0 then -- no cell.itemCount > 1 because tunneling - for item,_ in pairs(cell.items) do - items_dict[item] = true - end - end - end - end - end - end - end - - return items_dict -end - -local function getCellsTouchedBySegment(self, x1,y1,z1,x2,y2,z2) - local cells, cellsLen, visited = {}, 0, {} - - grid_traverse(self.cellSize, x1,y1,z1,x2,y2,z2, function(cx, cy, cz) - local plane = self.cells[cz] - if not plane then - return - end - - local row = plane[cy] - if not row then - return - end - - local cell = row[cx] - if not cell or visited[cell] then - return - end - - visited[cell] = true - cellsLen = cellsLen + 1 - cells[cellsLen] = cell - end) - - return cells, cellsLen -end - -local function getInfoAboutItemsTouchedBySegment(self, x1,y1,z1, x2,y2,z2, filter) - local cells, len = getCellsTouchedBySegment(self, x1,y1,z1,x2,y2,z2) - local cell, cube, x,y,z,w,h,d, ti1, ti2, tii0,tii1 - local visited, itemInfo, itemInfoLen = {}, {}, 0 - - for i = 1, len do - cell = cells[i] - for item in pairs(cell.items) do - if not visited[item] then - visited[item] = true - if (not filter or filter(item)) then - cube = self.cubes[item] - x, y, z, w, h, d = cube.x, cube.y, cube.z, cube.w, cube.h, cube.d - - ti1, ti2 = cube_getSegmentIntersectionIndices(x,y,z,w,h,d, x1,y1,z1, x2,y2,z2, 0, 1) - if ti1 and ((0 < ti1 and ti1 < 1) or (0 < ti2 and ti2 < 1)) then - -- the sorting is according to the t of an infinite line, not the segment - tii0, tii1 = cube_getSegmentIntersectionIndices(x,y,z,w,h,d, x1,y1,z1, x2,y2,z2, -math.huge, math.huge) - itemInfoLen = itemInfoLen + 1 - itemInfo[itemInfoLen] = {item = item, ti1 = ti1, ti2 = ti2, weight = min(tii0, tii1)} - end - end - end - end - end - - table.sort(itemInfo, sortByWeight) - - return itemInfo, itemInfoLen -end - -local function getResponseByName(self, name) - local response = self.responses[name] - if not response then - error(('Unknown collision type: %s (%s)'):format(name, type(name))) - end - - return response -end - - --- Misc Public Methods - -function World:addResponse(name, response) - self.responses[name] = response -end - -function World:projectMove(item, x,y,z,w,h,d, goalX,goalY,goalZ, filter) - local cols, len = {}, 0 - - filter = filter or defaultFilter - - local visited = {[item] = true} - local visitedFilter = function(itm, other) - if visited[other] then - return false - end - return filter(itm, other) - end - - local projected_cols, projected_len = self:project(item, x,y,z,w,h,d, goalX,goalY,goalZ, visitedFilter) - - while projected_len > 0 do - local col = projected_cols[1] - len = len + 1 - cols[len] = col - - visited[col.other] = true - - local response = getResponseByName(self, col.type) - - goalX, goalY, goalZ, projected_cols, projected_len = response( - self, - col, - x, y, z, w, h, d, - goalX, goalY, goalZ, - visitedFilter - ) - end - - return goalX, goalY, goalZ, cols, len -end - -function World:project(item, x,y,z,w,h,d, goalX,goalY,goalZ, filter) - assertIsCube(x, y, z, w, h, d) - - goalX = goalX or x - goalY = goalY or y - goalZ = goalZ or z - filter = filter or defaultFilter - - local collisions, len = {}, 0 - - local visited = {} - if item ~= nil then - visited[item] = true - end - - -- This could probably be done with less cells using a polygon raster over the cells instead of a - -- bounding cube of the whole movement. Conditional to building a queryPolygon method - local tx = min(goalX, x) - local ty = min(goalY, y) - local tz = min(goalZ, z) - local tx2 = max(goalX + w, x + w) - local ty2 = max(goalY + h, y + h) - local tz2 = max(goalZ + d, z + d) - local tw = tx2 - tx - local th = ty2 - ty - local td = tz2 - tz - - local cx,cy,cz,cw,ch,cd = grid_toCellCube(self.cellSize, tx,ty,tz, tw,th,td) - - local dictItemsInCellCube = getDictItemsInCellCube(self, cx,cy,cz,cw,ch,cd) - - for other,_ in pairs(dictItemsInCellCube) do - if not visited[other] then - visited[other] = true - - local responseName = filter(item, other) - if responseName then - local ox,oy,oz,ow,oh,od = self:getCube(other) - local col = cube_detectCollision(x,y,z,w,h,d, ox,oy,oz,ow,oh,od, goalX, goalY, goalZ) - - if col then - col.other = other - col.item = item - col.type = responseName - - len = len + 1 - collisions[len] = col - end - end - end - end - - table.sort(collisions, sortByTiAndDistance) - - return collisions, len -end - -function World:countCells() - local count = 0 - - for _, plane in pairs(self.cells) do - for _, row in pairs(plane) do - for _,_ in pairs(row) do - count = count + 1 - end - end - end - - return count -end - -function World:hasItem(item) - return not not self.cubes[item] -end - -function World:getItems() - local items, len = {}, 0 - for item,_ in pairs(self.cubes) do - len = len + 1 - items[len] = item - end - return items, len -end - -function World:countItems() - local len = 0 - for _ in pairs(self.cubes) do len = len + 1 end - return len -end - -function World:getCube(item) - local cube = self.cubes[item] - if not cube then - error('Item ' .. tostring(item) .. ' must be added to the world before getting its cube. Use world:add(item, x,y,z,w,h,d) to add it first.') - end - - return cube.x, cube.y, cube.z, cube.w, cube.h, cube.d -end - -function World:toWorld(cx, cy, cz) - return grid_toWorld(self.cellSize, cx, cy, cz) -end - -function World:toCell(x,y,z) - return grid_toCell(self.cellSize, x, y, z) -end - - --- Query methods - -function World:queryCube(x,y,z,w,h,d, filter) - assertIsCube(x,y,z,w,h,d) - - local cx,cy,cz,cw,ch,cd = grid_toCellCube(self.cellSize, x,y,z,w,h,d) - local dictItemsInCellCube = getDictItemsInCellCube(self, cx,cy,cz,cw,ch,cd) - - local items, len = {}, 0 - - local cube - for item,_ in pairs(dictItemsInCellCube) do - cube = self.cubes[item] - if (not filter or filter(item)) - and cube_isIntersecting(x,y,z,w,h,d, cube.x, cube.y, cube.z, cube.w, cube.h, cube.d) - then - len = len + 1 - items[len] = item - end - end - - return items, len -end - -function World:queryPoint(x,y,z, filter) - local cx,cy,cz = self:toCell(x,y,z) - local dictItemsInCellCube = getDictItemsInCellCube(self, cx,cy,cz, 1,1,1) - - local items, len = {}, 0 - - local cube - for item,_ in pairs(dictItemsInCellCube) do - cube = self.cubes[item] - if (not filter or filter(item)) - and cube_containsPoint(cube.x, cube.y, cube.z, cube.w, cube.h, cube.d, x, y, z) - then - len = len + 1 - items[len] = item - end - end - - return items, len -end - -function World:querySegment(x1, y1, z1, x2, y2, z2, filter) - local itemInfo, len = getInfoAboutItemsTouchedBySegment(self, x1, y1, z1, x2, y2, z2, filter) - local items = {} - for i = 1, len do - items[i] = itemInfo[i].item - end - - return items, len -end - --- function World:querySegmentWithCoords(x1, y1, z1, x2, y2, z2, filter) --- local itemInfo, len = getInfoAboutItemsTouchedBySegment(self, x1, y1, z1, x2, y2, z2, filter) --- local dx, dy, dz = x2 - x1, y2 - y1, z2 - z1 --- local info, ti1, ti2 --- for i=1, len do --- info = itemInfo[i] --- ti1 = info.ti1 --- ti2 = info.ti2 - --- info.weight = nil --- info.x1 = x1 + dx * ti1 --- info.y1 = y1 + dy * ti1 --- info.x2 = x1 + dx * ti2 --- info.y2 = y1 + dy * ti2 --- end --- return itemInfo, len --- end - - ---- Main methods - -function World:add(item, x,y,z,w,h,d) - local cube = self.cubes[item] - if cube then - error('Item ' .. tostring(item) .. ' added to the world twice.') - end - assertIsCube(x,y,z,w,h,d) - - self.cubes[item] = {x=x,y=y,z=z,w=w,h=h,d=d} - - local cl,ct,cs,cw,ch,cd = grid_toCellCube(self.cellSize, x,y,z,w,h,d) - for cz = cs, cs + cd - 1 do - for cy = ct, ct + ch - 1 do - for cx = cl, cl + cw - 1 do - addItemToCell(self, item, cx, cy, cz) - end - end - end - - return item -end - -function World:remove(item) - local x,y,z,w,h,d = self:getCube(item) - - self.cubes[item] = nil - local cl,ct,cs,cw,ch,cd = grid_toCellCube(self.cellSize, x,y,z,w,h,d) - for cz = cs, cs + cd - 1 do - for cy = ct, ct + ch - 1 do - for cx = cl, cl + cw - 1 do - removeItemFromCell(self, item, cx, cy, cz) - end - end - end -end - -function World:update(item, x2,y2,z2,w2,h2,d2) - local x1,y1,z1, w1,h1,d1 = self:getCube(item) - w2 = w2 or w1 - h2 = h2 or h1 - d2 = d2 or d1 - assertIsCube(x2,y2,z2,w2,h2,d2) - - if x1 == x2 and y1 == y2 and z1 == z2 and w1 == w2 and h1 == h2 and d1 == d2 then - return - end - - local cl1,ct1,cs1,cw1,ch1,cd1 = grid_toCellCube(self.cellSize, x1,y1,z1, w1,h1,d1) - local cl2,ct2,cs2,cw2,ch2,cd2 = grid_toCellCube(self.cellSize, x2,y2,z2, w2,h2,d2) - - if cl1 ~= cl2 or ct1 ~= ct2 or cs1 ~= cs2 or cw1 ~= cw2 or ch1 ~= ch2 or cd1 ~= cd2 then - local cr1 = cl1 + cw1 - 1 - local cr2 = cl2 + cw2 - 1 - local cb1 = ct1 + ch1 - 1 - local cb2 = ct2 + ch2 - 1 - local css1 = cs1 + cd1 - 1 - local css2 = cs2 + cd2 - 1 - local cyOut, czOut - - for cz = cs1, css1 do - czOut = cz < cs2 or cz > css2 - for cy = ct1, cb1 do - cyOut = cy < ct2 or cy > cb2 - for cx = cl1, cr1 do - if czOut or cyOut or cx < cl2 or cx > cr2 then - removeItemFromCell(self, item, cx, cy, cz) - end - end - end - end - - for cz = cs2, css2 do - czOut = cz < cs1 or cz > css1 - for cy = ct2, cb2 do - cyOut = cy < ct1 or cy > cb1 - for cx = cl2, cr2 do - if czOut or cyOut or cx < cl1 or cx > cr1 then - addItemToCell(self, item, cx, cy, cz) - end - end - end - end - end - - local cube = self.cubes[item] - cube.x, cube.y, cube.z, cube.w, cube.h, cube.d = x2, y2, z2, w2, h2, d2 -end - -function World:move(item, goalX, goalY, goalZ, filter) - local actualX, actualY, actualZ, cols, len = self:check(item, goalX, goalY, goalZ, filter) - - self:update(item, actualX, actualY, actualZ) - - return actualX, actualY, actualZ, cols, len -end - -function World:check(item, goalX, goalY, goalZ, filter) - local x,y,z,w,h,d = self:getCube(item) - - return self:projectMove(item, x,y,z,w,h,d, goalX,goalY,goalZ, filter) -end - - --- Public library functions - -bump.newWorld = function(cellSize) - cellSize = cellSize or 64 - assertIsPositiveNumber(cellSize, 'cellSize') - local world = setmetatable({ - cellSize = cellSize, - cubes = {}, - cells = {}, - nonEmptyCells = {}, - responses = {}, - }, World_mt) - - world:addResponse('touch', touch) - world:addResponse('cross', cross) - world:addResponse('slide', slide) - world:addResponse('bounce', bounce) - - return world -end - -bump.cube = { - getNearestCorner = cube_getNearestCorner, - getSegmentIntersectionIndices = cube_getSegmentIntersectionIndices, - getDiff = cube_getDiff, - containsPoint = cube_containsPoint, - isIntersecting = cube_isIntersecting, - getCubeDistance = cube_getCubeDistance, - detectCollision = cube_detectCollision -} - -bump.responses = { - touch = touch, - cross = cross, - slide = slide, - bounce = bounce -} - -return bump diff --git a/sonic-bluestreak.love/libs/level-libs/bump.lua b/sonic-bluestreak.love/libs/level-libs/bump.lua deleted file mode 100644 index 66d4cf1..0000000 --- a/sonic-bluestreak.love/libs/level-libs/bump.lua +++ /dev/null @@ -1,769 +0,0 @@ -local bump = { - _VERSION = 'bump v3.1.7', - _URL = 'https://github.com/kikito/bump.lua', - _DESCRIPTION = 'A collision detection library for Lua', - _LICENSE = [[ - MIT LICENSE - Copyright (c) 2014 Enrique García Cota - 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. - ]] -} - ------------------------------------------- --- Auxiliary functions ------------------------------------------- -local DELTA = 1e-10 -- floating-point margin of error - -local abs, floor, ceil, min, max = math.abs, math.floor, math.ceil, math.min, math.max - -local function sign(x) - if x > 0 then return 1 end - if x == 0 then return 0 end - return -1 -end - -local function nearest(x, a, b) - if abs(a - x) < abs(b - x) then return a else return b end -end - -local function assertType(desiredType, value, name) - if type(value) ~= desiredType then - error(name .. ' must be a ' .. desiredType .. ', but was ' .. tostring(value) .. '(a ' .. type(value) .. ')') - end -end - -local function assertIsPositiveNumber(value, name) - if type(value) ~= 'number' or value <= 0 then - error(name .. ' must be a positive integer, but was ' .. tostring(value) .. '(' .. type(value) .. ')') - end -end - -local function assertIsRect(x,y,w,h) - assertType('number', x, 'x') - assertType('number', y, 'y') - assertIsPositiveNumber(w, 'w') - assertIsPositiveNumber(h, 'h') -end - -local defaultFilter = function() - return 'slide' -end - ------------------------------------------- --- Rectangle functions ------------------------------------------- - -local function rect_getNearestCorner(x,y,w,h, px, py) - return nearest(px, x, x+w), nearest(py, y, y+h) -end - --- This is a generalized implementation of the liang-barsky algorithm, which also returns --- the normals of the sides where the segment intersects. --- Returns nil if the segment never touches the rect --- Notice that normals are only guaranteed to be accurate when initially ti1, ti2 == -math.huge, math.huge -local function rect_getSegmentIntersectionIndices(x,y,w,h, x1,y1,x2,y2, ti1,ti2) - ti1, ti2 = ti1 or 0, ti2 or 1 - local dx, dy = x2-x1, y2-y1 - local nx, ny - local nx1, ny1, nx2, ny2 = 0,0,0,0 - local p, q, r - - for side = 1,4 do - if side == 1 then nx,ny,p,q = -1, 0, -dx, x1 - x -- left - elseif side == 2 then nx,ny,p,q = 1, 0, dx, x + w - x1 -- right - elseif side == 3 then nx,ny,p,q = 0, -1, -dy, y1 - y -- top - else nx,ny,p,q = 0, 1, dy, y + h - y1 -- bottom - end - - if p == 0 then - if q <= 0 then return nil end - else - r = q / p - if p < 0 then - if r > ti2 then return nil - elseif r > ti1 then ti1,nx1,ny1 = r,nx,ny - end - else -- p > 0 - if r < ti1 then return nil - elseif r < ti2 then ti2,nx2,ny2 = r,nx,ny - end - end - end - end - - return ti1,ti2, nx1,ny1, nx2,ny2 -end - --- Calculates the minkowsky difference between 2 rects, which is another rect -local function rect_getDiff(x1,y1,w1,h1, x2,y2,w2,h2) - return x2 - x1 - w1, - y2 - y1 - h1, - w1 + w2, - h1 + h2 -end - -local function rect_containsPoint(x,y,w,h, px,py) - return px - x > DELTA and py - y > DELTA and - x + w - px > DELTA and y + h - py > DELTA -end - -local function rect_isIntersecting(x1,y1,w1,h1, x2,y2,w2,h2) - return x1 < x2+w2 and x2 < x1+w1 and - y1 < y2+h2 and y2 < y1+h1 -end - -local function rect_getSquareDistance(x1,y1,w1,h1, x2,y2,w2,h2) - local dx = x1 - x2 + (w1 - w2)/2 - local dy = y1 - y2 + (h1 - h2)/2 - return dx*dx + dy*dy -end - -local function rect_detectCollision(x1,y1,w1,h1, x2,y2,w2,h2, goalX, goalY) - goalX = goalX or x1 - goalY = goalY or y1 - - local dx, dy = goalX - x1, goalY - y1 - local x,y,w,h = rect_getDiff(x1,y1,w1,h1, x2,y2,w2,h2) - - local overlaps, ti, nx, ny - - if rect_containsPoint(x,y,w,h, 0,0) then -- item was intersecting other - local px, py = rect_getNearestCorner(x,y,w,h, 0, 0) - local wi, hi = min(w1, abs(px)), min(h1, abs(py)) -- area of intersection - ti = -wi * hi -- ti is the negative area of intersection - overlaps = true - else - local ti1,ti2,nx1,ny1 = rect_getSegmentIntersectionIndices(x,y,w,h, 0,0,dx,dy, -math.huge, math.huge) - - -- item tunnels into other - if ti1 - and ti1 < 1 - and (abs(ti1 - ti2) >= DELTA) -- special case for rect going through another rect's corner - and (0 < ti1 + DELTA - or 0 == ti1 and ti2 > 0) - then - ti, nx, ny = ti1, nx1, ny1 - overlaps = false - end - end - - if not ti then return end - - local tx, ty - - if overlaps then - if dx == 0 and dy == 0 then - -- intersecting and not moving - use minimum displacement vector - local px, py = rect_getNearestCorner(x,y,w,h, 0,0) - if abs(px) < abs(py) then py = 0 else px = 0 end - nx, ny = sign(px), sign(py) - tx, ty = x1 + px, y1 + py - else - -- intersecting and moving - move in the opposite direction - local ti1, _ - ti1,_,nx,ny = rect_getSegmentIntersectionIndices(x,y,w,h, 0,0,dx,dy, -math.huge, 1) - if not ti1 then return end - tx, ty = x1 + dx * ti1, y1 + dy * ti1 - end - else -- tunnel - tx, ty = x1 + dx * ti, y1 + dy * ti - end - - return { - overlaps = overlaps, - ti = ti, - move = {x = dx, y = dy}, - normal = {x = nx, y = ny}, - touch = {x = tx, y = ty}, - itemRect = {x = x1, y = y1, w = w1, h = h1}, - otherRect = {x = x2, y = y2, w = w2, h = h2} - } -end - ------------------------------------------- --- Grid functions ------------------------------------------- - -local function grid_toWorld(cellSize, cx, cy) - return (cx - 1)*cellSize, (cy-1)*cellSize -end - -local function grid_toCell(cellSize, x, y) - return floor(x / cellSize) + 1, floor(y / cellSize) + 1 -end - --- grid_traverse* functions are based on "A Fast Voxel Traversal Algorithm for Ray Tracing", --- by John Amanides and Andrew Woo - http://www.cse.yorku.ca/~amana/research/grid.pdf --- It has been modified to include both cells when the ray "touches a grid corner", --- and with a different exit condition - -local function grid_traverse_initStep(cellSize, ct, t1, t2) - local v = t2 - t1 - if v > 0 then - return 1, cellSize / v, ((ct + v) * cellSize - t1) / v - elseif v < 0 then - return -1, -cellSize / v, ((ct + v - 1) * cellSize - t1) / v - else - return 0, math.huge, math.huge - end -end - -local function grid_traverse(cellSize, x1,y1,x2,y2, f) - local cx1,cy1 = grid_toCell(cellSize, x1,y1) - local cx2,cy2 = grid_toCell(cellSize, x2,y2) - local stepX, dx, tx = grid_traverse_initStep(cellSize, cx1, x1, x2) - local stepY, dy, ty = grid_traverse_initStep(cellSize, cy1, y1, y2) - local cx,cy = cx1,cy1 - - f(cx, cy) - - -- The default implementation had an infinite loop problem when - -- approaching the last cell in some occassions. We finish iterating - -- when we are *next* to the last cell - while abs(cx - cx2) + abs(cy - cy2) > 1 do - if tx < ty then - tx, cx = tx + dx, cx + stepX - f(cx, cy) - else - -- Addition: include both cells when going through corners - if tx == ty then f(cx + stepX, cy) end - ty, cy = ty + dy, cy + stepY - f(cx, cy) - end - end - - -- If we have not arrived to the last cell, use it - if cx ~= cx2 or cy ~= cy2 then f(cx2, cy2) end - -end - -local function grid_toCellRect(cellSize, x,y,w,h) - local cx,cy = grid_toCell(cellSize, x, y) - local cr,cb = ceil((x+w) / cellSize), ceil((y+h) / cellSize) - return cx, cy, cr - cx + 1, cb - cy + 1 -end - ------------------------------------------- --- Responses ------------------------------------------- - -local touch = function(world, col, x,y,w,h, goalX, goalY, filter) - return col.touch.x, col.touch.y, {}, 0 -end - -local cross = function(world, col, x,y,w,h, goalX, goalY, filter) - local cols, len = world:project(col.item, x,y,w,h, goalX, goalY, filter) - return goalX, goalY, cols, len -end - -local slide = function(world, col, x,y,w,h, goalX, goalY, filter) - goalX = goalX or x - goalY = goalY or y - - local tch, move = col.touch, col.move - if move.x ~= 0 or move.y ~= 0 then - if col.normal.x ~= 0 then - goalX = tch.x - else - goalY = tch.y - end - end - - col.slide = {x = goalX, y = goalY} - - x,y = tch.x, tch.y - local cols, len = world:project(col.item, x,y,w,h, goalX, goalY, filter) - return goalX, goalY, cols, len -end - -local bounce = function(world, col, x,y,w,h, goalX, goalY, filter) - goalX = goalX or x - goalY = goalY or y - - local tch, move = col.touch, col.move - local tx, ty = tch.x, tch.y - - local bx, by = tx, ty - - if move.x ~= 0 or move.y ~= 0 then - local bnx, bny = goalX - tx, goalY - ty - if col.normal.x == 0 then bny = -bny else bnx = -bnx end - bx, by = tx + bnx, ty + bny - end - - col.bounce = {x = bx, y = by} - x,y = tch.x, tch.y - goalX, goalY = bx, by - - local cols, len = world:project(col.item, x,y,w,h, goalX, goalY, filter) - return goalX, goalY, cols, len -end - ------------------------------------------- --- World ------------------------------------------- - -local World = {} -local World_mt = {__index = World} - --- Private functions and methods - -local function sortByWeight(a,b) return a.weight < b.weight end - -local function sortByTiAndDistance(a,b) - if a.ti == b.ti then - local ir, ar, br = a.itemRect, a.otherRect, b.otherRect - local ad = rect_getSquareDistance(ir.x,ir.y,ir.w,ir.h, ar.x,ar.y,ar.w,ar.h) - local bd = rect_getSquareDistance(ir.x,ir.y,ir.w,ir.h, br.x,br.y,br.w,br.h) - return ad < bd - end - return a.ti < b.ti -end - -local function addItemToCell(self, item, cx, cy) - self.rows[cy] = self.rows[cy] or setmetatable({}, {__mode = 'v'}) - local row = self.rows[cy] - row[cx] = row[cx] or {itemCount = 0, x = cx, y = cy, items = setmetatable({}, {__mode = 'k'})} - local cell = row[cx] - self.nonEmptyCells[cell] = true - if not cell.items[item] then - cell.items[item] = true - cell.itemCount = cell.itemCount + 1 - end -end - -local function removeItemFromCell(self, item, cx, cy) - local row = self.rows[cy] - if not row or not row[cx] or not row[cx].items[item] then return false end - - local cell = row[cx] - cell.items[item] = nil - cell.itemCount = cell.itemCount - 1 - if cell.itemCount == 0 then - self.nonEmptyCells[cell] = nil - end - return true -end - -local function getDictItemsInCellRect(self, cl,ct,cw,ch) - local items_dict = {} - for cy=ct,ct+ch-1 do - local row = self.rows[cy] - if row then - for cx=cl,cl+cw-1 do - local cell = row[cx] - if cell and cell.itemCount > 0 then -- no cell.itemCount > 1 because tunneling - for item,_ in pairs(cell.items) do - items_dict[item] = true - end - end - end - end - end - - return items_dict -end - -local function getCellsTouchedBySegment(self, x1,y1,x2,y2) - - local cells, cellsLen, visited = {}, 0, {} - - grid_traverse(self.cellSize, x1,y1,x2,y2, function(cx, cy) - local row = self.rows[cy] - if not row then return end - local cell = row[cx] - if not cell or visited[cell] then return end - - visited[cell] = true - cellsLen = cellsLen + 1 - cells[cellsLen] = cell - end) - - return cells, cellsLen -end - -local function getInfoAboutItemsTouchedBySegment(self, x1,y1, x2,y2, filter) - local cells, len = getCellsTouchedBySegment(self, x1,y1,x2,y2) - local cell, rect, l,t,w,h, ti1,ti2, tii0,tii1 - local visited, itemInfo, itemInfoLen = {},{},0 - for i=1,len do - cell = cells[i] - for item in pairs(cell.items) do - if not visited[item] then - visited[item] = true - if (not filter or filter(item)) then - rect = self.rects[item] - l,t,w,h = rect.x,rect.y,rect.w,rect.h - - ti1,ti2 = rect_getSegmentIntersectionIndices(l,t,w,h, x1,y1, x2,y2, 0, 1) - if ti1 and ((0 < ti1 and ti1 < 1) or (0 < ti2 and ti2 < 1)) then - -- the sorting is according to the t of an infinite line, not the segment - tii0,tii1 = rect_getSegmentIntersectionIndices(l,t,w,h, x1,y1, x2,y2, -math.huge, math.huge) - itemInfoLen = itemInfoLen + 1 - itemInfo[itemInfoLen] = {item = item, ti1 = ti1, ti2 = ti2, weight = min(tii0,tii1)} - end - end - end - end - end - table.sort(itemInfo, sortByWeight) - return itemInfo, itemInfoLen -end - -local function getResponseByName(self, name) - local response = self.responses[name] - if not response then - error(('Unknown collision type: %s (%s)'):format(name, type(name))) - end - return response -end - - --- Misc Public Methods - -function World:addResponse(name, response) - self.responses[name] = response -end - -function World:project(item, x,y,w,h, goalX, goalY, filter) - assertIsRect(x,y,w,h) - - goalX = goalX or x - goalY = goalY or y - filter = filter or defaultFilter - - local collisions, len = {}, 0 - - local visited = {} - if item ~= nil then visited[item] = true end - - -- This could probably be done with less cells using a polygon raster over the cells instead of a - -- bounding rect of the whole movement. Conditional to building a queryPolygon method - local tl, tt = min(goalX, x), min(goalY, y) - local tr, tb = max(goalX + w, x+w), max(goalY + h, y+h) - local tw, th = tr-tl, tb-tt - - local cl,ct,cw,ch = grid_toCellRect(self.cellSize, tl,tt,tw,th) - - local dictItemsInCellRect = getDictItemsInCellRect(self, cl,ct,cw,ch) - - for other,_ in pairs(dictItemsInCellRect) do - if not visited[other] then - visited[other] = true - - local responseName = filter(item, other) - if responseName then - local ox,oy,ow,oh = self:getRect(other) - local col = rect_detectCollision(x,y,w,h, ox,oy,ow,oh, goalX, goalY) - - if col then - col.other = other - col.item = item - col.type = responseName - - len = len + 1 - collisions[len] = col - end - end - end - end - - table.sort(collisions, sortByTiAndDistance) - - return collisions, len -end - -function World:countCells() - local count = 0 - for _,row in pairs(self.rows) do - for _,_ in pairs(row) do - count = count + 1 - end - end - return count -end - -function World:hasItem(item) - return not not self.rects[item] -end - -function World:getItems() - local items, len = {}, 0 - for item,_ in pairs(self.rects) do - len = len + 1 - items[len] = item - end - return items, len -end - -function World:countItems() - local len = 0 - for _ in pairs(self.rects) do len = len + 1 end - return len -end - -function World:getRect(item) - local rect = self.rects[item] - if not rect then - error('Item ' .. tostring(item) .. ' must be added to the world before getting its rect. Use world:add(item, x,y,w,h) to add it first.') - end - return rect.x, rect.y, rect.w, rect.h -end - -function World:toWorld(cx, cy) - return grid_toWorld(self.cellSize, cx, cy) -end - -function World:toCell(x,y) - return grid_toCell(self.cellSize, x, y) -end - - ---- Query methods - -function World:queryRect(x,y,w,h, filter) - - assertIsRect(x,y,w,h) - - local cl,ct,cw,ch = grid_toCellRect(self.cellSize, x,y,w,h) - local dictItemsInCellRect = getDictItemsInCellRect(self, cl,ct,cw,ch) - - local items, len = {}, 0 - - local rect - for item,_ in pairs(dictItemsInCellRect) do - rect = self.rects[item] - if (not filter or filter(item)) - and rect_isIntersecting(x,y,w,h, rect.x, rect.y, rect.w, rect.h) - then - len = len + 1 - items[len] = item - end - end - - return items, len -end - -function World:queryPoint(x,y, filter) - local cx,cy = self:toCell(x,y) - local dictItemsInCellRect = getDictItemsInCellRect(self, cx,cy,1,1) - - local items, len = {}, 0 - - local rect - for item,_ in pairs(dictItemsInCellRect) do - rect = self.rects[item] - if (not filter or filter(item)) - and rect_containsPoint(rect.x, rect.y, rect.w, rect.h, x, y) - then - len = len + 1 - items[len] = item - end - end - - return items, len -end - -function World:querySegment(x1, y1, x2, y2, filter) - local itemInfo, len = getInfoAboutItemsTouchedBySegment(self, x1, y1, x2, y2, filter) - local items = {} - for i=1, len do - items[i] = itemInfo[i].item - end - return items, len -end - -function World:querySegmentWithCoords(x1, y1, x2, y2, filter) - local itemInfo, len = getInfoAboutItemsTouchedBySegment(self, x1, y1, x2, y2, filter) - local dx, dy = x2-x1, y2-y1 - local info, ti1, ti2 - for i=1, len do - info = itemInfo[i] - ti1 = info.ti1 - ti2 = info.ti2 - - info.weight = nil - info.x1 = x1 + dx * ti1 - info.y1 = y1 + dy * ti1 - info.x2 = x1 + dx * ti2 - info.y2 = y1 + dy * ti2 - end - return itemInfo, len -end - - ---- Main methods - -function World:add(item, x,y,w,h) - local rect = self.rects[item] - if rect then - error('Item ' .. tostring(item) .. ' added to the world twice.') - end - assertIsRect(x,y,w,h) - - self.rects[item] = {x=x,y=y,w=w,h=h} - - local cl,ct,cw,ch = grid_toCellRect(self.cellSize, x,y,w,h) - for cy = ct, ct+ch-1 do - for cx = cl, cl+cw-1 do - addItemToCell(self, item, cx, cy) - end - end - - return item -end - -function World:remove(item) - local x,y,w,h = self:getRect(item) - - self.rects[item] = nil - local cl,ct,cw,ch = grid_toCellRect(self.cellSize, x,y,w,h) - for cy = ct, ct+ch-1 do - for cx = cl, cl+cw-1 do - removeItemFromCell(self, item, cx, cy) - end - end -end - -function World:update(item, x2,y2,w2,h2) - local x1,y1,w1,h1 = self:getRect(item) - w2,h2 = w2 or w1, h2 or h1 - assertIsRect(x2,y2,w2,h2) - - if x1 ~= x2 or y1 ~= y2 or w1 ~= w2 or h1 ~= h2 then - - local cellSize = self.cellSize - local cl1,ct1,cw1,ch1 = grid_toCellRect(cellSize, x1,y1,w1,h1) - local cl2,ct2,cw2,ch2 = grid_toCellRect(cellSize, x2,y2,w2,h2) - - if cl1 ~= cl2 or ct1 ~= ct2 or cw1 ~= cw2 or ch1 ~= ch2 then - - local cr1, cb1 = cl1+cw1-1, ct1+ch1-1 - local cr2, cb2 = cl2+cw2-1, ct2+ch2-1 - local cyOut - - for cy = ct1, cb1 do - cyOut = cy < ct2 or cy > cb2 - for cx = cl1, cr1 do - if cyOut or cx < cl2 or cx > cr2 then - removeItemFromCell(self, item, cx, cy) - end - end - end - - for cy = ct2, cb2 do - cyOut = cy < ct1 or cy > cb1 - for cx = cl2, cr2 do - if cyOut or cx < cl1 or cx > cr1 then - addItemToCell(self, item, cx, cy) - end - end - end - - end - - local rect = self.rects[item] - rect.x, rect.y, rect.w, rect.h = x2,y2,w2,h2 - - end -end - -function World:move(item, goalX, goalY, filter) - local actualX, actualY, cols, len = self:check(item, goalX, goalY, filter) - - self:update(item, actualX, actualY) - - return actualX, actualY, cols, len -end - -function World:check(item, goalX, goalY, filter) - filter = filter or defaultFilter - - local visited = {[item] = true} - local visitedFilter = function(itm, other) - if visited[other] then return false end - return filter(itm, other) - end - - local cols, len = {}, 0 - - local x,y,w,h = self:getRect(item) - - local projected_cols, projected_len = self:project(item, x,y,w,h, goalX,goalY, visitedFilter) - - while projected_len > 0 do - local col = projected_cols[1] - len = len + 1 - cols[len] = col - - visited[col.other] = true - - local response = getResponseByName(self, col.type) - - goalX, goalY, projected_cols, projected_len = response( - self, - col, - x, y, w, h, - goalX, goalY, - visitedFilter - ) - end - - return goalX, goalY, cols, len -end - - --- Public library functions - -bump.newWorld = function(cellSize) - cellSize = cellSize or 64 - assertIsPositiveNumber(cellSize, 'cellSize') - local world = setmetatable({ - cellSize = cellSize, - rects = {}, - rows = {}, - nonEmptyCells = {}, - responses = {} - }, World_mt) - - world:addResponse('touch', touch) - world:addResponse('cross', cross) - world:addResponse('slide', slide) - world:addResponse('bounce', bounce) - - return world -end - -bump.rect = { - getNearestCorner = rect_getNearestCorner, - getSegmentIntersectionIndices = rect_getSegmentIntersectionIndices, - getDiff = rect_getDiff, - containsPoint = rect_containsPoint, - isIntersecting = rect_isIntersecting, - getSquareDistance = rect_getSquareDistance, - detectCollision = rect_detectCollision -} - -bump.responses = { - touch = touch, - cross = cross, - slide = slide, - bounce = bounce -} - -return bump diff --git a/sonic-bluestreak.love/libs/level-libs/tsort.lua b/sonic-bluestreak.love/libs/level-libs/tsort.lua deleted file mode 100644 index 3f8dfc9..0000000 --- a/sonic-bluestreak.love/libs/level-libs/tsort.lua +++ /dev/null @@ -1,84 +0,0 @@ --- See: https://github.com/bungle/lua-resty-tsort --- --- Copyright (c) 2016, Aapo Talvensaari --- All rights reserved. --- --- Redistribution and use in source and binary forms, with or without modification, --- are permitted provided that the following conditions are met: --- --- * Redistributions of source code must retain the above copyright notice, this --- list of conditions and the following disclaimer. --- --- * Redistributions in binary form must reproduce the above copyright notice, this --- list of conditions and the following disclaimer in the documentation and/or --- other materials provided with the distribution. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND --- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED --- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE --- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR --- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES --- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; --- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON --- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT --- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS --- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -local setmetatable = setmetatable -local pairs = pairs -local type = type -local function visit(k, n, m, s) - if m[k] == 0 then return 1 end - if m[k] == 1 then return end - m[k] = 0 - local f = n[k] - for i=1, #f do - if visit(f[i], n, m, s) then return 1 end - end - m[k] = 1 - s[#s+1] = k -end -local tsort = {} -tsort.__index = tsort -function tsort.new() - return setmetatable({ n = {} }, tsort) -end -function tsort:add(...) - local p = { ... } - local c = #p - if c == 0 then return self end - if c == 1 then - p = p[1] - if type(p) == "table" then - c = #p - else - p = { p } - end - end - local n = self.n - for i=1, c do - local f = p[i] - if n[f] == nil then n[f] = {} end - end - for i=2, c, 1 do - local f = p[i] - local t = p[i-1] - local o = n[f] - o[#o+1] = t - end - return self -end -function tsort:sort() - local n = self.n - local s = {} - local m = {} - for k in pairs(n) do - if m[k] == nil then - if visit(k, n, m, s) then - return nil, "There is a circular dependency in the graph. It is not possible to derive a topological sort." - end - end - end - return s -end -return tsort diff --git a/sonic-bluestreak.love/libs/lovebird.lua b/sonic-bluestreak.love/libs/lovebird.lua deleted file mode 100644 index 8b296eb..0000000 --- a/sonic-bluestreak.love/libs/lovebird.lua +++ /dev/null @@ -1,737 +0,0 @@ --- --- 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-bluestreak.love/libs/loveutils/filesystem.lua b/sonic-bluestreak.love/libs/loveutils/filesystem.lua deleted file mode 100644 index 3d38e27..0000000 --- a/sonic-bluestreak.love/libs/loveutils/filesystem.lua +++ /dev/null @@ -1,16 +0,0 @@ -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-bluestreak.love/libs/loveutils/graphics.lua b/sonic-bluestreak.love/libs/loveutils/graphics.lua deleted file mode 100644 index 79ad753..0000000 --- a/sonic-bluestreak.love/libs/loveutils/graphics.lua +++ /dev/null @@ -1,64 +0,0 @@ -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-bluestreak.love/libs/loveutils/init.lua b/sonic-bluestreak.love/libs/loveutils/init.lua deleted file mode 100644 index 0f6ea3c..0000000 --- a/sonic-bluestreak.love/libs/loveutils/init.lua +++ /dev/null @@ -1,7 +0,0 @@ -local cwd = (...):gsub('%.init$', '') .. "." - -return { - math = require(cwd .. "math"), - graphics = require(cwd .. "graphics"), - filesystem = require(cwd .. "filesystem") -} diff --git a/sonic-bluestreak.love/libs/loveutils/math.lua b/sonic-bluestreak.love/libs/loveutils/math.lua deleted file mode 100644 index 7738f68..0000000 --- a/sonic-bluestreak.love/libs/loveutils/math.lua +++ /dev/null @@ -1,104 +0,0 @@ -local Math = {} - -function Math.wrap(x, startnumber, endnumber) - local delta = endnumber - startnumber - if delta < 0 then - err("endnumber must be larger than startnumber") - end - while x >= endnumber do - x = x - delta - end - - while x < startnumber do - x = x + delta - end - - return x -end - -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) - vecy = 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