Minetest mod that adds spears in the game, improving the ones introduced within throwing enhanced
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
5.3KB

  1. function spears_throw (itemstack, player, pointed_thing)
  2. local spear = itemstack:get_name() .. '_entity'
  3. local player_pos = player:get_pos()
  4. local head_pos = vector.new(player_pos.x, player_pos.y + player:get_properties().eye_height, player_pos.z)
  5. local direction = player:get_look_dir()
  6. local throw_pos = vector.add(head_pos, vector.multiply(direction,0.5))
  7. local pitch = player:get_look_vertical()
  8. local yaw = player:get_look_horizontal()
  9. local rotation = vector.new(0, yaw + math.pi/2, pitch + math.pi/6)
  10. -- Plant into node
  11. if pointed_thing.type == "node" then
  12. local node = minetest.get_node(pointed_thing.under)
  13. if minetest.registered_nodes[node.name].walkable and vector.distance(pointed_thing.above, throw_pos) < 1 then
  14. local spear_object = minetest.add_entity(vector.divide(vector.add(vector.multiply(pointed_thing.above, 2), pointed_thing.under), 3), spear)
  15. spear_object:set_rotation(rotation)
  16. spear_object:get_luaentity()._wear = itemstack:get_wear()
  17. spear_object:get_luaentity()._stickpos = pointed_thing.under
  18. return
  19. end
  20. end
  21. -- Avoid hitting yourself and throw
  22. local throw_speed = 12
  23. while vector.distance(player_pos, throw_pos) < 1.2 do
  24. throw_pos = vector.add(throw_pos, vector.multiply(direction, 0.1))
  25. end
  26. local player_vel = player:get_player_velocity()
  27. local spear_object = minetest.add_entity(throw_pos, spear)
  28. spear_object:set_velocity(vector.add(player_vel, vector.multiply(direction, throw_speed)))
  29. spear_object:set_rotation(rotation)
  30. minetest.sound_play("spears_throw", {pos = player_pos}, true)
  31. spear_object:get_luaentity()._wear = itemstack:get_wear()
  32. spear_object:get_luaentity()._stickpos = nil
  33. return true
  34. end
  35. function spears_set_entity(spear_type, base_damage, toughness)
  36. local SPEAR_ENTITY={
  37. initial_properties = {
  38. physical = false,
  39. visual = "item",
  40. visual_size = {x = 0.3, y = 0.3, z = 0.3},
  41. wield_item = "spears:spear_" .. spear_type,
  42. collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
  43. },
  44. on_activate = function (self, staticdata, dtime_s)
  45. self.object:set_armor_groups({immortal = 1})
  46. end,
  47. on_punch = function (self, puncher)
  48. if puncher:is_player() then -- Grab the spear
  49. local stack = {name='spears:spear_' .. spear_type, wear = self._wear}
  50. local inv = puncher:get_inventory()
  51. if inv:room_for_item("main", stack) then
  52. inv:add_item("main", stack)
  53. self.object:remove()
  54. end
  55. end
  56. end,
  57. on_step = function(self, dtime)
  58. if not self._wear then
  59. self.object:remove()
  60. return
  61. end
  62. local velocity = self.object:get_velocity()
  63. local speed = vector.length(velocity)
  64. -- Spear is stuck ?
  65. if self._stickpos then
  66. local node = minetest.get_node(self._stickpos)
  67. local node_cracky = minetest.registered_nodes[node.name].groups.cracky
  68. if node_cracky and node_cracky < 3 then
  69. minetest.sound_play("default_metal_footstep", {pos = pos}, true)
  70. self.object:remove()
  71. minetest.add_item(self.object:get_pos(), {name='spears:spear_' .. spear_type, wear = self._wear})
  72. elseif not self._node_walkable then
  73. minetest.sound_play("default_place_node", {pos = throw_pos}, true)
  74. end
  75. self._node_walkable = minetest.registered_nodes[node.name].walkable
  76. if not node or not self._node_walkable then -- Fall when node is removed
  77. self.object:remove()
  78. minetest.add_item(self.object:get_pos(), {name='spears:spear_' .. spear_type, wear = self._wear})
  79. return
  80. end
  81. else -- Spear is flying
  82. local direction = vector.normalize(velocity)
  83. local yaw = minetest.dir_to_yaw(direction)
  84. local pitch = math.acos(velocity.y/speed) - math.pi/3
  85. local pos = self.object:get_pos()
  86. local spearhead_pos = vector.add(pos, vector.multiply(direction, 0.5))
  87. local node = minetest.get_node(spearhead_pos)
  88. self.object:set_rotation({x = 0, y = yaw + math.pi/2, z = pitch})
  89. -- Hit someone?
  90. local objects_in_radius = minetest.get_objects_inside_radius(spearhead_pos, 0.6)
  91. for _,object in ipairs(objects_in_radius) do
  92. if object:get_luaentity() ~= self and object:get_armor_groups().fleshy then
  93. local damage = (speed + base_damage)^1.15 - 20
  94. object:punch(self.object, 1.0, {full_punch_interval = 1.0, damage_groups = {fleshy=damage},}, direction)
  95. self.object:remove()
  96. minetest.sound_play("spears_hit", {pos = pos}, true)
  97. minetest.add_item(pos, {name='spears:spear_' .. spear_type, wear = self._wear + 65535/toughness})
  98. return
  99. end
  100. end
  101. -- Hit a node?
  102. if node and minetest.registered_nodes[node.name].walkable
  103. and not minetest.registered_nodes[node.name].buildable_to
  104. and not (minetest.registered_nodes[node.name].groups.slab and spearhead_pos.y % 1 < 0.5)
  105. then -- Stick
  106. self.object:set_acceleration({x = 0, y = 0, z = 0})
  107. self.object:set_velocity({x = 0, y = 0, z = 0})
  108. self._wear = self._wear + 65535/toughness
  109. if self._wear >= 65535 then
  110. minetest.sound_play("default_tool_breaks", {pos = pos}, true)
  111. self.object:remove()
  112. return
  113. end
  114. self._stickpos = spearhead_pos
  115. else -- Get drag
  116. local drag = math.max(minetest.registered_nodes[node.name].liquid_viscosity, 0.1)
  117. local acceleration = vector.multiply(velocity, -drag)
  118. acceleration.y = acceleration.y - 10 * ((7 - drag) / 7)
  119. self.object:set_acceleration(acceleration)
  120. end
  121. end
  122. end,
  123. }
  124. return SPEAR_ENTITY
  125. end