351 lines
9.2 KiB
Lua
351 lines
9.2 KiB
Lua
local oldprint = print
|
|
local function print(...)
|
|
oldprint("[Infatuated] "..string.format(...))
|
|
end
|
|
|
|
infatuated = {}
|
|
infatuated.print = print
|
|
infatuated.version = "11.3"
|
|
infatuated.versionCodename = "Mysterious Mysteries"
|
|
infatuated.conf = {
|
|
identity = nil,
|
|
appendidentity = false,
|
|
version = infatuated.version,
|
|
console = false,
|
|
accelerometerjoystick = true,
|
|
externalstorage = false,
|
|
gammacorrect = false,
|
|
audio = {
|
|
mic = false,
|
|
mixwithsystem = true,
|
|
},
|
|
window = {
|
|
--title = "Untitled",
|
|
icon = nil,
|
|
width = 800,
|
|
height = 600,
|
|
borderless = false,
|
|
resizable = false,
|
|
minwidth = 1,
|
|
minheight = 1,
|
|
fullscreen = false,
|
|
fullscreentype = "desktop",
|
|
vsync = 1,
|
|
msaa = 0,
|
|
depth = nil,
|
|
stencil = nil,
|
|
display = 1,
|
|
highdpi = false,
|
|
usedpiscale = true,
|
|
x = nil,
|
|
y = nil
|
|
},
|
|
modules = {
|
|
audio = true,
|
|
data = true,
|
|
event = true,
|
|
font = true,
|
|
graphics = true,
|
|
image = true,
|
|
joystick = true,
|
|
keyboard = true,
|
|
math = true,
|
|
mouse = true,
|
|
physics = true,
|
|
sound = true,
|
|
system = true,
|
|
thread = true,
|
|
timer = true,
|
|
touch = true,
|
|
video = true,
|
|
window = true
|
|
}
|
|
}
|
|
|
|
class = require "middleclass"
|
|
infatuated.classes = {}
|
|
|
|
local Object = class("Object")
|
|
infatuated.classes.Object = Object
|
|
function Object:initialize() end
|
|
function Object:release() end
|
|
function Object:type()
|
|
return tostring(self.class):match("^Class (.+)$")
|
|
end
|
|
function Object:typeOf(a)
|
|
assert(type(a) == "string", "bad argument #1 to typeOf (expected string)")
|
|
return self:type() == a or self:isInstanceOf(infatuated.classes[a])
|
|
end
|
|
|
|
local js = require "js"
|
|
infatuated.js = js
|
|
local window = js.global
|
|
local document = window.document
|
|
local canvas = document:getElementById("infatuated-canvas")
|
|
infatuated.canvas = canvas
|
|
local ctx = canvas:getContext("2d")
|
|
infatuated.ctx = ctx
|
|
|
|
infatuated.overlay = document:getElementById("infatuated-overlay")
|
|
infatuated.msgbox = {
|
|
root = document:getElementById("infatuated-msgbox"),
|
|
title = document:getElementById("infatuated-msgbox-title"),
|
|
text = document:getElementById("infatuated-msgbox-text"),
|
|
close = document:getElementById("infatuated-msgbox-close"),
|
|
buttons = document:getElementById("infatuated-msgbox-buttons")
|
|
}
|
|
function infatuated.msgbox:show(title, text, buttons, callback)
|
|
self.title.textContent = title
|
|
self.text.textContent = text
|
|
for k, v in pairs(document:querySelectorAll("#infatuated-msgbox-buttons button")) do
|
|
v:remove()
|
|
end
|
|
if buttons then
|
|
self.close.style.display = "unset"
|
|
function self.close.onclick()
|
|
self:hide()
|
|
callback(0)
|
|
end
|
|
for i=1, #buttons do
|
|
local btn = document:createElement("button")
|
|
btn.textContent = buttons[i]
|
|
--btn.dataset.id = i
|
|
self.buttons:append(btn)
|
|
btn:addEventListener("click", function()
|
|
self:hide()
|
|
callback(i)
|
|
end)
|
|
end
|
|
else
|
|
self.close.style.display = "none"
|
|
end
|
|
infatuated.overlay.dataset.hidden = false
|
|
self.root.dataset.hidden = false
|
|
end
|
|
function infatuated.msgbox:hide()
|
|
infatuated.canvas:focus()
|
|
infatuated.overlay.dataset.hidden = true
|
|
self.root.dataset.hidden = true
|
|
end
|
|
|
|
infatuated.path = window.infatuated.game:gsub("%.", "/")
|
|
infatuated.shims = {}
|
|
local i = 0
|
|
for name in (window.infatuated.shim..","):gmatch("(.+),") do
|
|
i = i+1
|
|
infatuated.shims[i] = name
|
|
end
|
|
|
|
print("Running game from path %q", infatuated.path)
|
|
|
|
local function errorprint(...)
|
|
window.console:error("[Infatuated] "..string.format(...))
|
|
end
|
|
|
|
function infatuated.stop(status)
|
|
print("Stopping with code %s", status or "null")
|
|
infatuated.stopDue = status
|
|
end
|
|
|
|
function infatuated.crash(errmsg)
|
|
errorprint("%s\n%s", errmsg, debug.traceback())
|
|
if infatuated.crashed then
|
|
print("Error handler crashed; stopping execution entirely")
|
|
infatuated.msgbox:show(
|
|
"Fatal error",
|
|
"An error occured, and then the error handler experienced an error of its own. Execution has stopped. Check console for details.",
|
|
{"OK"},
|
|
function() end
|
|
)
|
|
coroutine.yield()
|
|
elseif infatuated.crashInternal then
|
|
infatuated.msgbox:show(
|
|
"Fatal error",
|
|
"An error occurred during initialization and was not caught. Check console for details.",
|
|
{"OK"},
|
|
function() end
|
|
)
|
|
coroutine.yield()
|
|
else
|
|
infatuated.crashed = true
|
|
infatuated.loopGuest = love.errorhandler(errmsg)
|
|
end
|
|
end
|
|
|
|
function infatuated.parseColor(r, g, b, a)
|
|
if type(r) == "table" then
|
|
return infatuated.parseColor(r[1], r[2], r[3], r[4])
|
|
elseif type(r) == "number" then
|
|
a = a or 1
|
|
assert(type(g) == "number", "bad argument #2 to parseColor (expected number)")
|
|
assert(type(b) == "number", "bad argument #3 to parseColor (expected number)")
|
|
assert(type(a) == "number", "bad argument #4 to parseColor (expected number)")
|
|
r, g, b, a = r*255, g*255, b*255, a
|
|
return {r, g, b, a}, string.format("rgba(%f, %f, %f, %f)", r, g, b, a)
|
|
else
|
|
error("bad argument #1 to parseColor")
|
|
end
|
|
end
|
|
|
|
love = {}
|
|
|
|
function love.conf() end
|
|
function love.errorhandler(msg)
|
|
msg = tostring(msg)
|
|
if love.mouse then
|
|
love.mouse.setVisible(true)
|
|
love.mouse.setGrabbed(false)
|
|
--love.mouse.setRelativeMode(false)
|
|
love.mouse.setCursor()
|
|
end
|
|
if love.joystick then
|
|
for i, joystick in ipairs(love.joystick.getJoysticks()) do
|
|
joystick:setVibration()
|
|
end
|
|
end
|
|
if love.audio then love.audio.stop() end
|
|
|
|
love.graphics.reset()
|
|
|
|
-- original colors have absolute shit contrast
|
|
--local fr, fg, fb = 255, 255, 255
|
|
--local br, bg, bb = 89, 157, 220
|
|
local fr, fg, fb = 223, 223, 223
|
|
local br, bg, bb = 48, 48, 48
|
|
if love._version ~= "0.9.0" then
|
|
fr, fg, fb, br, bg, bb = fr/255, fg/255, fb/255, br/255, bg/255, bb/255
|
|
end
|
|
love.graphics.setColor(fr, fg, fb)
|
|
love.graphics.setBackgroundColor(br, bg, bb)
|
|
|
|
local p = 70
|
|
local url = (window.location.href.."?"):match("^(.-)?")
|
|
local traceback = debug.traceback(nil, 2):gsub(url, ""):gsub("\t", "\t\t\t\t")
|
|
local msg = string.format("An error has occurred.\n\n%s\n\n%s", msg, traceback)
|
|
return function()
|
|
local w, h = love.graphics.getDimensions()
|
|
love.graphics.clear()
|
|
love.graphics.printf(msg, p, p, w-p-p, "left")
|
|
love.graphics.present()
|
|
end
|
|
end
|
|
love.errhand = love.errorhandler
|
|
function love.run()
|
|
love.graphics.setColor(1, 1, 1, 1)
|
|
love.graphics.setBackgroundColor(0, 0, 0, 1)
|
|
love.graphics.setLineWidth(2)
|
|
|
|
if love.load then love.load() end
|
|
|
|
infatuated.startTime = window.performance:now()
|
|
infatuated.dt1 = infatuated.startTime
|
|
|
|
return function()
|
|
if infatuated.stopDue then return infatuated.stopDue end
|
|
if love.event then
|
|
love.event.pump()
|
|
-- TODO: varargs?
|
|
for name, a, b, c, d, e, f in love.event.poll() do
|
|
if name == "quit" then
|
|
if not love.quit or not love.quit() then
|
|
return a or 0
|
|
end
|
|
elseif love.handlers[name] then
|
|
love.handlers[name](a, b, c, d, e, f)
|
|
end
|
|
end
|
|
end
|
|
if love.update then love.update(infatuated.dt) end
|
|
if love.graphics and love.graphics.isActive() then
|
|
love.graphics.origin()
|
|
love.graphics.clear()
|
|
if love.draw then love.draw() end
|
|
love.graphics.present()
|
|
end
|
|
end
|
|
end
|
|
|
|
print("Coroutining now")
|
|
infatuated.thread = coroutine.create(function()
|
|
xpcall(function()
|
|
require "modules.audio"
|
|
require "modules.data"
|
|
require "modules.event"
|
|
require "modules.filesystem"
|
|
require "modules.graphics"
|
|
require "modules.handlers"
|
|
require "modules.image"
|
|
require "modules.math"
|
|
require "modules.mouse"
|
|
require "modules.system"
|
|
require "modules.timer"
|
|
require "modules.window"
|
|
|
|
love.run()
|
|
|
|
for i, path in ipairs(infatuated.shims) do
|
|
print("Shimming %s", path)
|
|
path = path:gsub("%.", "-")
|
|
require("shims."..path)
|
|
end
|
|
love._version = infatuated.version
|
|
love._version_codename = infatuated.versionCodename
|
|
print("Running as version %s (%s)", love._version, love._version_codename)
|
|
|
|
local oldrequire = require
|
|
infatuated.require = oldrequire
|
|
function require(path)
|
|
assert(type(path) == "string", "bad argument #1 to require")
|
|
if path == "love" then return love end
|
|
return oldrequire(infatuated.path.."."..path)
|
|
end
|
|
|
|
print("Importing conf")
|
|
|
|
local status, errmsg = pcall(oldrequire, infatuated.path..".conf")
|
|
if not status and not errmsg:find("^module '.-%.conf' not found:") then
|
|
infatuated.crash(errmsg)
|
|
end
|
|
if status then
|
|
local status, errmsg = pcall(love.conf, infatuated.conf)
|
|
if not status then infatuated.crash(errmsg) end
|
|
love.window.setTitle(infatuated.conf.window.title or infatuated.conf.title or "Untitled")
|
|
|
|
print("Importing main")
|
|
local status, errmsg = pcall(oldrequire, infatuated.path..".main")
|
|
if not status then infatuated.crash(errmsg) end
|
|
local status, errmsg = pcall(love.run)
|
|
if not status then
|
|
infatuated.crash(errmsg)
|
|
else
|
|
infatuated.loopGuest = errmsg
|
|
end
|
|
end
|
|
|
|
print("Starting event loop")
|
|
|
|
infatuated.dt1 = window.performance:now()
|
|
local function resume()
|
|
coroutine.resume(infatuated.thread)
|
|
end
|
|
while true do
|
|
local dt2 = window.performance:now()
|
|
infatuated.dt = (dt2-infatuated.dt1)/1000
|
|
infatuated.dt1 = dt2
|
|
local status, errmsg = pcall(infatuated.loopGuest)
|
|
if not status then
|
|
infatuated.crash(errmsg)
|
|
elseif errmsg then
|
|
print("Exited with code %d", errmsg or -1)
|
|
return
|
|
end
|
|
window:requestAnimationFrame(resume)
|
|
coroutine.yield()
|
|
end
|
|
end, function(errmsg)
|
|
infatuated.crashInternal = true
|
|
infatuated.crash(errmsg)
|
|
end)
|
|
end)
|
|
coroutine.resume(infatuated.thread)
|