init.lua 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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:get_pos()
  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:get_pos(), 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. -- Update jump timer.
  143. self.jump = (self.jump or 0) - dtime
  144. if self.jump < 0 then self.jump = 0 end
  145. -- Accelerate sled forwards if going downhill.
  146. local is_flying = false
  147. local last_y = self.y
  148. self.y = pos.y
  149. if self.y < last_y then
  150. if self.v > 2 then
  151. local node = minetest.get_node({x=pos.x, y=pos.y-2, z=pos.z})
  152. -- But not if sled is flying.
  153. if node.name ~= "air" then
  154. self.v = self.v + 0.2
  155. else
  156. -- Don't compute driver controls if flying.
  157. is_flying = true
  158. end
  159. end
  160. end
  161. -- Driver controls.
  162. if not is_flying and self.driver then
  163. local ctrl = self.driver:get_player_control()
  164. local yaw = self.object:get_yaw()
  165. if ctrl.up then
  166. -- Cannot accelerate faster than this if player-powered.
  167. if self.v < 7 then
  168. self.v = self.v + 0.1
  169. end
  170. elseif ctrl.down then
  171. self.v = self.v - 0.13
  172. end
  173. if ctrl.left then
  174. self.object:set_yaw(yaw + (1 + dtime) * 0.03)
  175. elseif ctrl.right then
  176. self.object:set_yaw(yaw - (1 + dtime) * 0.03)
  177. end
  178. -- Allow sled to jump, if velocity high enough and
  179. -- pilot hasn't already executed a jump.
  180. if ctrl.jump and self.v > 6 and (self.jump or 0) <= 0 then
  181. local sta = sprint.get_stamina(self.driver)
  182. local stacost = 5
  183. if sta >= stacost then
  184. velo.y = velo.y + 6
  185. self.v = self.v - 1 -- Knock velocity down a bit.
  186. self.jump = 1.5 -- Delay before pilot can jump again.
  187. sprint.add_stamina(self.driver, -stacost)
  188. end
  189. end
  190. end
  191. local new_velo = get_velocity(self.v, self.object:get_yaw(), velo.y)
  192. self.object:set_velocity(new_velo)
  193. end
  194. function sleds.on_place(itemstack, placer, pointed_thing)
  195. local under = pointed_thing.under
  196. local node = minetest.get_node(under)
  197. local udef = minetest.registered_nodes[node.name]
  198. if udef and udef.on_rightclick and
  199. not (placer and placer:get_player_control().sneak) then
  200. return udef.on_rightclick(under, node, placer, itemstack,
  201. pointed_thing) or itemstack
  202. end
  203. if pointed_thing.type ~= "node" then
  204. return itemstack
  205. end
  206. if not is_snow(pointed_thing.under) then
  207. return itemstack
  208. end
  209. pointed_thing.under.y = pointed_thing.under.y + 1.0
  210. local sled = minetest.add_entity(pointed_thing.under, "sleds:sled")
  211. if sled then
  212. sled:setyaw(placer:get_look_horizontal())
  213. if not minetest.setting_getbool("creative_mode") then
  214. itemstack:take_item()
  215. end
  216. end
  217. return itemstack
  218. end
  219. if not sleds.run_once then
  220. -- Sled entity.
  221. local sled = {
  222. visual = "mesh",
  223. mesh = "sled.obj",
  224. textures = {"sled.png"},
  225. stepheight = 0.5,
  226. physical = true,
  227. collisionbox = {-0.7, -0.20, -0.7, 0.7, 0.5, 0.7},
  228. --selection_box = {-0.7, -0.20, -0.7, 0.7, 0.2, 0.7},
  229. driver = nil,
  230. v = 0,
  231. y = 0,
  232. removed = false,
  233. on_rightclick = function(...)
  234. return sleds.on_rightclick(...)
  235. end,
  236. on_activate = function(...)
  237. return sleds.on_activate(...)
  238. end,
  239. get_staticdata = function(...)
  240. return sleds.get_staticdata(...)
  241. end,
  242. on_punch = function(...)
  243. return sleds.on_punch(...)
  244. end,
  245. on_step = function(...)
  246. return sleds.on_step(...)
  247. end,
  248. }
  249. minetest.register_entity("sleds:sled", sled)
  250. minetest.register_craftitem("sleds:sled", {
  251. description = "Sled",
  252. inventory_image = "snow_sled.png",
  253. wield_image = "snow_sled.png",
  254. wield_scale = {x=2, y=2, z=1},
  255. liquids_pointable = true,
  256. groups = {flammable = 2},
  257. on_place = function(...)
  258. return sleds.on_place(...)
  259. end,
  260. })
  261. minetest.register_craft({
  262. output = "sleds:sled",
  263. recipe = {
  264. {"group:stick", "", "group:stick"},
  265. {"group:wood", "group:wood", "group:wood"},
  266. {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
  267. },
  268. })
  269. minetest.register_craft({
  270. type = "fuel",
  271. recipe = "sleds:sled",
  272. burntime = 20,
  273. })
  274. -- File is reloadable.
  275. local c = "sleds:core"
  276. local f = sleds.modpath .. "/init.lua"
  277. reload.register_file(c, f, false)
  278. sleds.run_once = true
  279. end