init.lua 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. -- Sled mod, copied from boat mod and modified.
  2. -- Mod is reloadable.
  3. sleds = sleds or {}
  4. sleds.modpath = minetest.get_modpath("sleds")
  5. sleds.players = sleds.players or {}
  6. local function is_snow(pos)
  7. local nn = minetest.get_node(pos).name
  8. local def = minetest.registered_nodes[nn]
  9. if def and def.groups then
  10. if def.groups.snow and def.groups.snow > 0 then
  11. return true
  12. end
  13. if def.groups.ice and def.groups.ice > 0 then
  14. return true
  15. end
  16. end
  17. return false
  18. end
  19. local function is_snow_or_air(pos)
  20. local nn = minetest.get_node(pos).name
  21. if nn == "air" or snow.is_snow(nn) then
  22. return true
  23. end
  24. local def = minetest.registered_nodes[nn]
  25. if def and def.groups then
  26. if def.groups.snow and def.groups.snow > 0 then
  27. return true
  28. end
  29. if def.groups.ice and def.groups.ice > 0 then
  30. return true
  31. end
  32. end
  33. return false
  34. end
  35. local function get_velocity(v, yaw, y)
  36. local x = -math.sin(yaw) * v
  37. local z = math.cos(yaw) * v
  38. return {x=x, y=y, z=z}
  39. end
  40. local function get_v(v)
  41. return math.sqrt(v.x ^ 2 + v.z ^ 2)
  42. end
  43. function sleds.on_rightclick(self, clicker)
  44. if not clicker or not clicker:is_player() then
  45. return
  46. end
  47. if clicker:get_hp() == 0 then
  48. return
  49. end
  50. local name = clicker:get_player_name()
  51. if self.driver and clicker == self.driver then
  52. self.driver = nil
  53. clicker:set_detach()
  54. clicker:set_properties({collisionbox = sleds.players[name].cb})
  55. default.player_attached[name] = false
  56. default.player_set_animation(clicker, "stand" , 30)
  57. local pos = clicker:getpos()
  58. pos = {x = pos.x, y = pos.y + 0.2, z = pos.z}
  59. minetest.after(0.1, function() clicker:set_pos(pos) end)
  60. elseif not self.driver then
  61. -- Not while attached to something else!
  62. if default.player_attached[name] then
  63. return
  64. end
  65. local attach = clicker:get_attach()
  66. if attach and attach:get_luaentity() then
  67. local luaentity = attach:get_luaentity()
  68. if luaentity.driver then
  69. luaentity.driver = nil
  70. end
  71. clicker:set_detach()
  72. clicker:set_properties({collisionbox = sleds.players[name].cb})
  73. end
  74. self.driver = clicker
  75. clicker:set_attach(self.object, "", {x = 0, y = 0.1, z = -3}, {x = 0, y = 0, z = 0})
  76. default.player_attached[name] = true
  77. minetest.after(0.2, function() default.player_set_animation(clicker, "sit" , 30) end)
  78. clicker:set_look_horizontal(self.object:getyaw())
  79. --clicker:set_properties({stepheight=3})
  80. local pp = clicker:get_properties()
  81. sleds.players[name] = {}
  82. sleds.players[name].cb = pp.collisionbox
  83. clicker:set_properties({collisionbox = {0}})
  84. end
  85. end
  86. function sleds.on_activate(self, data)
  87. self.object:set_armor_groups({immortal = 1})
  88. self.object:set_acceleration({x = 0, y = -9.8, z = 0}) -- Gravity.
  89. if data then
  90. local info = minetest.deserialize(data) or {}
  91. self.v = info.v or 0
  92. self.y = info.y or 0
  93. end
  94. end
  95. function sleds.get_staticdata(self)
  96. return minetest.serialize({
  97. v = self.v,
  98. y = self.y,
  99. })
  100. end
  101. function sleds.on_punch(self, puncher, time_from_last_punch, tool_capabilities, dir)
  102. if not puncher or not puncher:is_player() or self.removed then
  103. return
  104. end
  105. if self.driver and puncher == self.driver then
  106. self.driver = nil
  107. local name = puncher:get_player_name()
  108. puncher:set_detach()
  109. puncher:set_properties({collisionbox = sleds.players[name].cb})
  110. default.player_attached[name] = false
  111. end
  112. if not self.driver then
  113. self.removed = true
  114. local inv = puncher:get_inventory()
  115. if not minetest.setting_getbool("creative_mode")
  116. or not inv:contains_item("main", "sleds:sled") then
  117. local leftover = inv:add_item("main", "sleds:sled")
  118. -- if no room in inventory add a replacement sled to the world
  119. if not leftover:is_empty() then
  120. minetest.add_item(self.object:getpos(), leftover)
  121. end
  122. end
  123. -- delay remove to ensure player is detached
  124. minetest.after(0.1, function()
  125. self.object:remove()
  126. end)
  127. end
  128. end
  129. function sleds.on_step(self, dtime)
  130. local velo = self.object:get_velocity()
  131. local pos = self.object:get_pos()
  132. self.v = get_v(velo)
  133. -- Slow the sled down gradually.
  134. if is_snow_or_air({x=pos.x, y=pos.y-0.3, z=pos.z}) then
  135. self.v = self.v - 0.02
  136. else
  137. self.v = self.v - 0.2
  138. end
  139. if self.v < 0 then
  140. self.v = 0
  141. end
  142. -- Accelerate sled forwards if going downhill.
  143. local is_flying = false
  144. local last_y = self.y
  145. self.y = pos.y
  146. if self.y < last_y then
  147. if self.v > 2 then
  148. local node = minetest.get_node({x=pos.x, y=pos.y-2, z=pos.z})
  149. -- But not if sled is flying.
  150. if node.name ~= "air" then
  151. self.v = self.v + 0.1
  152. else
  153. -- Don't compute driver controls if flying.
  154. is_flying = true
  155. end
  156. end
  157. end
  158. -- Driver controls.
  159. if not is_flying and self.driver then
  160. local ctrl = self.driver:get_player_control()
  161. local yaw = self.object:get_yaw()
  162. if ctrl.up then
  163. -- Cannot accelerate faster than this if player-powered.
  164. if self.v < 7 then
  165. self.v = self.v + 0.1
  166. end
  167. elseif ctrl.down then
  168. self.v = self.v - 0.13
  169. end
  170. if ctrl.left then
  171. self.object:set_yaw(yaw + (1 + dtime) * 0.03)
  172. elseif ctrl.right then
  173. self.object:set_yaw(yaw - (1 + dtime) * 0.03)
  174. end
  175. end
  176. local new_velo = get_velocity(self.v, self.object:get_yaw(), velo.y)
  177. self.object:set_velocity(new_velo)
  178. end
  179. function sleds.on_place(itemstack, placer, pointed_thing)
  180. local under = pointed_thing.under
  181. local node = minetest.get_node(under)
  182. local udef = minetest.registered_nodes[node.name]
  183. if udef and udef.on_rightclick and
  184. not (placer and placer:get_player_control().sneak) then
  185. return udef.on_rightclick(under, node, placer, itemstack,
  186. pointed_thing) or itemstack
  187. end
  188. if pointed_thing.type ~= "node" then
  189. return itemstack
  190. end
  191. if not is_snow(pointed_thing.under) then
  192. return itemstack
  193. end
  194. pointed_thing.under.y = pointed_thing.under.y + 1.0
  195. local sled = minetest.add_entity(pointed_thing.under, "sleds:sled")
  196. if sled then
  197. sled:setyaw(placer:get_look_horizontal())
  198. if not minetest.setting_getbool("creative_mode") then
  199. itemstack:take_item()
  200. end
  201. end
  202. return itemstack
  203. end
  204. if not sleds.run_once then
  205. -- Sled entity.
  206. local sled = {
  207. visual = "mesh",
  208. mesh = "sled.obj",
  209. textures = {"sled.png"},
  210. stepheight = 0.5,
  211. physical = true,
  212. collisionbox = {-0.7, -0.20, -0.7, 0.7, 0.5, 0.7},
  213. --selection_box = {-0.7, -0.20, -0.7, 0.7, 0.2, 0.7},
  214. driver = nil,
  215. v = 0,
  216. y = 0,
  217. removed = false,
  218. on_rightclick = function(...)
  219. return sleds.on_rightclick(...)
  220. end,
  221. on_activate = function(...)
  222. return sleds.on_activate(...)
  223. end,
  224. get_staticdata = function(...)
  225. return sleds.get_staticdata(...)
  226. end,
  227. on_punch = function(...)
  228. return sleds.on_punch(...)
  229. end,
  230. on_step = function(...)
  231. return sleds.on_step(...)
  232. end,
  233. }
  234. minetest.register_entity("sleds:sled", sled)
  235. minetest.register_craftitem("sleds:sled", {
  236. description = "Sled\nUseable on snow.",
  237. inventory_image = "snow_sled.png",
  238. wield_image = "snow_sled.png",
  239. wield_scale = {x=2, y=2, z=1},
  240. liquids_pointable = true,
  241. groups = {flammable = 2},
  242. on_place = function(...)
  243. return sleds.on_place(...)
  244. end,
  245. })
  246. minetest.register_craft({
  247. output = "sleds:sled",
  248. recipe = {
  249. {"group:stick", "", "group:stick"},
  250. {"group:wood", "group:wood", "group:wood"},
  251. {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
  252. },
  253. })
  254. minetest.register_craft({
  255. type = "fuel",
  256. recipe = "sleds:sled",
  257. burntime = 20,
  258. })
  259. -- File is reloadable.
  260. local c = "sleds:core"
  261. local f = sleds.modpath .. "/init.lua"
  262. reload.register_file(c, f, false)
  263. sleds.run_once = true
  264. end