Carts for Minetest, but optimized! Also compatible with MTG carts https://content.minetest.net/packages/Krock/boost_cart/
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.

269 lines
5.9KB

  1. function boost_cart:get_sign(z)
  2. if z == 0 then
  3. return 0
  4. else
  5. return z / math.abs(z)
  6. end
  7. end
  8. function boost_cart:manage_attachment(player, obj)
  9. if not player then
  10. return
  11. end
  12. local wants_attach = obj ~= nil
  13. local attached = player:get_attach() ~= nil
  14. if attached == wants_attach then
  15. return
  16. end
  17. local player_name = player:get_player_name()
  18. boost_cart.player_attached[player_name] = wants_attach
  19. if wants_attach then
  20. player:set_attach(obj, "", {x=0, y=-4, z=0}, {x=0, y=0, z=0})
  21. player:set_eye_offset({x=0, y=-4, z=0},{x=0, y=-4, z=0})
  22. else
  23. player:set_detach()
  24. player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
  25. -- HACK in effect! Force updating the attachment rotation
  26. player:set_properties({})
  27. end
  28. end
  29. function boost_cart:velocity_to_dir(v)
  30. if math.abs(v.x) > math.abs(v.z) then
  31. return {x=self:get_sign(v.x), y=self:get_sign(v.y), z=0}
  32. else
  33. return {x=0, y=self:get_sign(v.y), z=self:get_sign(v.z)}
  34. end
  35. end
  36. local get_node = minetest.get_node
  37. local get_item_group = minetest.get_item_group
  38. function boost_cart:is_rail(pos, railtype)
  39. local node = get_node(pos).name
  40. if node == "ignore" then
  41. local vm = minetest.get_voxel_manip()
  42. local emin, emax = vm:read_from_map(pos, pos)
  43. local area = VoxelArea:new{
  44. MinEdge = emin,
  45. MaxEdge = emax,
  46. }
  47. local data = vm:get_data()
  48. local vi = area:indexp(pos)
  49. node = minetest.get_name_from_content_id(data[vi])
  50. end
  51. if get_item_group(node, "rail") == 0 then
  52. return false
  53. end
  54. if not railtype then
  55. return true
  56. end
  57. return get_item_group(node, "connect_to_raillike") == railtype
  58. end
  59. function boost_cart:check_front_up_down(pos, dir_, check_up, railtype)
  60. local dir = vector.new(dir_)
  61. local cur = nil
  62. -- Front
  63. dir.y = 0
  64. cur = vector.add(pos, dir)
  65. if self:is_rail(cur, railtype) then
  66. return dir
  67. end
  68. -- Up
  69. if check_up then
  70. dir.y = 1
  71. cur = vector.add(pos, dir)
  72. if self:is_rail(cur, railtype) then
  73. return dir
  74. end
  75. end
  76. -- Down
  77. dir.y = -1
  78. cur = vector.add(pos, dir)
  79. if self:is_rail(cur, railtype) then
  80. return dir
  81. end
  82. return nil
  83. end
  84. function boost_cart:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
  85. local pos = vector.round(pos_)
  86. local cur = nil
  87. local left_check, right_check = true, true
  88. -- Check left and right
  89. local left = {x=0, y=0, z=0}
  90. local right = {x=0, y=0, z=0}
  91. if dir.z ~= 0 and dir.x == 0 then
  92. left.x = -dir.z
  93. right.x = dir.z
  94. elseif dir.x ~= 0 and dir.z == 0 then
  95. left.z = dir.x
  96. right.z = -dir.x
  97. end
  98. local straight_priority = ctrl and dir.y ~= 0
  99. -- Normal, to disallow rail switching up- & downhill
  100. if straight_priority then
  101. cur = self:check_front_up_down(pos, dir, true, railtype)
  102. if cur then
  103. return cur
  104. end
  105. end
  106. if ctrl then
  107. if old_switch == 1 then
  108. left_check = false
  109. elseif old_switch == 2 then
  110. right_check = false
  111. end
  112. if ctrl.left and left_check then
  113. cur = self:check_front_up_down(pos, left, false, railtype)
  114. if cur then
  115. return cur, 1
  116. end
  117. left_check = false
  118. end
  119. if ctrl.right and right_check then
  120. cur = self:check_front_up_down(pos, right, false, railtype)
  121. if cur then
  122. return cur, 2
  123. end
  124. right_check = true
  125. end
  126. end
  127. -- Normal
  128. if not straight_priority then
  129. cur = self:check_front_up_down(pos, dir, true, railtype)
  130. if cur then
  131. return cur
  132. end
  133. end
  134. -- Left, if not already checked
  135. if left_check then
  136. cur = self:check_front_up_down(pos, left, false, railtype)
  137. if cur then
  138. return cur
  139. end
  140. end
  141. -- Right, if not already checked
  142. if right_check then
  143. cur = self:check_front_up_down(pos, right, false, railtype)
  144. if cur then
  145. return cur
  146. end
  147. end
  148. -- Backwards
  149. if not old_switch then
  150. cur = self:check_front_up_down(pos, {
  151. x = -dir.x,
  152. y = dir.y,
  153. z = -dir.z
  154. }, true, railtype)
  155. if cur then
  156. return cur
  157. end
  158. end
  159. return {x=0, y=0, z=0}
  160. end
  161. function boost_cart:pathfinder(pos_, old_pos, old_dir, distance, ctrl,
  162. pf_switch, railtype)
  163. local pos = vector.round(pos_)
  164. if vector.equals(old_pos, pos) then
  165. return
  166. end
  167. local pf_pos = vector.round(old_pos)
  168. local pf_dir = vector.new(old_dir)
  169. distance = math.min(boost_cart.path_distance_max,
  170. math.floor(distance + 1))
  171. for i = 1, distance do
  172. pf_dir, pf_switch = self:get_rail_direction(
  173. pf_pos, pf_dir, ctrl, pf_switch or 0, railtype)
  174. if vector.equals(pf_dir, {x=0, y=0, z=0}) then
  175. -- No way forwards
  176. return pf_pos, pf_dir
  177. end
  178. pf_pos = vector.add(pf_pos, pf_dir)
  179. if vector.equals(pf_pos, pos) then
  180. -- Success! Cart moved on correctly
  181. return
  182. end
  183. end
  184. -- Not found. Put cart to predicted position
  185. return pf_pos, pf_dir
  186. end
  187. function boost_cart:boost_rail(pos, amount)
  188. minetest.get_meta(pos):set_string("cart_acceleration", tostring(amount))
  189. for _,obj_ in ipairs(minetest.get_objects_inside_radius(pos, 0.5)) do
  190. if not obj_:is_player() and
  191. obj_:get_luaentity() and
  192. obj_:get_luaentity().name == "carts:cart" then
  193. obj_:get_luaentity():on_punch()
  194. end
  195. end
  196. end
  197. function boost_cart:register_rail(name, def_overwrite)
  198. local sound_func = default.node_sound_metal_defaults
  199. or default.node_sound_defaults
  200. local def = {
  201. drawtype = "raillike",
  202. paramtype = "light",
  203. sunlight_propagates = true,
  204. is_ground_content = false,
  205. walkable = false,
  206. selection_box = {
  207. type = "fixed",
  208. fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
  209. },
  210. sounds = sound_func()
  211. }
  212. for k, v in pairs(def_overwrite) do
  213. def[k] = v
  214. end
  215. if not def.inventory_image then
  216. def.wield_image = def.tiles[1]
  217. def.inventory_image = def.tiles[1]
  218. end
  219. minetest.register_node(name, def)
  220. end
  221. function boost_cart:get_rail_groups(additional_groups)
  222. -- Get the default rail groups and add more when a table is given
  223. local groups = {
  224. dig_immediate = 2,
  225. attached_node = 1,
  226. rail = 1,
  227. connect_to_raillike = 1
  228. }
  229. if minetest.raillike_group then
  230. groups.connect_to_raillike = minetest.raillike_group("rail")
  231. end
  232. if type(additional_groups) == "table" then
  233. for k, v in pairs(additional_groups) do
  234. groups[k] = v
  235. end
  236. end
  237. return groups
  238. end