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