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