goblin_rogues.lua 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. local function goblin_debug(obj)
  2. local pos = core.pos_to_string(obj.last_job)
  3. local formspec =
  4. 'formspec_version[7]'..
  5. 'size[12,8]'..
  6. 'background[-1,-1;14,10;lobby_button_bg.png]'..
  7. 'label[3,1;Goblin state: '..obj.state..'.]'..
  8. 'label[3,2;Goblin health: '..obj.health..'.]'..
  9. 'label[3,3;Goblin old pos: '..pos..'.]'..
  10. 'button_exit[6,4;4,1;exit;Exit]'
  11. return formspec
  12. end
  13. core.register_entity('kobo:goblin_rogue', {
  14. initial_properties = {
  15. visual = 'mesh',
  16. mesh = 'kobo_goblin.obj',
  17. visual_size = {x=10, y=10},
  18. physical = true,
  19. collide_with_objects = false,
  20. collisionbox = {-.125, -.5, -.125, .125, -.125, .125},
  21. textures = {'kobo_goblin_rogue.png'},
  22. automatic_face_movement_dir = 0.0,
  23. },
  24. on_activate = function(self, staticdata, dtime_s)
  25. local data = core.deserialize(staticdata)
  26. if data then
  27. self.node_timer = data.node_timer
  28. self.state = data.state
  29. self.path = data.path
  30. self.step = data.step
  31. self.last_job = data.last_job
  32. self.health = data.health
  33. self.wander_count = data.wander_count
  34. else
  35. self.last_job = self.object:get_pos()
  36. self.state = 'idle'
  37. self.step = 0
  38. self.health = 40
  39. self.wander_count = 0
  40. end
  41. local dir = vector.random_direction()
  42. local clean_dir = vector.multiply(dir, {x=1, y=0, z=1})
  43. self.object:set_velocity(clean_dir)
  44. self.last_job = self.object:get_pos()
  45. end,
  46. get_staticdata = function(self)
  47. local data = {}
  48. data.node_timer = self.node_timer
  49. data.state = self.state
  50. data.path = self.path
  51. data.step = self.step
  52. data.last_job = self.last_job
  53. data.health = self.health
  54. data.wander_count = self.wander_count
  55. return core.serialize(data)
  56. end,
  57. on_step = function(self, dtime, moveresults)
  58. self.node_timer = (self.node_timer or 0) + dtime
  59. if self.node_timer > 1 then
  60. self.node_timer = 0
  61. if self.state == 'idle' then --Find a building to ravage
  62. local self_pos = vector.add(self.object:get_pos(), {x=0, y=1, z=0})
  63. local player_building = core.find_node_near(self_pos, 25, 'group:player_building')
  64. if player_building then
  65. local looting_spot = core.find_node_near(player_building, 1, 'air', true)
  66. local path = core.find_path(self_pos, vector.add(looting_spot, {x=0, y=1, z=0}), 5, 1, 1)
  67. if path then
  68. self.path = path
  69. self.step = 2
  70. self.state = 'traveling'
  71. else --Make the unit wander around for a while.
  72. self.state = 'idle'
  73. end
  74. else --Didn't find a player building, look for a goblin base
  75. local self_pos = vector.add(self.object:get_pos(), {x=0, y=1, z=0})
  76. local goblin_base = core.find_node_near(self_pos, 25, 'kobo:goblin_base')
  77. if goblin_base then
  78. local home = core.find_node_near(goblin_base, 1, 'air', true)
  79. local path = core.find_path(self_pos, vector.add(home, {x=0, y=1, z=0}), 5, 1, 1)
  80. if path then
  81. self.path = path
  82. self.step = 2
  83. self.state = 'traveling'
  84. else --Make the unit wander around for a while.
  85. self.state = 'idle'
  86. end
  87. else
  88. local dir = vector.random_direction()
  89. local clean_dir = vector.multiply(dir, {x=1, y=0, z=1})
  90. self.object:set_velocity(clean_dir)
  91. self.state = 'wandering'
  92. self.last_job = self_pos
  93. end
  94. end
  95. elseif self.state == 'traveling' then
  96. if #self.path > (self.step - 1) then
  97. local pos = self.object:get_pos()
  98. local perhaps = vector.direction(pos, self.path[self.step])
  99. self.object:set_velocity({x = perhaps.x, y = 0, z = perhaps.z})
  100. self.step = self.step + 1
  101. else
  102. local self_pos = vector.round(self.object:get_pos())
  103. local building = core.find_node_near(self_pos, 1, 'group:player_building', true)
  104. local goblin_base = core.find_node_near(self_pos, 1, 'kobo:goblin_base', true)
  105. if building then
  106. self.object:set_velocity({x=0, y=0, z=0})
  107. self.state = 'working'
  108. self.last_job = building
  109. elseif goblin_base then
  110. local goblin_resources = kobo.goblins
  111. goblin_resources.food = goblin_resources.food + 25
  112. goblin_resources.lumber= goblin_resources.lumber + 5
  113. self.object:remove()
  114. else
  115. self.state = 'idle'
  116. end
  117. end
  118. elseif self.state == 'working' then
  119. self.wander_count = 0
  120. local pos = self.last_job
  121. local node = core.get_node(pos)
  122. if core.get_item_group(node.name, 'player_building') > 0 then
  123. local meta = core.get_meta(pos)
  124. local health = meta:get_int('health')
  125. if health > 1 then
  126. meta:set_int('health', health - 1)
  127. elseif health <= 1 then
  128. core.remove_node(pos)
  129. local goblin_resources = kobo.goblins
  130. goblin_resources.xp = goblin_resources.xp + 5
  131. self.state = 'idle'
  132. end
  133. end
  134. elseif self.state == 'wandering' then
  135. self.wander_count = self.wander_count or 1
  136. self.step = self.step + 1
  137. if self.step > 20 then
  138. self.state = 'idle'
  139. self.step = 0
  140. self.wander_count = self.wander_count + 1
  141. end
  142. local self_pos = self.object:get_pos()
  143. if vector.distance(self.last_job, self_pos) < .25 then
  144. self.state = 'idle'
  145. end
  146. if self.wander_count > 20 then
  147. self.object:remove()
  148. end
  149. end
  150. elseif moveresults.collides then
  151. local hit_node = moveresults.collisions[1] and moveresults.collisions[1].type == 'node'
  152. if hit_node then
  153. local node_pos = moveresults.collisions[1].node_pos
  154. local node = core.get_node(node_pos)
  155. if core.get_item_group(node.name, 'player_building') > 0 then
  156. self.state = 'working'
  157. self.object:set_velocity({x=0, y=0, z=0})
  158. self.last_job = node_pos
  159. elseif node.name == 'kobo:goblin_base' then
  160. local goblin_resources = kobo.goblins
  161. goblin_resources.food = goblin_resources.food + 25
  162. goblin_resources.lumber= goblin_resources.lumber + 5
  163. self.object:remove()
  164. else
  165. local yaw = self.object:get_yaw()
  166. local x_yaw_random = math.random()
  167. local z_yaw_random = math.random()
  168. local new_vel = {
  169. x = (math.sin(yaw + x_yaw_random) * -1),
  170. y = 0,
  171. z = (math.cos(yaw + z_yaw_random) * 1)
  172. }
  173. self.object:set_velocity(new_vel)
  174. self.state = 'idle'
  175. end
  176. end
  177. end
  178. end,
  179. on_punch = function(self, puncher)
  180. self.health = self.health - 1
  181. if self.health <= 0 then
  182. self.object:remove()
  183. end
  184. end,
  185. on_deactivate = function(self, removal)
  186. if removal then
  187. local pos = self.object:get_pos()
  188. local tombstone = minetest.add_entity(pos, 'kobo:goblin_tombstone')
  189. local tombstone_entity = tombstone:get_luaentity()
  190. tombstone_entity.node_timer = 0
  191. end
  192. end,
  193. on_rightclick = function(self, clicker)
  194. if core.check_player_privs(clicker, {server = true}) then
  195. local player_name = clicker:get_player_name()
  196. core.show_formspec(player_name, 'kobo:goblin_debug', goblin_debug(self))
  197. end
  198. end,
  199. })