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