goblin.lua 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. Goblin = class()
  2. function Goblin:init(x, y)
  3. self.x = x
  4. self.y = y
  5. self.state = 'idle'
  6. self.heardX = 0
  7. self.heardY = 0
  8. self.fightTarget = nil
  9. self.dead = false -- TODO: Should this be a state?
  10. self.killsPlayer = true
  11. end
  12. function Goblin:update(world)
  13. -- Goblins are EXTREMELY SMART and have two ranges of sensing the player:
  14. -- Within 8 units of distance, they HEAR a player, and walk closer...
  15. -- Within 5 units of distance, they SEE a player (or are sure of where they
  16. -- are) and become angered, setting the player as their agro-target.
  17. -- States:
  18. -- Idle - will hang around picking its nails.
  19. -- Suspicious - will walk to the last point it heard something.
  20. -- Goblins are lazy so it won't do much extra searching - once it gets
  21. -- to the place it heard the potential threat, it'll go back to idling
  22. -- there, figuring that it'll hear if the threat comes back.
  23. -- Fight - will walk towards the threat to eat it.
  24. -- The goblin will ALWAYS prioritize chasing over checking out something
  25. -- suspicious, so if it sees a player it'll go and chase them right away.
  26. if self.state == 'idle' or self.state == 'suspicious' then
  27. local seePlayer = self:findPlayer(world, 5)
  28. if seePlayer ~= nil then
  29. self.fightTarget = seePlayer
  30. self.state = 'fight'
  31. end
  32. end
  33. if self.state == 'fight' then
  34. if distanceBetweenPoints(self, self.fightTarget) > 8 then
  35. self.fightTarget = nil
  36. self.state = 'idle'
  37. else
  38. self:walkTowards(world, self.fightTarget.x, self.fightTarget.y)
  39. end
  40. end
  41. if self.state == 'idle' or self.state == 'suspicious' then
  42. local hearPlayer = self:findPlayer(world, 8)
  43. if hearPlayer ~= nil then
  44. self.heardX = hearPlayer.x
  45. self.heardY = hearPlayer.y
  46. self.state = 'suspicious'
  47. end
  48. end
  49. if self.state == 'suspicious' then
  50. -- If we bump into a wall, forget what we were doing and stop
  51. -- searching for the player.
  52. if not self:walkTowards(world, self.heardX, self.heardY) then
  53. self.heardX = 0
  54. self.heardY = 0
  55. self.state = 'idle'
  56. end
  57. end
  58. local hearPlayer = self:findPlayer(world, 8)
  59. local seePlayer = self:findPlayer(world, 5)
  60. if self.agroTarget == nil and seePlayer ~= nil then
  61. self.agroTarget = seePlayer
  62. end
  63. if self.pattern ~= nil then
  64. self.pattern:update(world)
  65. if self.pattern.done then
  66. self.pattern = nil
  67. end
  68. end
  69. self:testDead(world)
  70. end
  71. function Goblin:testDead(world)
  72. -- defined in player.lua, should be moved maybe
  73. if testColl(world.bullets, self.x, self.y) then
  74. self.dead = true
  75. end
  76. end
  77. function Goblin:findPlayer(world, distance)
  78. if distanceBetweenPoints(self, world.player) <= distance then
  79. return world.player
  80. else
  81. return nil
  82. end
  83. end
  84. function Goblin:walkTowards(world, x, y)
  85. -- Occasionally stumble!
  86. if love.math.random(1, 6) == 1 then
  87. return true -- true so we don't quit the suspicious state.
  88. end
  89. -- Go either horizontal or vertical, prioritizing the further distance or
  90. -- horizontal if they are equal. If we bump into a wall while moving hori-
  91. -- zontally, try moving vertically.
  92. local success = false
  93. function horizontal()
  94. return goToWithoutTouchingAnything(self, world,
  95. self.x + sign(x - self.x), self.y
  96. )
  97. end
  98. if math.abs(self.x - x) > math.abs(self.y - y) then
  99. success = horizontal()
  100. end
  101. if not success then
  102. success = goToWithoutTouchingAnything(self, world,
  103. self.x, self.y + sign(y - self.y)
  104. )
  105. end
  106. if not success then
  107. success = horizontal()
  108. end
  109. return success
  110. end
  111. function Goblin:draw(text)
  112. text[self.y][self.x] = {
  113. char = 'G',
  114. color = ({idle=COLOR.WHITE, suspicious=COLOR.YELLOW, fight=COLOR.RED})[self.state]
  115. }
  116. end