]> git.lizzy.rs Git - Crafter.git/blob - mods/minecart/init.lua
061007f170e45b1d7f4dafbc2dae330d9e3fc986
[Crafter.git] / mods / minecart / init.lua
1 local path = minetest.get_modpath("minecart")
2 dofile(path.."/rail.lua")
3
4 --this begins the minecart library
5 local minecart = {}
6
7
8 --these are the variables for the minecart
9 minecart.max_speed = 15
10 minecart.speed = 0
11 minecart.rider = nil
12
13 --binary direction
14 minecart.get_dir = function(pos,pos2)
15         return(minetest.facedir_to_dir(minetest.dir_to_facedir(vector.direction(pos2,pos))))
16 end
17 --this gets the node position that the minecart is in
18 minecart.round_pos = function(pos)
19         return(vector.round(pos))
20 end
21
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
24 --will begin movement 
25 minecart.set_direction = function(self,dir)
26         if not self.goal then
27                 --reset the y to 0 since we will be checking up and down anyways
28                 dir.y = 0
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
33                 
34                 --next to
35                 if node == "minecart:rail" and node_under ~= "minecart:rail" then
36                         self.dir = dir
37                         self.goal = pos
38                 --downhill
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)
42                 --uphill
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)
46                 --rail not found
47                 else
48                         self.goal = nil
49                 end
50         end
51 end
52
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)
56 end
57
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)
64                 
65                 
66                 --make minecart slow down, but only so much
67                 
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
77                 end
78                 
79                 --
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)
87                                 self.goal = nil
88                         else
89                                 self.speed = 0
90                                 self.dir = nil
91                                 self.goal = nil
92                         end
93                 end
94                 
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))
99                         self.goal = nil
100                         --self.object:move_to(minecart.round_pos(self.object:get_pos()))
101                                 
102                         --otherwise try to keep going
103                         if self.dir then
104                                 --test to see if minecart will keep moving
105                                 minecart.set_direction(self,self.dir)
106                                 
107                                 --if not rail ahead then we'll try to turn
108                                 if not self.goal then                                   
109                                         minecart.flip_direction_axis(self)
110                                         
111                                         minecart.set_direction(self,self.dir)
112                                         
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)
117                                         end
118                                 end
119                                 
120                                 --and if everything fails, give up and stop
121                                 if not self.goal then
122                                         self.speed = 0
123                                 end
124                         end
125                 end
126                 
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))
130                 end
131                 
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))
140         end
141         
142         
143 end
144
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)
152         else
153                 self.object:set_animation({x=0,y=0}, 15, 0, true)
154         end
155 end
156
157 minecart.on_step = function(self,dtime)
158         local pos = self.object:get_pos()
159         
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))
165                         self.speed = 7
166                 end
167         end     
168         
169         --this makes the minecart actually move, it is also
170         --the begining of it's logic
171         minecart.movement(self)
172         
173         --set the minecart's mesh
174         minecart.set_mesh(self)
175 end
176
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()
182         
183         --get on the minecart
184         if not self.rider then
185                 self.rider = name
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
189                 self.rider = nil
190                 clicker:set_detach()
191         end
192 end
193
194 --get old data
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
198                 return
199         end
200         local data = minetest.deserialize(staticdata)
201         if type(data) ~= "table" then
202                 return
203         end
204         self.dir = data.dir
205         self.goal = data.goal
206         self.speed = data.speed
207         
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
210         if data.rider then
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})
215                 else
216                         self.rider = nil
217                 end
218         else
219                 self.rider = nil
220         end
221         
222         
223 end
224 --remember data
225 minecart.get_staticdata = function(self)
226         return minetest.serialize({
227                 dir = self.dir,
228                 goal = self.goal,
229                 speed = self.speed,
230                 rider = self.rider
231         })
232 end
233
234
235
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},
239         visual = "mesh",
240         mesh = "minecart.x",
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,
245 }
246
247
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")
250         self.object:remove()
251 end
252
253         
254
255 minetest.register_entity("minecart:minecart", minecart)
256
257
258
259
260
261
262
263
264
265
266
267
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
274                         return
275                 end
276                 
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)
281                         return
282                 end
283                 
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")
286                 else
287                         return
288                 end
289
290                 itemstack:take_item()
291
292                 return itemstack
293         end,
294 })
295
296 minetest.register_craft({
297         output = "minecart:minecart",
298         recipe = {
299                 {"main:iron", "", "main:iron"},
300                 {"main:iron", "main:iron", "main:iron"},
301         },
302 })