fishing_rod.lua 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. local thrown_bobbers = {}
  2. local catchables = {}
  3. local baits = {}
  4. for k,v in pairs(minetest.registered_items) do
  5. if minetest.get_item_group(k, "fishing_catch") ~= 0 then
  6. table.insert(catchables, k)
  7. elseif minetest.get_item_group(k, "fishing_bait") ~= 0 then
  8. table.insert(baits, k)
  9. end
  10. end
  11. local function fishing(bobber, elapsed)
  12. bobber:get_luaentity()._since_bobber_in_water = bobber:get_luaentity()._since_bobber_in_water + elapsed
  13. -- Wait atleast 5 seconds
  14. if math.floor(bobber:get_luaentity()._since_bobber_in_water) > 5 then
  15. local pos = bobber:get_pos()
  16. if not bobber:get_luaentity()._there_is_fish_to_catch then
  17. bobber:get_luaentity()._there_is_fish_to_catch = math.random(1, 200) == 42
  18. if pos.y % 1 ~= 0.5 then
  19. pos.y = (pos.y - (pos.y % 1)) + 0.5
  20. bobber:move_to(pos)
  21. bobber:get_luaentity()._bobber_down = false
  22. bobber:get_luaentity()._bob_travel_time = 1
  23. end
  24. else
  25. bobber:get_luaentity()._the_fish_waited = bobber:get_luaentity()._the_fish_waited + elapsed
  26. -- Visualise the fish's presence
  27. -- Bob the bobber
  28. if bobber:get_luaentity()._bob_travel_time > 0 and not bobber:get_luaentity()._bobber_down then
  29. pos.y = pos.y - 0.02
  30. bobber:get_luaentity()._bob_travel_time = bobber:get_luaentity()._bob_travel_time - 0.1
  31. bobber:set_pos(pos)
  32. elseif bobber:get_luaentity()._bob_travel_time <= 0 and not bobber:get_luaentity()._bobber_down then
  33. bobber:get_luaentity()._bobber_down = true
  34. elseif bobber:get_luaentity()._bob_travel_time <= 1 and bobber:get_luaentity()._bobber_down then
  35. pos.y = pos.y + 0.02
  36. bobber:get_luaentity()._bob_travel_time = bobber:get_luaentity()._bob_travel_time + 0.1
  37. bobber:set_pos(pos)
  38. elseif bobber:get_luaentity()._bob_travel_time >= 1 and bobber:get_luaentity()._bobber_down then
  39. bobber:get_luaentity()._bobber_down = false
  40. end
  41. -- Spray bubbles
  42. minetest.add_particle({
  43. pos = {
  44. x=pos.x + math.random(-1,1) * math.random() / 2,
  45. y=pos.y + 0.1,
  46. z=pos.z + math.random(-1,1) * math.random() / 2
  47. },
  48. velocity = {
  49. x = 0,
  50. y = 2,
  51. z = 0
  52. },
  53. acceleration = {
  54. x = 0,
  55. y = -5,
  56. z = 0},
  57. expirationtime = math.random(),
  58. size = math.random() + 0.5,
  59. collisiondetection = true,
  60. vertical = false,
  61. texture = "particles_bubble.png",
  62. })
  63. -- Play sound
  64. if bobber:get_luaentity()._bob_travel_time >= 0.4 and bobber:get_luaentity()._bob_travel_time <= 0.5 then
  65. minetest.sound_play("default_water_footstep", {
  66. pos,
  67. max_hear_distance = 10,
  68. gain = 10.0,
  69. })
  70. end
  71. if bobber:get_luaentity()._the_fish_waited > 5 then
  72. bobber:get_luaentity()._there_is_fish_to_catch = false
  73. bobber:get_luaentity()._the_fish_waited = 0
  74. end
  75. end
  76. end
  77. end
  78. local function has_bait_in_inventory(player)
  79. local inv = player:get_inventory()
  80. for _,v in ipairs(baits) do
  81. if inv:contains_item("main", v) then
  82. return v
  83. end
  84. end
  85. return false
  86. end
  87. minetest.register_entity("fishing:bobber_entity", {
  88. textures = {"fishing_bobber.png"},
  89. visual_size = {x=0.5, y=0.5},
  90. pointable = false,
  91. walkable = false,
  92. physical = false,
  93. collisionbox = {-0.1, -0.5, -0.1, 0.1, 0.3, 0.1},
  94. _owner = "",
  95. _since_bobber_in_water = 0,
  96. _there_is_fish_to_catch = false,
  97. _the_fish_waited = 0,
  98. _bob_travel_time = 1,
  99. _bobber_down = false,
  100. on_step = function(self, elapsed)
  101. local pos = self.object:get_pos()
  102. pos.y = math.floor(pos.y)
  103. local node = minetest.get_node(pos).name
  104. local owner = minetest.get_player_by_name(self.object:get_luaentity()._owner)
  105. -- Stop the bobber if collides with node
  106. if (node ~= "air") and (self.object:get_luaentity()._since_bobber_in_water == 0) then
  107. self.object:set_acceleration({x=0,y=0,z=0})
  108. self.object:set_velocity({x=0,y=0,z=0})
  109. -- correcting the bobber's position so it is halfway submerged in the water
  110. pos.y = pos.y + 0.5
  111. self.object:move_to(pos)
  112. end
  113. if owner then
  114. --If the player is too far from the bobber remove it
  115. if owner:get_pos().x > (pos.x + 15) or owner:get_pos().x < (pos.x - 15) or
  116. owner:get_pos().y > (pos.y + 15) or owner:get_pos().y < (pos.y - 15) or
  117. owner:get_pos().z > (pos.z + 15) or owner:get_pos().z < (pos.z - 15) then
  118. self.object:remove()
  119. thrown_bobbers[owner:get_player_name()] = nil
  120. return
  121. end
  122. -- If the player puts away the rod remove the bobber
  123. if owner:get_wielded_item():get_name() ~= "fishing:fishing_rod" then
  124. self.object:remove()
  125. thrown_bobbers[owner:get_player_name()] = nil
  126. return
  127. end
  128. -- the process of fishing
  129. if node == "default:water_source" and has_bait_in_inventory(owner) then
  130. fishing(self.object, elapsed)
  131. end
  132. else
  133. --If the bobber doesn't have an owner remove it
  134. self.object:remove()
  135. return
  136. end
  137. end,
  138. })
  139. -- Remove bobber if player leaves the game
  140. minetest.register_on_leaveplayer(function(player)
  141. local player_name = player:get_player_name()
  142. if thrown_bobbers[player_name] then
  143. thrown_bobbers[player_name]:remove()
  144. thrown_bobbers[player_name] = nil
  145. end
  146. end)
  147. -- Remove bobber if player dies
  148. minetest.register_on_dieplayer(function(player)
  149. local player_name = player:get_player_name()
  150. if thrown_bobbers[player_name] then
  151. thrown_bobbers[player_name]:remove()
  152. thrown_bobbers[player_name] = nil
  153. end
  154. end)
  155. local function cast_fishing_rod(itemstack, player, pointing_at)
  156. local bobber_gravity = 6
  157. local bobber_velocity = 10
  158. local player_name = player:get_player_name()
  159. local player_inv = player:get_inventory()
  160. local pos = player:getpos()
  161. local dir = player:get_look_dir()
  162. -- Bobber starting position correction.
  163. pos.y = pos.y + 1.5
  164. if not thrown_bobbers[player_name] then
  165. thrown_bobbers[player_name] = minetest.add_entity(pos, "fishing:bobber_entity")
  166. thrown_bobbers[player_name]:get_luaentity()._owner = player_name
  167. thrown_bobbers[player_name]:set_velocity({
  168. x = dir.x * bobber_velocity,
  169. y = dir.y * bobber_velocity,
  170. z = dir.z * bobber_velocity
  171. })
  172. thrown_bobbers[player_name]:set_acceleration({
  173. x = dir.x * -3,
  174. y = -bobber_gravity,
  175. z = dir.z * -3
  176. })
  177. else
  178. if thrown_bobbers[player_name]:get_luaentity()._there_is_fish_to_catch then
  179. local rand_loot = math.random(1, table.getn(catchables))
  180. local catch = catchables[rand_loot]
  181. if player_inv:room_for_item("main", catch) then
  182. player_inv:add_item("main", catch)
  183. else
  184. minetest.add_item(pos, catch)
  185. end
  186. -- Pherhaps take bait if not in creative
  187. if math.random(1, 5) == 1 and not minetest.settings:get_bool("creative_mode") then
  188. player_inv:remove_item("main", has_bait_in_inventory(player))
  189. end
  190. end
  191. thrown_bobbers[player_name]:remove()
  192. thrown_bobbers[player_name] = nil
  193. if not minetest.settings:get_bool("creative_mode") then
  194. -- Wear down fishing_rod
  195. local idef = itemstack:get_definition()
  196. itemstack:add_wear(65536/100)
  197. if itemstack:get_count() == 0 and idef.sound and idef.sound.breaks then
  198. minetest.sound_play(idef.sound.breaks, {pos=player:get_pos(), gain=0.5}, true)
  199. end
  200. end
  201. end
  202. return itemstack
  203. end
  204. minetest.register_tool("fishing:fishing_rod", {
  205. description = "Fishing Rod",
  206. groups = { tool=1 },
  207. inventory_image = "fishing_fishing_rod.png",
  208. wield_image = "fishing_fishing_rod.png",
  209. wield_scale = { x = 1.5, y = 1.5, z = 1 },
  210. stack_max = 1,
  211. on_use = cast_fishing_rod,
  212. sound = { breaks = "default_tool_breaks" },
  213. })
  214. minetest.register_craft({
  215. output = "fishing:fishing_rod",
  216. recipe = {
  217. {"","","group:stick"},
  218. {"","group:stick","farming:string"},
  219. {"group:stick","","farming:string"},
  220. }
  221. })
  222. minetest.register_craft({
  223. type = "fuel",
  224. recipe = "fishing:fishing_rod",
  225. burntime = 15,
  226. })