main.lua 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. --[========================================================================[--
  2. Main file for Thrust II Reloaded.
  3. Copyright © 2015 Pedro Gimeno Fortea
  4. Permission is hereby granted, free of charge, to any person obtaining a copy
  5. of this software and associated documentation files (the "Software"), to deal
  6. in the Software without restriction, including without limitation the rights
  7. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the Software is
  9. furnished to do so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in
  11. all copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18. SOFTWARE.
  19. --]========================================================================]--
  20. require('lovespaces')
  21. local volscale = 40
  22. local volgrabbed = false
  23. main = {}
  24. local active, canvas
  25. function main.activate(new)
  26. if active and active.deactivate then active.deactivate() end
  27. active = new
  28. if active.activate then active.activate() end
  29. end
  30. -- screens
  31. splash = require('splash')
  32. menu = require('menu')
  33. redef = require('redef')
  34. ready = require('getready')
  35. game = require('game')
  36. gameover = require('gameover')
  37. -- modules that are not screens
  38. main.map,
  39. main.enemytypes,
  40. main.enemies,
  41. main.orbs,
  42. main.decoys,
  43. main.targets,
  44. main.respawn,
  45. main.agents = require 'layout' ()
  46. local mods_to_init = { splash, menu, redef, ready, game, gameover }
  47. local function volume(vol, save)
  48. vol = (vol < 0) and 0 or vol
  49. vol = (vol > 1) and 1 or vol
  50. la.setVolume(vol^2)
  51. main.vol = vol
  52. if save then
  53. local tmp = main.vol .. ""
  54. lfs.write("vol.txt", tmp, #tmp)
  55. end
  56. end
  57. -- deepcopy from http://lua-users.org/wiki/CopyTable
  58. -- minus the parts that we don't need
  59. function main.deepcopy(orig)
  60. local orig_type = type(orig)
  61. local copy
  62. if orig_type == 'table' then
  63. copy = {}
  64. for orig_key, orig_value in next, orig, nil do
  65. -- copy[deepcopy(orig_key)] = deepcopy(orig_value)
  66. copy[orig_key] = main.deepcopy(orig_value)
  67. end
  68. -- setmetatable(copy, deepcopy(getmetatable(orig)))
  69. else -- number, string, boolean, etc
  70. copy = orig
  71. end
  72. return copy
  73. end
  74. function love.load(args)
  75. argv = args
  76. if not lg.isSupported("canvas") then
  77. error("This application requires canvas support. Unfortunately your graphics card does not support it.")
  78. end
  79. lfs.setIdentity("ThrustIIreloaded")
  80. main.ww, main.wh = lw.getDimensions()
  81. canvas = lg.newCanvas(main.ww, main.wh)
  82. main.font = lg.newImageFont("img/Font16x16.png",
  83. " !\"#$%&'()*+,-./0123456789:;<=>?\127ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~@")
  84. lg.setFont(main.font)
  85. main.keys =
  86. { left = "q", right = "w", thrust = "p", pickup = "l", fire = " " }
  87. if lfs.isFile("keys.txt") then
  88. local line = 0
  89. for s in lfs.lines("keys.txt") do
  90. line = line + 1
  91. if line == 1 then
  92. main.keys.left = s
  93. elseif line == 2 then
  94. main.keys.right = s
  95. elseif line == 3 then
  96. main.keys.thrust = s
  97. elseif line == 4 then
  98. main.keys.pickup = s
  99. elseif line == 5 then
  100. main.keys.fire = s
  101. else
  102. break
  103. end
  104. end
  105. else
  106. local s = main.keys.left .. "\n"
  107. .. main.keys.right .. "\n"
  108. .. main.keys.thrust .. "\n"
  109. .. main.keys.pickup .. "\n"
  110. .. main.keys.fire
  111. lfs.write("keys.txt", s, #s)
  112. end
  113. main.vol = 0.5
  114. if lfs.isFile("vol.txt") then
  115. local tmp
  116. main.vol, tmp = lfs.read("vol.txt")
  117. volume(main.vol + 0)
  118. else
  119. volume(main.vol, true)
  120. end
  121. for i, mod in ipairs(mods_to_init) do
  122. if mod and mod.load then mod.load(arg) end
  123. end
  124. mods_to_init = nil
  125. -- Bootstrap activation
  126. main.activate(splash)
  127. -- Allow volume change with auto-repeat
  128. lk.setKeyRepeat(true)
  129. -- Used to end quit status on key release. Otherwise the key up event
  130. -- that led to releasing the quit status is registered.
  131. main.dontquit = false
  132. main.unpause = false
  133. main.singlestep = false
  134. end
  135. function love.update(dt)
  136. if volgrabbed then
  137. volume((lmo.getX() - (main.ww/2 + 108)) / volscale)
  138. end
  139. if main.paused and not main.singlestep or main.quitrequest then return end
  140. if active.update then active.update(main.singlestep and 0.03125 or dt) end
  141. end
  142. local function roundrect(x, y, w, h, r)
  143. lg.setStencil(
  144. function()
  145. lg.rectangle("fill", x, y+r, w, h-2*r)
  146. lg.rectangle("fill", x+r, y, w-2*r, h)
  147. lg.circle("fill", x+r, y+r, r, 10)
  148. lg.circle("fill", x+w-r, y+r, r, 10)
  149. lg.circle("fill", x+r, y+h-r, r, 10)
  150. lg.circle("fill", x+w-r, y+h-r, r, 10)
  151. end
  152. )
  153. lg.rectangle("fill", x, y, w, h)
  154. lg.setStencil()
  155. end
  156. function main.centertext(text, x, y)
  157. lg.print(text, x-main.font:getWidth(text)/2, y-main.font:getHeight()/2)
  158. end
  159. function love.draw()
  160. if main.quitrequest then
  161. lg.setColor(85, 85, 85, 255)
  162. lg.rectangle("fill", 0, 0, main.ww, main.wh)
  163. lg.setColor(255, 255, 255, 120)
  164. lg.draw(canvas, 0, 0)
  165. lg.setColor(0, 0, 0, 200)
  166. roundrect(main.ww/2-130, main.wh/2-50, 260, 100, 7)
  167. lg.setColor(255, 255, 255, 255)
  168. main.centertext("REALLY QUIT?", main.ww/2, main.wh/2 - 20)
  169. lg.setColor(160, 240, 200)
  170. roundrect(main.ww/2-70, main.wh/2+4, 60, 24, 4)
  171. lg.setColor(240, 200, 160)
  172. roundrect(main.ww/2+10, main.wh/2+4, 60, 24, 4)
  173. lg.setColor(0, 0, 0, 255)
  174. main.centertext("YES", main.ww/2-40, main.wh/2+16)
  175. main.centertext("NO", main.ww/2+40, main.wh/2+16)
  176. lg.setColor(255, 255, 255, 255)
  177. else
  178. lg.setColor(255, 255, 255, 255)
  179. if main.paused and not main.singlestep then
  180. lg.draw(canvas, 0, 0)
  181. lg.setColor(64, 64, 64, 150)
  182. roundrect(main.ww/2-60, main.wh-44, 120, 40, 10)
  183. lg.setColor(255, 255, 255, 255)
  184. main.centertext("PAUSED", main.ww/2, main.wh - 24)
  185. else
  186. canvas:clear()
  187. if active.draw then canvas:renderTo(active.draw) end
  188. lg.draw(canvas, 0, 0)
  189. end
  190. end
  191. -- volume control
  192. local half = main.ww/2
  193. local volx = main.vol*volscale
  194. lg.setInvertedStencil(function()
  195. lg.setColor(255,255,255,255)
  196. lg.rectangle("fill", half + 103 + volx, main.wh-32, 10, 24)
  197. end)
  198. lg.setColor(0,0,0, 40)
  199. lg.polygon("fill", half + 92, main.wh - 11,
  200. half + 155, main.wh - 11,
  201. half + 155, main.wh - 29)
  202. lg.setColor(255, 255, 255, 60)
  203. lg.polygon("fill", half + 100, main.wh - 12,
  204. half + 154, main.wh - 12,
  205. half + 154, main.wh - 28)
  206. lg.setStencil()
  207. lg.setColor(0, 0, 0, 40)
  208. lg.rectangle("fill", half + 103 + volx, main.wh-32, 10, 24)
  209. lg.setColor(255, 255, 255, 70)
  210. lg.rectangle("fill", half + 104 + volx, main.wh-31, 8, 22)
  211. lg.setColor(255, 255, 255)
  212. if main.singlestep then main.singlestep = false end
  213. end
  214. function love.quit()
  215. if not main.quitaccepted then
  216. main.quitrequest = true
  217. main.dontquit = false
  218. if not main.paused and active.pause then active.pause(true) end
  219. return true -- don't quit
  220. end
  221. end
  222. function love.mousepressed(x, y, b)
  223. if main.quitrequest then
  224. if x >= main.ww/2-70 and x <= main.ww/2-10
  225. and y >= main.wh/2+4 and y <= main.wh/2+28
  226. then
  227. main.quitaccepted = true
  228. le.quit()
  229. elseif x >= main.ww/2+10 and x <= main.ww/2+70
  230. and y >= main.wh/2+4 and y <= main.wh/2+28
  231. then
  232. main.quitrequest = false
  233. if not main.paused and active.pause then active.pause(false) end
  234. end
  235. end
  236. if y >= main.wh-32 and y <= main.wh-8
  237. and x >= main.ww/2 + 104 + main.vol*volscale
  238. and x <= main.ww/2 + 112 + main.vol*volscale
  239. then
  240. lmo.setGrabbed(true)
  241. volgrabbed = true
  242. volume((x - (main.ww/2 + 108)) / volscale)
  243. end
  244. end
  245. --[[ (not in 0.9.1 - handled in love.update())
  246. function love.mousemoved(x, y, dx, dy)
  247. if volgrabbed then
  248. volume((x - (main.ww/2 + 108)) / volscale)
  249. end
  250. end
  251. ]]
  252. function love.mousereleased(x, y, b)
  253. if volgrabbed then
  254. lmo.setGrabbed(false)
  255. volgrabbed = false
  256. volume((x - (main.ww/2 + 108)) / volscale, true)
  257. end
  258. end
  259. function love.keypressed(k, r)
  260. if k == "kp-" or k == "kp+" then
  261. volume(main.vol + (k == "kp+" and 0.0625 or -0.0625), true)
  262. elseif r then
  263. -- nothing
  264. elseif main.quitrequest then
  265. if k == "escape" then
  266. main.dontquit = true
  267. end
  268. elseif k == "escape" then
  269. le.quit()
  270. elseif k == "pause" and not main.quitrequest and
  271. -- ctrl + pause = break, that breaks the game and must be passed down
  272. not (lk.isDown("lctrl") or lk.isDown("rctrl") or lk.isDown("ctrl"))
  273. then
  274. main.paused = not main.paused
  275. if active.pause then active.pause(main.paused) end
  276. elseif active.keypressed then
  277. active.keypressed(k, r)
  278. end
  279. --[[ debug ]]
  280. --if k == "1" and main.paused then main.singlestep = true end
  281. --]]
  282. end
  283. function love.textinput(c)
  284. if main.quitrequest then
  285. if c:lower() == "y" then
  286. main.quitaccepted = true
  287. le.quit()
  288. elseif c:lower() == "n" then
  289. main.dontquit = true
  290. end
  291. return
  292. end
  293. if active.textinput then active.textinput(c) end
  294. end
  295. function love.keyreleased(k)
  296. if main.quitrequest then
  297. if main.dontquit then
  298. main.dontquit = false
  299. main.quitrequest = false
  300. if not main.paused and active.pause then active.pause(false) end
  301. end
  302. elseif k ~= "pause" then
  303. if active.keyreleased then active.keyreleased(k) end
  304. end
  305. end