boot.lua 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. --[[
  2. Copyright (c) 2006-2010 LOVE Development Team
  3. This software is provided 'as-is', without any express or implied
  4. warranty. In no event will the authors be held liable for any damages
  5. arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it
  8. freely, subject to the following restrictions:
  9. 1. The origin of this software must not be misrepresented; you must not
  10. claim that you wrote the original software. If you use this software
  11. in a product, an acknowledgment in the product documentation would be
  12. appreciated but is not required.
  13. 2. Altered source versions must be plainly marked as such, and must not be
  14. misrepresented as being the original software.
  15. 3. This notice may not be removed or altered from any source distribution.
  16. --]]
  17. -- Make sure love table exists.
  18. if not love then love = {} end
  19. -- Used for setup:
  20. love.path = {}
  21. love.arg = {}
  22. -- Unparsed arguments:
  23. argv = {}
  24. -- Replace any \ with /.
  25. function love.path.normalslashes(p)
  26. return string.gsub(p, "\\", "/")
  27. end
  28. -- Makes sure there is a slash at the end
  29. -- of a path.
  30. function love.path.endslash(p)
  31. if string.sub(p, string.len(p)-1) ~= "/" then
  32. return p .. "/"
  33. else
  34. return p
  35. end
  36. end
  37. -- Checks whether a path is absolute or not.
  38. function love.path.abs(p)
  39. local tmp = love.path.normalslashes(p)
  40. -- Path is absolute if it starts with a "/".
  41. if string.find(tmp, "/") == 1 then
  42. return true
  43. end
  44. -- Path is absolute if it starts with a
  45. -- letter followed by a colon.
  46. if string.find(tmp, "%a:") == 1 then
  47. return true
  48. end
  49. -- Relative.
  50. return false
  51. end
  52. -- Converts any path into a full path.
  53. function love.path.getfull(p)
  54. if love.path.abs(p) then
  55. return love.path.normalslashes(p)
  56. end
  57. local cwd = love.filesystem.getWorkingDirectory()
  58. cwd = love.path.normalslashes(cwd)
  59. cwd = love.path.endslash(cwd)
  60. -- Construct a full path.
  61. return cwd .. love.path.normalslashes(p)
  62. end
  63. -- Returns the leaf of a full path.
  64. function love.path.leaf(p)
  65. local a = 1
  66. local last = p
  67. while a do
  68. a = string.find(p, "/", a+1)
  69. if a then
  70. last = string.sub(p, a+1)
  71. end
  72. end
  73. return last
  74. end
  75. -- Finds the key in the table with the lowest integral index. The lowest
  76. -- will typically the executable, for instance "lua5.1.exe".
  77. function love.arg.getLow(a)
  78. local m = math.huge
  79. for k,v in pairs(a) do
  80. if k < m then
  81. m = k
  82. end
  83. end
  84. return a[m]
  85. end
  86. love.arg.options = {
  87. console = { a = 0 },
  88. game = { a = 1 }
  89. }
  90. function love.arg.parse_option(m, i)
  91. m.set = true
  92. if m.a > 0 then
  93. m.arg = {}
  94. for j=i,i+m.a-1 do
  95. table.insert(m.arg, arg[j])
  96. i = j
  97. end
  98. end
  99. return i
  100. end
  101. function love.arg.parse_options()
  102. local game
  103. local argc = #arg
  104. for i=1,argc do
  105. -- Look for options.
  106. local s, e, m = string.find(arg[i], "%-%-(.+)")
  107. if m and love.arg.options[m] then
  108. i = love.arg.parse_option(love.arg.options[m], i+1)
  109. elseif not game then
  110. game = i
  111. end
  112. end
  113. if not love.arg.options.game.set then
  114. love.arg.parse_option(love.arg.options.game, game or 0)
  115. end
  116. end
  117. function love.createhandlers()
  118. -- Standard callback handlers.
  119. love.handlers = {
  120. kp = function (b, u)
  121. if love.keypressed then love.keypressed(b, u) end
  122. end,
  123. kr = function (b)
  124. if love.keyreleased then love.keyreleased(b) end
  125. end,
  126. mp = function (x,y,b)
  127. if love.mousepressed then love.mousepressed(x,y,b) end
  128. end,
  129. mr = function (x,y,b)
  130. if love.mousereleased then love.mousereleased(x,y,b) end
  131. end,
  132. jp = function (j,b)
  133. if love.joystickpressed then love.joystickpressed(j,b) end
  134. end,
  135. jr = function (j,b)
  136. if love.joystickreleased then love.joystickreleased(j,b) end
  137. end,
  138. q = function ()
  139. return
  140. end,
  141. }
  142. end
  143. -- This can't be overriden.
  144. function love.boot()
  145. -- This is absolutely needed.
  146. require("love")
  147. require("love.filesystem")
  148. love.arg.parse_options()
  149. local o = love.arg.options
  150. local abs_arg0 = love.path.getfull(love.arg.getLow(arg))
  151. love.filesystem.init(abs_arg0)
  152. -- Is this one of those fancy "fused" games?
  153. local can_has_game = pcall(love.filesystem.setSource, abs_arg0)
  154. if not can_has_game and o.game.set and o.game.arg[1] then
  155. local full_source = love.path.getfull(o.game.arg[1])
  156. local leaf = love.path.leaf(full_source)
  157. love.filesystem.setIdentity(leaf)
  158. can_has_game = pcall(love.filesystem.setSource, full_source)
  159. end
  160. if can_has_game and not (love.filesystem.exists("main.lua") or love.filesystem.exists("conf.lua")) then
  161. no_game_code = true
  162. end
  163. if not can_has_game then
  164. love.filesystem = nil
  165. love.nogame()
  166. end
  167. end
  168. function love.init()
  169. -- Create default configuration settings.
  170. local c = {
  171. title = "Untitled",
  172. author = "Unnamed",
  173. version = 0,
  174. screen = {
  175. width = 800,
  176. height = 600,
  177. fullscreen = false,
  178. vsync = true,
  179. fsaa = 0,
  180. },
  181. modules = {
  182. event = true,
  183. keyboard = true,
  184. mouse = true,
  185. timer = true,
  186. joystick = true,
  187. image = true,
  188. graphics = true,
  189. audio = true,
  190. physics = true,
  191. sound = true,
  192. font = true,
  193. thread = true,
  194. },
  195. console = false, -- Only relevant for windows.
  196. }
  197. -- If config file exists, load it and allow it to update config table.
  198. if not love.conf and love.filesystem and love.filesystem.exists("conf.lua") then
  199. require("conf.lua")
  200. end
  201. -- Yes, conf.lua might not exist, but there are other ways of making
  202. -- love.conf appear, so we should check for it anyway.
  203. if love.conf then
  204. local ok, err = pcall(love.conf, c)
  205. if not ok then
  206. print(err)
  207. -- continue
  208. end
  209. end
  210. if love.arg.options.console.set then
  211. c.console = true
  212. end
  213. -- Gets desired modules.
  214. for k,v in pairs(c.modules) do
  215. if v then
  216. require("love." .. k)
  217. end
  218. end
  219. if love.event then
  220. love.createhandlers()
  221. end
  222. -- Setup screen here.
  223. if c.screen and c.modules.graphics then
  224. if love.graphics.checkMode(c.screen.width, c.screen.height, c.screen.fullscreen) then
  225. assert(love.graphics.setMode(c.screen.width, c.screen.height, c.screen.fullscreen, c.screen.vsync, c.screen.fsaa), "Could not set screen mode")
  226. end
  227. love.graphics.setCaption(c.title)
  228. end
  229. if love.filesystem and love.filesystem.exists("main.lua") then require("main.lua") end
  230. if no_game_code then
  231. error("No code to run\nYour game might be packaged incorrectly\nMake sure main.lua is at the top level of the zip")
  232. end
  233. -- Console hack
  234. if c.console and love._openConsole then
  235. love._openConsole()
  236. end
  237. end
  238. function love.run()
  239. if love.load then love.load(arg) end
  240. local dt = 0
  241. -- Main loop time.
  242. while true do
  243. if love.timer then
  244. love.timer.step()
  245. dt = love.timer.getDelta()
  246. end
  247. if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled
  248. if love.graphics then
  249. love.graphics.clear()
  250. if love.draw then love.draw() end
  251. end
  252. -- Process events.
  253. if love.event then
  254. for e,a,b,c in love.event.poll() do
  255. if e == "q" then
  256. if love.audio then
  257. love.audio.stop()
  258. end
  259. return
  260. end
  261. love.handlers[e](a,b,c)
  262. end
  263. end
  264. if love.timer then love.timer.sleep(1) end
  265. if love.graphics then love.graphics.present() end
  266. end
  267. end
  268. -----------------------------------------------------------
  269. -- Default screen.
  270. -----------------------------------------------------------
  271. function love.nogame()
  272. love.load = function()
  273. major, minor, rev = string.match(love._version_string, "(%d)%.(%d)%.(%d)")
  274. if not major then major = 0 end
  275. if not minor then minor = 0 end
  276. if not rev then rev = 0 end
  277. love.graphics.setBackgroundColor(0x84, 0xca, 0xff)
  278. names = {
  279. "wheel_0",
  280. "wheel_1",
  281. "wheel_2",
  282. "wheel_3",
  283. "wheel_4",
  284. "wheel_5",
  285. "wheel_6",
  286. "wheel_7",
  287. "wheel_8",
  288. "wheel_9",
  289. "belt_tooth",
  290. "belt_track",
  291. "turret_body",
  292. "turret_cannon",
  293. "star",
  294. "knoll01",
  295. "knoll02",
  296. "knoll03",
  297. "knoll04",
  298. "tree01",
  299. "bubble",
  300. "love",
  301. }
  302. local decode = function(file)
  303. return love.graphics.newImage(love.image.newImageData(file))
  304. end
  305. images = {}
  306. for i,v in pairs(names) do
  307. images[v] = decode(love["_"..v.."_png"])
  308. end
  309. pools = {
  310. {
  311. images.knoll01,
  312. images.knoll02,
  313. },
  314. {
  315. images.knoll03,
  316. images.knoll04,
  317. },
  318. }
  319. List = {}
  320. List.__index = List
  321. List.new = function(self)
  322. local o = {
  323. head = nil,
  324. }
  325. setmetatable(o, List)
  326. return o
  327. end
  328. List.update = function(self, dt)
  329. local n = self.head
  330. while n do
  331. n:update(dt)
  332. n = n.next
  333. end
  334. end
  335. List.draw = function(self)
  336. local n = self.head
  337. while n do
  338. n:draw()
  339. n = n.next
  340. end
  341. end
  342. Node = {}
  343. Node.__index = Node
  344. Node.new = function(self, object)
  345. local o = {
  346. next = nil,
  347. }
  348. setmetatable(o, List)
  349. return o
  350. end
  351. Node.insert = function(self, list)
  352. local h = list.head
  353. list.head = self
  354. self.next = h
  355. end
  356. Node.remove = function(self)
  357. parent.next = self.next
  358. end
  359. Object = Node:new()
  360. Object.__index = Object
  361. setmetatable(Object, Node)
  362. Object.new = function(self)
  363. local o = {
  364. image = nil,
  365. x = 0,
  366. y = 0,
  367. dx = -400,
  368. dy = 0,
  369. scale = 1,
  370. r = 0,
  371. duration = 30,
  372. passed = 0,
  373. t = 0,
  374. alpha = 255
  375. }
  376. setmetatable(o, Object)
  377. return o
  378. end
  379. Object.update = function(self, dt)
  380. self.passed = self.passed + dt
  381. while self.passed > self.duration do
  382. self.passed = self.passed - self.duration
  383. end
  384. self.t = self.passed/self.duration
  385. end
  386. Object.draw = function(self)
  387. if self.image then
  388. local x = self.x + self.dx*self.t
  389. local y = self.y + self.dy*self.t
  390. local r = self.r*self.t
  391. love.graphics.setColor(255, 255, 255, self.alpha)
  392. love.graphics.draw(self.image, x, y, r, self.scale)
  393. love.graphics.setColor(255, 255, 255, 255)
  394. end
  395. end
  396. Tree = Object:new()
  397. Tree.__index = Tree
  398. setmetatable(Tree, Object)
  399. Tree.new = function(self)
  400. local o = {}
  401. o.image = images.tree01
  402. o.x = 800 + math.random(0, 800)
  403. o.y = 300 + math.random(0, 40)
  404. o.xt = -200;
  405. o.dx = o.xt - o.x
  406. o.speed = 100
  407. o.duration = -o.dx/o.speed
  408. setmetatable(o, Tree)
  409. return o
  410. end
  411. Star = Object:new()
  412. Star.__index = Star
  413. setmetatable(Star, Object)
  414. Star.new = function(self, speed, scale)
  415. local o = {}
  416. o.image = images.star
  417. o.x = 800 + math.random(0, 800)
  418. o.y = -200 + math.random(0, 300)
  419. o.xt = -50;
  420. o.dy = 400
  421. o.dx = o.xt - o.x
  422. o.speed = speed
  423. o.scale = scale
  424. o.duration = -o.dx/o.speed
  425. o.r = math.pi * 5
  426. o.alpha = 100 + math.random(155)
  427. setmetatable(o, Star)
  428. return o
  429. end
  430. Knoll = Object:new()
  431. Knoll.__index = Knoll
  432. setmetatable(Knoll, Object)
  433. Knoll.new = function(self, pool, var, speed)
  434. local o = {}
  435. o.image = pools[pool][math.random(1, #pools[pool])]
  436. o.x = 800 + math.random(0, 800)
  437. o.y = 300 + var - math.random(0, var*2)
  438. o.xt = -200;
  439. o.dx = o.xt - o.x
  440. o.speed = speed
  441. o.duration = -o.dx/o.speed
  442. setmetatable(o, Star)
  443. return o
  444. end
  445. Belt = Object:new()
  446. Belt.__index = Belt
  447. setmetatable(Belt, Object)
  448. Belt.new = function(self, n)
  449. local o = {}
  450. o.r = 30
  451. o.d = o.r*2
  452. o.half_c = math.pi*o.r
  453. o.c = 2*o.half_c
  454. o.x = 200
  455. o.y = 300
  456. o.th = 1
  457. o.ta = 1
  458. o.w = o.th*o.half_c
  459. o.total = o.th*2+o.ta*2
  460. o.teeth = {}
  461. for i=0,n-1 do
  462. local b = { x = 0, y = 0, t = (o.total/n)*i }
  463. table.insert(o.teeth, b)
  464. end
  465. setmetatable(o, Belt)
  466. return o
  467. end
  468. Belt.update = function(self, dt)
  469. for i,b in ipairs(self.teeth) do
  470. b.t = b.t + dt
  471. if b.t < self.th then
  472. local t = b.t
  473. b.x = self.x + self.w * (t/self.th)
  474. b.y = self.y
  475. elseif b.t < self.th + self.ta then
  476. local t = (self.th + self.ta - b.t)
  477. b.x = self.x + self.w + math.cos(-math.pi*t + math.pi/2)*self.r
  478. b.y = self.y + self.r + math.sin(-math.pi*t + math.pi/2)*self.r
  479. elseif b.t < self.th*2 + self.ta then
  480. local t = (b.t - self.th*2 + self.ta)/self.th
  481. b.x = self.x + self.w * (2-t)
  482. b.y = self.y + self.d
  483. elseif b.t < self.total then
  484. local t = (self.th*2 + self.ta - b.t)
  485. b.x = self.x + math.cos(-math.pi*t + math.pi/2)*self.r
  486. b.y = self.y + self.r + math.sin(-math.pi*t + math.pi/2)*self.r
  487. else
  488. b.t = b.t - self.total
  489. end
  490. end
  491. end
  492. Belt.draw = function(self)
  493. for i,b in ipairs(self.teeth) do
  494. love.graphics.draw(images.belt_tooth, b.x, b.y)
  495. end
  496. end
  497. Tank = Object:new()
  498. Tank.__index = Tank
  499. setmetatable(Tank, Object)
  500. Tank.new = function(self)
  501. local o = {}
  502. o.x = 200
  503. o.y = 490
  504. o.i = 49
  505. o.belt = Belt:new(30)
  506. o.belt.x = o.x-7
  507. o.belt.y = o.y-37
  508. o.angle = 0
  509. setmetatable(o, Tank)
  510. return o
  511. end
  512. Tank.update = function(self, dt)
  513. self.angle = self.angle + dt * math.pi/2
  514. self.belt:update(dt)
  515. end
  516. Tank.draw = function(self)
  517. love.graphics.draw(images.turret_cannon, self.x+30, self.y-80)
  518. love.graphics.draw(images.turret_body, self.x-12, self.y-110)
  519. love.graphics.draw(images.belt_track, self.belt.x-74, self.belt.y-28)
  520. love.graphics.draw(images["wheel_"..tostring(major)], self.x, self.y, self.angle, 1, 1, 32, 32)
  521. love.graphics.draw(images["wheel_"..tostring(minor)], self.x+self.i, self.y, self.angle, 1, 1, 32, 32)
  522. love.graphics.draw(images["wheel_"..tostring(rev)], self.x+self.i*2, self.y, self.angle, 1, 1, 32, 32)
  523. self.belt:draw()
  524. end
  525. Bubble = Object:new()
  526. Bubble.__index = Bubble
  527. setmetatable(Bubble, Object)
  528. Bubble.new = function(self)
  529. local o = {}
  530. o.x = 240
  531. o.y = 190
  532. o.angle = 0
  533. setmetatable(o, Bubble)
  534. return o
  535. end
  536. Bubble.update = function(self, dt)
  537. self.angle = self.angle + dt*5
  538. end
  539. Bubble.draw = function(self)
  540. local yv = math.sin(self.angle)*5
  541. love.graphics.draw(images.bubble, self.x, self.y+yv)
  542. love.graphics.draw(images.love, self.x+8, self.y+yv+95)
  543. end
  544. timers = {}
  545. Timer = {}
  546. Timer.__index = Timer
  547. Timer.spawn = function(self, tick, f)
  548. local o = {
  549. passed = 0,
  550. tick = tick,
  551. f = f
  552. }
  553. setmetatable(o, Timer)
  554. table.insert(timers, o)
  555. end
  556. Timer.update = function(self, dt)
  557. self.passed = self.passed + dt
  558. while self.passed > self.tick do
  559. self.passed = self.passed - self.tick
  560. self.f()
  561. end
  562. end
  563. lists = {
  564. b = List:new(),
  565. f = List:new()
  566. }
  567. do
  568. local t = Bubble:new()
  569. t:insert(lists.f)
  570. end
  571. do
  572. local t = Tank:new()
  573. t:insert(lists.f)
  574. end
  575. for i=1,3 do
  576. local t = Tree:new(50, 300)
  577. t:insert(lists.b)
  578. end
  579. for i=1,2 do
  580. local t = Knoll:new(1, 50, 100)
  581. t:insert(lists.b)
  582. end
  583. for i=1,40 do
  584. local t = Star:new(100, 1)
  585. t:insert(lists.b)
  586. end
  587. for i=1,5 do
  588. local t = Knoll:new(2, 100, 50)
  589. t:insert(lists.b)
  590. end
  591. for i,v in pairs(lists) do
  592. v:update(10)
  593. end
  594. end
  595. love.update = function(dt)
  596. for i,v in ipairs(timers) do v:update(dt) end
  597. for i,v in pairs(lists) do
  598. v:update(dt)
  599. end
  600. love.timer.sleep(10)
  601. end
  602. love.draw = function()
  603. lists.b:draw()
  604. -- Ground
  605. love.graphics.setColor(146, 201, 87)
  606. love.graphics.rectangle("fill", 0, 530, 800, 70)
  607. love.graphics.setColor(205, 227, 161)
  608. love.graphics.rectangle("fill", 0, 520, 800, 10)
  609. love.graphics.setColor(255, 255, 255)
  610. lists.f:draw()
  611. end
  612. love.conf = function(t)
  613. t.title = "*Tank* you for using LOVE " .. love._version_string .. " (" .. love._version_codename .. ")"
  614. t.modules.audio = false
  615. t.modules.sound = false
  616. t.modules.physics = false
  617. t.modules.joystick = false
  618. t.modules.native = false
  619. t.modules.font = false
  620. end
  621. end
  622. -----------------------------------------------------------
  623. -- Error screen.
  624. -----------------------------------------------------------
  625. local debug = debug
  626. local function error_printer(msg, layer)
  627. print((debug.traceback("Error: " .. msg, 1+(layer or 1)):gsub("\n[^\n]+$", "")))
  628. end
  629. function love.errhand(msg)
  630. error_printer(msg, 2)
  631. if not love.graphics or not love.event or not love.graphics.isCreated() then
  632. return
  633. end
  634. -- Load.
  635. love.graphics.setScissor()
  636. love.graphics.setBackgroundColor(89, 157, 220)
  637. local font = love.graphics.newFont(love._vera_ttf, 14)
  638. love.graphics.setFont(font)
  639. love.graphics.setColor(255, 255, 255, 255)
  640. local trace = debug.traceback()
  641. love.graphics.clear()
  642. local err = {}
  643. table.insert(err, "Error\n")
  644. table.insert(err, msg.."\n\n")
  645. for l in string.gmatch(trace, "(.-)\n") do
  646. if not string.match(l, "boot.lua") then
  647. l = string.gsub(l, "stack traceback:", "Traceback\n")
  648. table.insert(err, l)
  649. end
  650. end
  651. local p = table.concat(err, "\n")
  652. p = string.gsub(p, "\t", "")
  653. p = string.gsub(p, "%[string \"(.-)\"%]", "%1")
  654. local function draw()
  655. love.graphics.clear()
  656. love.graphics.printf(p, 70, 70, love.graphics.getWidth() - 70)
  657. love.graphics.present()
  658. end
  659. draw()
  660. local e, a, b, c
  661. while true do
  662. e, a, b, c = love.event.wait()
  663. if e == "q" then
  664. return
  665. end
  666. if e == "kp" and a == "escape" then
  667. return
  668. end
  669. draw()
  670. end
  671. end
  672. -----------------------------------------------------------
  673. -- The root of all calls.
  674. -----------------------------------------------------------
  675. local result = xpcall(love.boot, error_printer)
  676. if not result then return end
  677. local result = xpcall(love.init, love.errhand)
  678. if not result then return end
  679. local result = xpcall(love.run, love.errhand)
  680. if not result then return end