9 make player able to push cart
11 make carts push each other away --repel axis
13 make chest and furnace cart
16 minetest.dir_to_facedir(dir, is6d) - to get player direction converted and to convert the minecart direction
19 local path = minetest.get_modpath("minecart")
20 dofile(path.."/rail.lua")
24 local function is_rail(x,y,z)
25 return(minetest.get_node_group(minetest.get_node(vector.new(x,y,z)).name,"rail")>0)
29 initial_properties = {
30 physical = false, -- otherwise going uphill breaks
31 collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},--{-0.5, -0.4, -0.5, 0.5, 0.25, 0.5},
33 mesh = "minecart.obj",
34 visual_size = {x=1, y=1},
35 textures = {"minecart.png"},
36 automatic_face_movement_dir = 90.0,
45 function minecart:on_rightclick(clicker)
46 if not clicker or not clicker:is_player() then
49 local player_name = clicker:get_player_name()
51 if self.rider and player_name == self.rider then
53 --carts:manage_attachment(clicker, nil)
54 elseif not self.rider then
55 self.rider = player_name
56 clicker:set_attach(self.object, "", {x=0, y=-4.5, z=0}, {x=0, y=0, z=0})
57 --player:set_eye_offset({x=0, y=-4, z=0},{x=0, y=-4, z=0})
58 --carts:manage_attachment(clicker, self.object)
60 -- player_api does not update the animation
61 -- when the player is attached, reset to default animation
63 --player_api.set_animation(clicker, "stand")
67 function minecart:on_activate(staticdata, dtime_s)
68 self.object:set_armor_groups({immortal=1})
69 if string.sub(staticdata, 1, string.len("return")) ~= "return" then
72 local data = minetest.deserialize(staticdata)
73 if type(data) ~= "table" then
76 self.railtype = data.railtype
78 self.old_dir = data.old_dir
82 function minecart:get_staticdata()
83 return minetest.serialize({
86 function minecart:on_punch(puncher, time_from_last_punch, tool_capabilities, dir, damage)
95 --repel from players on track "push"
96 function minecart:push(self)
97 local pos = self.object:getpos()
98 for _,object in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
99 if object:is_player() and object:get_player_name() ~= self.rider then
100 local player_pos = object:getpos()
104 local vel = vector.subtract(pos, player_pos)
105 vel = vector.normalize(vel)
106 local distance = vector.distance(pos,player_pos)
108 distance = (1-distance)*10
110 vel = vector.multiply(vel,distance)
112 --only push if it's faster than current speed
113 if distance > self.speed then
114 self.object:setvelocity(vel)
115 self.speed = distance
121 function minecart:ride_rail(self)
122 local pos = vector.floor(vector.add(self.object:getpos(),0.5))
123 local speed = self.speed
124 if self.speed > 10 then
128 local vel = self.object:getvelocity()
129 local x = math.abs(vel.x)
130 local z = math.abs(vel.z)
133 local dir = {x=0,y=0,z=0}
138 if vel.x>0 then xdir=1 elseif vel.x<0 then xdir=-1 end
140 --print(minetest.get_node(vector.new(pos.x,pos.y,pos.z)).name)
143 if is_rail(pos.x+xdir,pos.y+1,pos.z) or (not is_rail(pos.x,pos.y,pos.z) and is_rail(pos.x+xdir,pos.y,pos.z)) then
149 elseif (is_rail(pos.x,pos.y-1,pos.z) or vel.y < 0) and not is_rail(pos.x+xdir,pos.y,pos.z) then
155 elseif is_rail(pos.x,pos.y,pos.z) then --currently on rail
157 --print("forward inside")
159 if dir.y == 0 and self.object:getpos().y ~= pos.y then
160 --print("correcting y")
161 local posser = self.object:getpos()
162 self.object:moveto(vector.new(posser.x,pos.y,posser.z))
168 if vel.z>0 then zdir=1 elseif vel.z<0 then zdir=-1 end
170 --print(minetest.get_node(vector.new(pos.x,pos.y,pos.z)).name)
173 if is_rail(pos.x,pos.y+1,pos.z+zdir) or (not is_rail(pos.x,pos.y,pos.z) and is_rail(pos.x,pos.y,pos.z+zdir)) then
179 elseif (is_rail(pos.x,pos.y-1,pos.z) or vel.y < 0) and not is_rail(pos.x,pos.y,pos.z+zdir) then
186 elseif is_rail(pos.x,pos.y,pos.z) then --currently on rail
188 --print("forward inside")
190 if dir.y == 0 and self.object:getpos().y ~= pos.y then
191 --print("correcting y")
192 local posser = self.object:getpos()
193 self.object:moveto(vector.new(posser.x,pos.y,posser.z))
202 if vel.x>0 then turnx=1 elseif vel.x<0 then turnx=-1 end
203 if vel.z>0 then turnz=1 elseif vel.z<0 then turnz=-1 end
206 if turnx and turnz and dir.y == 0 and not vector.equals(dir, vector.new(0,0,0)) and not is_rail(pos.x+turnx,pos.y-1,pos.z+turnz) and not is_rail(pos.x+turnx,pos.y,pos.z+turnz) and not is_rail(pos.x+turnx,pos.y+1,pos.z+turnz) then
209 if is_rail(pos.x,pos.y+y,pos.z+1) then
212 --recenter on the rail
213 self.object:moveto(pos)
214 elseif is_rail(pos.x,pos.y+y,pos.z-1) then
217 --recenter on the rail
218 self.object:moveto(pos)
223 if is_rail(pos.x+1,pos.y+y,pos.z) then
226 --recenter on the rail
227 self.object:moveto(pos)
228 elseif is_rail(pos.x-1,pos.y+y,pos.z) then
231 --recenter on the rail
232 self.object:moveto(pos)
239 --if not vector.equals(dir,vector.new(0,0,0)) then
240 self.object:setvelocity(dir)
242 self.oldpos=self.object:getpos()
244 --make the cart move up and down on hills
245 self.object:set_properties({mesh="minecart.obj"})
247 self.object:set_properties({mesh="minecart_down.obj"})
248 elseif vel.y > 0 then
249 self.object:set_properties({mesh="minecart_up.obj"})
253 if self.speed > 0 then
254 self.speed = self.speed - 0.01
256 if self.speed < 0 then
264 function minecart:on_step(dtime)
266 minecart:ride_rail(self)
269 minetest.register_entity("minecart:minecart", minecart)
290 minetest.register_craftitem("minecart:minecart", {
291 description = "Minecart",
292 inventory_image = "minecartitem.png",
293 wield_image = "minecartitem.png",
294 on_place = function(itemstack, placer, pointed_thing)
295 if not pointed_thing.type == "node" then
299 if minetest.get_item_group(minetest.get_node(pointed_thing.under).name, "rail")>0 then
300 minetest.add_entity(pointed_thing.under, "minecart:minecart")
305 itemstack:take_item()
311 minetest.register_craft({
312 output = "minecart:minecart",
314 {"main:iron", "", "main:iron"},
315 {"main:iron", "main:iron", "main:iron"},