-- Make sure love table exists. if not love then love = {} end -- Used for setup: love.path = {} love.arg = {} -- 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 last = 0 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) end last = i end if not love.arg.options.game.set then love.arg.parse_option(love.arg.options.game, last) 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, 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 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, }, console = false, -- Only relevant for windows. } -- 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.keyboard 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 love.filesystem.exists("main.lua") then require("main.lua") end -- Console hack if c.console and love._openConsole then love._openConsole() end end function love.run() if love.load then love.load() end -- Main loop time. while true do love.timer.step() if love.update then love.update(love.timer.getDelta()) end love.graphics.clear() if love.draw then love.draw() end -- Process events. for e,a,b,c in love.event.poll() do if e == "q" then if love.audio then love.audio.stop() end return end love.handlers[e](a,b,c) end love.timer.sleep(1) love.graphics.present() end end ----------------------------------------------------------- -- Default screen. ----------------------------------------------------------- function love.nogame() love.load = function() love.graphics.setBackgroundColor(0x84, 0xca, 0xff) names = { "wheel_major", "wheel_minor", "wheel_revision", "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_major, self.x, self.y, self.angle, 1, 1, 32, 32) love.graphics.draw(images.wheel_minor, self.x+self.i, self.y, self.angle, 1, 1, 32, 32) love.graphics.draw(images.wheel_revision, 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. ----------------------------------------------------------- function love.errhand(msg) if not love.graphics or not love.event or not love.graphics.isCreated() then return error_printer(msg) end -- 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") love.graphics.printf(p, 70, 70, love.graphics.getWidth() - 70) love.graphics.present() 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 end end ----------------------------------------------------------- -- The root of all calls. ----------------------------------------------------------- function error_printer(msg) print("boot", msg, debug.traceback()) end result = xpcall(love.boot, error_printer) if not result then return end result = xpcall(love.init, love.errhand) if not result then return end result = xpcall(love.run, love.errhand) if not result then return end