]> git.lizzy.rs Git - Crafter.git/blob - mods/minecart/init.lua
Add functioning rail coupling
[Crafter.git] / mods / minecart / init.lua
1 local pool = {}
2
3 local player_pool = {}
4
5
6 local dirs = {
7         {x= 1,y= 0,z= 0},
8         {x=-1,y= 0,z= 0},
9
10         {x= 1,y= 1,z= 0}, 
11         {x=-1,y= 1,z= 0},
12
13         {x= 1,y=-1,z= 0},
14         {x=-1,y=-1,z= 0},
15
16         {x= 0,y= 0,z= 1},
17         {x= 0,y= 0,z=-1},
18
19         {x= 0,y= 1,z= 1},
20         {x= 0,y= 1,z=-1},
21
22         {x= 0,y=-1,z= 1},
23         {x= 0,y=-1,z=-1},
24 }
25
26 local axis_order = {
27
28 }
29 local function data_injection(pos,data)
30         if data then
31                 pool[minetest.hash_node_position(pos)] = true
32         else
33                 pool[minetest.hash_node_position(pos)] = nil
34         end
35 end
36
37 local function speed_limiter(self,speed)
38         local test = self.object:get_velocity()--vector.multiply(self.velocity,new_vel)
39
40         if test.x > speed then
41                 test.x = speed
42         elseif test.x < -speed then
43                 test.x = -speed
44         end
45         if test.z > speed then
46                 test.z = speed
47         elseif test.z < -speed then
48                 test.z = -speed         
49         end
50         self.object:set_velocity(test)
51 end
52
53 local function create_axis(pos)
54         local possible_dirs = {}
55         for _,dir in pairs(dirs) do
56                 local pos2 = vector.add(pos,dir)
57                 if pool[minetest.hash_node_position(pos2)] then
58                         table.insert(possible_dirs,dir)
59                 end
60         end
61         return(possible_dirs)
62 end
63
64 local function collision_detect(self)
65         if not self.axis_lock then return end
66         local pos = self.object:get_pos()
67         for _,object in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
68                 if object:is_player() then
69                         local pos2 = object:get_pos()
70                         if self.axis_lock == "x" then
71
72                                 local velocity = (1-vector.distance(vector.new(pos.x,0,0),vector.new(pos2.x,0,0)))*5
73                                 local dir = vector.direction(vector.new(pos2.x,0,0),vector.new(pos.x,0,0))
74                                 local new_vel = vector.multiply(dir,velocity)
75                                 self.object:add_velocity(new_vel)
76                                 self.dir = dir
77                         elseif self.axis_lock == "z" then
78                                 local velocity = (1-vector.distance(vector.new(0,0,pos.z),vector.new(0,0,pos2.z)))*5
79                                 local dir = vector.direction(vector.new(0,0,pos2.z),vector.new(0,0,pos.z))
80                                 local new_vel = vector.multiply(dir,velocity)
81                                 self.object:add_velocity(new_vel)
82                                 self.dir = dir
83                         end
84                         return
85                 end
86         end
87 end
88
89 local function direction_snap(self)
90         local dir = self.dir
91         local pitch = 0
92         if dir.y == 1 then pitch = math.pi/4 end
93         if dir.y == -1 then pitch = -math.pi/4 end
94         local yaw = minetest.dir_to_yaw(dir)
95         self.object:set_rotation(vector.new(pitch,yaw,0))
96 end
97
98 local function turn_snap(pos,self,dir,dir2)
99         if self.axis_lock == "x" then
100                 if dir.x ~= 0 and dir2.z ~= 0 then
101                         local velocity = self.object:get_velocity()
102                         local inertia = math.abs(velocity.x)
103                         self.object:set_velocity(vector.multiply(dir2,inertia))
104                         self.dir = dir2
105                         self.axis_lock = "z"
106                         self.object:set_pos(pos)
107                         direction_snap(self)
108                         return(true)
109                 end
110         end
111         if self.axis_lock == "z" then
112                 if dir.z ~= 0 and dir2.x ~= 0 then
113                         local velocity = self.object:get_velocity()
114                         local inertia = math.abs(velocity.z)
115                         self.object:set_velocity(vector.multiply(dir2,inertia))
116                         self.dir = dir2
117                         self.axis_lock = "x"
118                         self.object:set_pos(pos)
119                         direction_snap(self)
120                         return(true)
121                 end
122         end
123         return(false)
124 end
125
126 local function climb_snap(pos,self,dir,dir2)
127         if self.axis_lock == "x" then
128                 if dir.x == dir2.x and dir2.y ~= 0 then
129                         local velocity = self.object:get_velocity()
130                         local inertia = math.abs(velocity.x)
131                         self.object:set_velocity(vector.multiply(dir2,inertia))
132                         self.dir = dir2
133                         self.axis_lock = "x"
134                         self.object:set_pos(pos)
135                         direction_snap(self)
136                         return(true)
137                 end
138         end
139         if self.axis_lock == "z" then
140                 if dir.z == dir2.z and dir2.y ~= 0 then
141                         local velocity = self.object:get_velocity()
142                         local inertia = math.abs(velocity.z)
143                         self.object:set_velocity(vector.multiply(dir2,inertia))
144                         self.dir = dir2
145                         self.axis_lock = "z"
146                         self.object:set_pos(pos)
147                         direction_snap(self)
148                         return(true)
149                 end
150         end
151         return(false)
152 end
153
154 local function straight_snap(pos,self,dir)
155         if self.axis_lock == "x" then
156                 if dir.x ~= 0 and pool[minetest.hash_node_position(vector.add(pos,vector.new(dir.x,0,0)))] then
157                         local velocity = self.object:get_velocity()
158                         self.object:set_velocity(vector.new(velocity.x,0,0))
159                         self.dir = vector.new(dir.x,0,0)
160                         self.axis_lock = "x"
161                         self.object:set_pos(pos)
162                         direction_snap(self)
163                         return(true)
164                 end
165         end
166         if self.axis_lock == "z" then
167                 if dir.z ~= 0 and pool[minetest.hash_node_position(vector.add(pos,vector.new(0,0,dir.z)))] then
168                         local velocity = self.object:get_velocity()
169                         self.object:set_velocity(vector.new(0,0,velocity.z))
170                         self.dir = vector.new(0,0,dir.z)
171                         self.axis_lock = "z"
172                         self.object:set_pos(pos)
173                         direction_snap(self)
174                         return(true)
175                 end
176         end
177         return(false)
178 end
179
180
181 local function coupling_logic(self)
182         
183         if not self.axis_lock then return end
184
185         if not self.coupler1 then return end
186
187         if self.dir.y ~= 0 then return end
188
189         local pos = self.object:get_pos()
190         
191         local pos2 = self.coupler1:get_pos()
192
193         if self.axis_lock == "x" then
194                 local velocity_real = self.object:get_velocity()
195                 local distance = vector.distance(pos,pos2)
196                 local new_vel = vector.new(0,0,0)
197                 if distance > 1.5 then
198                         local velocity = (distance-1)
199                         local dir = vector.direction(vector.new(pos.x,0,0),vector.new(pos2.x,0,0))
200                         self.dir = dir
201                         new_vel = vector.multiply(dir,velocity)
202                 else
203                         new_vel = vector.multiply(velocity_real,-1)
204                 end
205                 self.object:add_velocity(new_vel)
206         elseif self.axis_lock == "z" then
207                 local velocity_real = self.object:get_velocity()
208                 local distance = vector.distance(pos,pos2)
209                 local new_vel = vector.new(0,0,0)
210                 if distance > 1.5 then
211                         local velocity = (distance-1)
212                         local dir = vector.direction(vector.new(0,0,pos.z),vector.new(0,0,pos2.z))
213                         self.dir = dir
214                         new_vel = vector.multiply(dir,velocity)
215                 else
216                         new_vel = vector.multiply(velocity_real,-1)
217                 end
218                 self.object:add_velocity(new_vel)
219         end
220
221         return
222 end
223
224
225 local function rail_brain(self,pos)
226
227
228         if not self.dir then self.dir = vector.new(0,0,0) end
229
230         local pos2 = self.object:get_pos()
231
232         local dir = self.dir
233
234         speed_limiter(self,6)
235
236         if not pool[minetest.hash_node_position(vector.add(pos,dir))] then
237
238                 if straight_snap(pos,self,dir) then
239                         return
240                 end
241
242                 local possible_dirs = create_axis(pos)
243
244                 if table.getn(possible_dirs) == 0 then
245                         --stop slow down become physical
246                 else
247                         for _,dir2 in pairs(possible_dirs) do
248                                 if turn_snap(pos,self,dir,dir2) then
249                                         return
250                                 end
251                                 if climb_snap(pos,self,dir,dir2) then
252                                         return
253                                 end
254                         end
255                 end
256         else
257                 coupling_logic(self)
258         end
259
260 end
261
262 local minecart = {}
263
264 minecart.on_step = function(self,dtime)
265         local pos = vector.round(self.object:get_pos())
266         if not self.axis_lock then
267                 local possible_dirs = create_axis(pos)
268                 for _,dir in pairs(possible_dirs) do
269                         if dir.x ~=0 then
270                                 self.axis_lock = "x"
271                                 self.dir = dir
272                                 direction_snap(self)
273                                 break
274                         elseif dir.z ~= 0 then
275                                 self.axis_lock = "z"
276                                 self.dir = dir
277                                 direction_snap(self)
278                                 break
279                         end
280                 end
281         else
282                 rail_brain(self,pos)
283                 collision_detect(self)
284         end
285 end
286
287 minecart.on_rightclick = function(self,clicker)
288         local name = clicker:get_player_name()
289         if not pool[name] then
290                 pool[name] = self.object
291         else
292                 self.coupler1 = pool[name]
293                 --pool[name]:get_luaentity().coupler1 = self.object
294                 pool[name] = nil
295         end
296 end
297
298 --get old data
299 minecart.on_activate = function(self,staticdata, dtime_s)
300         self.object:set_armor_groups({immortal=1})
301         if string.sub(staticdata, 1, string.len("return")) ~= "return" then
302                 return
303         end
304         local data = minetest.deserialize(staticdata)
305         if type(data) ~= "table" then
306                 return
307         end
308         self.old_pos = self.object:get_pos()
309         self.velocity = vector.new(0,0,0)
310 end
311
312 minecart.get_staticdata = function(self)
313         return minetest.serialize({
314         })
315 end
316
317
318
319 minecart.initial_properties = {
320         physical = false, -- otherwise going uphill breaks
321         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},
322         visual = "mesh",
323         mesh = "minecart.x",
324         visual_size = {x=1, y=1},
325         textures = {"minecart.png"},
326 }
327
328
329 minecart.on_punch = function(self,puncher, time_from_last_punch, tool_capabilities, dir, damage)
330         --local obj = minetest.add_item(self.object:getpos(), "minecart:minecart")
331         --self.object:remove()
332 end
333
334         
335
336 minetest.register_entity("minecart:minecart", minecart)
337
338
339
340
341
342
343
344
345
346
347
348
349 minetest.register_craftitem("minecart:minecart", {
350         description = "Minecart",
351         inventory_image = "minecartitem.png",
352         wield_image = "minecartitem.png",
353         on_place = function(itemstack, placer, pointed_thing)
354                 if not pointed_thing.type == "node" then
355                         return
356                 end
357                 
358                 local sneak = placer:get_player_control().sneak
359                 local noddef = minetest.registered_nodes[minetest.get_node(pointed_thing.under).name]
360                 if not sneak and noddef.on_rightclick then
361                         minetest.item_place(itemstack, placer, pointed_thing)
362                         return
363                 end
364                 
365                 if minetest.get_item_group(minetest.get_node(pointed_thing.under).name, "rail")>0 then
366                         minetest.add_entity(pointed_thing.under, "minecart:minecart")
367                 else
368                         return
369                 end
370
371                 itemstack:take_item()
372
373                 return itemstack
374         end,
375 })
376
377 minetest.register_craft({
378         output = "minecart:minecart",
379         recipe = {
380                 {"main:iron", "", "main:iron"},
381                 {"main:iron", "main:iron", "main:iron"},
382         },
383 })
384
385
386
387
388
389 minetest.register_node("minecart:rail",{
390         description = "Rail",
391         wield_image = "rail.png",
392         tiles = {
393                 "rail.png", "railcurve.png",
394                 "railt.png", "railcross.png"
395         },
396         drawtype = "raillike",
397         paramtype = "light",
398         sunlight_propagates = true,
399         is_ground_content = false,
400         walkable = false,
401         node_placement_prediction = "",
402         selection_box = {
403                 type = "fixed",
404                 fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
405         },
406         sounds = main.stoneSound(),
407         after_place_node = function(pos)
408                 data_injection(pos,true)
409         end,
410         after_destruct = function(pos)
411                 data_injection(pos)
412         end,
413         groups={stone=1,wood=1,rail=1,attached_node=1},
414 })
415
416
417 minetest.register_lbm({
418         name = "minecart:rail",
419         nodenames = {"minecart:rail"},
420         run_at_every_load = true,
421         action = function(pos)
422                 data_injection(pos,true)
423         end,
424 })
425
426 minetest.register_craft({
427         output = "minecart:rail 32",
428         recipe = {
429                 {"main:iron","","main:iron"},
430                 {"main:iron","main:stick","main:iron"},
431                 {"main:iron","","main:iron"}
432         }
433 })