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