split uranium-core into its own repository
This commit is contained in:
parent
36ee8fd056
commit
f14f71a846
|
@ -1 +1,2 @@
|
||||||
pull.rebase=true
|
pull.rebase=true
|
||||||
|
submodule.recurse=true
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "template"]
|
||||||
|
path = template
|
||||||
|
url = https://git.oat.zone/oat/uranium-core
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 0e8905d660d4104886dc559eba8b41ce8901b6fc
|
|
@ -1,6 +0,0 @@
|
||||||
<ActorFrame InitCommand="%oat._actor.initFrame">
|
|
||||||
<children>
|
|
||||||
<Layer Condition="oat._actor.cond()" Type="@oat._actor.type()" File="@oat._actor.file()" Font="@oat._actor.font()" InitCommand="%oat._actor.init"/>
|
|
||||||
<Layer Condition="oat._actor.next()" File="actors.xml" />
|
|
||||||
</children>
|
|
||||||
</ActorFrame>
|
|
|
@ -1,528 +0,0 @@
|
||||||
<Layer Type="ActorFrame" InitCommand="%function(self)
|
|
||||||
_G.oat = {}
|
|
||||||
oat._main = self
|
|
||||||
|
|
||||||
setmetatable(oat, {
|
|
||||||
-- if something isn't found in the table, fall back to a global lookup
|
|
||||||
__index = _G,
|
|
||||||
|
|
||||||
-- handle oat() calls to set the environment
|
|
||||||
__call = function(self, f)
|
|
||||||
setfenv(f or 2, self)
|
|
||||||
return f
|
|
||||||
end
|
|
||||||
})
|
|
||||||
oat()
|
|
||||||
|
|
||||||
local function copy(src)
|
|
||||||
local dest = {}
|
|
||||||
for k, v in pairs(src) do
|
|
||||||
dest[k] = v
|
|
||||||
end
|
|
||||||
return dest
|
|
||||||
end
|
|
||||||
|
|
||||||
oat.oat = _G.oat
|
|
||||||
oat.type = _G.type
|
|
||||||
oat.print = _G.print
|
|
||||||
oat.pairs = _G.pairs
|
|
||||||
oat.ipairs = _G.ipairs
|
|
||||||
oat.unpack = _G.unpack
|
|
||||||
oat.tonumber = _G.tonumber
|
|
||||||
oat.tostring = _G.tostring
|
|
||||||
oat.math = copy(_G.math)
|
|
||||||
oat.table = copy(_G.table)
|
|
||||||
oat.string = copy(_G.string)
|
|
||||||
|
|
||||||
oat.scx = SCREEN_CENTER_X
|
|
||||||
oat.scy = SCREEN_CENTER_Y
|
|
||||||
oat.sw = SCREEN_WIDTH
|
|
||||||
oat.sh = SCREEN_HEIGHT
|
|
||||||
oat.dw = DISPLAY:GetDisplayWidth()
|
|
||||||
oat.dh = DISPLAY:GetDisplayHeight()
|
|
||||||
|
|
||||||
local uraniumFunc = {}
|
|
||||||
|
|
||||||
function uraniumFunc:call(event, ...)
|
|
||||||
if self._callbacks[event] then
|
|
||||||
for _, callback in ipairs(self._callbacks[event]) do
|
|
||||||
callback(unpack(arg))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local uraniumMeta = {}
|
|
||||||
|
|
||||||
function uraniumMeta:__newindex(key, value)
|
|
||||||
if self._callbacks[key] then
|
|
||||||
table.insert(self._callbacks[key], value)
|
|
||||||
else
|
|
||||||
self._callbacks[key] = {value}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
uraniumMeta.__index = uraniumFunc
|
|
||||||
|
|
||||||
uranium = setmetatable({_callbacks = {}}, uraniumMeta)
|
|
||||||
|
|
||||||
function backToSongWheel(message)
|
|
||||||
if message then
|
|
||||||
SCREENMAN:SystemMessage(message)
|
|
||||||
print(message)
|
|
||||||
end
|
|
||||||
GAMESTATE:FinishSong()
|
|
||||||
-- disable update_command
|
|
||||||
self:hidden(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
local actorsInitialized = false -- if true, no new actors can be created
|
|
||||||
|
|
||||||
local luaobj
|
|
||||||
|
|
||||||
local globalQueue = {} -- for resetting
|
|
||||||
|
|
||||||
local patchedFunctions = {}
|
|
||||||
local function patchFunction(f, obj)
|
|
||||||
if not patchedFunctions[f] then patchedFunctions[f] = {} end
|
|
||||||
if not patchedFunctions[f][obj] then
|
|
||||||
patchedFunctions[f][obj] = function(...)
|
|
||||||
arg[1] = obj
|
|
||||||
local results
|
|
||||||
local status, result = pcall(function()
|
|
||||||
-- doing it this way instead of returning because lua
|
|
||||||
-- offers no way of grabbing everything BUT the first
|
|
||||||
-- argument out of pcall
|
|
||||||
results = {f(unpack(arg))}
|
|
||||||
end)
|
|
||||||
if not status then
|
|
||||||
error(result, 2)
|
|
||||||
else
|
|
||||||
return unpack(results)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return patchedFunctions[f][obj]
|
|
||||||
end
|
|
||||||
|
|
||||||
local function onCommand(self)
|
|
||||||
actorsInitialized = true
|
|
||||||
uranium:call('init')
|
|
||||||
end
|
|
||||||
|
|
||||||
function reset(actor)
|
|
||||||
if not actorsInitialized then error('uranium: cannot reset an actor during initialization', 2) end
|
|
||||||
for _, q in ipairs(globalQueue) do
|
|
||||||
local queueActor = q[1]
|
|
||||||
if queueActor == actor.__raw then
|
|
||||||
local v = q[2]
|
|
||||||
|
|
||||||
local func = queueActor[v[1]]
|
|
||||||
if not func then
|
|
||||||
-- uhmmm ??? hm. what do we do??
|
|
||||||
else
|
|
||||||
patchFunction(func, queueActor)(unpack(v[2]))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- runs once during ScreenReadyCommand, before the user code is loaded
|
|
||||||
-- hides various actors that are placed by the theme
|
|
||||||
local function hideThemeActors()
|
|
||||||
for _, element in ipairs {
|
|
||||||
'Overlay', 'Underlay',
|
|
||||||
'ScoreP1', 'ScoreP2',
|
|
||||||
'LifeP1', 'LifeP2',
|
|
||||||
} do
|
|
||||||
local child = SCREENMAN(element)
|
|
||||||
if child then child:hidden(1) end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local lastt = GAMESTATE:GetSongTime()
|
|
||||||
local function screen_ready_command(self)
|
|
||||||
hideThemeActors()
|
|
||||||
self:hidden(0)
|
|
||||||
|
|
||||||
local errored = false
|
|
||||||
local firstrun = true
|
|
||||||
self:addcommand('Update', function()
|
|
||||||
if errored then
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
errored = true
|
|
||||||
|
|
||||||
t = os.clock()
|
|
||||||
b = GAMESTATE:GetSongBeat()
|
|
||||||
local dt = t - lastt
|
|
||||||
lastt = t
|
|
||||||
|
|
||||||
if firstrun then
|
|
||||||
firstrun = false
|
|
||||||
dt = 0
|
|
||||||
self:GetChildren()[2]:hidden(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, q in ipairs(globalQueue) do
|
|
||||||
local actor = q[1]
|
|
||||||
local v = q[2]
|
|
||||||
|
|
||||||
local func = actor[v[1]]
|
|
||||||
if not func then
|
|
||||||
-- uhmmm ??? hm. what do we do??
|
|
||||||
else
|
|
||||||
patchFunction(func, actor)(unpack(v[2]))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
uranium:call('update', dt)
|
|
||||||
|
|
||||||
errored = false
|
|
||||||
|
|
||||||
return 0
|
|
||||||
end)
|
|
||||||
self:luaeffect('Update')
|
|
||||||
end
|
|
||||||
|
|
||||||
GAMESTATE:ApplyModifiers('clearall')
|
|
||||||
|
|
||||||
local function formatError(file, e)
|
|
||||||
local _, _, err = string.find(e, 'error loading package `[^`\']+\' %((.+)%)')
|
|
||||||
return (file and err) and ('error loading \'' .. file .. '\':\n' .. err) or e
|
|
||||||
end
|
|
||||||
|
|
||||||
local songName = GAMESTATE:GetCurrentSong():GetSongDir()
|
|
||||||
local additionalSongFolders = PREFSMAN:GetPreference('AdditionalSongFolders')
|
|
||||||
local additionalFolders = PREFSMAN:GetPreference('AdditionalFolders')
|
|
||||||
local function attemptload(f, filename) -- not to be confused with tryload
|
|
||||||
local err = ''
|
|
||||||
local lasterr = ''
|
|
||||||
local func
|
|
||||||
|
|
||||||
local s = '.' .. songName .. f
|
|
||||||
|
|
||||||
func, lasterr = loadfile(s)
|
|
||||||
if func then return func end
|
|
||||||
if not string.find(lasterr, '\' from path `') then return nil, formatError(filename, lasterr), nil end
|
|
||||||
err = err .. s .. '\n'
|
|
||||||
|
|
||||||
s = f
|
|
||||||
|
|
||||||
func, lasterr = loadfile(s)
|
|
||||||
if func then return func end
|
|
||||||
if not string.find(lasterr, '\' from path `') then return nil, formatError(filename, lasterr), nil end
|
|
||||||
err = err .. s .. '\n'
|
|
||||||
|
|
||||||
-- cut off 'Songs/' from the path
|
|
||||||
local _,index = string.find(songName,'Songs/')
|
|
||||||
local songLoc = string.sub(songName,index)
|
|
||||||
|
|
||||||
-- for every songfolder in the additionalsongfolders
|
|
||||||
if additionalSongFolders and additionalSongFolders ~= '' then
|
|
||||||
for songFolder in string.gfind(additionalSongFolders,'[^,]+') do
|
|
||||||
s = songFolder .. songLoc .. f
|
|
||||||
|
|
||||||
func, lasterr = loadfile(s)
|
|
||||||
if func then return func end
|
|
||||||
err = err .. s .. '\n'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if additionalFolders and additionalFolders ~= '' then
|
|
||||||
for folder in string.gfind(additionalFolders,'[^,]+') do
|
|
||||||
s = folder .. songName .. f
|
|
||||||
|
|
||||||
func, lasterr = loadfile(s)
|
|
||||||
if func then return func end
|
|
||||||
err = err .. s .. '\n'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil, lasterr, string.sub(err, 0, -2)
|
|
||||||
end
|
|
||||||
|
|
||||||
oat._loadPath = ''
|
|
||||||
|
|
||||||
function tryload(f)
|
|
||||||
local func, err, trace = attemptload(oat._loadPath .. f, f)
|
|
||||||
if not func then
|
|
||||||
if trace then
|
|
||||||
backToSongWheel('finding \'' .. f .. '\' failed, check log for more details')
|
|
||||||
error('uranium: finding \'' .. f .. '\' failed! tried these paths: ' .. '\n' .. trace, 2)
|
|
||||||
Trace(trace)
|
|
||||||
else
|
|
||||||
error(err, 2)
|
|
||||||
Trace('loading \'' .. f .. '\' failed!' .. '\n' .. err)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return oat(func)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function getFolderStructure(path)
|
|
||||||
local folders = {}
|
|
||||||
for folder in string.gfind(path, '[^/]+') do
|
|
||||||
table.insert(folders, folder)
|
|
||||||
end
|
|
||||||
table.remove(folders, #folders)
|
|
||||||
return table.concat(folders, '/')
|
|
||||||
end
|
|
||||||
|
|
||||||
oat._requirePath = ''
|
|
||||||
|
|
||||||
function require(f)
|
|
||||||
-- . -> /
|
|
||||||
f = string.gsub(f, '%.', '/')
|
|
||||||
-- add .lua
|
|
||||||
f = f .. '.lua'
|
|
||||||
|
|
||||||
local oldpath = oat._requirePath
|
|
||||||
local folder = getFolderStructure(f)
|
|
||||||
if folder ~= '' then
|
|
||||||
oat._requirePath = oat._requirePath .. folder .. '/'
|
|
||||||
end
|
|
||||||
local res, c = pcall(tryload, oldpath .. f)
|
|
||||||
if not res then
|
|
||||||
error(c, 2)
|
|
||||||
else
|
|
||||||
local success, s = pcall(c)
|
|
||||||
if success then
|
|
||||||
return s
|
|
||||||
else
|
|
||||||
error('uranium: error loading \'' .. f .. '\':\n' .. s, 2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
oat._requirePath = oldpath
|
|
||||||
end
|
|
||||||
|
|
||||||
-- actors
|
|
||||||
|
|
||||||
local actorQueue = {}
|
|
||||||
local currentActor = nil
|
|
||||||
|
|
||||||
oat._actor = {}
|
|
||||||
|
|
||||||
function oat._actor.next()
|
|
||||||
local actor = actorQueue[1]
|
|
||||||
if actor then
|
|
||||||
table.remove(actorQueue, 1)
|
|
||||||
currentActor = actor
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.cond()
|
|
||||||
return currentActor ~= nil
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.type()
|
|
||||||
return currentActor.type
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.file()
|
|
||||||
return currentActor.file
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.font()
|
|
||||||
return currentActor.font
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.init(self)
|
|
||||||
currentActor.init(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.initFrame(self)
|
|
||||||
local nextChild = self(2)
|
|
||||||
self:SetDrawFunction(function()
|
|
||||||
if nextChild then
|
|
||||||
nextChild:Draw()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function createProxyActor(name)
|
|
||||||
local queue = {}
|
|
||||||
local initCommands = {}
|
|
||||||
local lockedActor
|
|
||||||
|
|
||||||
return setmetatable({}, {
|
|
||||||
__index = function(self, key)
|
|
||||||
if key == '__raw' then
|
|
||||||
return lockedActor
|
|
||||||
end
|
|
||||||
if lockedActor then
|
|
||||||
local val = lockedActor[key]
|
|
||||||
if type(val) == 'function' then
|
|
||||||
return patchFunction(val, lockedActor)
|
|
||||||
end
|
|
||||||
return val
|
|
||||||
end
|
|
||||||
if key == '__lock' then
|
|
||||||
return function(actor)
|
|
||||||
for _, v in ipairs(queue) do
|
|
||||||
local func = actor[v[1]]
|
|
||||||
if not func then
|
|
||||||
error(
|
|
||||||
'uranium: error on \'' .. name .. '\' initialization on ' .. v[3].short_src .. ':' .. v[3].currentline .. ':\n' ..
|
|
||||||
'you\'re calling a function \'' .. v[1] .. '\' on a ' .. name .. ' which doesn\'t exist!:\n'
|
|
||||||
)
|
|
||||||
else
|
|
||||||
local success, result = pcall(function()
|
|
||||||
patchFunction(func, actor)(unpack(v[2]))
|
|
||||||
end)
|
|
||||||
if not success then
|
|
||||||
error(
|
|
||||||
'uranium: error on \'' .. name .. '\' initialization on ' .. v[3].short_src .. ':' .. v[3].currentline .. ':\n' ..
|
|
||||||
result
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- now that we know there's no poisonous methods in queue, let's offload them
|
|
||||||
for _, v in ipairs(queue) do
|
|
||||||
table.insert(globalQueue, {actor, v})
|
|
||||||
end
|
|
||||||
-- let's also properly route everything from the proxied actor to the actual actor
|
|
||||||
lockedActor = actor
|
|
||||||
-- and now let's run the initcommands
|
|
||||||
for _, c in ipairs(initCommands) do
|
|
||||||
local func = c[1]
|
|
||||||
local success, result = pcall(function()
|
|
||||||
func(actor)
|
|
||||||
end)
|
|
||||||
if not success then
|
|
||||||
error(
|
|
||||||
'uranium: error on \'' .. name .. '\' InitCommand defined on ' .. v[3].short_src .. ':' .. v[3].currentline .. ':\n' ..
|
|
||||||
result
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
initCommands = {}
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return function(...)
|
|
||||||
if key == 'addcommand' and arg[2] == 'Init' then
|
|
||||||
table.insert(initCommands, {arg[3], debug.getinfo(2, 'Sl')})
|
|
||||||
else
|
|
||||||
table.insert(queue, {key, arg, debug.getinfo(2, 'Sl')})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
__newindex = function()
|
|
||||||
error('uranium: cannot set properties on actors!', 2)
|
|
||||||
end,
|
|
||||||
__tostring = function() return name end,
|
|
||||||
__name = name
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
local function createGenericFunc(type)
|
|
||||||
return function()
|
|
||||||
if actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
|
||||||
local actor = createProxyActor(type)
|
|
||||||
table.insert(actorQueue, {
|
|
||||||
type = type,
|
|
||||||
file = nil,
|
|
||||||
init = function(a)
|
|
||||||
actor.__lock(a)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
return actor
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Quad = createGenericFunc('Quad')
|
|
||||||
ActorProxy = createGenericFunc('ActorProxy')
|
|
||||||
Polygon = createGenericFunc('Polygon')
|
|
||||||
|
|
||||||
function Sprite(file)
|
|
||||||
if actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
|
||||||
if not file then error('uranium: cannot create a Sprite without a file', 2) end
|
|
||||||
local actor = createProxyActor('Sprite')
|
|
||||||
table.insert(actorQueue, {
|
|
||||||
type = nil,
|
|
||||||
file = '../src/' .. oat._requirePath .. file,
|
|
||||||
init = function(a)
|
|
||||||
actor.__lock(a)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
return actor
|
|
||||||
end
|
|
||||||
|
|
||||||
function Model(file)
|
|
||||||
if actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
|
||||||
if not file then error('uranium: cannot create a Model without a file', 2) end
|
|
||||||
local actor = createProxyActor('Model')
|
|
||||||
table.insert(actorQueue, {
|
|
||||||
type = nil,
|
|
||||||
file = '../src/' .. oat._requirePath .. file,
|
|
||||||
init = function(a)
|
|
||||||
actor.__lock(a)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
return actor
|
|
||||||
end
|
|
||||||
|
|
||||||
function BitmapText(font, text)
|
|
||||||
if actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
|
||||||
local actor = createProxyActor('BitmapText')
|
|
||||||
table.insert(actorQueue, {
|
|
||||||
type = 'BitmapText',
|
|
||||||
font = font and ('../src/' .. oat._requirePath .. font) or 'common',
|
|
||||||
init = function(a)
|
|
||||||
if text then a:settext(text) end
|
|
||||||
actor.__lock(a)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
return actor
|
|
||||||
end
|
|
||||||
|
|
||||||
function ActorSound(file)
|
|
||||||
if actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
|
||||||
if not file then error('uranium: cannot create an ActorSound without a file', 2) end
|
|
||||||
local actor = createProxyActor('ActorSound')
|
|
||||||
table.insert(actorQueue, {
|
|
||||||
type = 'ActorSound',
|
|
||||||
file = '../src/' .. oat._requirePath .. file,
|
|
||||||
init = function(a)
|
|
||||||
actor.__lock(a)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
return actor
|
|
||||||
end
|
|
||||||
|
|
||||||
oat._loadPath = 'template/stdlib/'
|
|
||||||
oat.tryload('index')()
|
|
||||||
oat._loadPath = 'src/'
|
|
||||||
lua = oat.tryload('main')
|
|
||||||
|
|
||||||
if lua then
|
|
||||||
local success, result = pcall(lua)
|
|
||||||
if success then
|
|
||||||
luaobj = result
|
|
||||||
|
|
||||||
self:addcommand('On', onCommand)
|
|
||||||
self:addcommand('Ready', screen_ready_command)
|
|
||||||
self:queuecommand('Ready')
|
|
||||||
else
|
|
||||||
Trace('got an error loading main.lua!')
|
|
||||||
Trace(result)
|
|
||||||
backToSongWheel('loading .lua file failed, check log for details')
|
|
||||||
error('uranium: loading main.lua file failed:\n' .. result)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Trace('luaobj doesnt exist despite passing checks. thats VERY odd')
|
|
||||||
backToSongWheel('uranium: loading .lua file failed, check log for details')
|
|
||||||
error('loading main.lua file failed: \'lua\' variable doesn\'t exist despite passing checks')
|
|
||||||
end
|
|
||||||
|
|
||||||
-- NotITG and OpenITG have a long standing bug where the InitCommand on an actor can run twice in certain cases.
|
|
||||||
-- By removing the command after it's done, it can only ever run once
|
|
||||||
self:removecommand('Init')
|
|
||||||
end"><children>
|
|
||||||
<Layer Condition="oat._actor.next()" File="actors.xml"/>
|
|
||||||
<Layer Type="Quad" InitCommand="xywh,SCREEN_CENTER_X,SCREEN_CENTER_Y,SCREEN_WIDTH,SCREEN_HEIGHT;diffuse,#000000;sleep,9e9"/>
|
|
||||||
</children></Layer>
|
|
|
@ -1,343 +0,0 @@
|
||||||
local M = {_TYPE='module', _NAME='bitop.funcs', _VERSION='1.0-0'}
|
|
||||||
|
|
||||||
local floor = math.floor
|
|
||||||
|
|
||||||
local MOD = math.pow(2, 32)
|
|
||||||
local MODM = MOD-1
|
|
||||||
|
|
||||||
local function memoize(f)
|
|
||||||
|
|
||||||
local mt = {}
|
|
||||||
local t = setmetatable({}, mt)
|
|
||||||
|
|
||||||
function mt:__index(k)
|
|
||||||
local v = f(k)
|
|
||||||
t[k] = v
|
|
||||||
return v
|
|
||||||
end
|
|
||||||
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
|
|
||||||
local function make_bitop_uncached(t, m)
|
|
||||||
local function bitop(a, b)
|
|
||||||
local res,p = 0,1
|
|
||||||
while a ~= 0 and b ~= 0 do
|
|
||||||
local am, bm = a%m, b%m
|
|
||||||
res = res + t[am][bm]*p
|
|
||||||
a = (a - am) / m
|
|
||||||
b = (b - bm) / m
|
|
||||||
p = p*m
|
|
||||||
end
|
|
||||||
res = res + (a+b) * p
|
|
||||||
return res
|
|
||||||
end
|
|
||||||
return bitop
|
|
||||||
end
|
|
||||||
|
|
||||||
local function make_bitop(t)
|
|
||||||
local op1 = make_bitop_uncached(t, math.pow(2, 1))
|
|
||||||
local op2 = memoize(function(a)
|
|
||||||
return memoize(function(b)
|
|
||||||
return op1(a, b)
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
return make_bitop_uncached(op2, math.pow(2, (t.n or 1)))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ok? probably not if running on a 32-bit int Lua number type platform
|
|
||||||
function M.tobit(x)
|
|
||||||
return x % math.pow(2, 32)
|
|
||||||
end
|
|
||||||
|
|
||||||
M.bxor = make_bitop {[0]={[0]=0,[1]=1},[1]={[0]=1,[1]=0}, n=4}
|
|
||||||
local bxor = M.bxor
|
|
||||||
|
|
||||||
function M.bnot(a) return MODM - a end
|
|
||||||
local bnot = M.bnot
|
|
||||||
|
|
||||||
function M.band(a,b) return ((a+b) - bxor(a,b))/2 end
|
|
||||||
local band = M.band
|
|
||||||
|
|
||||||
function M.bor(a,b) return MODM - band(MODM - a, MODM - b) end
|
|
||||||
local bor = M.bor
|
|
||||||
|
|
||||||
local lshift, rshift -- forward declare
|
|
||||||
|
|
||||||
function M.rshift(a,disp) -- Lua5.2 insipred
|
|
||||||
if disp < 0 then return lshift(a,-disp) end
|
|
||||||
return floor(a % math.pow(2, 32) / math.pow(2, disp))
|
|
||||||
end
|
|
||||||
rshift = M.rshift
|
|
||||||
|
|
||||||
function M.lshift(a,disp) -- Lua5.2 inspired
|
|
||||||
if disp < 0 then return rshift(a,-disp) end
|
|
||||||
return (a * math.pow(2, disp)) % math.pow(2, 32)
|
|
||||||
end
|
|
||||||
lshift = M.lshift
|
|
||||||
|
|
||||||
function M.tohex(x, n) -- BitOp style
|
|
||||||
n = n or 8
|
|
||||||
local up
|
|
||||||
if n <= 0 then
|
|
||||||
if n == 0 then return '' end
|
|
||||||
up = true
|
|
||||||
n = - n
|
|
||||||
end
|
|
||||||
x = band(x, math.pow(16, n-1))
|
|
||||||
return ('%0'..n..(up and 'X' or 'x')):format(x)
|
|
||||||
end
|
|
||||||
local tohex = M.tohex
|
|
||||||
|
|
||||||
function M.extract(n, field, width) -- Lua5.2 inspired
|
|
||||||
width = width or 1
|
|
||||||
return band(rshift(n, field), math.pow(2, width-1))
|
|
||||||
end
|
|
||||||
local extract = M.extract
|
|
||||||
|
|
||||||
function M.replace(n, v, field, width) -- Lua5.2 inspired
|
|
||||||
width = width or 1
|
|
||||||
local mask1 = math.pow(2, width-1)
|
|
||||||
v = band(v, mask1) -- required by spec?
|
|
||||||
local mask = bnot(lshift(mask1, field))
|
|
||||||
return band(n, mask) + lshift(v, field)
|
|
||||||
end
|
|
||||||
local replace = M.replace
|
|
||||||
|
|
||||||
function M.bswap(x) -- BitOp style
|
|
||||||
local a = band(x, 0xff); x = rshift(x, 8)
|
|
||||||
local b = band(x, 0xff); x = rshift(x, 8)
|
|
||||||
local c = band(x, 0xff); x = rshift(x, 8)
|
|
||||||
local d = band(x, 0xff)
|
|
||||||
return lshift(lshift(lshift(a, 8) + b, 8) + c, 8) + d
|
|
||||||
end
|
|
||||||
local bswap = M.bswap
|
|
||||||
|
|
||||||
function M.rrotate(x, disp) -- Lua5.2 inspired
|
|
||||||
disp = disp % 32
|
|
||||||
local low = band(x, math.pow(2, disp-1))
|
|
||||||
return rshift(x, disp) + lshift(low, 32-disp)
|
|
||||||
end
|
|
||||||
local rrotate = M.rrotate
|
|
||||||
|
|
||||||
function M.lrotate(x, disp) -- Lua5.2 inspired
|
|
||||||
return rrotate(x, -disp)
|
|
||||||
end
|
|
||||||
local lrotate = M.lrotate
|
|
||||||
|
|
||||||
M.rol = M.lrotate -- LuaOp inspired
|
|
||||||
M.ror = M.rrotate -- LuaOp insipred
|
|
||||||
|
|
||||||
|
|
||||||
function M.arshift(x, disp) -- Lua5.2 inspired
|
|
||||||
local z = rshift(x, disp)
|
|
||||||
if x >= 0x80000000 then z = z + lshift(math.pow(2, disp-1), 32-disp) end
|
|
||||||
return z
|
|
||||||
end
|
|
||||||
local arshift = M.arshift
|
|
||||||
|
|
||||||
function M.btest(x, y) -- Lua5.2 inspired
|
|
||||||
return band(x, y) ~= 0
|
|
||||||
end
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Start Lua 5.2 "bit32" compat section.
|
|
||||||
--
|
|
||||||
|
|
||||||
M.bit32 = {} -- Lua 5.2 'bit32' compatibility
|
|
||||||
|
|
||||||
|
|
||||||
local function bit32_bnot(x)
|
|
||||||
return (-1 - x) % MOD
|
|
||||||
end
|
|
||||||
M.bit32.bnot = bit32_bnot
|
|
||||||
|
|
||||||
-- something here causes a syntax error so im just commenting out since i dont need it anyways
|
|
||||||
--[[
|
|
||||||
local function bit32_bxor(a, b, c, ...)
|
|
||||||
local z
|
|
||||||
if b then
|
|
||||||
a = a % MOD
|
|
||||||
b = b % MOD
|
|
||||||
z = bxor(a, b)
|
|
||||||
if c then
|
|
||||||
z = bit32_bxor(z, c, ...)
|
|
||||||
end
|
|
||||||
return z
|
|
||||||
elseif a then
|
|
||||||
return a % MOD
|
|
||||||
else
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
M.bit32.bxor = bit32_bxor
|
|
||||||
|
|
||||||
local function bit32_band(a, b, c, ...)
|
|
||||||
local z
|
|
||||||
if b then
|
|
||||||
a = a % MOD
|
|
||||||
b = b % MOD
|
|
||||||
z = ((a+b) - bxor(a,b)) / 2
|
|
||||||
if c then
|
|
||||||
z = bit32_band(z, c, ...)
|
|
||||||
end
|
|
||||||
return z
|
|
||||||
elseif a then
|
|
||||||
return a % MOD
|
|
||||||
else
|
|
||||||
return MODM
|
|
||||||
end
|
|
||||||
end
|
|
||||||
M.bit32.band = bit32_band
|
|
||||||
|
|
||||||
local function bit32_bor(a, b, c, ...)
|
|
||||||
local z
|
|
||||||
if b then
|
|
||||||
a = a % MOD
|
|
||||||
b = b % MOD
|
|
||||||
z = MODM - band(MODM - a, MODM - b)
|
|
||||||
if c then
|
|
||||||
z = bit32_bor(z, c, ...)
|
|
||||||
end
|
|
||||||
return z
|
|
||||||
elseif a then
|
|
||||||
return a % MOD
|
|
||||||
else
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
M.bit32.bor = bit32_bor
|
|
||||||
|
|
||||||
function M.bit32.btest(...)
|
|
||||||
return bit32_band(...) ~= 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.bit32.lrotate(x, disp)
|
|
||||||
return lrotate(x % MOD, disp)
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.bit32.rrotate(x, disp)
|
|
||||||
return rrotate(x % MOD, disp)
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.bit32.lshift(x,disp)
|
|
||||||
if disp > 31 or disp < -31 then return 0 end
|
|
||||||
return lshift(x % MOD, disp)
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.bit32.rshift(x,disp)
|
|
||||||
if disp > 31 or disp < -31 then return 0 end
|
|
||||||
return rshift(x % MOD, disp)
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.bit32.arshift(x,disp)
|
|
||||||
x = x % MOD
|
|
||||||
if disp >= 0 then
|
|
||||||
if disp > 31 then
|
|
||||||
return (x >= 0x80000000) and MODM or 0
|
|
||||||
else
|
|
||||||
local z = rshift(x, disp)
|
|
||||||
if x >= 0x80000000 then z = z + lshift(math.pow(2, disp-1), 32-disp) end
|
|
||||||
return z
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return lshift(x, -disp)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.bit32.extract(x, field, ...)
|
|
||||||
local width = ... or 1
|
|
||||||
if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end
|
|
||||||
x = x % MOD
|
|
||||||
return extract(x, field, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.bit32.replace(x, v, field, ...)
|
|
||||||
local width = ... or 1
|
|
||||||
if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end
|
|
||||||
x = x % MOD
|
|
||||||
v = v % MOD
|
|
||||||
return replace(x, v, field, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Start LuaBitOp "bit" compat section.
|
|
||||||
--
|
|
||||||
|
|
||||||
M.bit = {} -- LuaBitOp "bit" compatibility
|
|
||||||
|
|
||||||
function M.bit.tobit(x)
|
|
||||||
x = x % MOD
|
|
||||||
if x >= 0x80000000 then x = x - MOD end
|
|
||||||
return x
|
|
||||||
end
|
|
||||||
local bit_tobit = M.bit.tobit
|
|
||||||
|
|
||||||
function M.bit.tohex(x, ...)
|
|
||||||
return tohex(x % MOD, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.bit.bnot(x)
|
|
||||||
return bit_tobit(bnot(x % MOD))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function bit_bor(a, b, c, ...)
|
|
||||||
if c then
|
|
||||||
return bit_bor(bit_bor(a, b), c, ...)
|
|
||||||
elseif b then
|
|
||||||
return bit_tobit(bor(a % MOD, b % MOD))
|
|
||||||
else
|
|
||||||
return bit_tobit(a)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
M.bit.bor = bit_bor
|
|
||||||
|
|
||||||
local function bit_band(a, b, c, ...)
|
|
||||||
if c then
|
|
||||||
return bit_band(bit_band(a, b), c, ...)
|
|
||||||
elseif b then
|
|
||||||
return bit_tobit(band(a % MOD, b % MOD))
|
|
||||||
else
|
|
||||||
return bit_tobit(a)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
M.bit.band = bit_band
|
|
||||||
|
|
||||||
local function bit_bxor(a, b, c, ...)
|
|
||||||
if c then
|
|
||||||
return bit_bxor(bit_bxor(a, b), c, ...)
|
|
||||||
elseif b then
|
|
||||||
return bit_tobit(bxor(a % MOD, b % MOD))
|
|
||||||
else
|
|
||||||
return bit_tobit(a)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
M.bit.bxor = bit_bxor
|
|
||||||
|
|
||||||
function M.bit.lshift(x, n)
|
|
||||||
return bit_tobit(lshift(x % MOD, n % 32))
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.bit.rshift(x, n)
|
|
||||||
return bit_tobit(rshift(x % MOD, n % 32))
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.bit.arshift(x, n)
|
|
||||||
return bit_tobit(arshift(x % MOD, n % 32))
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.bit.rol(x, n)
|
|
||||||
return bit_tobit(lrotate(x % MOD, n % 32))
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.bit.ror(x, n)
|
|
||||||
return bit_tobit(rrotate(x % MOD, n % 32))
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.bit.bswap(x)
|
|
||||||
return bit_tobit(bswap(x % MOD))
|
|
||||||
end
|
|
||||||
]]
|
|
||||||
|
|
||||||
return M
|
|
|
@ -1,300 +0,0 @@
|
||||||
|
|
||||||
--[[
|
|
||||||
* Converts an HSL color value to RGB. Conversion formula
|
|
||||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
|
||||||
* Assumes h, s, and l are contained in the set [0, 1] and
|
|
||||||
* returns r, g, and b in the set [0, 1].
|
|
||||||
]]
|
|
||||||
local function hslToRgb(h, s, l)
|
|
||||||
local r, g, b
|
|
||||||
|
|
||||||
if s == 0 then
|
|
||||||
r, g, b = l, l, l -- achromatic
|
|
||||||
else
|
|
||||||
function hue2rgb(p, q, t)
|
|
||||||
if t < 0 then t = t + 1 end
|
|
||||||
if t > 1 then t = t - 1 end
|
|
||||||
if t < 1/6 then return p + (q - p) * 6 * t end
|
|
||||||
if t < 1/2 then return q end
|
|
||||||
if t < 2/3 then return p + (q - p) * (2/3 - t) * 6 end
|
|
||||||
return p
|
|
||||||
end
|
|
||||||
|
|
||||||
local q
|
|
||||||
if l < 0.5 then q = l * (1 + s) else q = l + s - l * s end
|
|
||||||
local p = 2 * l - q
|
|
||||||
|
|
||||||
r = hue2rgb(p, q, h + 1/3)
|
|
||||||
g = hue2rgb(p, q, h)
|
|
||||||
b = hue2rgb(p, q, h - 1/3)
|
|
||||||
end
|
|
||||||
|
|
||||||
return r, g, b
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
* Converts an HSL color value to RGB. Conversion formula
|
|
||||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
|
||||||
* Assumes h, s, and l are contained in the set [0, 1] and
|
|
||||||
* returns r, g, and b in the set [0, 1].
|
|
||||||
]]
|
|
||||||
local function rgbToHsl(r, g, b)
|
|
||||||
local max, min = math.max(r, g, b), math.min(r, g, b)
|
|
||||||
local h, s, l
|
|
||||||
|
|
||||||
l = (max + min) / 2
|
|
||||||
if max == 0 then s = 0 else s = (max - min) / max end
|
|
||||||
|
|
||||||
if max == min then
|
|
||||||
h, s = 0, 0 -- achromatic
|
|
||||||
else
|
|
||||||
local d = max - min
|
|
||||||
local s
|
|
||||||
if l > 0.5 then s = d / (2 - max - min) else s = d / (max + min) end
|
|
||||||
if max == r then
|
|
||||||
h = (g - b) / d
|
|
||||||
if g < b then h = h + 6 end
|
|
||||||
elseif max == g then h = (b - r) / d + 2
|
|
||||||
elseif max == b then h = (r - g) / d + 4
|
|
||||||
end
|
|
||||||
h = h / 6
|
|
||||||
end
|
|
||||||
|
|
||||||
return h, s, l
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--[[
|
|
||||||
* Converts an RGB color value to HSV. Conversion formula
|
|
||||||
* adapted from http://en.wikipedia.org/wiki/HSV_color_space.
|
|
||||||
* Assumes r, g, and b are contained in the set [0, 1] and
|
|
||||||
* returns h, s, and v in the set [0, 1].
|
|
||||||
]]
|
|
||||||
local function rgbToHsv(r, g, b)
|
|
||||||
local max, min = math.max(r, g, b), math.min(r, g, b)
|
|
||||||
local h, s, v
|
|
||||||
v = max
|
|
||||||
|
|
||||||
local d = max - min
|
|
||||||
if max == 0 then s = 0 else s = d / max end
|
|
||||||
|
|
||||||
if max == min then
|
|
||||||
h = 0 -- achromatic
|
|
||||||
else
|
|
||||||
if max == r then
|
|
||||||
h = (g - b) / d
|
|
||||||
if g < b then h = h + 6 end
|
|
||||||
elseif max == g then h = (b - r) / d + 2
|
|
||||||
elseif max == b then h = (r - g) / d + 4
|
|
||||||
end
|
|
||||||
h = h / 6
|
|
||||||
end
|
|
||||||
|
|
||||||
return h, s, v
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
* Converts an HSV color value to RGB. Conversion formula
|
|
||||||
* adapted from http://en.wikipedia.org/wiki/HSV_color_space.
|
|
||||||
* Assumes h, s, and v are contained in the set [0, 1] and
|
|
||||||
* returns r, g, and b in the set [0, 1].
|
|
||||||
]]
|
|
||||||
local function hsvToRgb(h, s, v)
|
|
||||||
local r, g, b
|
|
||||||
|
|
||||||
local i = math.floor(h * 6);
|
|
||||||
local f = h * 6 - i;
|
|
||||||
local p = v * (1 - s);
|
|
||||||
local q = v * (1 - f * s);
|
|
||||||
local t = v * (1 - (1 - f) * s);
|
|
||||||
|
|
||||||
i = i % 6
|
|
||||||
|
|
||||||
if i == 0 then r, g, b = v, t, p
|
|
||||||
elseif i == 1 then r, g, b = q, v, p
|
|
||||||
elseif i == 2 then r, g, b = p, v, t
|
|
||||||
elseif i == 3 then r, g, b = p, q, v
|
|
||||||
elseif i == 4 then r, g, b = t, p, v
|
|
||||||
elseif i == 5 then r, g, b = v, p, q
|
|
||||||
end
|
|
||||||
|
|
||||||
return r, g, b
|
|
||||||
end
|
|
||||||
|
|
||||||
---@class color
|
|
||||||
---@field r number @red, 0.0 - 1.0
|
|
||||||
---@field g number @green, 0.0 - 1.0
|
|
||||||
---@field b number @blue, 0.0 - 1.0
|
|
||||||
---@field a number @alpha, 0.0 - 1.0
|
|
||||||
---@operator add(color): color
|
|
||||||
---@operator add(number): color
|
|
||||||
---@operator sub(color): color
|
|
||||||
---@operator sub(number): color
|
|
||||||
---@operator mul(color): color
|
|
||||||
---@operator mul(number): color
|
|
||||||
---@operator div(color): color
|
|
||||||
---@operator div(number): color
|
|
||||||
local col = {}
|
|
||||||
|
|
||||||
--- for use in actor:diffuse(col:unpack())
|
|
||||||
---@return number, number, number, number
|
|
||||||
function col:unpack()
|
|
||||||
return self.r, self.g, self.b, self.a
|
|
||||||
end
|
|
||||||
|
|
||||||
-- conversions
|
|
||||||
|
|
||||||
---@return number, number, number
|
|
||||||
function col:rgb()
|
|
||||||
return self.r, self.g, self.b
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return number, number, number
|
|
||||||
function col:hsl()
|
|
||||||
return rgbToHsl(self.r, self.g, self.b)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return number, number, number
|
|
||||||
function col:hsv()
|
|
||||||
return rgbToHsv(self.r, self.g, self.b)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return string
|
|
||||||
function col:hex()
|
|
||||||
return string.format('%02x%02x%02x',
|
|
||||||
math.floor(self.r * 255),
|
|
||||||
math.floor(self.g * 255),
|
|
||||||
math.floor(self.b * 255))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- setters
|
|
||||||
|
|
||||||
---@return color
|
|
||||||
function col:hue(h)
|
|
||||||
local _, s, v = self:hsv()
|
|
||||||
return hsv(h % 1, s, v, self.a)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return color
|
|
||||||
function col:huesmooth(h)
|
|
||||||
local _, s, v = self:hsv()
|
|
||||||
return shsv(h % 1, s, v, self.a)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return color
|
|
||||||
function col:alpha(a)
|
|
||||||
return rgb(self.r, self.g, self.b, a)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- multiplies current alpha by provided value
|
|
||||||
---@return color
|
|
||||||
function col:malpha(a)
|
|
||||||
return rgb(self.r, self.g, self.b, self.a * a)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- effects
|
|
||||||
|
|
||||||
---@return color
|
|
||||||
function col:invert()
|
|
||||||
return rgb(1 - self.r, 1 - self.g, 1 - self.b, self.a)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return color
|
|
||||||
function col:grayscale()
|
|
||||||
return rgb(self.r * 0.299 + self.g * 0.587 + self.b * 0.114, self.a)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return color
|
|
||||||
function col:hueshift(a)
|
|
||||||
local h, s, v = self:hsv()
|
|
||||||
return hsv((h + a) % 1, s, v, self.a)
|
|
||||||
end
|
|
||||||
|
|
||||||
local colmeta = {}
|
|
||||||
|
|
||||||
function colmeta:__index(i)
|
|
||||||
if i == 1 then return self.r end
|
|
||||||
if i == 2 then return self.g end
|
|
||||||
if i == 3 then return self.b end
|
|
||||||
if i == 4 then return self.a end
|
|
||||||
return col[i]
|
|
||||||
end
|
|
||||||
|
|
||||||
local function typ(a)
|
|
||||||
return (type(a) == 'table' and a.r and a.g and a.b and a.a) and 'color' or type(a)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function genericop(a, b, f, name)
|
|
||||||
local typea = typ(a)
|
|
||||||
local typeb = typ(b)
|
|
||||||
if typea == 'number' then
|
|
||||||
return rgb(f(b.r, a), f(b.g, a), f(b.b, a), b.a)
|
|
||||||
elseif typeb == 'number' then
|
|
||||||
return rgb(f(a.r, b), f(a.g, b), f(a.b, b), a.a)
|
|
||||||
elseif typea == 'color' and typeb == 'color' then
|
|
||||||
return rgb(f(a.r, b.r), f(a.g, b.g), f(a.b, b.b), f(a.a, b.a))
|
|
||||||
end
|
|
||||||
error('cant apply ' .. name .. ' to ' .. typea .. ' and ' .. typeb, 3)
|
|
||||||
end
|
|
||||||
|
|
||||||
function colmeta.__add(a, b)
|
|
||||||
return genericop(a, b, function(a, b) return a + b end, 'add')
|
|
||||||
end
|
|
||||||
function colmeta.__sub(a, b)
|
|
||||||
return genericop(a, b, function(a, b) return a - b end, 'sub')
|
|
||||||
end
|
|
||||||
function colmeta.__mul(a, b)
|
|
||||||
return genericop(a, b, function(a, b) return a * b end, 'mul')
|
|
||||||
end
|
|
||||||
function colmeta.__div(a, b)
|
|
||||||
return genericop(a, b, function(a, b) return a / b end, 'div')
|
|
||||||
end
|
|
||||||
|
|
||||||
function colmeta.__eq(a, b)
|
|
||||||
return (typ(a) == 'color' and typ(b) == 'color') and (a.r == b.r and a.g == b.g and a.b == b.b and a.a == b.a)
|
|
||||||
end
|
|
||||||
|
|
||||||
function colmeta:__tostring()
|
|
||||||
return '#' .. self:hex()
|
|
||||||
end
|
|
||||||
colmeta.__name = 'color'
|
|
||||||
|
|
||||||
-- constructors
|
|
||||||
|
|
||||||
---@return color
|
|
||||||
function rgb(r, g, b, a)
|
|
||||||
a = a or 1
|
|
||||||
return setmetatable({r = r, g = g, b = b, a = a or 1}, colmeta)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return color
|
|
||||||
function hsl(h, s, l, a)
|
|
||||||
a = a or 1
|
|
||||||
local r, g, b = hslToRgb(h % 1, s, l)
|
|
||||||
return setmetatable({r = r, g = g, b = b, a = a or 1}, colmeta)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return color
|
|
||||||
function hsv(h, s, v, a)
|
|
||||||
a = a or 1
|
|
||||||
local r, g, b = hsvToRgb(h % 1, s, v)
|
|
||||||
return setmetatable({r = r, g = g, b = b, a = a or 1}, colmeta)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- smoother hsv. not correct but looks nicer
|
|
||||||
---@return color
|
|
||||||
function shsv(h, s, v, a)
|
|
||||||
h = h % 1
|
|
||||||
return hsv(h * h * (3 - 2 * h), s, v, a)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param hex string
|
|
||||||
---@return color
|
|
||||||
function hex(hex)
|
|
||||||
hex = string.gsub(hex, '#', '')
|
|
||||||
if string.len(hex) == 3 then
|
|
||||||
return rgb((tonumber('0x' .. string.sub(hex, 1, 1)) * 17) / 255, (tonumber('0x' .. string.sub(hex, 2, 2)) * 17) / 255, (tonumber('0x' .. string.sub(hex, 3, 3)) * 17) / 255)
|
|
||||||
else
|
|
||||||
return rgb(tonumber('0x' .. string.sub(hex, 1, 2)) / 255, tonumber('0x' .. string.sub(hex, 3, 4)) / 255, tonumber('0x' .. string.sub(hex, 5, 6)) / 255)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,80 +0,0 @@
|
||||||
---@class easable
|
|
||||||
---@field public a number @the eased value
|
|
||||||
---@field public toa number @the target, uneased value
|
|
||||||
---@field protected onUpdateFuncs fun():nil[]
|
|
||||||
local eas = {}
|
|
||||||
|
|
||||||
---@param new number @New value to ease to
|
|
||||||
---@return void
|
|
||||||
function eas:set(new)
|
|
||||||
self.toa = new
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param new number @New value
|
|
||||||
---@return void
|
|
||||||
function eas:reset(new)
|
|
||||||
self.toa = new
|
|
||||||
self.a = new
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param new number @How much to add to current value to ease to
|
|
||||||
---@return void
|
|
||||||
function eas:add(new)
|
|
||||||
self.toa = self.toa + new
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param func fun(a: number):void @Adds a callback function that will run each time the eased value changes
|
|
||||||
---@return void
|
|
||||||
function eas:onUpdate(func)
|
|
||||||
table.insert(self.onUpdateFuncs, func)
|
|
||||||
end
|
|
||||||
|
|
||||||
local easmeta = {}
|
|
||||||
|
|
||||||
easmeta.__index = eas
|
|
||||||
easmeta.__name = 'easable'
|
|
||||||
|
|
||||||
function easmeta.__add(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) + ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__sub(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) - ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__mul(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) * ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__div(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) / ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__mod(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) % ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__eq(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) == ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__lt(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) < ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__le(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) <= ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
|
|
||||||
function easmeta:__call(dt)
|
|
||||||
self.a = mix(self.a, self.toa, dt)
|
|
||||||
for _, callback in ipairs(self.onUpdateFuncs) do
|
|
||||||
callback(self.a)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function easmeta:__tostring()
|
|
||||||
return tostring(self.a)
|
|
||||||
end
|
|
||||||
function easmeta:__unm(self)
|
|
||||||
return -self.a
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param default number
|
|
||||||
---@return easable
|
|
||||||
function easable(default)
|
|
||||||
default = default or 0
|
|
||||||
return setmetatable({a = default, toa = default, onUpdateFuncs = {}}, easmeta)
|
|
||||||
end
|
|
|
@ -1,90 +0,0 @@
|
||||||
---@class easable2
|
|
||||||
---@field public a number @the eased value
|
|
||||||
---@field public toa number @the target, uneased value
|
|
||||||
---@field public ease fun(a:number):number @the ease to use
|
|
||||||
---@field protected onUpdateFuncs fun(a:number):nil[]
|
|
||||||
---@field protected _a number @the internal value, linearly eased
|
|
||||||
local eas = {}
|
|
||||||
|
|
||||||
---@param new number @New value to ease to
|
|
||||||
---@return void
|
|
||||||
function eas:set(new)
|
|
||||||
self.toa = new
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param new number @New value
|
|
||||||
---@return void
|
|
||||||
function eas:reset(new)
|
|
||||||
self.toa = new
|
|
||||||
self._a = new
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param new number @How much to add to current value to ease to
|
|
||||||
---@return void
|
|
||||||
function eas:add(new)
|
|
||||||
self.toa = self.toa + new
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param func fun(a: number):void @Adds a callback function that will run each time the eased value changes
|
|
||||||
---@return void
|
|
||||||
function eas:onUpdate(func)
|
|
||||||
table.insert(self.onUpdateFuncs, func)
|
|
||||||
end
|
|
||||||
|
|
||||||
local easmeta = {}
|
|
||||||
|
|
||||||
easmeta.__index = eas
|
|
||||||
easmeta.__name = 'easable2'
|
|
||||||
|
|
||||||
function easmeta.__add(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) + ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__sub(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) - ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__mul(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) * ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__div(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) / ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__mod(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) % ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__eq(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) == ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__lt(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) < ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__le(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) <= ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
|
|
||||||
function easmeta:__call(dt)
|
|
||||||
if self._a == self.toa then
|
|
||||||
-- do nothing
|
|
||||||
elseif self._a < self.toa then
|
|
||||||
self._a = self._a + math.min(dt, math.abs(self._a - self.toa))
|
|
||||||
else
|
|
||||||
self._a = self._a - math.min(dt, math.abs(self._a - self.toa))
|
|
||||||
end
|
|
||||||
self.a = self.ease(self._a)
|
|
||||||
|
|
||||||
for _, callback in ipairs(self.onUpdateFuncs) do
|
|
||||||
callback(self.a)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function easmeta:__tostring()
|
|
||||||
return tostring(self.a)
|
|
||||||
end
|
|
||||||
function easmeta:__unm(self)
|
|
||||||
return -self.a
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param default number
|
|
||||||
---@return easable2
|
|
||||||
function easable2(default, ease)
|
|
||||||
default = default or 0
|
|
||||||
return setmetatable({a = default, toa = default, onUpdateFuncs = {}, ease = ease or outSine, _a = default}, easmeta)
|
|
||||||
end
|
|
|
@ -1,338 +0,0 @@
|
||||||
-- nabbed straight from mirin template:
|
|
||||||
-- https://github.com/XeroOl/notitg-mirin/blob/d1e9a8e71026aeabe81c682a114ce265cbd6362a/template/ease.lua
|
|
||||||
|
|
||||||
local sqrt = math.sqrt
|
|
||||||
local sin = math.sin
|
|
||||||
local asin = math.asin
|
|
||||||
local cos = math.cos
|
|
||||||
local pow = math.pow
|
|
||||||
local exp = math.exp
|
|
||||||
local pi = math.pi
|
|
||||||
local abs = math.abs
|
|
||||||
|
|
||||||
-- ===================================================================== --
|
|
||||||
|
|
||||||
-- Utility functions
|
|
||||||
|
|
||||||
--- Flip any easing function, making it go from 1 to 0
|
|
||||||
-- Example use:
|
|
||||||
-- ```lua
|
|
||||||
-- ease {0, 20, flip(outQuad), 50, 'modname'}
|
|
||||||
-- ```
|
|
||||||
flip = setmetatable({}, {
|
|
||||||
__call = function(self, fn)
|
|
||||||
self[fn] = self[fn] or function(x) return 1 - fn(x) end
|
|
||||||
return self[fn]
|
|
||||||
end
|
|
||||||
})
|
|
||||||
|
|
||||||
-- Mix two easing functions together into a new ease
|
|
||||||
-- the new ease starts by acting like the first argument, and then ends like the second argument
|
|
||||||
-- Example: ease {0, 20, blendease(inQuad, outQuad), 100, 'modname'}
|
|
||||||
blendease = setmetatable({}, {
|
|
||||||
__index = function(self, key)
|
|
||||||
self[key] = {}
|
|
||||||
return self[key]
|
|
||||||
end,
|
|
||||||
__call = function(self, fn1, fn2)
|
|
||||||
if not self[fn1][fn2] then
|
|
||||||
local transient1 = fn1(1) <= 0.5
|
|
||||||
local transient2 = fn2(1) <= 0.5
|
|
||||||
if transient1 and not transient2 then
|
|
||||||
error('blendease: the first argument is a transient ease, but the second argument doesn\'t match')
|
|
||||||
end
|
|
||||||
if transient2 and not transient1 then
|
|
||||||
error('blendease: the second argument is a transient ease, but the first argument doesn\'t match')
|
|
||||||
end
|
|
||||||
self[fn1][fn2] = function(x)
|
|
||||||
local mixFactor = 3*x^2-2*x^3
|
|
||||||
return (1 - mixFactor) * fn1(x) + mixFactor * fn2(x)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return self[fn1][fn2]
|
|
||||||
end
|
|
||||||
})
|
|
||||||
|
|
||||||
local function param1cache(self, param1)
|
|
||||||
self.cache[param1] = self.cache[param1] or function(x)
|
|
||||||
return self.fn(x, param1)
|
|
||||||
end
|
|
||||||
return self.cache[param1]
|
|
||||||
end
|
|
||||||
|
|
||||||
local param1mt = {
|
|
||||||
__call = function(self, x, param1)
|
|
||||||
return self.fn(x, param1 or self.dp1)
|
|
||||||
end,
|
|
||||||
__index = {
|
|
||||||
param = param1cache,
|
|
||||||
params = param1cache,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Declare an easing function taking one custom parameter
|
|
||||||
function with1param(fn, defaultparam1)
|
|
||||||
return setmetatable({
|
|
||||||
fn = fn,
|
|
||||||
dp1 = defaultparam1,
|
|
||||||
cache = {},
|
|
||||||
}, param1mt)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function param2cache(self, param1, param2)
|
|
||||||
self.cache[param1] = self.cache[param1] or {}
|
|
||||||
self.cache[param1][param2] = self.cache[param1][param2] or function(x)
|
|
||||||
return self.fn(x, param1, param2)
|
|
||||||
end
|
|
||||||
return self.cache[param1][param2]
|
|
||||||
end
|
|
||||||
|
|
||||||
local param2mt = {
|
|
||||||
__call = function(self, x, param1, param2)
|
|
||||||
return self.fn(x, param1 or self.dp1, param2 or self.dp2)
|
|
||||||
end,
|
|
||||||
__index = {
|
|
||||||
param=param2cache,
|
|
||||||
params=param2cache,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Declare an easing function taking two custom parameters
|
|
||||||
function with2params(fn, defaultparam1, defaultparam2)
|
|
||||||
return setmetatable({
|
|
||||||
fn = fn,
|
|
||||||
dp1 = defaultparam1,
|
|
||||||
dp2 = defaultparam2,
|
|
||||||
cache = {},
|
|
||||||
}, param2mt)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ===================================================================== --
|
|
||||||
|
|
||||||
-- Easing functions
|
|
||||||
|
|
||||||
function bounce(t) return 4 * t * (1 - t) end
|
|
||||||
function tri(t) return 1 - abs(2 * t - 1) end
|
|
||||||
function bell(t) return inOutQuint(tri(t)) end
|
|
||||||
function pop(t) return 3.5 * (1 - t) * (1 - t) * sqrt(t) end
|
|
||||||
function tap(t) return 3.5 * t * t * sqrt(1 - t) end
|
|
||||||
function pulse(t) return t < .5 and tap(t * 2) or -pop(t * 2 - 1) end
|
|
||||||
|
|
||||||
function spike(t) return exp(-10 * abs(2 * t - 1)) end
|
|
||||||
function inverse(t) return t * t * (1 - t) * (1 - t) / (0.5 - t) end
|
|
||||||
|
|
||||||
local function popElasticInternal(t, damp, count)
|
|
||||||
return (1000 ^ -(t ^ damp) - 0.001) * sin(count * pi * t)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function tapElasticInternal(t, damp, count)
|
|
||||||
return (1000 ^ -((1 - t) ^ damp) - 0.001) * sin(count * pi * (1 - t))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function pulseElasticInternal(t, damp, count)
|
|
||||||
if t < .5 then
|
|
||||||
return tapElasticInternal(t * 2, damp, count)
|
|
||||||
else
|
|
||||||
return -popElasticInternal(t * 2 - 1, damp, count)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
popElastic = with2params(popElasticInternal, 1.4, 6)
|
|
||||||
tapElastic = with2params(tapElasticInternal, 1.4, 6)
|
|
||||||
pulseElastic = with2params(pulseElasticInternal, 1.4, 6)
|
|
||||||
|
|
||||||
impulse = with1param(function(t, damp)
|
|
||||||
t = t ^ damp
|
|
||||||
return t * (1000 ^ -t - 0.001) * 18.6
|
|
||||||
end, 0.9)
|
|
||||||
|
|
||||||
function instant() return 1 end
|
|
||||||
function linear(t) return t end
|
|
||||||
function inQuad(t) return t * t end
|
|
||||||
function outQuad(t) return -t * (t - 2) end
|
|
||||||
function inOutQuad(t)
|
|
||||||
t = t * 2
|
|
||||||
if t < 1 then
|
|
||||||
return 0.5 * t ^ 2
|
|
||||||
else
|
|
||||||
return 1 - 0.5 * (2 - t) ^ 2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function outInQuad(t)
|
|
||||||
t = t * 2
|
|
||||||
if t < 1 then
|
|
||||||
return 0.5 - 0.5 * (1 - t) ^ 2
|
|
||||||
else
|
|
||||||
return 0.5 + 0.5 * (t - 1) ^ 2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function inCubic(t) return t * t * t end
|
|
||||||
function outCubic(t) return 1 - (1 - t) ^ 3 end
|
|
||||||
function inOutCubic(t)
|
|
||||||
t = t * 2
|
|
||||||
if t < 1 then
|
|
||||||
return 0.5 * t ^ 3
|
|
||||||
else
|
|
||||||
return 1 - 0.5 * (2 - t) ^ 3
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function outInCubic(t)
|
|
||||||
t = t * 2
|
|
||||||
if t < 1 then
|
|
||||||
return 0.5 - 0.5 * (1 - t) ^ 3
|
|
||||||
else
|
|
||||||
return 0.5 + 0.5 * (t - 1) ^ 3
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function inQuart(t) return t * t * t * t end
|
|
||||||
function outQuart(t) return 1 - (1 - t) ^ 4 end
|
|
||||||
function inOutQuart(t)
|
|
||||||
t = t * 2
|
|
||||||
if t < 1 then
|
|
||||||
return 0.5 * t ^ 4
|
|
||||||
else
|
|
||||||
return 1 - 0.5 * (2 - t) ^ 4
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function outInQuart(t)
|
|
||||||
t = t * 2
|
|
||||||
if t < 1 then
|
|
||||||
return 0.5 - 0.5 * (1 - t) ^ 4
|
|
||||||
else
|
|
||||||
return 0.5 + 0.5 * (t - 1) ^ 4
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function inQuint(t) return t ^ 5 end
|
|
||||||
function outQuint(t) return 1 - (1 - t) ^ 5 end
|
|
||||||
function inOutQuint(t)
|
|
||||||
t = t * 2
|
|
||||||
if t < 1 then
|
|
||||||
return 0.5 * t ^ 5
|
|
||||||
else
|
|
||||||
return 1 - 0.5 * (2 - t) ^ 5
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function outInQuint(t)
|
|
||||||
t = t * 2
|
|
||||||
if t < 1 then
|
|
||||||
return 0.5 - 0.5 * (1 - t) ^ 5
|
|
||||||
else
|
|
||||||
return 0.5 + 0.5 * (t - 1) ^ 5
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function inExpo(t) return 1000 ^ (t - 1) - 0.001 end
|
|
||||||
function outExpo(t) return 1.001 - 1000 ^ -t end
|
|
||||||
function inOutExpo(t)
|
|
||||||
t = t * 2
|
|
||||||
if t < 1 then
|
|
||||||
return 0.5 * 1000 ^ (t - 1) - 0.0005
|
|
||||||
else
|
|
||||||
return 1.0005 - 0.5 * 1000 ^ (1 - t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function outInExpo(t)
|
|
||||||
if t < 0.5 then
|
|
||||||
return outExpo(t * 2) * 0.5
|
|
||||||
else
|
|
||||||
return inExpo(t * 2 - 1) * 0.5 + 0.5
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function inCirc(t) return 1 - sqrt(1 - t * t) end
|
|
||||||
function outCirc(t) return sqrt(-t * t + 2 * t) end
|
|
||||||
function inOutCirc(t)
|
|
||||||
t = t * 2
|
|
||||||
if t < 1 then
|
|
||||||
return 0.5 - 0.5 * sqrt(1 - t * t)
|
|
||||||
else
|
|
||||||
t = t - 2
|
|
||||||
return 0.5 + 0.5 * sqrt(1 - t * t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function outInCirc(t)
|
|
||||||
if t < 0.5 then
|
|
||||||
return outCirc(t * 2) * 0.5
|
|
||||||
else
|
|
||||||
return inCirc(t * 2 - 1) * 0.5 + 0.5
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function outBounce(t)
|
|
||||||
if t < 1 / 2.75 then
|
|
||||||
return 7.5625 * t * t
|
|
||||||
elseif t < 2 / 2.75 then
|
|
||||||
t = t - 1.5 / 2.75
|
|
||||||
return 7.5625 * t * t + 0.75
|
|
||||||
elseif t < 2.5 / 2.75 then
|
|
||||||
t = t - 2.25 / 2.75
|
|
||||||
return 7.5625 * t * t + 0.9375
|
|
||||||
else
|
|
||||||
t = t - 2.625 / 2.75
|
|
||||||
return 7.5625 * t * t + 0.984375
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function inBounce(t) return 1 - outBounce(1 - t) end
|
|
||||||
function inOutBounce(t)
|
|
||||||
if t < 0.5 then
|
|
||||||
return inBounce(t * 2) * 0.5
|
|
||||||
else
|
|
||||||
return outBounce(t * 2 - 1) * 0.5 + 0.5
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function outInBounce(t)
|
|
||||||
if t < 0.5 then
|
|
||||||
return outBounce(t * 2) * 0.5
|
|
||||||
else
|
|
||||||
return inBounce(t * 2 - 1) * 0.5 + 0.5
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function inSine(x) return 1 - cos(x * (pi * 0.5)) end
|
|
||||||
function outSine(x) return sin(x * (pi * 0.5)) end
|
|
||||||
function inOutSine(x)
|
|
||||||
return 0.5 - 0.5 * cos(x * pi)
|
|
||||||
end
|
|
||||||
function outInSine(t)
|
|
||||||
if t < 0.5 then
|
|
||||||
return outSine(t * 2) * 0.5
|
|
||||||
else
|
|
||||||
return inSine(t * 2 - 1) * 0.5 + 0.5
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function outElasticInternal(t, a, p)
|
|
||||||
return a * pow(2, -10 * t) * sin((t - p / (2 * pi) * asin(1/a)) * 2 * pi / p) + 1
|
|
||||||
end
|
|
||||||
local function inElasticInternal(t, a, p)
|
|
||||||
return 1 - outElasticInternal(1 - t, a, p)
|
|
||||||
end
|
|
||||||
function inOutElasticInternal(t, a, p)
|
|
||||||
return t < 0.5
|
|
||||||
and 0.5 * inElasticInternal(t * 2, a, p)
|
|
||||||
or 0.5 + 0.5 * outElasticInternal(t * 2 - 1, a, p)
|
|
||||||
end
|
|
||||||
function outInElasticInternal(t, a, p)
|
|
||||||
return t < 0.5
|
|
||||||
and 0.5 * outElasticInternal(t * 2, a, p)
|
|
||||||
or 0.5 + 0.5 * inElasticInternal(t * 2 - 1, a, p)
|
|
||||||
end
|
|
||||||
|
|
||||||
inElastic = with2params(inElasticInternal, 1, 0.3)
|
|
||||||
outElastic = with2params(outElasticInternal, 1, 0.3)
|
|
||||||
inOutElastic = with2params(inOutElasticInternal, 1, 0.3)
|
|
||||||
outInElastic = with2params(outInElasticInternal, 1, 0.3)
|
|
||||||
|
|
||||||
function inBackInternal(t, a) return t * t * (a * t + t - a) end
|
|
||||||
function outBackInternal(t, a) t = t - 1 return t * t * ((a + 1) * t + a) + 1 end
|
|
||||||
function inOutBackInternal(t, a)
|
|
||||||
return t < 0.5
|
|
||||||
and 0.5 * inBackInternal(t * 2, a)
|
|
||||||
or 0.5 + 0.5 * outBackInternal(t * 2 - 1, a)
|
|
||||||
end
|
|
||||||
function outInBackInternal(t, a)
|
|
||||||
return t < 0.5
|
|
||||||
and 0.5 * outBackInternal(t * 2, a)
|
|
||||||
or 0.5 + 0.5 * inBackInternal(t * 2 - 1, a)
|
|
||||||
end
|
|
||||||
|
|
||||||
inBack = with1param(inBackInternal, 1.70158)
|
|
||||||
outBack = with1param(outBackInternal, 1.70158)
|
|
||||||
inOutBack = with1param(inOutBackInternal, 1.70158)
|
|
||||||
outInBack = with1param(outInBackInternal, 1.70158)
|
|
|
@ -1,10 +0,0 @@
|
||||||
require('input')
|
|
||||||
bitop = require('bitop') -- TODO: tons of this is commented out because of '...'. FIX. IT.
|
|
||||||
require('rng')
|
|
||||||
require('easable')
|
|
||||||
require('easable2')
|
|
||||||
require('color')
|
|
||||||
require('vector2D')
|
|
||||||
require('ease')
|
|
||||||
uwuify = require('uwuify')
|
|
||||||
require('util')
|
|
|
@ -1,39 +0,0 @@
|
||||||
inputs = { -- -1 for not pressed, time for time of press
|
|
||||||
Left = -1,
|
|
||||||
Down = -1,
|
|
||||||
Up = -1,
|
|
||||||
Right = -1
|
|
||||||
}
|
|
||||||
rawInputs = {
|
|
||||||
Left = -1,
|
|
||||||
Down = -1,
|
|
||||||
Up = -1,
|
|
||||||
Right = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
directions = {
|
|
||||||
Left = {-1, 0},
|
|
||||||
Down = {0, 1},
|
|
||||||
Up = {0, -1},
|
|
||||||
Right = {1, 0}
|
|
||||||
}
|
|
||||||
|
|
||||||
function uranium.init()
|
|
||||||
for pn = 1, 2 do
|
|
||||||
for i,j in ipairs({'Left', 'Down', 'Up', 'Right'}) do
|
|
||||||
local i = i -- lua scope funnies
|
|
||||||
local j = j
|
|
||||||
|
|
||||||
_main:addcommand('StepP' .. pn .. j .. 'PressMessage', function()
|
|
||||||
rawInputs[j] = t
|
|
||||||
if uranium:call('press', j) then return end
|
|
||||||
inputs[j] = t
|
|
||||||
end)
|
|
||||||
_main:addcommand('StepP' .. pn .. j .. 'LiftMessage', function()
|
|
||||||
if uranium:call('release', j) then return end
|
|
||||||
inputs[j] = -1
|
|
||||||
rawInputs[j] = -1
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,172 +0,0 @@
|
||||||
-- xoshiro128** 1.1 by David Blackman and Sebastiano Vigna (vigna@acm.org) https://prng.di.unimi.it/xoshiro128starstar.c
|
|
||||||
-- Lua implementation by Jill "oatmealine" Monoids
|
|
||||||
-- Licensed under CC-BY-SA
|
|
||||||
|
|
||||||
local RAND_MAX = 4294967295
|
|
||||||
|
|
||||||
---@param x int
|
|
||||||
---@param k int
|
|
||||||
local function rotl(x, k)
|
|
||||||
return bitop.bor(bitop.lshift(x, k), bitop.rshift(x, (32 - k)))
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param state int[] @array of size 4; will be mutated
|
|
||||||
local function next(state)
|
|
||||||
local result = rotl(state[2] * 5, 7) * 9
|
|
||||||
local t = bitop.lshift(state[2], 9)
|
|
||||||
|
|
||||||
state[3] = bitop.bxor(state[3], state[1])
|
|
||||||
state[4] = bitop.bxor(state[4], state[2])
|
|
||||||
state[2] = bitop.bxor(state[2], state[3])
|
|
||||||
state[1] = bitop.bxor(state[1], state[4])
|
|
||||||
|
|
||||||
state[2] = bitop.bxor(state[3], t)
|
|
||||||
|
|
||||||
state[3] = rotl(state[4], 11)
|
|
||||||
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
local JUMP = { 0x8764000b, 0xf542d2d3, 0x6fa035c3, 0x77f2db5b }
|
|
||||||
|
|
||||||
---@param state int[] @array of size 4; will be mutated
|
|
||||||
local function jump(state)
|
|
||||||
local s0 = 0
|
|
||||||
local s1 = 0
|
|
||||||
local s2 = 0
|
|
||||||
local s3 = 0
|
|
||||||
|
|
||||||
for _, j in ipairs(JUMP) do
|
|
||||||
for b = 0, 31 do
|
|
||||||
if bitop.band(j, bitop.lshift(1, b)) ~= 0 then
|
|
||||||
s0 = bitop.bxor(s0, state[1])
|
|
||||||
s1 = bitop.bxor(s1, state[2])
|
|
||||||
s2 = bitop.bxor(s2, state[3])
|
|
||||||
s3 = bitop.bxor(s3, state[4])
|
|
||||||
end
|
|
||||||
next(state)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
state[1] = s0
|
|
||||||
state[2] = s1
|
|
||||||
state[3] = s2
|
|
||||||
state[4] = s3
|
|
||||||
end
|
|
||||||
|
|
||||||
local LONG_JUMP = { 0xb523952e, 0x0b6f099f, 0xccf5a0ef, 0x1c580662 }
|
|
||||||
|
|
||||||
---@param state int[] @array of size 4; will be mutated
|
|
||||||
local function long_jump(state)
|
|
||||||
local s0 = 0
|
|
||||||
local s1 = 0
|
|
||||||
local s2 = 0
|
|
||||||
local s3 = 0
|
|
||||||
|
|
||||||
for _, j in ipairs(LONG_JUMP) do
|
|
||||||
for b = 0, 31 do
|
|
||||||
if bitop.band(j, bitop.lshift(1, b)) ~= 0 then
|
|
||||||
s0 = bitop.bxor(s0, state[1])
|
|
||||||
s1 = bitop.bxor(s1, state[2])
|
|
||||||
s2 = bitop.bxor(s2, state[3])
|
|
||||||
s3 = bitop.bxor(s3, state[4])
|
|
||||||
end
|
|
||||||
next(state)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
state[1] = s0
|
|
||||||
state[2] = s1
|
|
||||||
state[3] = s2
|
|
||||||
state[4] = s3
|
|
||||||
end
|
|
||||||
|
|
||||||
---@class rng a xoshiro128** pseudorandom implementation
|
|
||||||
---@field public state int[] the current state, size of 4
|
|
||||||
rng = {}
|
|
||||||
|
|
||||||
--- gets the next pseudo-random value; recommended to use abstractions (like __call) over this
|
|
||||||
---@return int
|
|
||||||
function rng:next()
|
|
||||||
return next(self.state)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- This is the jump function for the generator. It is equivalent
|
|
||||||
--- to 2^64 calls to next(); it can be used to generate 2^64
|
|
||||||
--- non-overlapping subsequences for parallel computations.
|
|
||||||
---@return void
|
|
||||||
function rng:jump()
|
|
||||||
return jump(self.state)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- This is the long-jump function for the generator. It is equivalent to
|
|
||||||
--- 2^96 calls to next(); it can be used to generate 2^32 starting points,
|
|
||||||
--- from each of which jump() will generate 2^32 non-overlapping
|
|
||||||
--- subsequences for parallel distributed computations.
|
|
||||||
---@return void
|
|
||||||
function rng:longJump()
|
|
||||||
return long_jump(self.state)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- if `max` is not given, `min` will be used as the maximum and the minimum will be 1
|
|
||||||
--- if min is 1 and max is 4, the returned value can be 1, 2, 3 or 4
|
|
||||||
---@param min int
|
|
||||||
---@param max int
|
|
||||||
---@return int
|
|
||||||
function rng:int(min, max)
|
|
||||||
if not max then
|
|
||||||
local m = min
|
|
||||||
min = 1
|
|
||||||
max = m
|
|
||||||
end
|
|
||||||
|
|
||||||
local _min = min
|
|
||||||
local _max = max
|
|
||||||
min = math.min(_min, _max)
|
|
||||||
max = math.max(_min, _max)
|
|
||||||
|
|
||||||
return min + (self:next() % (max - min + 1))
|
|
||||||
end
|
|
||||||
|
|
||||||
--- if `max` is not given, it will be 1
|
|
||||||
---@param max float
|
|
||||||
---@return float
|
|
||||||
function rng:float(max)
|
|
||||||
return ((self:next() % RAND_MAX) / RAND_MAX) * (max or 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
---@return boolean
|
|
||||||
function rng:bool()
|
|
||||||
return self:next() % 2 == 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function rng:seed(seed)
|
|
||||||
self.state = {seed, seed, seed, seed}
|
|
||||||
self:next()
|
|
||||||
end
|
|
||||||
|
|
||||||
local rngmeta = {}
|
|
||||||
|
|
||||||
--- acts identical to math.random()
|
|
||||||
function rngmeta:__call(a, b)
|
|
||||||
if a then
|
|
||||||
return self:int(a, b)
|
|
||||||
end
|
|
||||||
return self:float()
|
|
||||||
end
|
|
||||||
|
|
||||||
rngmeta.__index = rng
|
|
||||||
|
|
||||||
--- creates a new RNG object
|
|
||||||
---@param seed int[] @array of size 4, will default to os.time() if not given
|
|
||||||
---@return rng
|
|
||||||
function rng.init(seed)
|
|
||||||
seed = seed or os.time()
|
|
||||||
local state = {seed, seed, seed, seed}
|
|
||||||
local this = setmetatable({state = state}, rngmeta)
|
|
||||||
this:next() -- just to prevent the state from being all the same number; i dont know a cleaner way of doing this
|
|
||||||
return this
|
|
||||||
end
|
|
||||||
|
|
||||||
return rng
|
|
|
@ -1,157 +0,0 @@
|
||||||
---@param a number
|
|
||||||
---@param b number
|
|
||||||
---@param x number
|
|
||||||
---@return number
|
|
||||||
function mix(a, b, x)
|
|
||||||
return a * (1 - x) + b * x
|
|
||||||
end
|
|
||||||
lerp = mix
|
|
||||||
|
|
||||||
---@param x number
|
|
||||||
---@return number
|
|
||||||
function sign(x)
|
|
||||||
if x > 0 then return 1 end
|
|
||||||
if x < 0 then return -1 end
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function deepcopy(obj)
|
|
||||||
if type(obj) ~= 'table' then return obj end
|
|
||||||
local res = {}
|
|
||||||
for k, v in pairs(obj) do res[deepcopy(k)] = deepcopy(v) end
|
|
||||||
return res
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param a number
|
|
||||||
---@param x number
|
|
||||||
---@param y number
|
|
||||||
---@return number
|
|
||||||
function clamp(a, x, y)
|
|
||||||
return math.max(math.min(a, math.max(x, y)), math.min(x, y))
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param tab any[]
|
|
||||||
---@param elem any
|
|
||||||
function includes(tab, elem)
|
|
||||||
if not tab then error('bad argument #1 (expected table, got nil)', 2) end
|
|
||||||
for _, v in pairs(tab) do
|
|
||||||
if elem == v then return true end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param text string
|
|
||||||
---@param length int
|
|
||||||
function truncate(text, length)
|
|
||||||
local addellipses = false
|
|
||||||
|
|
||||||
local firstLine = nil
|
|
||||||
for line in string.gfind(text, '([^\n]*)\n?') do
|
|
||||||
if not firstLine then
|
|
||||||
firstLine = line
|
|
||||||
elseif line ~= '' then
|
|
||||||
addellipses = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
text = firstLine
|
|
||||||
if string.len(text) > length then
|
|
||||||
text = string.sub(text, 1, length)
|
|
||||||
addellipses = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if addellipses then text = text .. '...' end
|
|
||||||
return text
|
|
||||||
end
|
|
||||||
|
|
||||||
function padLeft(str, num, fill)
|
|
||||||
local s = {}
|
|
||||||
for i = 1, num - #str do
|
|
||||||
table.insert(s, fill)
|
|
||||||
end
|
|
||||||
table.insert(s, str)
|
|
||||||
return table.concat(s, '')
|
|
||||||
end
|
|
||||||
|
|
||||||
function padLeft(str, num, fill)
|
|
||||||
local s = {}
|
|
||||||
table.insert(s, str)
|
|
||||||
for i = 1, num - #str do
|
|
||||||
table.insert(s, fill)
|
|
||||||
end
|
|
||||||
return table.concat(s, '')
|
|
||||||
end
|
|
||||||
|
|
||||||
local whitespaces = {' ', '\n', '\r'}
|
|
||||||
|
|
||||||
---@param str string
|
|
||||||
function trimLeft(str)
|
|
||||||
while includes(whitespaces, string.sub(str, 1, 1)) do
|
|
||||||
str = string.sub(str, 2)
|
|
||||||
end
|
|
||||||
return str
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param str string
|
|
||||||
function trimRight(str)
|
|
||||||
while includes(whitespaces, string.sub(str, -1, -1)) do
|
|
||||||
str = string.sub(str, 1, -2)
|
|
||||||
end
|
|
||||||
return str
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param str string
|
|
||||||
function trim(str)
|
|
||||||
return trimRight(trimLeft(str))
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param o any
|
|
||||||
---@return string
|
|
||||||
--- stringify an object
|
|
||||||
function fullDump(o, r)
|
|
||||||
if type(o) == 'table' and (not r or r > 0) then
|
|
||||||
local s = '{'
|
|
||||||
local first = true
|
|
||||||
for k,v in pairs(o) do
|
|
||||||
if not first then
|
|
||||||
s = s .. ', '
|
|
||||||
end
|
|
||||||
local nr = nil
|
|
||||||
if r then
|
|
||||||
nr = r - 1
|
|
||||||
end
|
|
||||||
if type(k) ~= 'number' then
|
|
||||||
s = s .. tostring(k) .. ' = ' .. fullDump(v, nr)
|
|
||||||
else
|
|
||||||
s = s .. fullDump(v, nr)
|
|
||||||
end
|
|
||||||
first = false
|
|
||||||
end
|
|
||||||
return s .. '}'
|
|
||||||
elseif type(o) == 'string' then
|
|
||||||
return '"' .. o .. '"'
|
|
||||||
else
|
|
||||||
return tostring(o)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param t1 any[]
|
|
||||||
---@param t2 any[]
|
|
||||||
---@return any[]
|
|
||||||
function tableConcat(t1, t2)
|
|
||||||
for i = 1, #t2 do
|
|
||||||
t1[#t1 + 1] = t2[i]
|
|
||||||
end
|
|
||||||
return t1
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param tab table
|
|
||||||
function clearMetatables(tab)
|
|
||||||
setmetatable(tab, nil)
|
|
||||||
for _, obj in pairs(tab) do
|
|
||||||
if type(obj) == 'table' then
|
|
||||||
clearMetatables(obj)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,23 +0,0 @@
|
||||||
local endings = {'rawr x3', 'OwO', 'UwU', 'o.O', '-.-', '>w<', '(˘ω˘)', 'σωσ', 'ʘwʘ', ':3', 'XD', 'nyaa~~', 'mya', '>_<', 'rawr', '^^', '^^;;', '(^•ω•^)'}
|
|
||||||
|
|
||||||
return function(str)
|
|
||||||
str = string.lower(str)
|
|
||||||
|
|
||||||
str = string.gsub(str, 'small', 'smol')
|
|
||||||
str = string.gsub(str, 'cute', 'kawaii~')
|
|
||||||
str = string.gsub(str, 'fluff', 'floof')
|
|
||||||
str = string.gsub(str, 'love', 'luv')
|
|
||||||
str = string.gsub(str, 'stupid', 'baka')
|
|
||||||
str = string.gsub(str, 'meow', 'nya~')
|
|
||||||
|
|
||||||
str = string.gsub(str, 'l', 'w')
|
|
||||||
str = string.gsub(str, 'r', 'w')
|
|
||||||
|
|
||||||
str = string.gsub(str, 'n([aeiou])', 'ny%1')
|
|
||||||
|
|
||||||
str = string.gsub(str, '[.!?]%s', function(e) return e .. endings[math.random(1, #endings)] .. ' ' end)
|
|
||||||
|
|
||||||
str = string.gsub(str, '(%s)(%a)(%a)', function(space, rep, other) if math.random() < 0.05 then return space .. rep .. '-' .. rep .. other else return space .. rep .. other end end)
|
|
||||||
|
|
||||||
return str
|
|
||||||
end
|
|
|
@ -1,142 +0,0 @@
|
||||||
---@class vector2D A vector can be defined as a set of 2 coordinates. They can be obtained by doing either vect.x and vect.y or vect[1] and vect[2], for compatibility purposes.
|
|
||||||
---The reason such a simple class exists is to do simplified math with it - math abstracted as :length(), :angle(), etc is much easier to read.
|
|
||||||
---@field public x number @x coordinate
|
|
||||||
---@field public y number @y coordinate
|
|
||||||
---@operator add(vector2D): vector2D
|
|
||||||
---@operator add(number): vector2D
|
|
||||||
---@operator sub(vector2D): vector2D
|
|
||||||
---@operator sub(number): vector2D
|
|
||||||
---@operator mul(vector2D): vector2D
|
|
||||||
---@operator mul(number): vector2D
|
|
||||||
---@operator div(vector2D): vector2D
|
|
||||||
---@operator div(number): vector2D
|
|
||||||
---@operator unm: vector2D
|
|
||||||
local vect = {}
|
|
||||||
|
|
||||||
---@return number
|
|
||||||
function vect:length()
|
|
||||||
return math.sqrt(self.x * self.x + self.y * self.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return number
|
|
||||||
function vect:lengthSquared()
|
|
||||||
return self.x * self.x + self.y * self.y
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return number
|
|
||||||
function vect:angle()
|
|
||||||
return math.atan2(self.y, self.x)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return vector2D
|
|
||||||
function vect:normalize()
|
|
||||||
local len = self:length()
|
|
||||||
if len ~= 0 and len ~= 1 then
|
|
||||||
return vector2D(self.x / len, self.y / len)
|
|
||||||
else
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return vector2D
|
|
||||||
function vect:resize(x)
|
|
||||||
local n = self:normalize()
|
|
||||||
return vector2D(n.x * x, n.y * x)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return vector2D
|
|
||||||
function vect:rotate(ang)
|
|
||||||
local a = self:angle()
|
|
||||||
local len = self:length()
|
|
||||||
return vectorFromAngle(a + ang, len)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@return number, number
|
|
||||||
function vect:unpack()
|
|
||||||
return self.x, self.y
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param v2 vector2D
|
|
||||||
---@return number
|
|
||||||
function vect:distance(v2)
|
|
||||||
return (self - v2):length()
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param v2 vector2D
|
|
||||||
---@return number
|
|
||||||
function vect:distanceSquared(v2)
|
|
||||||
return (self - v2):lengthSquared()
|
|
||||||
end
|
|
||||||
|
|
||||||
local vectmeta = {}
|
|
||||||
|
|
||||||
local function typ(a)
|
|
||||||
return (type(a) == 'table' and a.x and a.y) and 'vector' or type(a)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function genericop(a, b, f, name)
|
|
||||||
local typea = typ(a)
|
|
||||||
local typeb = typ(b)
|
|
||||||
if typea == 'number' then
|
|
||||||
return vector2D(f(b.x, a), f(b.y, a))
|
|
||||||
elseif typeb == 'number' then
|
|
||||||
return vector2D(f(a.x, b), f(a.y, b))
|
|
||||||
elseif typea == 'vector' and typeb == 'vector' then
|
|
||||||
return vector2D(f(a.x, b.x), f(a.y, b.y))
|
|
||||||
end
|
|
||||||
error('cant apply ' .. name .. ' to ' .. typea .. ' and ' .. typeb, 3)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vectmeta.__add(a, b)
|
|
||||||
return genericop(a, b, function(a, b) return a + b end, 'add')
|
|
||||||
end
|
|
||||||
function vectmeta.__sub(a, b)
|
|
||||||
return genericop(a, b, function(a, b) return a - b end, 'sub')
|
|
||||||
end
|
|
||||||
function vectmeta.__mul(a, b)
|
|
||||||
return genericop(a, b, function(a, b) return a * b end, 'mul')
|
|
||||||
end
|
|
||||||
function vectmeta.__div(a, b)
|
|
||||||
return genericop(a, b, function(a, b) return a / b end, 'div')
|
|
||||||
end
|
|
||||||
|
|
||||||
function vectmeta.__eq(a, b)
|
|
||||||
return (typ(a) == 'vector' and typ(b) == 'vector') and (a.x == b.x and a.y == b.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vectmeta:__unm()
|
|
||||||
return vector2D(-self.x, -self.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vectmeta:__tostring()
|
|
||||||
return '(' .. self.x .. ', ' .. self.y .. ')'
|
|
||||||
end
|
|
||||||
vectmeta.__name = 'vector'
|
|
||||||
|
|
||||||
function vectmeta:__index(i)
|
|
||||||
if i == 1 then return self.x end
|
|
||||||
if i == 2 then return self.y end
|
|
||||||
return vect[i]
|
|
||||||
end
|
|
||||||
|
|
||||||
--- create a new vector
|
|
||||||
---@param x number | nil
|
|
||||||
---@param y number | nil
|
|
||||||
---@return vector2D
|
|
||||||
function vector2D(x, y)
|
|
||||||
x = x or 0
|
|
||||||
y = y or x
|
|
||||||
return setmetatable({x = x, y = y}, vectmeta)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- create a new vector from an angle
|
|
||||||
---@param ang number | nil @angle in degrees
|
|
||||||
---@param amp number | nil
|
|
||||||
---@return vector2D
|
|
||||||
function vectorFromAngle(ang, amp)
|
|
||||||
ang = math.rad(ang or 0)
|
|
||||||
amp = amp or 1
|
|
||||||
return vector2D(math.cos(ang) * amp, math.sin(ang) * amp)
|
|
||||||
end
|
|
||||||
|
|
||||||
vector = vector2D
|
|
|
@ -1,85 +0,0 @@
|
||||||
---@meta
|
|
||||||
|
|
||||||
-- cleaning up some notitg typing jank... ehe
|
|
||||||
---@alias int number
|
|
||||||
---@alias float number
|
|
||||||
---@alias Quad Actor
|
|
||||||
---@alias void nil
|
|
||||||
|
|
||||||
---@return Quad
|
|
||||||
--- Defines a Quad actor.
|
|
||||||
function Quad() end
|
|
||||||
---@return ActorProxy
|
|
||||||
--- Defines an ActorProxy actor.
|
|
||||||
function ActorProxy() end
|
|
||||||
---@return Polygon
|
|
||||||
--- Defines a Polygon actor.
|
|
||||||
function Polygon() end
|
|
||||||
---@param file string
|
|
||||||
---@return Sprite
|
|
||||||
--- Defines a Sprite actor.
|
|
||||||
function Sprite(file) end
|
|
||||||
---@param file string
|
|
||||||
---@return Model
|
|
||||||
--- Defines a Model actor.
|
|
||||||
function Model(file) end
|
|
||||||
---@param font string?
|
|
||||||
---@param text string?
|
|
||||||
---@return BitmapText
|
|
||||||
--- Defines a BitmapText actor.
|
|
||||||
function BitmapText(font, text) end
|
|
||||||
---@param file string
|
|
||||||
---@return ActorSound
|
|
||||||
--- Defines an ActorSound actor.
|
|
||||||
function ActorSound(file) end
|
|
||||||
|
|
||||||
---@param actor Actor
|
|
||||||
--- Resets an actor to its initial state
|
|
||||||
function reset(actor) end
|
|
||||||
|
|
||||||
---@type number
|
|
||||||
--- A simple timer. Ticks upwards at a rate of 1/sec.
|
|
||||||
---
|
|
||||||
--- **The start time is undefined!** This uses `os.clock()`, meaning this will be inconsistent between modfile starts.
|
|
||||||
---
|
|
||||||
--- It's recommended to only use this for eg. `math.sin`, rotations, and other similar visual effects. If you want a proper timer, see `b`.
|
|
||||||
t = 0
|
|
||||||
|
|
||||||
---@type number
|
|
||||||
--- The amount of beats that have passed since the start of the file.
|
|
||||||
b = 0
|
|
||||||
|
|
||||||
---@type ActorFrame
|
|
||||||
--- The root ActorFrame. Use this for `addcommand` and similar!
|
|
||||||
_main = {}
|
|
||||||
|
|
||||||
---@type number
|
|
||||||
--- The center of the screen on the X axis. Equal to `SCREEN_CENTER_X`.
|
|
||||||
scx = 0
|
|
||||||
---@type number
|
|
||||||
--- The center of the screen on the Y axis. Equal to `SCREEN_CENTER_Y`.
|
|
||||||
scy = 0
|
|
||||||
---@type number
|
|
||||||
--- The screen width. Equal to `SCREEN_WIDTH`.
|
|
||||||
sw = 0
|
|
||||||
---@type number
|
|
||||||
--- The screen height. Equal to `SCREEN_HEIGHT`.
|
|
||||||
sh = 0
|
|
||||||
|
|
||||||
--- The Uranium Template table! Mostly callback-related stuff goes here.
|
|
||||||
uranium = {}
|
|
||||||
|
|
||||||
--- A callback for initialization. Called on `OnCommand`.
|
|
||||||
uranium.init = function() end
|
|
||||||
--- A callback for updates. Called every frame. Draw stuff here!
|
|
||||||
uranium.update = function() end
|
|
||||||
|
|
||||||
---@param event string
|
|
||||||
---@param ... any
|
|
||||||
---@return any
|
|
||||||
--- Call a defined callback.
|
|
||||||
function uranium:call(event, ...) end
|
|
||||||
|
|
||||||
--- Equivalent to a modfile-sandboxed `_G`, similar to Mirin's `xero`. You shouldn't need this; and if you do, *what are you doing?*
|
|
||||||
---@type table<any, any>
|
|
||||||
oat = {}
|
|
Loading…
Reference in New Issue