]> git.lizzy.rs Git - Crafter.git/blob - mods/minecart/init.lua
87258cc666b9515e6d27a1e04730b6386784f3c6
[Crafter.git] / mods / minecart / init.lua
1 --[[
2
3 Basic idealogy
4
5 keep it simple stupid
6
7 make cart make noise
8
9 make player able to push cart
10
11 make carts push each other away --repel axis
12
13 make chest and furnace cart
14
15
16 minetest.dir_to_facedir(dir, is6d) - to get player direction converted and to convert the minecart direction
17
18 ]]--
19 local path = minetest.get_modpath("minecart")
20 dofile(path.."/rail.lua")
21
22
23
24 local function is_rail(x,y,z)
25         return(minetest.get_node_group(minetest.get_node(vector.new(x,y,z)).name,"rail")>0)
26 end
27
28 local minecart = {
29         initial_properties = {
30                 physical = false, -- otherwise going uphill breaks
31                 collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},--{-0.5, -0.4, -0.5, 0.5, 0.25, 0.5},
32                 visual = "mesh",
33                 mesh = "minecart.obj",
34                 visual_size = {x=1, y=1},
35                 textures = {"minecart.png"},
36                 automatic_face_movement_dir = 90.0,
37                 automatic_face_movement_max_rotation_per_sec = 600,
38         },
39
40         rider = nil,
41         punched = false,
42         speed = 0,
43         
44 }
45
46 function minecart:on_rightclick(clicker)
47         if not clicker or not clicker:is_player() then
48                 return
49         end
50         local player_name = clicker:get_player_name()
51         
52         if self.rider and player_name == self.rider then
53                 self.rider = nil
54                 --carts:manage_attachment(clicker, nil)
55         elseif not self.rider then
56                 self.rider = player_name
57                 clicker:set_attach(self.object, "", {x=0, y=-4.5, z=0}, {x=0, y=0, z=0})
58                 --player:set_eye_offset({x=0, y=-4, z=0},{x=0, y=-4, z=0})
59                 --carts:manage_attachment(clicker, self.object)
60
61                 -- player_api does not update the animation
62                 -- when the player is attached, reset to default animation
63                 
64                 --player_api.set_animation(clicker, "stand")
65         end
66 end
67
68 function minecart:on_activate(staticdata, dtime_s)
69         self.object:set_armor_groups({immortal=1})
70         if string.sub(staticdata, 1, string.len("return")) ~= "return" then
71                 return
72         end
73         local data = minetest.deserialize(staticdata)
74         if type(data) ~= "table" then
75                 return
76         end
77         self.railtype = data.railtype
78         if data.old_dir then
79                 self.old_dir = data.old_dir
80         end
81 end
82
83 function minecart:get_staticdata()
84         return minetest.serialize({
85         })
86 end
87 function minecart:on_punch(puncher, time_from_last_punch, tool_capabilities, dir, damage)
88         local obj = minetest.add_item(self.object:getpos(), "minecart:minecart")
89         obj:get_luaentity().collection_timer = 2
90         self.object:remove()
91 end
92
93
94
95
96
97
98 --repel from players on track "push"
99 function minecart:push(self)
100         local pos = self.object:getpos()
101         for _,object in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
102                 if object:is_player() and object:get_player_name() ~= self.rider then
103                         local player_pos = object:getpos()
104                         pos.y = 0
105                         player_pos.y = 0
106                         
107                         local vel = vector.subtract(pos, player_pos)
108                         vel = vector.normalize(vel)
109                         local distance = vector.distance(pos,player_pos)
110                         
111                         distance = (1-distance)*10
112                         
113                         vel = vector.multiply(vel,distance)
114                         
115                         --only push if it's faster than current speed
116                         if distance > self.speed then
117                                 self.object:setvelocity(vel)
118                                 self.speed = distance
119                         end             
120                 end
121         end
122 end
123
124 function minecart:ride_rail(self)
125         local pos = vector.floor(vector.add(self.object:getpos(),0.5))
126         local speed = self.speed
127         if self.speed > 10 then
128                 self.speed = 10
129         end
130         
131         local vel = self.object:getvelocity()
132         local x = math.abs(vel.x)
133         local z = math.abs(vel.z)
134         local xdir
135         local zdir
136         local dir = {x=0,y=0,z=0}
137         
138         --check direction
139         --x axis
140         if x > z then
141                 if vel.x>0 then xdir=1 elseif vel.x<0 then xdir=-1 end
142                 
143                 --print(minetest.get_node(vector.new(pos.x,pos.y,pos.z)).name)
144                 
145                 --go up
146                 if is_rail(pos.x+xdir,pos.y+1,pos.z) or (not is_rail(pos.x,pos.y,pos.z) and is_rail(pos.x+xdir,pos.y,pos.z)) then
147                         --print("up")
148                         dir.y = speed
149                         dir.x = xdir*speed
150
151                 --go down
152                 elseif (is_rail(pos.x,pos.y-1,pos.z) or vel.y < 0) and not is_rail(pos.x+xdir,pos.y,pos.z) then
153                         --print("down")
154                         dir.y = -speed
155                         dir.x = xdir*speed
156                 
157                 --go flat
158                 elseif is_rail(pos.x,pos.y,pos.z) then --currently on rail
159                         --print("flat")
160                         --print("forward inside")
161                         --correct y position
162                         if dir.y == 0 and self.object:getpos().y ~= pos.y then
163                                 --print("correcting y")
164                                 local posser = self.object:getpos()
165                                 self.object:moveto(vector.new(posser.x,pos.y,posser.z))
166                         end
167                         dir.x = xdir*speed
168                 end
169         --z axis
170         elseif z > x then
171                 if vel.z>0 then zdir=1 elseif vel.z<0 then zdir=-1 end
172                 
173                 --print(minetest.get_node(vector.new(pos.x,pos.y,pos.z)).name)
174                 
175                 --go up
176                 if is_rail(pos.x,pos.y+1,pos.z+zdir) or (not is_rail(pos.x,pos.y,pos.z) and is_rail(pos.x,pos.y,pos.z+zdir)) then
177                         --print("up")
178                         dir.y = speed
179                         dir.z = zdir*speed
180                 
181                 --go down
182                 elseif (is_rail(pos.x,pos.y-1,pos.z) or vel.y < 0) and not is_rail(pos.x,pos.y,pos.z+zdir) then
183                         --print("down")
184                         dir.y = -speed
185                         dir.z = zdir*speed
186                 
187                 
188                 --go flat
189                 elseif is_rail(pos.x,pos.y,pos.z) then --currently on rail
190                         --print("flat")
191                         --print("forward inside")
192                         --correct y position
193                         if dir.y == 0 and self.object:getpos().y ~= pos.y then
194                                 --print("correcting y")
195                                 local posser = self.object:getpos()
196                                 self.object:moveto(vector.new(posser.x,pos.y,posser.z))
197                         end
198                         dir.z = zdir*speed
199                 end
200         end
201         --turn
202         local turnx = 0
203         local turnz = 0
204         
205         if vel.x>0 then turnx=1 elseif vel.x<0 then turnx=-1 end
206         if vel.z>0 then turnz=1 elseif vel.z<0 then turnz=-1 end
207         
208
209         if turnx and turnz and dir.y == 0 and not vector.equals(dir, vector.new(0,0,0)) and not is_rail(pos.x+turnx,pos.y-1,pos.z+turnz) and not is_rail(pos.x+turnx,pos.y,pos.z+turnz) and not is_rail(pos.x+turnx,pos.y+1,pos.z+turnz) then
210                 if x > z then
211                         for y = -1,1 do
212                                 if is_rail(pos.x,pos.y+y,pos.z+1) then
213                                         dir.z = speed
214                                         dir.x = 0
215                                         --recenter on the rail
216                                         self.object:moveto(pos)
217                                 elseif is_rail(pos.x,pos.y+y,pos.z-1) then
218                                         dir.z = -speed
219                                         dir.x = 0
220                                         --recenter on the rail
221                                         self.object:moveto(pos)
222                                 end
223                         end
224                 elseif z > x then
225                         for y = -1,1 do
226                                 if is_rail(pos.x+1,pos.y+y,pos.z) then
227                                         dir.x = speed
228                                         dir.z = 0
229                                         --recenter on the rail
230                                         self.object:moveto(pos)
231                                 elseif is_rail(pos.x-1,pos.y+y,pos.z) then
232                                         dir.x = -speed
233                                         dir.z = 0
234                                         --recenter on the rail
235                                         self.object:moveto(pos)
236                                 end
237                         end
238                 end
239                 
240         end
241         --apply
242         --if not vector.equals(dir,vector.new(0,0,0)) then
243         self.object:setvelocity(dir)
244         --end
245         self.oldpos=self.object:getpos()
246         
247         --make the cart move up and down on hills
248         self.object:set_properties({mesh="minecart.obj"})
249         if vel.y <0  then
250                 self.object:set_properties({mesh="minecart_down.obj"})
251         elseif vel.y > 0 then
252                 self.object:set_properties({mesh="minecart_up.obj"})
253         end
254         
255         --slow it down
256         if self.speed > 0 then
257                 self.speed = self.speed - 0.01
258         end
259         if self.speed < 0 then
260                 self.speed = 0
261         end
262         
263 end
264
265 function minecart:on_step(dtime)
266         minecart:push(self)
267         minecart:ride_rail(self)
268 end
269
270 minetest.register_entity("minecart:minecart", minecart)
271
272
273 minetest.register_craftitem("minecart:minecart", {
274         description = "Minecart",
275         inventory_image = "minecartitem.png",
276         wield_image = "minecartitem.png",
277         on_place = function(itemstack, placer, pointed_thing)
278                 if not pointed_thing.type == "node" then
279                         return
280                 end
281                 
282                 if minetest.get_item_group(minetest.get_node(pointed_thing.under).name, "rail")>0 then
283                         minetest.add_entity(pointed_thing.under, "minecart:minecart")
284                 else
285                         return
286                 end
287
288                 itemstack:take_item()
289
290                 return itemstack
291         end,
292 })
293
294 minetest.register_craft({
295         output = "minecart:minecart",
296         recipe = {
297                 {"main:iron", "", "main:iron"},
298                 {"main:iron", "main:iron", "main:iron"},
299         },
300 })