game.lua 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. Game = class()
  2. function Game:load(user, options, info)
  3. self.options = options
  4. if self.options.textureSmoothing then
  5. data.media.graphics.juju:setMipmapFilter('linear', 1)
  6. data.media.graphics.map.forest:setMipmapFilter('linear', 1)
  7. data.media.graphics.map.forestSpirit:setMipmapFilter('linear', 1)
  8. data.media.graphics.atlas.hud:setMipmapFilter('linear', 1)
  9. data.media.graphics.hud.population:setMipmapFilter('linear', 1)
  10. data.media.graphics.hud.clockBlue:setMipmapFilter('linear', 1)
  11. data.media.graphics.hud.clockBronze:setMipmapFilter('linear', 1)
  12. data.media.graphics.hud.clockSilver:setMipmapFilter('linear', 1)
  13. data.media.graphics.hud.clockGold:setMipmapFilter('linear', 1)
  14. end
  15. self.user = user
  16. self.id = 1
  17. self.mode = info.mode
  18. self.biome = info.biome
  19. self.paused = false
  20. self.ded = false
  21. self.timer = 0
  22. self.event = Event()
  23. self.view = View()
  24. self.map = Map()
  25. self.players = Players()
  26. self.player = ctx.players:add(1)
  27. self.shrujus = Shrujus()
  28. self.hud = Hud()
  29. self.upgrades = Upgrades
  30. self.shrines = Manager()
  31. self.shrine = self.shrines:add(Shrine, {x = ctx.map.width / 2, team = 1})
  32. self.units = Units()
  33. self.spells = Spells()
  34. self.particles = Particles()
  35. self.target = Target()
  36. self.sound = Sound(self.options)
  37. self.effects = Effects()
  38. self.jujus = Jujus()
  39. self.achievements = Achievements(self.user)
  40. self.tutorial = Tutorial(info.tutorial, info.destination)
  41. Upgrades.clear()
  42. self.event:on('shrine.dead', function(data)
  43. self.youlose = ctx.sound:play('youlose')
  44. ctx.sound:play('death')
  45. self.ded = true
  46. self:distribute()
  47. end)
  48. self.backgroundSound = self.sound:loop(self.biome)
  49. love.keyboard.setKeyRepeat(false)
  50. if self.options.mute then self.sound:mute() end
  51. for i = 1, 8 * 60 / ls.tickrate do
  52. self:update()
  53. ctx.units:each(function(unit)
  54. unit:hurt(1000000)
  55. end)
  56. end
  57. ctx.player:addJuju(1200)
  58. end
  59. function Game:update()
  60. if self.hud.upgrades.active or self.paused or self.ded then
  61. self.hud:update()
  62. if self.ded and self.effects:get('deathblur') then self.effects:get('deathblur'):update() end
  63. self.players:paused()
  64. self.units:paused()
  65. self.spells:paused()
  66. self.particles:update()
  67. self.tutorial:update()
  68. return
  69. end
  70. self.timer = self.timer + 1
  71. ls.framerate = self.options.powersave and (love.system.getPowerInfo() == 'battery' and 30 or 60) or -1
  72. self.players:update()
  73. self.units:update()
  74. self.shrines:update()
  75. self.jujus:update()
  76. self.spells:update()
  77. self.map:update()
  78. self.view:update()
  79. self.hud:update()
  80. self.effects:update()
  81. self.shrujus:update()
  82. self.tutorial:update()
  83. end
  84. function Game:unload()
  85. self.backgroundSound:stop()
  86. if self.youlose then self.youlose:stop() end
  87. end
  88. function Game:draw()
  89. self.view:draw()
  90. end
  91. function Game:resize()
  92. self.hud:resize()
  93. self.view:resize()
  94. self.effects:resize()
  95. end
  96. function Game:keypressed(key)
  97. if not self.ded then
  98. if key == 'p' or (key == 'escape' and not self.hud:menuActive()) then self.paused = not self.paused
  99. elseif key == 'm' then
  100. -- self.options.mute = not self.options.mute
  101. self.sound:mute()
  102. end
  103. end
  104. self.hud:keypressed(key)
  105. self.players:keypressed(key)
  106. self.tutorial:keypressed(key)
  107. end
  108. function Game:keyreleased(...)
  109. self.hud:keyreleased(...)
  110. end
  111. function Game:mousepressed(...)
  112. self.hud:mousepressed(...)
  113. end
  114. function Game:mousereleased(...)
  115. self.hud:mousereleased(...)
  116. end
  117. function Game:mousemoved(...)
  118. self.hud:mousemoved(...)
  119. end
  120. function Game:gamepadpressed(gamepad, button)
  121. print('Game:gamepadpressed', gamepad, button)
  122. if button == 'start' or button == 'guide' then self.paused = not self.paused end
  123. self.hud:gamepadpressed(gamepad, button)
  124. self.players:gamepadpressed(gamepad, button)
  125. end
  126. function Game:gamepadaxis(...)
  127. self.players:gamepadaxis(...)
  128. end
  129. function Game:distribute()
  130. local function tableRandom(t)
  131. return t[love.math.random(1, #t)]
  132. end
  133. -- So the hud can draw them
  134. self.rewards = {runes = {}, medals = {}, minions = {}, hats = {}, highscore = false}
  135. local time = math.floor(self.timer * ls.tickrate)
  136. if self.mode == 'campaign' then
  137. local bronze = time >= config.medals.bronze
  138. local silver = time >= config.medals.silver
  139. local gold = time >= config.medals.gold
  140. -- Distribute medals
  141. if bronze and not ctx.user.campaign.medals[self.biome].bronze then
  142. table.insert(self.rewards.medals, 'bronze')
  143. self.user.campaign.medals[self.biome].bronze = true
  144. end
  145. if silver and not ctx.user.campaign.medals[self.biome].silver then
  146. local nextMinions = {forest = 'xuju', cavern = 'kuju', tundra = 'thuju'}
  147. if nextMinions[self.biome] then
  148. table.insert(self.rewards.minions, nextMinions[self.biome])
  149. end
  150. table.insert(self.rewards.medals, 'silver')
  151. self.user.campaign.medals[self.biome].silver = true
  152. end
  153. if gold and not ctx.user.campaign.medals[self.biome].gold then
  154. table.insert(self.rewards.medals, 'gold')
  155. self.user.campaign.medals[self.biome].gold = true
  156. local hatPool = table.copy(config.hats)
  157. for i = 1, #config.hats do
  158. local index = love.math.random(1, #hatPool)
  159. if table.has(self.user.hats, hatPool[index]) then
  160. table.remove(hatPool, i)
  161. else
  162. local hat = hatPool[index]
  163. table.insert(self.rewards.hats, hat)
  164. table.insert(self.user.hats, hat)
  165. self.user.campaign.hatHistory[self.biome] = hat
  166. break
  167. end
  168. if #hatPool == 0 then break end
  169. end
  170. end
  171. -- Distribute runes
  172. local runeCount = 0
  173. if bronze then runeCount = runeCount + 1 end
  174. if silver and love.math.random() < .3 then runeCount = runeCount + 1 end
  175. if gold and love.math.random() < .2 then runeCount = runeCount + 1 end
  176. for i = 1, runeCount do
  177. -- Basics
  178. local rune = {}
  179. local maxLevel = config.runes.maxLevels[self.biome]
  180. local mu = 0
  181. if gold then mu = maxLevel
  182. elseif silver then mu = maxLevel * .8
  183. elseif bronze then mu = maxLevel * .5 end
  184. local runeLevel = math.clamp(love.math.randomNormal(10, mu), 1, 100)
  185. -- Generate prefix
  186. local prefixes = config.runes.prefixes
  187. local prefixLevel = math.clamp(runeLevel + love.math.random(-4, 4), 0, 100)
  188. local prefix = prefixes[1 + math.round((prefixLevel / 100) * (#prefixes - 1))]
  189. rune.name = prefix .. ' Rune'
  190. -- Generate bonuses
  191. local r = love.math.random()
  192. if r < .33 then
  193. -- Attributes
  194. rune.attributes = {}
  195. local attribute = tableRandom(config.attributes.list)
  196. local attributeLevels = math.max(math.round((runeLevel / 100) * 8), 1)
  197. local attributeLevelsDistributed = 0
  198. local attributesDistributed = {attribute}
  199. while attributeLevelsDistributed < attributeLevels do
  200. local amount = love.math.random(1, attributeLevels - attributeLevelsDistributed)
  201. rune.attributes[attribute] = (rune.attributes[attribute] or 0) + amount
  202. attributeLevelsDistributed = attributeLevelsDistributed + amount
  203. if #attributesDistributed < 2 and love.math.random() < .4 then
  204. attribute = tableRandom(config.attributes.list)
  205. if not table.has(attributesDistributed, attribute) then
  206. table.insert(attributesDistributed, attribute)
  207. end
  208. end
  209. end
  210. table.sort(attributesDistributed)
  211. rune.name = rune.name .. ' of ' .. tableRandom(config.runes.suffixes.attributes[table.concat(attributesDistributed)])
  212. elseif r < .67 then
  213. -- Stat bonuses
  214. local stats = config.runes.stats
  215. local stat = stats[love.math.random(1, #stats)]
  216. local min, max = unpack(config.runes.statRanges[stat])
  217. local mu, sigma = math.lerp(min, max, runeLevel / 100), (max - min) / 10
  218. local amount = math.clamp(love.math.randomNormal(sigma, mu), min, max)
  219. rune.stats = {[stat] = amount}
  220. rune.name = rune.name .. ' of ' .. tableRandom(config.runes.suffixes.stats[stat])
  221. else
  222. -- Ability bonuses
  223. local unit = tableRandom(table.keys(config.runes.abilities))
  224. if self.mode == 'campaign' and love.math.random() < .5 then unit = config.biomes[ctx.biome].minion end
  225. local ability = tableRandom(table.keys(config.runes.abilities[unit]))
  226. local stat = tableRandom(table.keys(config.runes.abilities[unit][ability]))
  227. local min, max = unpack(config.runes.abilities[unit][ability][stat])
  228. local mu, sigma = math.lerp(min, max, runeLevel / 100), (max - min) / 10
  229. local amount = math.clamp(love.math.randomNormal(sigma, mu), min, max)
  230. rune.unit = unit
  231. rune.abilities = {[ability] = {[stat] = amount}}
  232. rune.name = rune.name .. ' of ' .. tableRandom(config.runes.suffixes.abilities[ability])
  233. end
  234. -- Generate appearance
  235. rune.color = tableRandom(table.keys(config.runes.colors))
  236. rune.image = love.math.random(1, config.runes.imageCount)
  237. rune.background = runeLevel < 30 and 'broken' or 'normal'
  238. -- Add to account
  239. if table.count(ctx.user.runes.stash) < 32 then
  240. for i = 1, 32 do
  241. if not self.user.runes.stash[i] then
  242. self.user.runes.stash[i] = rune
  243. table.insert(self.rewards.runes, rune)
  244. break
  245. end
  246. end
  247. end
  248. end
  249. end
  250. -- Calculate highscores
  251. if self.mode == 'survival' and time > self.user.survival.bestTime then
  252. self.user.survival.bestTime = time
  253. self.rewards.highscore = true
  254. end
  255. saveUser(self.user)
  256. end