Files
love/src/scripts/boot.lua
T
vrld 9afc5dfb08 On Error, switch to default framebuffer before showing bluescreen.
Bluescreens might not be shown if the error happens with a render target
different from the default framebuffer, because it gets rendered to
the attached framebuffer object. Fix that.
2010-09-03 14:46:01 +02:00

857 lines
18 KiB
Lua

--[[
Copyright (c) 2006-2010 LOVE Development Team
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.
--]]
-- Make sure love table exists.
if not love then love = {} end
-- Used for setup:
love.path = {}
love.arg = {}
-- Unparsed arguments:
argv = {}
-- Replace any \ with /.
function love.path.normalslashes(p)
return string.gsub(p, "\\", "/")
end
-- Makes sure there is a slash at the end
-- of a path.
function love.path.endslash(p)
if string.sub(p, string.len(p)-1) ~= "/" then
return p .. "/"
else
return p
end
end
-- Checks whether a path is absolute or not.
function love.path.abs(p)
local tmp = love.path.normalslashes(p)
-- Path is absolute if it starts with a "/".
if string.find(tmp, "/") == 1 then
return true
end
-- Path is absolute if it starts with a
-- letter followed by a colon.
if string.find(tmp, "%a:") == 1 then
return true
end
-- Relative.
return false
end
-- Converts any path into a full path.
function love.path.getfull(p)
if love.path.abs(p) then
return love.path.normalslashes(p)
end
local cwd = love.filesystem.getWorkingDirectory()
cwd = love.path.normalslashes(cwd)
cwd = love.path.endslash(cwd)
-- Construct a full path.
return cwd .. love.path.normalslashes(p)
end
-- Returns the leaf of a full path.
function love.path.leaf(p)
local a = 1
local last = p
while a do
a = string.find(p, "/", a+1)
if a then
last = string.sub(p, a+1)
end
end
return last
end
-- Finds the key in the table with the lowest integral index. The lowest
-- will typically the executable, for instance "lua5.1.exe".
function love.arg.getLow(a)
local m = math.huge
for k,v in pairs(a) do
if k < m then
m = k
end
end
return a[m]
end
love.arg.options = {
console = { a = 0 },
game = { a = 1 }
}
function love.arg.parse_option(m, i)
m.set = true
if m.a > 0 then
m.arg = {}
for j=i,i+m.a-1 do
table.insert(m.arg, arg[j])
i = j
end
end
return i
end
function love.arg.parse_options()
local game
local argc = #arg
for i=1,argc do
-- Look for options.
local s, e, m = string.find(arg[i], "%-%-(.+)")
if m and love.arg.options[m] then
i = love.arg.parse_option(love.arg.options[m], i+1)
elseif not game then
game = i
end
end
if not love.arg.options.game.set then
love.arg.parse_option(love.arg.options.game, game or 0)
end
end
function love.createhandlers()
-- Standard callback handlers.
love.handlers = {
kp = function (b, u)
if love.keypressed then love.keypressed(b, u) end
end,
kr = function (b)
if love.keyreleased then love.keyreleased(b) end
end,
mp = function (x,y,b)
if love.mousepressed then love.mousepressed(x,y,b) end
end,
mr = function (x,y,b)
if love.mousereleased then love.mousereleased(x,y,b) end
end,
jp = function (j,b)
if love.joystickpressed then love.joystickpressed(j,b) end
end,
jr = function (j,b)
if love.joystickreleased then love.joystickreleased(j,b) end
end,
f = function (f)
if love.focus then love.focus(f) end
end,
q = function ()
return
end,
}
end
-- This can't be overriden.
function love.boot()
-- This is absolutely needed.
require("love")
require("love.filesystem")
love.arg.parse_options()
local o = love.arg.options
local abs_arg0 = love.path.getfull(love.arg.getLow(arg))
love.filesystem.init(abs_arg0)
-- Is this one of those fancy "fused" games?
local can_has_game = pcall(love.filesystem.setSource, abs_arg0)
if not can_has_game and o.game.set and o.game.arg[1] then
local full_source = love.path.getfull(o.game.arg[1])
local leaf = love.path.leaf(full_source)
love.filesystem.setIdentity(leaf)
can_has_game = pcall(love.filesystem.setSource, full_source)
end
if can_has_game and not (love.filesystem.exists("main.lua") or love.filesystem.exists("conf.lua")) then
no_game_code = true
end
if not can_has_game then
love.filesystem = nil
love.nogame()
end
end
function love.init()
-- Create default configuration settings.
local c = {
title = "Untitled",
author = "Unnamed",
version = 0,
screen = {
width = 800,
height = 600,
fullscreen = false,
vsync = true,
fsaa = 0,
},
modules = {
event = true,
keyboard = true,
mouse = true,
timer = true,
joystick = true,
image = true,
graphics = true,
audio = true,
physics = true,
sound = true,
font = true,
thread = true,
},
console = false, -- Only relevant for windows.
identity = false,
}
-- If config file exists, load it and allow it to update config table.
if not love.conf and love.filesystem and love.filesystem.exists("conf.lua") then
require("conf.lua")
end
-- Yes, conf.lua might not exist, but there are other ways of making
-- love.conf appear, so we should check for it anyway.
if love.conf then
local ok, err = pcall(love.conf, c)
if not ok then
print(err)
-- continue
end
end
if love.arg.options.console.set then
c.console = true
end
-- Gets desired modules.
for k,v in pairs(c.modules) do
if v then
require("love." .. k)
end
end
if love.event then
love.createhandlers()
end
-- Setup screen here.
if c.screen and c.modules.graphics then
if love.graphics.checkMode(c.screen.width, c.screen.height, c.screen.fullscreen) then
assert(love.graphics.setMode(c.screen.width, c.screen.height, c.screen.fullscreen, c.screen.vsync, c.screen.fsaa), "Could not set screen mode")
end
love.graphics.setCaption(c.title)
end
if love.filesystem and c.identity then love.filesystem.setIdentity(c.identity) end
if love.filesystem and love.filesystem.exists("main.lua") then require("main.lua") end
if no_game_code then
error("No code to run\nYour game might be packaged incorrectly\nMake sure main.lua is at the top level of the zip")
end
-- Console hack
if c.console and love._openConsole then
love._openConsole()
end
end
function love.run()
if love.load then love.load(arg) end
local dt = 0
-- Main loop time.
while true do
if love.timer then
love.timer.step()
dt = love.timer.getDelta()
end
if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled
if love.graphics then
love.graphics.clear()
if love.draw then love.draw() end
end
-- Process events.
if love.event then
for e,a,b,c in love.event.poll() do
if e == "q" then
if not love.quit or not love.quit() then
if love.audio then
love.audio.stop()
end
return
end
end
love.handlers[e](a,b,c)
end
end
if love.timer then love.timer.sleep(1) end
if love.graphics then love.graphics.present() end
end
end
-----------------------------------------------------------
-- Default screen.
-----------------------------------------------------------
function love.nogame()
love.load = function()
major, minor, rev = string.match(love._version_string, "(%d)%.(%d)%.(%d)")
if not major then major = 0 end
if not minor then minor = 0 end
if not rev then rev = 0 end
love.graphics.setBackgroundColor(0x84, 0xca, 0xff)
names = {
"wheel_0",
"wheel_1",
"wheel_2",
"wheel_3",
"wheel_4",
"wheel_5",
"wheel_6",
"wheel_7",
"wheel_8",
"wheel_9",
"belt_tooth",
"belt_track",
"turret_body",
"turret_cannon",
"star",
"knoll01",
"knoll02",
"knoll03",
"knoll04",
"tree01",
"bubble",
"love",
}
local decode = function(file)
return love.graphics.newImage(love.image.newImageData(file))
end
images = {}
for i,v in pairs(names) do
images[v] = decode(love["_"..v.."_png"])
end
pools = {
{
images.knoll01,
images.knoll02,
},
{
images.knoll03,
images.knoll04,
},
}
List = {}
List.__index = List
List.new = function(self)
local o = {
head = nil,
}
setmetatable(o, List)
return o
end
List.update = function(self, dt)
local n = self.head
while n do
n:update(dt)
n = n.next
end
end
List.draw = function(self)
local n = self.head
while n do
n:draw()
n = n.next
end
end
Node = {}
Node.__index = Node
Node.new = function(self, object)
local o = {
next = nil,
}
setmetatable(o, List)
return o
end
Node.insert = function(self, list)
local h = list.head
list.head = self
self.next = h
end
Node.remove = function(self)
parent.next = self.next
end
Object = Node:new()
Object.__index = Object
setmetatable(Object, Node)
Object.new = function(self)
local o = {
image = nil,
x = 0,
y = 0,
dx = -400,
dy = 0,
scale = 1,
r = 0,
duration = 30,
passed = 0,
t = 0,
alpha = 255
}
setmetatable(o, Object)
return o
end
Object.update = function(self, dt)
self.passed = self.passed + dt
while self.passed > self.duration do
self.passed = self.passed - self.duration
end
self.t = self.passed/self.duration
end
Object.draw = function(self)
if self.image then
local x = self.x + self.dx*self.t
local y = self.y + self.dy*self.t
local r = self.r*self.t
love.graphics.setColor(255, 255, 255, self.alpha)
love.graphics.draw(self.image, x, y, r, self.scale)
love.graphics.setColor(255, 255, 255, 255)
end
end
Tree = Object:new()
Tree.__index = Tree
setmetatable(Tree, Object)
Tree.new = function(self)
local o = {}
o.image = images.tree01
o.x = 800 + math.random(0, 800)
o.y = 300 + math.random(0, 40)
o.xt = -200;
o.dx = o.xt - o.x
o.speed = 100
o.duration = -o.dx/o.speed
setmetatable(o, Tree)
return o
end
Star = Object:new()
Star.__index = Star
setmetatable(Star, Object)
Star.new = function(self, speed, scale)
local o = {}
o.image = images.star
o.x = 800 + math.random(0, 800)
o.y = -200 + math.random(0, 300)
o.xt = -50;
o.dy = 400
o.dx = o.xt - o.x
o.speed = speed
o.scale = scale
o.duration = -o.dx/o.speed
o.r = math.pi * 5
o.alpha = 100 + math.random(155)
setmetatable(o, Star)
return o
end
Knoll = Object:new()
Knoll.__index = Knoll
setmetatable(Knoll, Object)
Knoll.new = function(self, pool, var, speed)
local o = {}
o.image = pools[pool][math.random(1, #pools[pool])]
o.x = 800 + math.random(0, 800)
o.y = 300 + var - math.random(0, var*2)
o.xt = -200;
o.dx = o.xt - o.x
o.speed = speed
o.duration = -o.dx/o.speed
setmetatable(o, Star)
return o
end
Belt = Object:new()
Belt.__index = Belt
setmetatable(Belt, Object)
Belt.new = function(self, n)
local o = {}
o.r = 30
o.d = o.r*2
o.half_c = math.pi*o.r
o.c = 2*o.half_c
o.x = 200
o.y = 300
o.th = 1
o.ta = 1
o.w = o.th*o.half_c
o.total = o.th*2+o.ta*2
o.teeth = {}
for i=0,n-1 do
local b = { x = 0, y = 0, t = (o.total/n)*i }
table.insert(o.teeth, b)
end
setmetatable(o, Belt)
return o
end
Belt.update = function(self, dt)
for i,b in ipairs(self.teeth) do
b.t = b.t + dt
if b.t < self.th then
local t = b.t
b.x = self.x + self.w * (t/self.th)
b.y = self.y
elseif b.t < self.th + self.ta then
local t = (self.th + self.ta - b.t)
b.x = self.x + self.w + math.cos(-math.pi*t + math.pi/2)*self.r
b.y = self.y + self.r + math.sin(-math.pi*t + math.pi/2)*self.r
elseif b.t < self.th*2 + self.ta then
local t = (b.t - self.th*2 + self.ta)/self.th
b.x = self.x + self.w * (2-t)
b.y = self.y + self.d
elseif b.t < self.total then
local t = (self.th*2 + self.ta - b.t)
b.x = self.x + math.cos(-math.pi*t + math.pi/2)*self.r
b.y = self.y + self.r + math.sin(-math.pi*t + math.pi/2)*self.r
else
b.t = b.t - self.total
end
end
end
Belt.draw = function(self)
for i,b in ipairs(self.teeth) do
love.graphics.draw(images.belt_tooth, b.x, b.y)
end
end
Tank = Object:new()
Tank.__index = Tank
setmetatable(Tank, Object)
Tank.new = function(self)
local o = {}
o.x = 200
o.y = 490
o.i = 49
o.belt = Belt:new(30)
o.belt.x = o.x-7
o.belt.y = o.y-37
o.angle = 0
setmetatable(o, Tank)
return o
end
Tank.update = function(self, dt)
self.angle = self.angle + dt * math.pi/2
self.belt:update(dt)
end
Tank.draw = function(self)
love.graphics.draw(images.turret_cannon, self.x+30, self.y-80)
love.graphics.draw(images.turret_body, self.x-12, self.y-110)
love.graphics.draw(images.belt_track, self.belt.x-74, self.belt.y-28)
love.graphics.draw(images["wheel_"..tostring(major)], self.x, self.y, self.angle, 1, 1, 32, 32)
love.graphics.draw(images["wheel_"..tostring(minor)], self.x+self.i, self.y, self.angle, 1, 1, 32, 32)
love.graphics.draw(images["wheel_"..tostring(rev)], self.x+self.i*2, self.y, self.angle, 1, 1, 32, 32)
self.belt:draw()
end
Bubble = Object:new()
Bubble.__index = Bubble
setmetatable(Bubble, Object)
Bubble.new = function(self)
local o = {}
o.x = 240
o.y = 190
o.angle = 0
setmetatable(o, Bubble)
return o
end
Bubble.update = function(self, dt)
self.angle = self.angle + dt*5
end
Bubble.draw = function(self)
local yv = math.sin(self.angle)*5
love.graphics.draw(images.bubble, self.x, self.y+yv)
love.graphics.draw(images.love, self.x+8, self.y+yv+95)
end
timers = {}
Timer = {}
Timer.__index = Timer
Timer.spawn = function(self, tick, f)
local o = {
passed = 0,
tick = tick,
f = f
}
setmetatable(o, Timer)
table.insert(timers, o)
end
Timer.update = function(self, dt)
self.passed = self.passed + dt
while self.passed > self.tick do
self.passed = self.passed - self.tick
self.f()
end
end
lists = {
b = List:new(),
f = List:new()
}
do
local t = Bubble:new()
t:insert(lists.f)
end
do
local t = Tank:new()
t:insert(lists.f)
end
for i=1,3 do
local t = Tree:new(50, 300)
t:insert(lists.b)
end
for i=1,2 do
local t = Knoll:new(1, 50, 100)
t:insert(lists.b)
end
for i=1,40 do
local t = Star:new(100, 1)
t:insert(lists.b)
end
for i=1,5 do
local t = Knoll:new(2, 100, 50)
t:insert(lists.b)
end
for i,v in pairs(lists) do
v:update(10)
end
end
love.update = function(dt)
for i,v in ipairs(timers) do v:update(dt) end
for i,v in pairs(lists) do
v:update(dt)
end
love.timer.sleep(10)
end
love.draw = function()
lists.b:draw()
-- Ground
love.graphics.setColor(146, 201, 87)
love.graphics.rectangle("fill", 0, 530, 800, 70)
love.graphics.setColor(205, 227, 161)
love.graphics.rectangle("fill", 0, 520, 800, 10)
love.graphics.setColor(255, 255, 255)
lists.f:draw()
end
love.conf = function(t)
t.title = "*Tank* you for using LOVE " .. love._version_string .. " (" .. love._version_codename .. ")"
t.modules.audio = false
t.modules.sound = false
t.modules.physics = false
t.modules.joystick = false
t.modules.native = false
t.modules.font = false
end
end
-----------------------------------------------------------
-- Error screen.
-----------------------------------------------------------
local debug = debug
local function error_printer(msg, layer)
print((debug.traceback("Error: " .. msg, 1+(layer or 1)):gsub("\n[^\n]+$", "")))
end
function love.errhand(msg)
error_printer(msg, 2)
if not love.graphics or not love.event or not love.graphics.isCreated() then
return
end
love.graphics.setRenderTarget()
-- Load.
love.graphics.setScissor()
love.graphics.setBackgroundColor(89, 157, 220)
local font = love.graphics.newFont(love._vera_ttf, 14)
love.graphics.setFont(font)
love.graphics.setColor(255, 255, 255, 255)
local trace = debug.traceback()
love.graphics.clear()
local err = {}
table.insert(err, "Error\n")
table.insert(err, msg.."\n\n")
for l in string.gmatch(trace, "(.-)\n") do
if not string.match(l, "boot.lua") then
l = string.gsub(l, "stack traceback:", "Traceback\n")
table.insert(err, l)
end
end
local p = table.concat(err, "\n")
p = string.gsub(p, "\t", "")
p = string.gsub(p, "%[string \"(.-)\"%]", "%1")
local function draw()
love.graphics.clear()
love.graphics.printf(p, 70, 70, love.graphics.getWidth() - 70)
love.graphics.present()
end
draw()
local e, a, b, c
while true do
e, a, b, c = love.event.wait()
if e == "q" then
return
end
if e == "kp" and a == "escape" then
return
end
draw()
end
end
-----------------------------------------------------------
-- The root of all calls.
-----------------------------------------------------------
local result = xpcall(love.boot, error_printer)
if not result then return end
local result = xpcall(love.init, love.errhand)
if not result then return end
local result = xpcall(love.run, love.errhand)
if not result then return end