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