init.lua 7.5 KB

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