]> git.lizzy.rs Git - Crafter.git/blob - mods/boat/init.lua
Make boats placable on land
[Crafter.git] / mods / boat / init.lua
1 --minetest.get_node_level(pos)
2 minetest.register_entity("boat:boat", {
3         initial_properties = {
4                 hp_max = 1,
5                 physical = true,
6                 collide_with_objects = false,
7                 collisionbox = {-0.4, 0, -0.4, 0.4, 0.5, 0.4},
8                 visual = "mesh",
9                 mesh = "boat.x",
10                 textures = {"boat.png"},
11                 visual_size = {x=1,y=1,z=1},
12                 is_visible = true,
13                 automatic_face_movement_dir = -90.0,
14                 automatic_face_movement_max_rotation_per_sec = 600,
15         },
16         
17         rider = nil,
18         boat = true,
19
20         get_staticdata = function(self)
21                 return minetest.serialize({
22                         --itemstring = self.itemstring,
23                 })
24         end,
25
26         on_activate = function(self, staticdata, dtime_s)
27                 if string.sub(staticdata, 1, string.len("return")) == "return" then
28                         local data = minetest.deserialize(staticdata)
29                         if data and type(data) == "table" then
30                                 --self.itemstring = data.itemstring
31                         end
32                 else
33                         --self.itemstring = staticdata
34                 end
35                 self.object:set_armor_groups({immortal = 1})
36                 self.object:set_velocity({x = 0, y = 0, z = 0})
37                 self.object:set_acceleration({x = 0, y = 0, z = 0})
38         end,
39         on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
40                 local pos = self.object:get_pos()
41                 minetest.add_item(pos, "boat:boat")
42                 self.object:remove()
43         end,
44         
45         
46         on_rightclick = function(self,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                         clicker:set_detach()
54                         local pos = self.object:get_pos()
55                         pos.y = pos.y + 1
56                         clicker:move_to(pos)
57                         clicker:add_player_velocity(vector.new(0,11,0))
58                         self.rider = nil
59                         
60                         player_is_attached(clicker,false)
61                         force_update_animation(clicker)
62
63                 elseif not self.rider then
64                         self.rider = player_name
65                         clicker:set_attach(self.object, "", {x=0, y=2, z=0}, {x=0, y=0, z=0})
66                         
67                         set_player_animation(clicker,"sit",0)
68                         player_is_attached(clicker,true)
69                 end
70         end,
71         --check if the boat is stuck on land
72         check_if_on_land = function(self)
73                 local pos = self.object:get_pos()
74                 pos.y = pos.y - 0.37
75                 local bottom_node = minetest.get_node(pos).name
76                 if (bottom_node == "main:water" or bottom_node == "main:waterflow" or bottom_node == "air") then
77                         self.on_land = false
78                 else
79                         self.on_land = true
80                 end
81         
82         end,
83         
84         --players drive the baot
85         drive = function(self)
86                 if self.rider and not self.on_land == true then
87                         local rider = minetest.get_player_by_name(self.rider)
88                         local move = rider:get_player_control().up
89                         self.moving = nil
90                         if move then
91                                 local currentvel = self.object:get_velocity()
92                                 local goal = rider:get_look_dir()
93                                 goal = vector.multiply(goal,20)
94                                 local acceleration = vector.new(goal.x-currentvel.x,0,goal.z-currentvel.z)
95                                 acceleration = vector.multiply(acceleration, 0.01)
96                                 self.object:add_velocity(acceleration)
97                                 self.moving = true
98                         end
99                 else
100                         self.moving = nil
101                 end
102         end,
103         
104         --players push boat
105         push = function(self)
106                 local pos = self.object:get_pos()
107                 for _,object in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
108                         if object:is_player() and object:get_player_name() ~= self.rider then
109                                 local player_pos = object:get_pos()
110                                 pos.y = 0
111                                 player_pos.y = 0
112                                 
113                                 local currentvel = self.object:get_velocity()
114                                 local vel = vector.subtract(pos, player_pos)
115                                 vel = vector.normalize(vel)
116                                 local distance = vector.distance(pos,player_pos)
117                                 distance = (1-distance)*10
118                                 vel = vector.multiply(vel,distance)
119                                 local acceleration = vector.new(vel.x-currentvel.x,0,vel.z-currentvel.z)
120                                 self.object:add_velocity(acceleration)
121                                 acceleration = vector.multiply(acceleration, -1)
122                                 object:add_player_velocity(acceleration)
123                         end
124                 end
125         end,
126         
127         --makes the boat float
128         float = function(self)
129                 local pos = self.object:get_pos()
130                 local node = minetest.get_node(pos).name
131                 self.swimming = false
132                 
133                 --flow normally if floating else don't
134                 if node == "main:water" or node =="main:waterflow" then
135                         self.object:set_acceleration(vector.new(0,0,0))
136                         self.swimming = true
137                         local vel = self.object:get_velocity()
138                         local goal = 9
139                         local acceleration = vector.new(0,goal-vel.y,0)
140                         acceleration = vector.multiply(acceleration, 0.01)
141                         self.object:add_velocity(acceleration)
142                         --self.object:set_acceleration(vector.new(0,0,0))
143                 else
144                         self.object:set_acceleration(vector.new(0,-10,0))
145                 end
146         end,
147         
148         --makes boats flow
149         flow = function(self)
150                 local pos = self.object:get_pos()
151                 pos.y = pos.y - 0.4
152                 local node = minetest.get_node(pos).name
153                 local node_above = minetest.get_node(vector.new(pos.x,pos.y+1,pos.z)).name
154                 local goalx = 0
155                 local goalz = 0
156                 --print(node_above)
157                 if (node == "main:waterflow" or node == "main:water" ) and not self.moving == true and (node_above ~= "main:water" and node_above ~= "main:waterflow") then
158                         local currentvel = self.object:get_velocity()
159                         local level = minetest.get_node_level(pos)
160                         local pos = self.object:get_pos()
161                         for x = -1,1 do
162                                 for y = -1,0 do
163                                         for z = -1,1 do
164                                                 if (x == 0 and z ~= 0) or (z == 0 and x ~=0) then
165                                                         local nodename = minetest.get_node(vector.new(pos.x+x,pos.y+y,pos.z+z)).name
166                                                         local level2 = minetest.get_node_level(vector.new(pos.x+x,pos.y+y,pos.z+z))
167                                                         if (level2 < level and nodename == "main:waterflow") or (nodename == "main:water" and level2 == 7)  then
168                                                                 goalx = x*7
169                                                                 goalz = z*7
170                                                                 --break
171                                                         end
172                                                 end
173                                         end
174                                 end
175                         end
176                         --only add velocity if there is one
177                         --else this stops the boat
178                         if goalx ~= 0 or goalz ~= 0 then
179                                 local acceleration = vector.new(goalx-currentvel.x,0,goalz-currentvel.z)
180                                 acceleration = vector.multiply(acceleration, 0.01)
181                                 self.object:add_velocity(acceleration)
182                         end
183                 end
184         end,
185         
186         
187         --slows the boat down
188         slowdown = function(self)
189                 if not self.moving == true then
190                         local vel = self.object:get_velocity()
191                         local acceleration = vector.new(-vel.x,0,-vel.z)
192                         local deceleration = vector.multiply(acceleration, 0.01)
193                         self.object:add_velocity(deceleration)
194                 end
195         end,
196
197         lag_correction = function(self,dtime)
198                 local pos = self.object:get_pos()
199                 local velocity = self.object:get_velocity()
200                 if self.lag_check then
201                         local chugent = minetest.get_us_time()/1000000 - self.lag_check
202
203                         --print("lag = "..chugent.." ms")
204                         if chugent > 1 and  self.old_pos and self.old_velocity then
205                                 self.object:move_to(self.old_pos)
206                                 self.object:set_velocity(self.old_velocity)
207                         end
208                 end
209                 self.old_pos = pos
210                 self.old_velocity = vel
211                 self.lag_check = minetest.get_us_time()/1000000
212         end,
213
214         on_step = function(self, dtime)
215                 self.check_if_on_land(self)
216                 self.push(self)
217                 self.drive(self)
218                 self.float(self)
219                 self.flow(self)
220                 self.slowdown(self)
221                 self.lag_correction(self,dtime)
222         end,
223 })
224
225 minetest.register_craftitem("boat:boat", {
226         description = "Boat",
227         inventory_image = "boatitem.png",
228         wield_image = "boatitem.png",
229         liquids_pointable = true,
230         on_place = function(itemstack, placer, pointed_thing)
231                 if not pointed_thing.type == "node" then
232                         return
233                 end
234                 
235                 local sneak = placer:get_player_control().sneak
236                 local noddef = minetest.registered_nodes[minetest.get_node(pointed_thing.under).name]
237                 if not sneak and noddef.on_rightclick then
238                         minetest.item_place(itemstack, placer, pointed_thing)
239                         return
240                 end
241                 
242                 minetest.add_entity(pointed_thing.above, "boat:boat")
243
244                 itemstack:take_item()
245
246                 return itemstack
247         end,
248 })
249
250 minetest.register_craft({
251         output = "boat:boat",
252         recipe = {
253                 {"main:wood", "", "main:wood"},
254                 {"main:wood", "main:wood", "main:wood"},
255         },
256 })
257
258 ----------------------------------
259
260
261
262 minetest.register_entity("boat:iron_boat", {
263         initial_properties = {
264                 hp_max = 1,
265                 physical = true,
266                 collide_with_objects = false,
267                 collisionbox = {-0.4, 0, -0.4, 0.4, 0.5, 0.4},
268                 visual = "mesh",
269                 mesh = "boat.x",
270                 textures = {"iron_boat.png"},
271                 visual_size = {x=1,y=1,z=1},
272                 is_visible = true,
273                 automatic_face_movement_dir = -90.0,
274                 automatic_face_movement_max_rotation_per_sec = 600,
275         },
276         
277         rider = nil,
278         iron_boat = true,
279
280         get_staticdata = function(self)
281                 return minetest.serialize({
282                         --itemstring = self.itemstring,
283                 })
284         end,
285
286         on_activate = function(self, staticdata, dtime_s)
287                 if string.sub(staticdata, 1, string.len("return")) == "return" then
288                         local data = minetest.deserialize(staticdata)
289                         if data and type(data) == "table" then
290                                 --self.itemstring = data.itemstring
291                         end
292                 else
293                         --self.itemstring = staticdata
294                 end
295                 self.object:set_armor_groups({immortal = 1})
296                 self.object:set_velocity({x = 0, y = 0, z = 0})
297                 self.object:set_acceleration({x = 0, y = 0, z = 0})
298         end,
299         on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
300                 local pos = self.object:get_pos()
301                 minetest.add_item(pos, "boat:iron_boat")
302                 self.object:remove()
303         end,
304         
305         
306         on_rightclick = function(self,clicker)
307                 if not clicker or not clicker:is_player() then
308                         return
309                 end
310                 local player_name = clicker:get_player_name()
311                 
312                 if self.rider and player_name == self.rider then
313                         clicker:set_detach()
314                         local pos = self.object:get_pos()
315                         pos.y = pos.y + 1
316                         clicker:move_to(pos)
317                         clicker:add_player_velocity(vector.new(0,11,0))
318                         self.rider = nil
319                         
320                         player_is_attached(clicker,false)
321                         force_update_animation(clicker)
322
323                 elseif not self.rider then
324                         self.rider = player_name
325                         clicker:set_attach(self.object, "", {x=0, y=2, z=0}, {x=0, y=0, z=0})
326                         
327                         set_player_animation(clicker,"sit",0)
328                         player_is_attached(clicker,true)
329                 end
330         end,
331         --check if the boat is stuck on land
332         check_if_on_land = function(self)
333                 local pos = self.object:get_pos()
334                 pos.y = pos.y - 0.37
335                 local bottom_node = minetest.get_node(pos).name
336                 if (bottom_node == "nether:lava" or bottom_node == "nether:lavaflow" or bottom_node == "air") then
337                         self.on_land = false
338                 else
339                         self.on_land = true
340                 end
341         
342         end,
343         
344         --players drive the baot
345         drive = function(self)
346                 if self.rider and not self.on_land == true then
347                         local rider = minetest.get_player_by_name(self.rider)
348                         local move = rider:get_player_control().up
349                         self.moving = nil
350                         if move then
351                                 local currentvel = self.object:get_velocity()
352                                 local goal = rider:get_look_dir()
353                                 goal = vector.multiply(goal,20)
354                                 local acceleration = vector.new(goal.x-currentvel.x,0,goal.z-currentvel.z)
355                                 acceleration = vector.multiply(acceleration, 0.01)
356                                 self.object:add_velocity(acceleration)
357                                 self.moving = true
358                         end
359                 else
360                         self.moving = nil
361                 end
362         end,
363         
364         --players push boat
365         push = function(self)
366                 local pos = self.object:get_pos()
367                 for _,object in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
368                         if object:is_player() and object:get_player_name() ~= self.rider then
369                                 local player_pos = object:get_pos()
370                                 pos.y = 0
371                                 player_pos.y = 0
372                                 
373                                 local currentvel = self.object:get_velocity()
374                                 local vel = vector.subtract(pos, player_pos)
375                                 vel = vector.normalize(vel)
376                                 local distance = vector.distance(pos,player_pos)
377                                 distance = (1-distance)*10
378                                 vel = vector.multiply(vel,distance)
379                                 local acceleration = vector.new(vel.x-currentvel.x,0,vel.z-currentvel.z)
380                                 self.object:add_velocity(acceleration)
381                                 acceleration = vector.multiply(acceleration, -1)
382                                 object:add_player_velocity(acceleration)
383                         end
384                 end
385         end,
386         
387         --makes the boat float
388         float = function(self)
389                 local pos = self.object:get_pos()
390                 local node = minetest.get_node(pos).name
391                 self.swimming = false
392                 
393                 --flow normally if floating else don't
394                 if node == "nether:lava" or node =="nether:lavaflow" then
395                         self.swimming = true
396                         local vel = self.object:get_velocity()
397                         local goal = 9
398                         local acceleration = vector.new(0,goal-vel.y,0)
399                         acceleration = vector.multiply(acceleration, 0.01)
400                         self.object:add_velocity(acceleration)
401                         --self.object:set_acceleration(vector.new(0,0,0))
402                 else
403                         local vel = self.object:get_velocity()
404                         local goal = -9.81
405                         local acceleration = vector.new(0,goal-vel.y,0)
406                         acceleration = vector.multiply(acceleration, 0.01)
407                         self.object:add_velocity(acceleration)
408                         --self.object:set_acceleration(vector.new(0,0,0))
409                 end
410         end,
411         
412         --makes boats flow
413         flow = function(self)
414                 local pos = self.object:get_pos()
415                 pos.y = pos.y - 0.4
416                 local node = minetest.get_node(pos).name
417                 local node_above = minetest.get_node(vector.new(pos.x,pos.y+1,pos.z)).name
418                 local goalx = 0
419                 local goalz = 0
420                 --print(node_above)
421                 if (node == "nether:lavaflow" or node == "nether:lava" ) and not self.moving == true and (node_above ~= "nether:lava" and node_above ~= "nether:lavaflow") then
422                         local currentvel = self.object:get_velocity()
423                         local level = minetest.get_node_level(pos)
424                         local pos = self.object:get_pos()
425                         for x = -1,1 do
426                                 for y = -1,0 do
427                                         for z = -1,1 do
428                                                 if (x == 0 and z ~= 0) or (z == 0 and x ~=0) then
429                                                         local nodename = minetest.get_node(vector.new(pos.x+x,pos.y+y,pos.z+z)).name
430                                                         local level2 = minetest.get_node_level(vector.new(pos.x+x,pos.y+y,pos.z+z))
431                                                         if (level2 < level and nodename == "main:lavaflow") or (nodename == "main:lava" and level2 == 7)  then
432                                                                 goalx = x*7
433                                                                 goalz = z*7
434                                                                 --break
435                                                         end
436                                                 end
437                                         end
438                                 end
439                         end
440                         --only add velocity if there is one
441                         --else this stops the boat
442                         if goalx ~= 0 or goalz ~= 0 then
443                                 local acceleration = vector.new(goalx-currentvel.x,0,goalz-currentvel.z)
444                                 acceleration = vector.multiply(acceleration, 0.01)
445                                 self.object:add_velocity(acceleration)
446                         end
447                 end
448         end,
449         
450         
451         --slows the boat down
452         slowdown = function(self)
453                 if not self.moving == true then
454                         local vel = self.object:get_velocity()
455                         local acceleration = vector.new(-vel.x,0,-vel.z)
456                         local deceleration = vector.multiply(acceleration, 0.01)
457                         self.object:add_velocity(deceleration)
458                 end
459         end,
460
461         lag_correction = function(self,dtime)
462                 local pos = self.object:get_pos()
463                 local velocity = self.object:get_velocity()
464                 if self.lag_check then
465                         local chugent = minetest.get_us_time()/1000000- self.lag_check
466
467                         --print("lag = "..chugent.." ms")
468                         if chugent > 70 and  self.old_pos and self.old_velocity then
469                                 self.object:move_to(self.old_pos)
470                                 self.object:set_velocity(self.old_velocity)
471                         end
472                 end
473                 self.old_pos = pos
474                 self.old_velocity = vel
475                 self.lag_check = minetest.get_us_time()/1000000
476         end,
477
478         on_step = function(self, dtime)
479                 self.check_if_on_land(self)
480                 self.push(self)
481                 self.drive(self)
482                 self.float(self)
483                 self.flow(self)
484                 self.slowdown(self)
485                 self.lag_correction(self,dtime)
486         end,
487 })
488
489 minetest.register_craftitem("boat:iron_boat", {
490         description = "Nether Iron Boat",
491         inventory_image = "iron_boatitem.png",
492         wield_image = "iron_boatitem.png",
493         liquids_pointable = true,
494         on_place = function(itemstack, placer, pointed_thing)
495                 if not pointed_thing.type == "node" then
496                         return
497                 end
498                 
499                 local sneak = placer:get_player_control().sneak
500                 local noddef = minetest.registered_nodes[minetest.get_node(pointed_thing.under).name]
501                 if not sneak and noddef.on_rightclick then
502                         minetest.item_place(itemstack, placer, pointed_thing)
503                         return
504                 end
505                 
506                 minetest.add_entity(pointed_thing.above, "boat:iron_boat")
507
508                 itemstack:take_item()
509
510                 return itemstack
511         end,
512 })
513
514 minetest.register_craft({
515         output = "boat:iron_boat",
516         recipe = {
517                 {"main:iron", "main:coal", "main:iron"},
518                 {"main:iron", "main:iron", "main:iron"},
519         },
520 })