1 local path = minetest.get_modpath("minecart")
2 dofile(path.."/rail.lua")
4 --this begins the minecart library
8 --these are the variables for the minecart
9 minecart.max_speed = 15
14 minecart.get_dir = function(pos,pos2)
15 return(minetest.facedir_to_dir(minetest.dir_to_facedir(vector.direction(pos2,pos))))
17 --this gets the node position that the minecart is in
18 minecart.round_pos = function(pos)
19 return(vector.round(pos))
22 --this is called when a player is standing next to the minecart
23 --it will take their position and convert it into binary then
25 minecart.set_direction = function(self,dir)
27 --reset the y to 0 since we will be checking up and down anyways
29 local pos = vector.add(minecart.round_pos(self.object:get_pos()),dir)
30 local node = minetest.get_node(pos).name
31 local node_above = minetest.get_node(vector.new(pos.x,pos.y+1,pos.z)).name
32 local node_under = minetest.get_node(vector.new(pos.x,pos.y-1,pos.z)).name
35 if node == "minecart:rail" and node_under ~= "minecart:rail" then
39 elseif node == "air" and node_under == "minecart:rail" then
40 self.dir = vector.new(dir.x,dir.y-1,dir.z)
41 self.goal = vector.new(pos.x,pos.y-1,pos.z)
43 elseif node ~= "minecart:rail" and node_above == "minecart:rail" then
44 self.dir = vector.new(dir.x,dir.y+1,dir.z)
45 self.goal = vector.new(pos.x,pos.y+1,pos.z)
53 --this will turn the z into x and x into z
54 minecart.flip_direction_axis = function(self)
55 self.dir = vector.new(self.dir.z,0,self.dir.x)
58 --this makes the minecart move in "blocks"
59 --it will go to it's goal then when it has reached the goal, move to another goal
60 minecart.movement = function(self)
61 if self.dir and self.goal then
62 local pos = self.object:get_pos()
63 local distance_from_goal = vector.distance(pos,self.goal)
66 --make minecart slow down, but only so much
68 --speed up going downhill
69 if self.dir and (self.dir.y == -1 or self.rider) and self.speed < 10 then
70 self.speed = self.speed + 0.1
71 --slow down going uphill
72 elseif self.dir and self.dir.y == 1 then
73 self.speed = self.speed - 0.12
74 --normal flat friction slowdown
75 elseif self.speed > 0.1 then
76 self.speed = self.speed - 0.01
80 --if the minecart is slowed down below 1 nph (node per hour)
81 --try to flip direction if pointing up
82 --then stop it if failed
83 if self.speed < 0.2 then
84 if self.dir.y == 1 then
85 self.dir = vector.multiply(self.dir, -1)
86 minecart.set_direction(self,self.dir)
95 --this checks how far the minecart is from the "goal node"
96 --aka the node that the minecart was supposed to go to
97 if distance_from_goal < 0.2 or self.goal == nil then
98 self.object:set_velocity(vector.new(0,0,0))
100 --self.object:move_to(minecart.round_pos(self.object:get_pos()))
102 --otherwise try to keep going
104 --test to see if minecart will keep moving
105 minecart.set_direction(self,self.dir)
107 --if not rail ahead then we'll try to turn
108 if not self.goal then
109 minecart.flip_direction_axis(self)
111 minecart.set_direction(self,self.dir)
113 --if trying to turn that direcion failed we'll try the other
114 if not self.goal then
115 self.dir = vector.multiply(self.dir, -1)
116 minecart.set_direction(self,self.dir)
120 --and if everything fails, give up and stop
121 if not self.goal then
127 if self.dir and self.goal then
128 local movement = vector.direction(pos,self.goal)
129 self.object:set_velocity(vector.multiply(movement,self.speed))
132 --stop the minecart from flying off into the distance
133 elseif not vector.equals(self.object:get_velocity(), vector.new(0,0,0)) and (self.speed == 0 or not self.speed) then
134 self.object:set_velocity(vector.new(0,0,0))
135 --this is when the minecart is stopped
136 --gotta figure out some way to apply gravity and make it physical
137 --without breaking the rest of it
138 elseif self.speed == 0 then
139 --self.object:add_velocity(vector.new(0,-10,0))
145 --this simply sets the mesh based on if the minecart is moving up or down
146 --this will be replaced by set animation in the future
147 minecart.set_mesh = function(self)
148 if self.dir and self.dir.y < 0 then
149 self.object:set_animation({x=2,y=2}, 15, 0, true)
150 elseif self.dir and self.dir.y > 0 then
151 self.object:set_animation({x=1,y=1}, 15, 0, true)
153 self.object:set_animation({x=0,y=0}, 15, 0, true)
157 minecart.on_step = function(self,dtime)
158 local pos = self.object:get_pos()
160 --get player input (standing next to the minecart)
161 for _,object in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
162 if self.object ~= object and object:is_player() and object:get_player_name() ~= self.rider then
163 local pos2 = object:get_pos()
164 minecart.set_direction(self, minecart.get_dir(pos,pos2))
169 --this makes the minecart actually move, it is also
170 --the begining of it's logic
171 minecart.movement(self)
173 --set the minecart's mesh
174 minecart.set_mesh(self)
177 --make the player ride the minecart
178 --or make the player get off
179 minecart.on_rightclick = function(self,clicker)
180 if not clicker or not clicker:is_player() then return end
181 local name = clicker:get_player_name()
183 --get on the minecart
184 if not self.rider then
186 clicker:set_attach(self.object, "", {x=0, y=0, z=0}, {x=0, y=0, z=0})
187 --get off the minecart
188 elseif name == self.rider then
195 minecart.on_activate = function(self,staticdata, dtime_s)
196 self.object:set_armor_groups({immortal=1})
197 if string.sub(staticdata, 1, string.len("return")) ~= "return" then
200 local data = minetest.deserialize(staticdata)
201 if type(data) ~= "table" then
205 self.goal = data.goal
206 self.speed = data.speed
208 --run through if there was a rider then check if they exist and put them back on
209 --and if they don't exist then nillify the rider value
211 if minetest.player_exists(data.rider) then
212 self.rider = data.rider
213 local player = minetest.get_player_by_name(data.rider)
214 player:set_attach(self.object, "", {x=0, y=0, z=0}, {x=0, y=0, z=0})
225 minecart.get_staticdata = function(self)
226 return minetest.serialize({
236 minecart.initial_properties = {
237 physical = false, -- otherwise going uphill breaks
238 collisionbox = {-0.4, -0.5, -0.4, 0.4, 0.45, 0.4},--{-0.5, -0.4, -0.5, 0.5, 0.25, 0.5},
241 visual_size = {x=1, y=1},
242 textures = {"minecart.png"},
243 automatic_face_movement_dir = 90.0,
244 automatic_face_movement_max_rotation_per_sec = 1200,
248 minecart.on_punch = function(self,puncher, time_from_last_punch, tool_capabilities, dir, damage)
249 local obj = minetest.add_item(self.object:getpos(), "minecart:minecart")
255 minetest.register_entity("minecart:minecart", minecart)
268 minetest.register_craftitem("minecart:minecart", {
269 description = "Minecart",
270 inventory_image = "minecartitem.png",
271 wield_image = "minecartitem.png",
272 on_place = function(itemstack, placer, pointed_thing)
273 if not pointed_thing.type == "node" then
277 local sneak = placer:get_player_control().sneak
278 local noddef = minetest.registered_nodes[minetest.get_node(pointed_thing.under).name]
279 if not sneak and noddef.on_rightclick then
280 minetest.item_place(itemstack, placer, pointed_thing)
284 if minetest.get_item_group(minetest.get_node(pointed_thing.under).name, "rail")>0 then
285 minetest.add_entity(pointed_thing.under, "minecart:minecart")
290 itemstack:take_item()
296 minetest.register_craft({
297 output = "minecart:minecart",
299 {"main:iron", "", "main:iron"},
300 {"main:iron", "main:iron", "main:iron"},