Cpp11 initializers: last src root changeset (#6022)
[oweals/minetest.git] / src / localplayer.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "localplayer.h"
21
22 #include "event.h"
23 #include "collision.h"
24 #include "nodedef.h"
25 #include "settings.h"
26 #include "environment.h"
27 #include "map.h"
28 #include "client.h"
29 #include "content_cao.h"
30
31 /*
32         LocalPlayer
33 */
34
35 LocalPlayer::LocalPlayer(Client *client, const char *name):
36         Player(name, client->idef()),
37         m_client(client)
38 {
39 }
40
41 LocalPlayer::~LocalPlayer()
42 {
43 }
44
45 static aabb3f getTopBoundingBox(const std::vector<aabb3f> &nodeboxes)
46 {
47         aabb3f b_max;
48         b_max.reset(-BS, -BS, -BS);
49         for (std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
50                         it != nodeboxes.end(); ++it) {
51                 aabb3f box = *it;
52                 if (box.MaxEdge.Y > b_max.MaxEdge.Y)
53                         b_max = box;
54                 else if (box.MaxEdge.Y == b_max.MaxEdge.Y)
55                         b_max.addInternalBox(box);
56         }
57         return aabb3f(v3f(b_max.MinEdge.X, b_max.MaxEdge.Y, b_max.MinEdge.Z), b_max.MaxEdge);
58 }
59
60 #define GETNODE(map, p3, v2, y, valid) \
61         (map)->getNodeNoEx((p3) + v3s16((v2).X, y, (v2).Y), valid)
62
63 // pos is the node the player is standing inside(!)
64 static bool detectSneakLadder(Map *map, INodeDefManager *nodemgr, v3s16 pos)
65 {
66         // Detects a structure known as "sneak ladder" or "sneak elevator"
67         // that relies on bugs to provide a fast means of vertical transportation,
68         // the bugs have since been fixed but this function remains to keep it working.
69         // NOTE: This is just entirely a huge hack and causes way too many problems.
70         bool is_valid_position;
71         MapNode node;
72         // X/Z vectors for 4 neighboring nodes
73         static const v2s16 vecs[] = { v2s16(-1, 0), v2s16(1, 0), v2s16(0, -1), v2s16(0, 1) };
74
75         for (u16 i = 0; i < ARRLEN(vecs); i++) {
76                 const v2s16 vec = vecs[i];
77
78                 // walkability of bottom & top node should differ
79                 node = GETNODE(map, pos, vec, 0, &is_valid_position);
80                 if (!is_valid_position)
81                         continue;
82                 bool w = nodemgr->get(node).walkable;
83                 node = GETNODE(map, pos, vec, 1, &is_valid_position);
84                 if (!is_valid_position || w == nodemgr->get(node).walkable)
85                         continue;
86
87                 // check one more node above OR below with corresponding walkability
88                 node = GETNODE(map, pos, vec, -1, &is_valid_position);
89                 bool ok = is_valid_position && w != nodemgr->get(node).walkable;
90                 if (!ok) {
91                         node = GETNODE(map, pos, vec, 2, &is_valid_position);
92                         ok = is_valid_position && w == nodemgr->get(node).walkable;
93                 }
94
95                 if (ok)
96                         return true;
97         }
98
99         return false;
100 }
101
102 static bool detectLedge(Map *map, INodeDefManager *nodemgr, v3s16 pos)
103 {
104         bool is_valid_position;
105         MapNode node;
106         // X/Z vectors for 4 neighboring nodes
107         static const v2s16 vecs[] = {v2s16(-1, 0), v2s16(1, 0), v2s16(0, -1), v2s16(0, 1)};
108
109         for (u16 i = 0; i < ARRLEN(vecs); i++) {
110                 const v2s16 vec = vecs[i];
111
112                 node = GETNODE(map, pos, vec, 1, &is_valid_position);
113                 if (is_valid_position && nodemgr->get(node).walkable) {
114                         // Ledge exists
115                         node = GETNODE(map, pos, vec, 2, &is_valid_position);
116                         if (is_valid_position && !nodemgr->get(node).walkable)
117                                 // Space above ledge exists
118                                 return true;
119                 }
120         }
121
122         return false;
123 }
124
125 #undef GETNODE
126
127 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
128                 std::vector<CollisionInfo> *collision_info)
129 {
130         // Temporary option for old move code
131         if (!physics_override_new_move) {
132                 old_move(dtime, env, pos_max_d, collision_info);
133                 return;
134         }
135
136         Map *map = &env->getMap();
137         INodeDefManager *nodemgr = m_client->ndef();
138
139         v3f position = getPosition();
140
141         // Copy parent position if local player is attached
142         if(isAttached)
143         {
144                 setPosition(overridePosition);
145                 m_sneak_node_exists = false;
146                 return;
147         }
148
149         // Skip collision detection if noclip mode is used
150         bool fly_allowed = m_client->checkLocalPrivilege("fly");
151         bool noclip = m_client->checkLocalPrivilege("noclip") &&
152                 g_settings->getBool("noclip");
153         bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
154         if (free_move) {
155                 position += m_speed * dtime;
156                 setPosition(position);
157                 m_sneak_node_exists = false;
158                 return;
159         }
160
161         /*
162                 Collision detection
163         */
164
165         bool is_valid_position;
166         MapNode node;
167         v3s16 pp;
168
169         /*
170                 Check if player is in liquid (the oscillating value)
171         */
172
173         // If in liquid, the threshold of coming out is at higher y
174         if (in_liquid)
175         {
176                 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
177                 node = map->getNodeNoEx(pp, &is_valid_position);
178                 if (is_valid_position) {
179                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
180                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
181                 } else {
182                         in_liquid = false;
183                 }
184         }
185         // If not in liquid, the threshold of going in is at lower y
186         else
187         {
188                 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
189                 node = map->getNodeNoEx(pp, &is_valid_position);
190                 if (is_valid_position) {
191                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
192                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
193                 } else {
194                         in_liquid = false;
195                 }
196         }
197
198
199         /*
200                 Check if player is in liquid (the stable value)
201         */
202         pp = floatToInt(position + v3f(0,0,0), BS);
203         node = map->getNodeNoEx(pp, &is_valid_position);
204         if (is_valid_position) {
205                 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
206         } else {
207                 in_liquid_stable = false;
208         }
209
210         /*
211                 Check if player is climbing
212         */
213
214
215         pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
216         v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
217         node = map->getNodeNoEx(pp, &is_valid_position);
218         bool is_valid_position2;
219         MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
220
221         if (!(is_valid_position && is_valid_position2)) {
222                 is_climbing = false;
223         } else {
224                 is_climbing = (nodemgr->get(node.getContent()).climbable
225                                 || nodemgr->get(node2.getContent()).climbable) && !free_move;
226         }
227
228
229         /*
230                 Collision uncertainty radius
231                 Make it a bit larger than the maximum distance of movement
232         */
233         //f32 d = pos_max_d * 1.1;
234         // A fairly large value in here makes moving smoother
235         f32 d = 0.15*BS;
236
237         // This should always apply, otherwise there are glitches
238         sanity_check(d > pos_max_d);
239
240         // Max. distance (X, Z) over border for sneaking determined by collision box
241         // * 0.49 to keep the center just barely on the node
242         v3f sneak_max = m_collisionbox.getExtent() * 0.49;
243         if (m_sneak_ladder_detected) {
244                 // restore legacy behaviour (this makes the m_speed.Y hack necessary)
245                 sneak_max = v3f(0.4 * BS, 0, 0.4 * BS);
246         }
247
248         /*
249                 If sneaking, keep in range from the last walked node and don't
250                 fall off from it
251         */
252         if (control.sneak && m_sneak_node_exists &&
253                         !(fly_allowed && g_settings->getBool("free_move")) &&
254                         !in_liquid && !is_climbing &&
255                         physics_override_sneak) {
256                 const v3f sn_f = intToFloat(m_sneak_node, BS);
257                 const v3f bmin = sn_f + m_sneak_node_bb_top.MinEdge;
258                 const v3f bmax = sn_f + m_sneak_node_bb_top.MaxEdge;
259                 const v3f old_pos = position;
260                 const v3f old_speed = m_speed;
261
262                 position.X = rangelim(position.X,
263                                 bmin.X - sneak_max.X, bmax.X + sneak_max.X);
264                 position.Z = rangelim(position.Z,
265                                 bmin.Z - sneak_max.Z, bmax.Z + sneak_max.Z);
266
267                 if (position.X != old_pos.X)
268                         m_speed.X = 0;
269                 if (position.Z != old_pos.Z)
270                         m_speed.Z = 0;
271
272                 // Because we keep the player collision box on the node, limiting
273                 // position.Y is not necessary but useful to prevent players from
274                 // being inside a node if sneaking on e.g. the lower part of a stair
275                 if (!m_sneak_ladder_detected) {
276                         position.Y = MYMAX(position.Y, bmax.Y);
277                 } else {
278                         // legacy behaviour that sometimes causes some weird slow sinking
279                         m_speed.Y = MYMAX(m_speed.Y, 0);
280                 }
281
282                 if (collision_info != NULL &&
283                                 m_speed.Y - old_speed.Y > BS) {
284                         // Collide with sneak node, report fall damage
285                         CollisionInfo sn_info;
286                         sn_info.node_p = m_sneak_node;
287                         sn_info.old_speed = old_speed;
288                         sn_info.new_speed = m_speed;
289                         collision_info->push_back(sn_info);
290                 }
291         }
292
293         // TODO: this shouldn't be hardcoded but transmitted from server
294         float player_stepheight = (touching_ground) ? (BS * 0.6f) : (BS * 0.2f);
295
296 #ifdef __ANDROID__
297         player_stepheight += (0.6f * BS);
298 #endif
299
300         v3f accel_f = v3f(0,0,0);
301
302         collisionMoveResult result = collisionMoveSimple(env, m_client,
303                 pos_max_d, m_collisionbox, player_stepheight, dtime,
304                 &position, &m_speed, accel_f);
305
306         /*
307                 If the player's feet touch the topside of any node, this is
308                 set to true.
309
310                 Player is allowed to jump when this is true.
311         */
312         bool touching_ground_was = touching_ground;
313         touching_ground = result.touching_ground;
314
315         // We want the top of the sneak node to be below the players feet
316         f32 position_y_mod;
317         if (m_sneak_node_exists)
318                 position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - 0.05 * BS;
319         else
320                 position_y_mod = (0.5 - 0.05) * BS;
321         v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
322         /*
323                 Check the nodes under the player to see from which node the
324                 player is sneaking from, if any.  If the node from under
325                 the player has been removed, the player falls.
326         */
327         if (m_sneak_node_exists &&
328                         nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
329                         m_old_node_below_type != "air") {
330                 // Old node appears to have been removed; that is,
331                 // it wasn't air before but now it is
332                 m_need_to_get_new_sneak_node = false;
333                 m_sneak_node_exists = false;
334         } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
335                 // We are on something, so make sure to recalculate the sneak
336                 // node.
337                 m_need_to_get_new_sneak_node = true;
338         }
339
340         if (m_need_to_get_new_sneak_node && physics_override_sneak) {
341                 v2f player_p2df(position.X, position.Z);
342                 f32 min_distance_f = 100000.0 * BS;
343                 v3s16 new_sneak_node = m_sneak_node;
344                 for(s16 x=-1; x<=1; x++)
345                 for(s16 z=-1; z<=1; z++)
346                 {
347                         v3s16 p = current_node + v3s16(x,0,z);
348                         v3f pf = intToFloat(p, BS);
349                         v2f node_p2df(pf.X, pf.Z);
350                         f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
351
352                         if (distance_f > min_distance_f ||
353                                         fabs(player_p2df.X-node_p2df.X) > (.5+.1)*BS + sneak_max.X ||
354                                         fabs(player_p2df.Y-node_p2df.Y) > (.5+.1)*BS + sneak_max.Z)
355                                 continue;
356
357
358                         // The node to be sneaked on has to be walkable
359                         node = map->getNodeNoEx(p, &is_valid_position);
360                         if (!is_valid_position || !nodemgr->get(node).walkable)
361                                 continue;
362                         // And the node(s) above have to be nonwalkable
363                         bool ok = true;
364                         if (!physics_override_sneak_glitch) {
365                                 u16 height = ceilf(
366                                                 (m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS
367                                 );
368                                 for (u16 y = 1; y <= height; y++) {
369                                         node = map->getNodeNoEx(p + v3s16(0,y,0), &is_valid_position);
370                                         if (!is_valid_position || nodemgr->get(node).walkable) {
371                                                 ok = false;
372                                                 break;
373                                         }
374                                 }
375                         } else {
376                                 // legacy behaviour: check just one node
377                                 node = map->getNodeNoEx(p + v3s16(0,1,0), &is_valid_position);
378                                 ok = is_valid_position && !nodemgr->get(node).walkable;
379                         }
380                         if (!ok)
381                                 continue;
382
383                         min_distance_f = distance_f;
384                         new_sneak_node = p;
385                 }
386
387                 bool sneak_node_found = (min_distance_f < 100000.0 * BS);
388                 m_sneak_node = new_sneak_node;
389                 m_sneak_node_exists = sneak_node_found;
390
391                 if (sneak_node_found) {
392                         // Update saved top bounding box of sneak node
393                         MapNode n = map->getNodeNoEx(m_sneak_node);
394                         std::vector<aabb3f> nodeboxes;
395                         n.getCollisionBoxes(nodemgr, &nodeboxes);
396                         m_sneak_node_bb_top = getTopBoundingBox(nodeboxes);
397
398                         m_sneak_ladder_detected = physics_override_sneak_glitch &&
399                                         detectSneakLadder(map, nodemgr, floatToInt(position, BS));
400                 } else {
401                         m_sneak_ladder_detected = false;
402                 }
403         }
404
405         /*
406                 If 'sneak glitch' enabled detect ledge for old sneak-jump
407                 behaviour of climbing onto a ledge 2 nodes up.
408         */
409         if (physics_override_sneak_glitch && control.sneak && control.jump)
410                 m_ledge_detected = detectLedge(map, nodemgr, floatToInt(position, BS));
411
412         /*
413                 Set new position but keep sneak node set
414         */
415         bool sneak_node_exists = m_sneak_node_exists;
416         setPosition(position);
417         m_sneak_node_exists = sneak_node_exists;
418
419         /*
420                 Report collisions
421         */
422
423         // Dont report if flying
424         if(collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
425                 for(size_t i=0; i<result.collisions.size(); i++) {
426                         const CollisionInfo &info = result.collisions[i];
427                         collision_info->push_back(info);
428                 }
429         }
430
431         if(!result.standing_on_object && !touching_ground_was && touching_ground) {
432                 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
433                 m_client->event()->put(e);
434
435                 // Set camera impact value to be used for view bobbing
436                 camera_impact = getSpeed().Y * -1;
437         }
438
439         {
440                 camera_barely_in_ceiling = false;
441                 v3s16 camera_np = floatToInt(getEyePosition(), BS);
442                 MapNode n = map->getNodeNoEx(camera_np);
443                 if(n.getContent() != CONTENT_IGNORE){
444                         if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
445                                 camera_barely_in_ceiling = true;
446                         }
447                 }
448         }
449
450         /*
451                 Update the node last under the player
452         */
453         m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS);
454         m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
455
456         /*
457                 Check properties of the node on which the player is standing
458         */
459         const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
460         // Determine if jumping is possible
461         m_can_jump = touching_ground && !in_liquid;
462         if (itemgroup_get(f.groups, "disable_jump"))
463                 m_can_jump = false;
464         else if (control.sneak && m_sneak_ladder_detected && !in_liquid && !is_climbing)
465                 m_can_jump = true;
466
467         // Jump key pressed while jumping off from a bouncy block
468         if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
469                 m_speed.Y >= -0.5 * BS) {
470                 float jumpspeed = movement_speed_jump * physics_override_jump;
471                 if (m_speed.Y > 1) {
472                         // Reduce boost when speed already is high
473                         m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
474                 } else {
475                         m_speed.Y += jumpspeed;
476                 }
477                 setSpeed(m_speed);
478                 m_can_jump = false;
479         }
480 }
481
482 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d)
483 {
484         move(dtime, env, pos_max_d, NULL);
485 }
486
487 void LocalPlayer::applyControl(float dtime)
488 {
489         // Clear stuff
490         swimming_vertical = false;
491
492         setPitch(control.pitch);
493         setYaw(control.yaw);
494
495         // Nullify speed and don't run positioning code if the player is attached
496         if(isAttached)
497         {
498                 setSpeed(v3f(0,0,0));
499                 return;
500         }
501
502         v3f move_direction = v3f(0,0,1);
503         move_direction.rotateXZBy(getYaw());
504
505         v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
506         v3f speedV = v3f(0,0,0); // Vertical (Y)
507
508         bool fly_allowed = m_client->checkLocalPrivilege("fly");
509         bool fast_allowed = m_client->checkLocalPrivilege("fast");
510
511         bool free_move = fly_allowed && g_settings->getBool("free_move");
512         bool fast_move = fast_allowed && g_settings->getBool("fast_move");
513         // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
514         bool fast_climb = fast_move && control.aux1 && !g_settings->getBool("aux1_descends");
515         bool continuous_forward = g_settings->getBool("continuous_forward");
516         bool always_fly_fast = g_settings->getBool("always_fly_fast");
517
518         // Whether superspeed mode is used or not
519         bool superspeed = false;
520
521         if (always_fly_fast && free_move && fast_move)
522                 superspeed = true;
523
524         // Old descend control
525         if(g_settings->getBool("aux1_descends"))
526         {
527                 // If free movement and fast movement, always move fast
528                 if(free_move && fast_move)
529                         superspeed = true;
530
531                 // Auxiliary button 1 (E)
532                 if(control.aux1)
533                 {
534                         if(free_move)
535                         {
536                                 // In free movement mode, aux1 descends
537                                 if(fast_move)
538                                         speedV.Y = -movement_speed_fast;
539                                 else
540                                         speedV.Y = -movement_speed_walk;
541                         }
542                         else if(in_liquid || in_liquid_stable)
543                         {
544                                 speedV.Y = -movement_speed_walk;
545                                 swimming_vertical = true;
546                         }
547                         else if(is_climbing)
548                         {
549                                 speedV.Y = -movement_speed_climb;
550                         }
551                         else
552                         {
553                                 // If not free movement but fast is allowed, aux1 is
554                                 // "Turbo button"
555                                 if(fast_move)
556                                         superspeed = true;
557                         }
558                 }
559         }
560         // New minecraft-like descend control
561         else
562         {
563                 // Auxiliary button 1 (E)
564                 if(control.aux1)
565                 {
566                         if(!is_climbing)
567                         {
568                                 // aux1 is "Turbo button"
569                                 if(fast_move)
570                                         superspeed = true;
571                         }
572                 }
573
574                 if(control.sneak)
575                 {
576                         if(free_move)
577                         {
578                                 // In free movement mode, sneak descends
579                                 if (fast_move && (control.aux1 || always_fly_fast))
580                                         speedV.Y = -movement_speed_fast;
581                                 else
582                                         speedV.Y = -movement_speed_walk;
583                         }
584                         else if(in_liquid || in_liquid_stable)
585                         {
586                                 if(fast_climb)
587                                         speedV.Y = -movement_speed_fast;
588                                 else
589                                         speedV.Y = -movement_speed_walk;
590                                 swimming_vertical = true;
591                         }
592                         else if(is_climbing)
593                         {
594                                 if(fast_climb)
595                                         speedV.Y = -movement_speed_fast;
596                                 else
597                                         speedV.Y = -movement_speed_climb;
598                         }
599                 }
600         }
601
602         if (continuous_forward)
603                 speedH += move_direction;
604
605         if (control.up) {
606                 if (continuous_forward) {
607                         if (fast_move)
608                                 superspeed = true;
609                 } else {
610                         speedH += move_direction;
611                 }
612         }
613         if (control.down) {
614                 speedH -= move_direction;
615         }
616         if (!control.up && !control.down) {
617                 speedH -= move_direction *
618                         (control.forw_move_joystick_axis / 32767.f);
619         }
620         if (control.left) {
621                 speedH += move_direction.crossProduct(v3f(0,1,0));
622         }
623         if (control.right) {
624                 speedH += move_direction.crossProduct(v3f(0,-1,0));
625         }
626         if (!control.left && !control.right) {
627                 speedH -= move_direction.crossProduct(v3f(0,1,0)) *
628                         (control.sidew_move_joystick_axis / 32767.f);
629         }
630         if(control.jump)
631         {
632                 if (free_move) {
633                         if (g_settings->getBool("aux1_descends") || always_fly_fast) {
634                                 if (fast_move)
635                                         speedV.Y = movement_speed_fast;
636                                 else
637                                         speedV.Y = movement_speed_walk;
638                         } else {
639                                 if(fast_move && control.aux1)
640                                         speedV.Y = movement_speed_fast;
641                                 else
642                                         speedV.Y = movement_speed_walk;
643                         }
644                 }
645                 else if(m_can_jump)
646                 {
647                         /*
648                                 NOTE: The d value in move() affects jump height by
649                                 raising the height at which the jump speed is kept
650                                 at its starting value
651                         */
652                         v3f speedJ = getSpeed();
653                         if(speedJ.Y >= -0.5 * BS) {
654                                 if (m_ledge_detected) {
655                                         // Limit jump speed to a minimum that allows
656                                         // jumping up onto a ledge 2 nodes up.
657                                         speedJ.Y = movement_speed_jump *
658                                                         MYMAX(physics_override_jump, 1.3f);
659                                         setSpeed(speedJ);
660                                         m_ledge_detected = false;
661                                 } else {
662                                         speedJ.Y = movement_speed_jump * physics_override_jump;
663                                         setSpeed(speedJ);
664                                 }
665
666                                 MtEvent *e = new SimpleTriggerEvent("PlayerJump");
667                                 m_client->event()->put(e);
668                         }
669                 }
670                 else if(in_liquid)
671                 {
672                         if(fast_climb)
673                                 speedV.Y = movement_speed_fast;
674                         else
675                                 speedV.Y = movement_speed_walk;
676                         swimming_vertical = true;
677                 }
678                 else if(is_climbing)
679                 {
680                         if(fast_climb)
681                                 speedV.Y = movement_speed_fast;
682                         else
683                                 speedV.Y = movement_speed_climb;
684                 }
685         }
686
687         // The speed of the player (Y is ignored)
688         if(superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
689                 speedH = speedH.normalize() * movement_speed_fast;
690         else if(control.sneak && !free_move && !in_liquid && !in_liquid_stable)
691                 speedH = speedH.normalize() * movement_speed_crouch;
692         else
693                 speedH = speedH.normalize() * movement_speed_walk;
694
695         // Acceleration increase
696         f32 incH = 0; // Horizontal (X, Z)
697         f32 incV = 0; // Vertical (Y)
698         if((!touching_ground && !free_move && !is_climbing && !in_liquid) || (!free_move && m_can_jump && control.jump))
699         {
700                 // Jumping and falling
701                 if(superspeed || (fast_move && control.aux1))
702                         incH = movement_acceleration_fast * BS * dtime;
703                 else
704                         incH = movement_acceleration_air * BS * dtime;
705                 incV = 0; // No vertical acceleration in air
706         }
707         else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
708                 incH = incV = movement_acceleration_fast * BS * dtime;
709         else
710                 incH = incV = movement_acceleration_default * BS * dtime;
711
712         // Accelerate to target speed with maximum increment
713         accelerateHorizontal(speedH * physics_override_speed, incH * physics_override_speed);
714         accelerateVertical(speedV * physics_override_speed, incV * physics_override_speed);
715 }
716
717 v3s16 LocalPlayer::getStandingNodePos()
718 {
719         if(m_sneak_node_exists)
720                 return m_sneak_node;
721         return floatToInt(getPosition() - v3f(0, BS, 0), BS);
722 }
723
724 v3s16 LocalPlayer::getFootstepNodePos()
725 {
726         if (touching_ground)
727                 // BS * 0.05 below the player's feet ensures a 1/16th height
728                 // nodebox is detected instead of the node below it.
729                 return floatToInt(getPosition() - v3f(0, BS * 0.05f, 0), BS);
730         // A larger distance below is necessary for a footstep sound
731         // when landing after a jump or fall. BS * 0.5 ensures water
732         // sounds when swimming in 1 node deep water.
733         return floatToInt(getPosition() - v3f(0, BS * 0.5f, 0), BS);
734 }
735
736 v3s16 LocalPlayer::getLightPosition() const
737 {
738         return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
739 }
740
741 v3f LocalPlayer::getEyeOffset() const
742 {
743         float eye_height = camera_barely_in_ceiling ? 1.5f : 1.625f;
744         return v3f(0, BS * eye_height, 0);
745 }
746
747 // Horizontal acceleration (X and Z), Y direction is ignored
748 void LocalPlayer::accelerateHorizontal(const v3f &target_speed, const f32 max_increase)
749 {
750         if (max_increase == 0)
751                 return;
752
753         v3f d_wanted = target_speed - m_speed;
754         d_wanted.Y = 0;
755         f32 dl = d_wanted.getLength();
756         if (dl > max_increase)
757                 dl = max_increase;
758
759         v3f d = d_wanted.normalize() * dl;
760
761         m_speed.X += d.X;
762         m_speed.Z += d.Z;
763 }
764
765 // Vertical acceleration (Y), X and Z directions are ignored
766 void LocalPlayer::accelerateVertical(const v3f &target_speed, const f32 max_increase)
767 {
768         if (max_increase == 0)
769                 return;
770
771         f32 d_wanted = target_speed.Y - m_speed.Y;
772         if (d_wanted > max_increase)
773                 d_wanted = max_increase;
774         else if (d_wanted < -max_increase)
775                 d_wanted = -max_increase;
776
777         m_speed.Y += d_wanted;
778 }
779
780 // Temporary option for old move code
781 void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
782                 std::vector<CollisionInfo> *collision_info)
783 {
784         Map *map = &env->getMap();
785         INodeDefManager *nodemgr = m_client->ndef();
786
787         v3f position = getPosition();
788
789         // Copy parent position if local player is attached
790         if (isAttached) {
791                 setPosition(overridePosition);
792                 m_sneak_node_exists = false;
793                 return;
794         }
795
796         // Skip collision detection if noclip mode is used
797         bool fly_allowed = m_client->checkLocalPrivilege("fly");
798         bool noclip = m_client->checkLocalPrivilege("noclip") &&
799                 g_settings->getBool("noclip");
800         bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
801         if (free_move) {
802                 position += m_speed * dtime;
803                 setPosition(position);
804                 m_sneak_node_exists = false;
805                 return;
806         }
807
808         /*
809                 Collision detection
810         */
811         bool is_valid_position;
812         MapNode node;
813         v3s16 pp;
814
815         /*
816                 Check if player is in liquid (the oscillating value)
817         */
818         if (in_liquid) {
819                 // If in liquid, the threshold of coming out is at higher y
820                 pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS);
821                 node = map->getNodeNoEx(pp, &is_valid_position);
822                 if (is_valid_position) {
823                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
824                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
825                 } else {
826                         in_liquid = false;
827                 }
828         } else {
829                 // If not in liquid, the threshold of going in is at lower y
830                 pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS);
831                 node = map->getNodeNoEx(pp, &is_valid_position);
832                 if (is_valid_position) {
833                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
834                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
835                 } else {
836                         in_liquid = false;
837                 }
838         }
839
840         /*
841                 Check if player is in liquid (the stable value)
842         */
843         pp = floatToInt(position + v3f(0, 0, 0), BS);
844         node = map->getNodeNoEx(pp, &is_valid_position);
845         if (is_valid_position)
846                 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
847         else
848                 in_liquid_stable = false;
849
850         /*
851                 Check if player is climbing
852         */
853         pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS);
854         v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS);
855         node = map->getNodeNoEx(pp, &is_valid_position);
856         bool is_valid_position2;
857         MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
858
859         if (!(is_valid_position && is_valid_position2))
860                 is_climbing = false;
861         else
862                 is_climbing = (nodemgr->get(node.getContent()).climbable ||
863                                 nodemgr->get(node2.getContent()).climbable) && !free_move;
864
865         /*
866                 Collision uncertainty radius
867                 Make it a bit larger than the maximum distance of movement
868         */
869         //f32 d = pos_max_d * 1.1;
870         // A fairly large value in here makes moving smoother
871         f32 d = 0.15 * BS;
872         // This should always apply, otherwise there are glitches
873         sanity_check(d > pos_max_d);
874         // Maximum distance over border for sneaking
875         f32 sneak_max = BS * 0.4;
876
877         /*
878                 If sneaking, keep in range from the last walked node and don't
879                 fall off from it
880         */
881         if (control.sneak && m_sneak_node_exists &&
882                         !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
883                         physics_override_sneak) {
884                 f32 maxd = 0.5 * BS + sneak_max;
885                 v3f lwn_f = intToFloat(m_sneak_node, BS);
886                 position.X = rangelim(position.X, lwn_f.X - maxd, lwn_f.X + maxd);
887                 position.Z = rangelim(position.Z, lwn_f.Z - maxd, lwn_f.Z + maxd);
888
889                 if (!is_climbing) {
890                         // Move up if necessary
891                         f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
892                         if (position.Y < new_y)
893                                 position.Y = new_y;
894                         /*
895                                 Collision seems broken, since player is sinking when
896                                 sneaking over the edges of current sneaking_node.
897                                 TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
898                         */
899                         if (m_speed.Y < 0)
900                                 m_speed.Y = 0;
901                 }
902         }
903
904         // this shouldn't be hardcoded but transmitted from server
905         float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2);
906
907 #ifdef __ANDROID__
908         player_stepheight += (0.6 * BS);
909 #endif
910
911         v3f accel_f = v3f(0, 0, 0);
912
913         collisionMoveResult result = collisionMoveSimple(env, m_client,
914                 pos_max_d, m_collisionbox, player_stepheight, dtime,
915                 &position, &m_speed, accel_f);
916
917         /*
918                 If the player's feet touch the topside of any node, this is
919                 set to true.
920
921                 Player is allowed to jump when this is true.
922         */
923         bool touching_ground_was = touching_ground;
924         touching_ground = result.touching_ground;
925
926     //bool standing_on_unloaded = result.standing_on_unloaded;
927
928         /*
929                 Check the nodes under the player to see from which node the
930                 player is sneaking from, if any.  If the node from under
931                 the player has been removed, the player falls.
932         */
933         f32 position_y_mod = 0.05 * BS;
934         if (m_sneak_node_bb_ymax > 0)
935                 position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
936         v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
937         if (m_sneak_node_exists &&
938                         nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
939                         m_old_node_below_type != "air") {
940                 // Old node appears to have been removed; that is,
941                 // it wasn't air before but now it is
942                 m_need_to_get_new_sneak_node = false;
943                 m_sneak_node_exists = false;
944         } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
945                 // We are on something, so make sure to recalculate the sneak
946                 // node.
947                 m_need_to_get_new_sneak_node = true;
948         }
949
950         if (m_need_to_get_new_sneak_node && physics_override_sneak) {
951                 m_sneak_node_bb_ymax = 0;
952                 v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
953                 v2f player_p2df(position.X, position.Z);
954                 f32 min_distance_f = 100000.0 * BS;
955                 // If already seeking from some node, compare to it.
956                 v3s16 new_sneak_node = m_sneak_node;
957                 for (s16 x= -1; x <= 1; x++)
958                 for (s16 z= -1; z <= 1; z++) {
959                         v3s16 p = pos_i_bottom + v3s16(x, 0, z);
960                         v3f pf = intToFloat(p, BS);
961                         v2f node_p2df(pf.X, pf.Z);
962                         f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
963                         f32 max_axis_distance_f = MYMAX(
964                                         fabs(player_p2df.X - node_p2df.X),
965                                         fabs(player_p2df.Y - node_p2df.Y));
966
967                         if (distance_f > min_distance_f ||
968                                         max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS)
969                                 continue;
970
971                         // The node to be sneaked on has to be walkable
972                         node = map->getNodeNoEx(p, &is_valid_position);
973                         if (!is_valid_position || nodemgr->get(node).walkable == false)
974                                 continue;
975                         // And the node above it has to be nonwalkable
976                         node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
977                         if (!is_valid_position || nodemgr->get(node).walkable)
978                                 continue;
979                         // If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable
980                         if (!physics_override_sneak_glitch) {
981                                 node =map->getNodeNoEx(p + v3s16(0, 2, 0), &is_valid_position);
982                                 if (!is_valid_position || nodemgr->get(node).walkable)
983                                         continue;
984                         }
985
986                         min_distance_f = distance_f;
987                         new_sneak_node = p;
988                 }
989
990                 bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
991
992                 m_sneak_node = new_sneak_node;
993                 m_sneak_node_exists = sneak_node_found;
994
995                 if (sneak_node_found) {
996                         f32 cb_max = 0;
997                         MapNode n = map->getNodeNoEx(m_sneak_node);
998                         std::vector<aabb3f> nodeboxes;
999                         n.getCollisionBoxes(nodemgr, &nodeboxes);
1000                         for (std::vector<aabb3f>::iterator it = nodeboxes.begin();
1001                                         it != nodeboxes.end(); ++it) {
1002                                 aabb3f box = *it;
1003                                 if (box.MaxEdge.Y > cb_max)
1004                                         cb_max = box.MaxEdge.Y;
1005                         }
1006                         m_sneak_node_bb_ymax = cb_max;
1007                 }
1008
1009                 /*
1010                         If sneaking, the player's collision box can be in air, so
1011                         this has to be set explicitly
1012                 */
1013                 if (sneak_node_found && control.sneak)
1014                         touching_ground = true;
1015         }
1016
1017         /*
1018                 Set new position but keep sneak node set
1019         */
1020         bool sneak_node_exists = m_sneak_node_exists;
1021         setPosition(position);
1022         m_sneak_node_exists = sneak_node_exists;
1023
1024         /*
1025                 Report collisions
1026         */
1027         // Dont report if flying
1028         if (collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
1029                 for (size_t i = 0; i < result.collisions.size(); i++) {
1030                         const CollisionInfo &info = result.collisions[i];
1031                         collision_info->push_back(info);
1032                 }
1033         }
1034
1035         if (!result.standing_on_object && !touching_ground_was && touching_ground) {
1036                 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
1037                 m_client->event()->put(e);
1038                 // Set camera impact value to be used for view bobbing
1039                 camera_impact = getSpeed().Y * -1;
1040         }
1041
1042         {
1043                 camera_barely_in_ceiling = false;
1044                 v3s16 camera_np = floatToInt(getEyePosition(), BS);
1045                 MapNode n = map->getNodeNoEx(camera_np);
1046                 if (n.getContent() != CONTENT_IGNORE) {
1047                         if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
1048                                 camera_barely_in_ceiling = true;
1049                 }
1050         }
1051
1052         /*
1053                 Update the node last under the player
1054         */
1055         m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS);
1056         m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
1057
1058         /*
1059                 Check properties of the node on which the player is standing
1060         */
1061         const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
1062         // Determine if jumping is possible
1063         m_can_jump = touching_ground && !in_liquid;
1064         if (itemgroup_get(f.groups, "disable_jump"))
1065                 m_can_jump = false;
1066         // Jump key pressed while jumping off from a bouncy block
1067         if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
1068                         m_speed.Y >= -0.5 * BS) {
1069                 float jumpspeed = movement_speed_jump * physics_override_jump;
1070                 if (m_speed.Y > 1) {
1071                         // Reduce boost when speed already is high
1072                         m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
1073                 } else {
1074                         m_speed.Y += jumpspeed;
1075                 }
1076                 setSpeed(m_speed);
1077                 m_can_jump = false;
1078         }
1079 }