menumap.lua 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. local g = love.graphics
  2. local tween = require 'lib/deps/tween/tween'
  3. MenuMap = class()
  4. function MenuMap:init()
  5. self.geometry = setmetatable({}, {__index = function(t, k)
  6. return rawset(t, k, self.geometryFunctions[k]())[k]
  7. end})
  8. self.geometryFunctions = {
  9. frame = function()
  10. local u, v = ctx.u, ctx.v
  11. local factor = self.factor
  12. local width = math.lerp(.95 * u, .98 * u, factor ^ 4)
  13. local height = width * (v / u)
  14. local x = math.lerp(u * .5, u * .5, factor)
  15. local y = math.lerp(-(height * .4), v * .5, factor)
  16. return {x - width / 2, y - height / 2, width, height}
  17. end,
  18. forest = function()
  19. local x, y, w, h = unpack(self.geometry.frame)
  20. return {x + .327 * w, y + .814 * h, .025 * w}
  21. end,
  22. cavern = function()
  23. local x, y, w, h = unpack(self.geometry.frame)
  24. return {x + .566 * w, y + .791 * h, .025 * w}
  25. end,
  26. tundra = function()
  27. local x, y, w, h = unpack(self.geometry.frame)
  28. return {x + .632 * w, y + .435 * h, .025 * w}
  29. end,
  30. volcano = function()
  31. local x, y, w, h = unpack(self.geometry.frame)
  32. return {x + .253 * w, y + .435 * h, .025 * w}
  33. end,
  34. forestTitle = function()
  35. local x, y, w, h = unpack(self.geometry.frame)
  36. return {x + .23 * w, y + .64 * h}
  37. end,
  38. cavernTitle = function()
  39. local x, y, w, h = unpack(self.geometry.frame)
  40. return {x + .677 * w, y + .694 * h}
  41. end,
  42. tundraTitle = function()
  43. local x, y, w, h = unpack(self.geometry.frame)
  44. return {x + .793 * w, y + .269 * h}
  45. end,
  46. volcanoTitle = function()
  47. local x, y, w, h = unpack(self.geometry.frame)
  48. return {x + .18 * w, y + .18 * h}
  49. end,
  50. trail1 = function()
  51. local x, y, w, h = unpack(self.geometry.frame)
  52. return {x + .444 * w, y + .830 * h}
  53. end,
  54. trail2 = function()
  55. local x, y, w, h = unpack(self.geometry.frame)
  56. return {x + .782 * w, y + .509 * h}
  57. end,
  58. trail3 = function()
  59. local x, y, w, h = unpack(self.geometry.frame)
  60. return {x + .439 * w, y + .469 * h}
  61. end
  62. }
  63. self.active = false
  64. self.focused = true
  65. self.factor = 1
  66. self.tweenDuration = .6
  67. self.tweenMethod = 'outQuint'
  68. self.tween = tween.new(self.tweenDuration, self, {factor = 1}, self.tweenMethod)
  69. self.alpha = 0
  70. self.prevAlpha = self.alpha
  71. self.nudge = 0
  72. self.prevNudge = self.nudge
  73. self.hovers = {}
  74. self.prevHovers = {}
  75. self.dirtyHovers = {}
  76. end
  77. function MenuMap:update()
  78. if not self.active then return end
  79. local u, v = ctx.u, ctx.v
  80. local mx, my = love.mouse.getPosition()
  81. self.prevAlpha = self.alpha
  82. self.alpha = math.lerp(self.alpha, self.focused and 1 or 0, math.min(6 * ls.tickrate, 1))
  83. self.prevNudge = self.nudge
  84. self.nudge = math.lerp(self.nudge, my < .08 * v and 1 or 0, math.min(6 * ls.tickrate, 1))
  85. if self.focused then self.nudge = 0 end
  86. for k, biome in ipairs(config.biomeOrder) do
  87. local hover = math.inside(mx, my, self:getHitbox(biome))
  88. self.prevHovers[biome] = self.hovers[biome] or 0
  89. self.hovers[biome] = math.lerp(self.hovers[biome] or 0, (not self:isLocked(biome) and hover) and 1 or 0, math.min(10 * ls.tickrate, 1))
  90. if not hover then
  91. self.dirtyHovers[biome] = false
  92. elseif not self.dirtyHovers[biome] and not self:isLocked(biome) then
  93. ctx.sound:play('juju1', function(sound) sound:setPitch(.75) end)
  94. self.dirtyHovers[biome] = true
  95. end
  96. end
  97. end
  98. function MenuMap:draw()
  99. if not self.active then return end
  100. self.tween:update(ls.dt)
  101. local u, v = ctx.u, ctx.v
  102. local mx, my = love.mouse.getPosition()
  103. if self.tween.clock < self.tweenDuration then
  104. table.clear(self.geometry)
  105. end
  106. local alpha = math.lerp(self.prevAlpha, self.alpha, ls.accum / ls.tickrate)
  107. g.setColor(0, 0, 0, 80 * alpha)
  108. g.rectangle('fill', 0, 0, u, v)
  109. local x, y, w, h = unpack(self.geometry.frame)
  110. local image = data.media.graphics.worldmap.background
  111. local xscale = w / image:getWidth()
  112. local yscale = h / image:getHeight()
  113. local nudge = math.lerp(self.prevNudge, self.nudge, ls.accum / ls.tickrate)
  114. g.setColor(255, 255, 255)
  115. y = y + nudge * .1 * v
  116. g.draw(image, x, y, 0, xscale, yscale)
  117. for k, biome in ipairs(config.biomeOrder) do
  118. local factor = math.lerp(self.prevHovers[biome] or 0, self.hovers[biome] or 0, ls.accum / ls.tickrate)
  119. local hover = math.inside(mx, my, self:getHitbox(biome))
  120. local active = hover and love.mouse.isDown('l')
  121. if k >= 2 then
  122. local x, y = unpack(self.geometry['trail' .. (k - 1)])
  123. local image = data.media.graphics.worldmap['trail' .. (k - 1)]
  124. g.setColor(255, 255, 255)
  125. g.draw(image, x, y, 0, xscale, yscale, image:getWidth() / 2, image:getHeight() / 2)
  126. end
  127. if not self:isLocked(biome) then
  128. local x, y, r = unpack(self.geometry[biome])
  129. local image = data.media.graphics.worldmap.circle
  130. local scale = r * 2 / image:getWidth()
  131. if active then y = y + 2 end
  132. scale = scale * (.7 + .2 * factor)
  133. g.setColor(255, 255, 255)
  134. g.draw(image, x, y, 0, scale, scale, image:getWidth() / 2, image:getHeight() / 2)
  135. end
  136. local image = data.media.graphics.worldmap[biome]
  137. local x, y = unpack(self.geometry[biome .. 'Title'])
  138. local xscale, yscale = xscale * (1 + .1 * factor), yscale * (1 + .1 * factor)
  139. g.setColor(255, 255, 255)
  140. g.draw(image, x, y, 0, xscale, yscale, image:getWidth() / 2, image:getHeight() / 2)
  141. g.setBlendMode('additive')
  142. g.setColor(255, 255, 255, 50 * factor)
  143. g.draw(image, x + 2 * factor, y + 2 * factor, 0, xscale, yscale, image:getWidth() / 2, image:getHeight() / 2)
  144. g.setBlendMode('alpha')
  145. local x, y, r = unpack(self.geometry[biome])
  146. g.setColor(255, 255, 255)
  147. if not self:isLocked(biome) then
  148. local standard = ''
  149. for _, medal in ipairs({'bronze', 'silver', 'gold'}) do
  150. if ctx.user.campaign.medals[biome][medal] then
  151. standard = medal
  152. end
  153. end
  154. local image = data.media.graphics.worldmap[standard .. 'standard']
  155. local scale = .15 * v / image:getHeight()
  156. if active then y = y + 2 end
  157. scale = scale * (1 + .2 * factor)
  158. g.draw(image, x, y, 0, scale, scale, image:getWidth() / 2, image:getHeight())
  159. else
  160. local image = data.media.graphics.menu.lock
  161. local scale = .08 * v / image:getHeight()
  162. g.draw(image, x, y - .02 * v, 0, scale, scale, image:getWidth() / 2, image:getHeight() / 2)
  163. end
  164. end
  165. end
  166. function MenuMap:keyreleased(key)
  167. if key == 'escape' and self.focused then
  168. ctx:setPage('start')
  169. return true
  170. end
  171. end
  172. function MenuMap:mousereleased(mx, my, b)
  173. if b ~= 'l' then return end
  174. local u, v = ctx.u, ctx.v
  175. for k, v in ipairs(config.biomeOrder) do
  176. if not self:isLocked(v) and math.inside(mx, my, self:getHitbox(v)) then
  177. ctx.campaign:setBiome(v)
  178. self:setFocus(false)
  179. ctx.sound:play('juju1', function(sound) sound:setPitch(1) end)
  180. return
  181. end
  182. end
  183. if my < .08 * v and not self.focused then
  184. self:setFocus(true)
  185. end
  186. end
  187. function MenuMap:resize()
  188. table.clear(self.geometry)
  189. end
  190. function MenuMap:toggle()
  191. if self.tween.clock < self.tweenDuration then return end
  192. if self.focused then
  193. self.tween = tween.new(self.tweenDuration, self, {factor = 0}, self.tweenMethod)
  194. else
  195. self.tween = tween.new(self.tweenDuration, self, {factor = 1}, self.tweenMethod)
  196. end
  197. self.focused = not self.focused
  198. end
  199. function MenuMap:setFocus(focused)
  200. if focused ~= self.focused then self:toggle() end
  201. end
  202. function MenuMap:isLocked(biome)
  203. if biome == 'forest' then return false end
  204. local prevs = {
  205. cavern = 'forest',
  206. tundra = 'cavern',
  207. volcano = 'tundra'
  208. }
  209. return not ctx.user.campaign.medals[prevs[biome]].silver
  210. end
  211. function MenuMap:getHitbox(biome)
  212. local u, v = ctx.u, ctx.v
  213. local x, y = unpack(self.geometry[biome])
  214. local w, h = .1 * v, .2 * v
  215. return x - w / 2, y - h + .02 * v, w, h
  216. end