Remove minetest.inventorycube
[oweals/minetest_game.git] / mods / boats / init.lua
1 --
2 -- Helper functions
3 --
4
5 local function is_water(pos)
6         local nn = minetest.get_node(pos).name
7         return minetest.get_item_group(nn, "water") ~= 0
8 end
9
10
11 local function get_sign(i)
12         if i == 0 then
13                 return 0
14         else
15                 return i / math.abs(i)
16         end
17 end
18
19
20 local function get_velocity(v, yaw, y)
21         local x = -math.sin(yaw) * v
22         local z =  math.cos(yaw) * v
23         return {x = x, y = y, z = z}
24 end
25
26
27 local function get_v(v)
28         return math.sqrt(v.x ^ 2 + v.z ^ 2)
29 end
30
31 --
32 -- Boat entity
33 --
34
35 local boat = {
36         physical = true,
37         collisionbox = {-0.5, -0.35, -0.5, 0.5, 0.3, 0.5},
38         visual = "mesh",
39         mesh = "boats_boat.obj",
40         textures = {"default_wood.png"},
41
42         driver = nil,
43         v = 0,
44         last_v = 0,
45         removed = false
46 }
47
48
49 function boat.on_rightclick(self, clicker)
50         if not clicker or not clicker:is_player() then
51                 return
52         end
53         local name = clicker:get_player_name()
54         if self.driver and clicker == self.driver then
55                 self.driver = nil
56                 clicker:set_detach()
57                 default.player_attached[name] = false
58                 default.player_set_animation(clicker, "stand" , 30)
59                 local pos = clicker:getpos()
60                 pos = {x = pos.x, y = pos.y + 0.2, z = pos.z}
61                 minetest.after(0.1, function()
62                         clicker:setpos(pos)
63                 end)
64         elseif not self.driver then
65                 local attach = clicker:get_attach()
66                 if attach and attach:get_luaentity() then
67                         local luaentity = attach:get_luaentity()
68                         if luaentity.driver then
69                                 luaentity.driver = nil
70                         end
71                         clicker:set_detach()
72                 end
73                 self.driver = clicker
74                 clicker:set_attach(self.object, "",
75                         {x = 0, y = 11, z = -3}, {x = 0, y = 0, z = 0})
76                 default.player_attached[name] = true
77                 minetest.after(0.2, function()
78                         default.player_set_animation(clicker, "sit" , 30)
79                 end)
80                 self.object:setyaw(clicker:get_look_yaw() - math.pi / 2)
81         end
82 end
83
84
85 function boat.on_activate(self, staticdata, dtime_s)
86         self.object:set_armor_groups({immortal = 1})
87         if staticdata then
88                 self.v = tonumber(staticdata)
89         end
90         self.last_v = self.v
91 end
92
93
94 function boat.get_staticdata(self)
95         return tostring(self.v)
96 end
97
98
99 function boat.on_punch(self, puncher)
100         if not puncher or not puncher:is_player() or self.removed then
101                 return
102         end
103         if self.driver and puncher == self.driver then
104                 self.driver = nil
105                 puncher:set_detach()
106                 default.player_attached[puncher:get_player_name()] = false
107         end
108         if not self.driver then
109                 self.removed = true
110                 -- delay remove to ensure player is detached
111                 minetest.after(0.1, function()
112                         self.object:remove()
113                 end)
114                 if not minetest.setting_getbool("creative_mode") then
115                         local inv = puncher:get_inventory()
116                         if inv:room_for_item("main", "boats:boat") then
117                                 inv:add_item("main", "boats:boat")
118                         else
119                                 minetest.add_item(self.object:getpos(), "boats:boat")
120                         end
121                 end
122         end
123 end
124
125
126 function boat.on_step(self, dtime)
127         self.v = get_v(self.object:getvelocity()) * get_sign(self.v)
128         if self.driver then
129                 local ctrl = self.driver:get_player_control()
130                 local yaw = self.object:getyaw()
131                 if ctrl.up then
132                         self.v = self.v + 0.1
133                 elseif ctrl.down then
134                         self.v = self.v - 0.1
135                 end
136                 if ctrl.left then
137                         if self.v < 0 then
138                                 self.object:setyaw(yaw - (1 + dtime) * 0.03)
139                         else
140                                 self.object:setyaw(yaw + (1 + dtime) * 0.03)
141                         end
142                 elseif ctrl.right then
143                         if self.v < 0 then
144                                 self.object:setyaw(yaw + (1 + dtime) * 0.03)
145                         else
146                                 self.object:setyaw(yaw - (1 + dtime) * 0.03)
147                         end
148                 end
149         end
150         local velo = self.object:getvelocity()
151         if self.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then
152                 self.object:setpos(self.object:getpos())
153                 return
154         end
155         local s = get_sign(self.v)
156         self.v = self.v - 0.02 * s
157         if s ~= get_sign(self.v) then
158                 self.object:setvelocity({x = 0, y = 0, z = 0})
159                 self.v = 0
160                 return
161         end
162         if math.abs(self.v) > 4.5 then
163                 self.v = 4.5 * get_sign(self.v)
164         end
165
166         local p = self.object:getpos()
167         p.y = p.y - 0.5
168         local new_velo = {x = 0, y = 0, z = 0}
169         local new_acce = {x = 0, y = 0, z = 0}
170         if not is_water(p) then
171                 local nodedef = minetest.registered_nodes[minetest.get_node(p).name]
172                 if (not nodedef) or nodedef.walkable then
173                         self.v = 0
174                         new_acce = {x = 0, y = 1, z = 0}
175                 else
176                         new_acce = {x = 0, y = -9.8, z = 0}
177                 end
178                 new_velo = get_velocity(self.v, self.object:getyaw(),
179                         self.object:getvelocity().y)
180                 self.object:setpos(self.object:getpos())
181         else
182                 p.y = p.y + 1
183                 if is_water(p) then
184                         local y = self.object:getvelocity().y
185                         if y >= 4.5 then
186                                 y = 4.5
187                         elseif y < 0 then
188                                 new_acce = {x = 0, y = 20, z = 0}
189                         else
190                                 new_acce = {x = 0, y = 5, z = 0}
191                         end
192                         new_velo = get_velocity(self.v, self.object:getyaw(), y)
193                         self.object:setpos(self.object:getpos())
194                 else
195                         new_acce = {x = 0, y = 0, z = 0}
196                         if math.abs(self.object:getvelocity().y) < 1 then
197                                 local pos = self.object:getpos()
198                                 pos.y = math.floor(pos.y) + 0.5
199                                 self.object:setpos(pos)
200                                 new_velo = get_velocity(self.v, self.object:getyaw(), 0)
201                         else
202                                 new_velo = get_velocity(self.v, self.object:getyaw(),
203                                         self.object:getvelocity().y)
204                                 self.object:setpos(self.object:getpos())
205                         end
206                 end
207         end
208         self.object:setvelocity(new_velo)
209         self.object:setacceleration(new_acce)
210 end
211
212
213 minetest.register_entity("boats:boat", boat)
214
215
216 minetest.register_craftitem("boats:boat", {
217         description = "Boat",
218         inventory_image = "boats_inventory.png",
219         wield_image = "boats_wield.png",
220         wield_scale = {x = 2, y = 2, z = 1},
221         liquids_pointable = true,
222
223         on_place = function(itemstack, placer, pointed_thing)
224                 if pointed_thing.type ~= "node" then
225                         return
226                 end
227                 if not is_water(pointed_thing.under) then
228                         return
229                 end
230                 pointed_thing.under.y = pointed_thing.under.y + 0.5
231                 minetest.add_entity(pointed_thing.under, "boats:boat")
232                 if not minetest.setting_getbool("creative_mode") then
233                         itemstack:take_item()
234                 end
235                 return itemstack
236         end,
237 })
238
239
240 minetest.register_craft({
241         output = "boats:boat",
242         recipe = {
243                 {"",           "",           ""          },
244                 {"group:wood", "",           "group:wood"},
245                 {"group:wood", "group:wood", "group:wood"},
246         },
247 })