player.lua 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. Player = class()
  2. Player.width = 45
  3. Player.height = 90
  4. Player.walkSpeed = 65
  5. Player.maxHealth = 100
  6. Player.depth = -10
  7. function Player:init()
  8. self.health = 100
  9. self.healthDisplay = self.health
  10. self.x = love.graphics.getWidth() / 2
  11. self.y = love.graphics.getHeight() - ctx.environment.groundHeight - self.height
  12. self.prevx = self.x
  13. self.prevy = self.y
  14. self.speed = 0
  15. self.jujuRealm = 0
  16. self.juju = 30
  17. self.jujuTimer = 1
  18. self.dead = false
  19. self.minions = {Zuju}
  20. self.minioncds = {0}
  21. self.selectedMinion = 1
  22. self.recentSelect = 0
  23. self.direction = 1
  24. self.invincible = 0
  25. self.summonedMinions = 0
  26. self.hasMoved = false
  27. local joysticks = love.joystick.getJoysticks()
  28. for _, joystick in ipairs(joysticks) do
  29. if joystick:isGamepad() then self.gamepad = joystick break end
  30. end
  31. self.gamepadSelectDirty = false
  32. self.skeleton = Skeleton({name = 'muju', x = self.x, y = self.y, scale = .6})
  33. self.animator = Animator({
  34. skeleton = self.skeleton,
  35. mixes = {
  36. {from = 'idle', to = 'idle', time = .1},
  37. {from = 'walk', to = 'idle', time = .2},
  38. {from = 'idle', to = 'walk', time = .2},
  39. {from = 'walk', to = 'summon', time = .1},
  40. {from = 'summon', to = 'walk', time = .2},
  41. {from = 'idle', to = 'summon', time = .1},
  42. {from = 'summon', to = 'idle', time = .2},
  43. {from = 'death', to = 'resurrect', time = .2},
  44. {from = 'idle', to = 'death', time = .2},
  45. {from = 'walk', to = 'death', time = .2},
  46. {from = 'death', to = 'idle', time = .2}
  47. }
  48. })
  49. self.animationState = 'idle'
  50. self.animator:add(self.animationState, true)
  51. self.animator.state.onComplete = function(trackIndex)
  52. local name = self.animator.state:getCurrent(trackIndex).animation.name
  53. if name == 'summon' or name == 'death' or name == 'resurrect' then
  54. self.animationLock = nil
  55. end
  56. end
  57. self.animationSpeeds = table.map({
  58. walk = function() return tickRate * math.abs(self.speed / self.walkSpeed) end,
  59. idle = tickRate * .4,
  60. summon = tickRate * 1.85,
  61. resurrect = tickRate * 2,
  62. death = tickRate
  63. }, f.val)
  64. ctx.view:register(self)
  65. end
  66. function Player:update()
  67. self.prevx = self.x
  68. self.prevy = self.y
  69. if self.dead or self.animationState == 'summon' or self.animationState == 'death' or self.animationState == 'resurrect' then
  70. self.speed = 0
  71. else
  72. local maxSpeed = self.walkSpeed
  73. if self.gamepad and math.abs(self.gamepad:getGamepadAxis('leftx')) > .5 then
  74. maxSpeed = self.walkSpeed * math.abs(self.gamepad:getGamepadAxis('leftx'))
  75. end
  76. if love.keyboard.isDown('left', 'a') or (self.gamepad and self.gamepad:getGamepadAxis('leftx') < -.5) then
  77. self.speed = math.lerp(self.speed, -maxSpeed, math.min(10 * tickRate, 1))
  78. elseif love.keyboard.isDown('right', 'd') or (self.gamepad and self.gamepad:getGamepadAxis('leftx') > .5) then
  79. self.speed = math.lerp(self.speed, maxSpeed, math.min(10 * tickRate, 1))
  80. else
  81. self.speed = math.lerp(self.speed, 0, math.min(10 * tickRate, 1))
  82. end
  83. if self.speed ~= 0 then self.hasMoved = true end
  84. local delta = self.x + self.speed * tickRate
  85. self.x = self.x + self.speed * tickRate
  86. self.direction = self.speed == 0 and self.direction or math.sign(self.speed)
  87. -- Controller
  88. if self.gamepad then
  89. local ltrigger = self.gamepad:getGamepadAxis('triggerleft') > .5
  90. local rtrigger = self.gamepad:getGamepadAxis('triggerright') > .5
  91. if not self.gamepadSelectDirty then
  92. if rtrigger then self.selectedMinion = self.selectedMinion + 1 end
  93. if ltrigger then self.selectedMinion = self.selectedMinion - 1 end
  94. if ltrigger or rtrigger then self.recentSelect = 1 end
  95. if self.selectedMinion <= 0 then self.selectedMinion = #self.minions
  96. elseif self.selectedMinion > #self.minions then self.selectedMinion = 1 end
  97. end
  98. self.gamepadSelectDirty = rtrigger or ltrigger
  99. end
  100. end
  101. self.x = math.clamp(self.x, 0, love.graphics.getWidth())
  102. self.jujuRealm = timer.rot(self.jujuRealm, function()
  103. self.invincible = 2
  104. self.health = self.maxHealth
  105. self.dead = false
  106. self.ghost:despawn()
  107. self.ghost = nil
  108. self.animationState = 'resurrect'
  109. self.animationLock = true
  110. self.animator:set('resurrect', false)
  111. end)
  112. self.invincible = timer.rot(self.invincible)
  113. table.each(self.minioncds, function(cooldown, index)
  114. self.minioncds[index] = timer.rot(cooldown, function()
  115. ctx.hud.selectExtra[index] = 1
  116. end)
  117. end)
  118. if self.ghost then
  119. self.ghost:update()
  120. end
  121. self:hurt(self.maxHealth * .033 * tickRate)
  122. self.healthDisplay = math.lerp(self.healthDisplay, self.health, 20 * tickRate)
  123. self.jujuTimer = timer.rot(self.jujuTimer, function()
  124. self.juju = self.juju + 1
  125. return 1
  126. end)
  127. self.recentSelect = timer.rot(self.recentSelect)
  128. self:animate()
  129. end
  130. function Player:animate()
  131. if not self.animationLock and not self.dead then
  132. local old = self.animationState
  133. if self.animationState ~= 'walk' and math.abs(self.speed) > self.walkSpeed / 2 then
  134. self.animationState = 'walk'
  135. elseif self.animationState ~= 'idle' and math.abs(self.speed) <= self.walkSpeed / 2 then
  136. self.animationState = 'idle'
  137. end
  138. if old ~= self.animationState then
  139. self.animator:set(self.animationState, true)
  140. end
  141. end
  142. self.skeleton.skeleton.x = self.x
  143. self.skeleton.skeleton.y = self.y + self.height / 2
  144. if self.animationState == 'resurrect' then self.skeleton.skeleton.y = self.skeleton.skeleton.y - 16 end
  145. if self.speed ~= 0 then
  146. self.skeleton.skeleton.flipX = self.speed > 0
  147. end
  148. self.animator:update(self.animationSpeeds[self.animationState]())
  149. end
  150. function Player:spend(amount)
  151. -- Check if Muju is broke
  152. if self.juju >= amount then
  153. -- He's not broke!
  154. self.juju = self.juju - amount
  155. return true
  156. else
  157. -- He's broke!
  158. return false
  159. end
  160. end
  161. function Player:draw()
  162. if math.floor(self.invincible * 4) % 2 == 0 then
  163. love.graphics.setColor(255, 255, 255)
  164. self.animator:draw()
  165. end
  166. end
  167. function Player:cooldown()
  168. end
  169. function Player:summon()
  170. local minion = self.minions[self.selectedMinion]
  171. local cooldown = self.minioncds[self.selectedMinion]
  172. local cost = minion:getCost()
  173. if cooldown == 0 and self:spend(cost) then
  174. ctx.minions:add(minion, {x = self.x + love.math.random(-20, 20), direction = self.direction})
  175. self.minioncds[self.selectedMinion] = minion.cooldown * (1 - (.1 * ctx.upgrades.muju.flow.level))
  176. if ctx.upgrades.muju.refresh.level == 1 and love.math.random() < .15 then
  177. self.minioncds[self.selectedMinion] = 0
  178. end
  179. self.summonedMinions = self.summonedMinions + 1
  180. self.animationLock = true
  181. self.animationState = 'summon'
  182. self.animator:set('summon', false)
  183. local summonSound = love.math.random(1, 3)
  184. ctx.sound:play({sound = ctx.sounds['summon' .. summonSound]})
  185. end
  186. end
  187. function Player:hurt(amount, source)
  188. if self.invincible == 0 then
  189. self.health = math.max(self.health - amount, 0)
  190. if self.gamepad and self.gamepad:isVibrationSupported() then
  191. local l, r = .25, .25
  192. if source then
  193. if source.x > self.x then r = .5
  194. elseif source.x < self.x then l = .5 end
  195. end
  196. self.gamepad:setVibration(l, r, .25)
  197. end
  198. end
  199. -- Check whether or not to enter Juju Realm
  200. if self.health <= 0 and self.jujuRealm == 0 then
  201. -- We jujuin'
  202. self.jujuRealm = 7
  203. self.dead = true
  204. self.ghost = GhostPlayer()
  205. self.animationState = 'death'
  206. self.animationLock = true
  207. self.animator:set('death', false)
  208. ctx.sound:play({sound = ctx.sounds.death})
  209. if self.gamepad and self.gamepad:isVibrationSupported() then
  210. self.gamepad:setVibration(1, 1, .5)
  211. end
  212. return true
  213. end
  214. end
  215. function Player:keypressed(key)
  216. for i = 1, #self.minions do
  217. if tonumber(key) == i then
  218. self.selectedMinion = i
  219. self.recentSelect = 1
  220. return
  221. end
  222. end
  223. if key == ' ' and not self.dead then
  224. self:summon()
  225. end
  226. end
  227. function Player:gamepadpressed(gamepad, button)
  228. if gamepad == self.gamepad then
  229. if (button == 'a' or button == 'rightstick' or button == 'rightshoulder') and not self.dead then
  230. self:summon()
  231. end
  232. end
  233. end