]> git.lizzy.rs Git - dragonfireclient.git/blob - src/localplayer.cpp
9dc3bf5aa87446568b95599da711b428326b2a01
[dragonfireclient.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
30 /*
31         LocalPlayer
32 */
33
34 LocalPlayer::LocalPlayer(Client *client, const char *name):
35         Player(name, client->idef()),
36         parent(0),
37         hp(PLAYER_MAX_HP),
38         got_teleported(false),
39         isAttached(false),
40         touching_ground(false),
41         in_liquid(false),
42         in_liquid_stable(false),
43         liquid_viscosity(0),
44         is_climbing(false),
45         swimming_vertical(false),
46         // Movement overrides are multipliers and must be 1 by default
47         physics_override_speed(1.0f),
48         physics_override_jump(1.0f),
49         physics_override_gravity(1.0f),
50         physics_override_sneak(true),
51         physics_override_sneak_glitch(true),
52         overridePosition(v3f(0,0,0)),
53         last_position(v3f(0,0,0)),
54         last_speed(v3f(0,0,0)),
55         last_pitch(0),
56         last_yaw(0),
57         last_keyPressed(0),
58         last_camera_fov(0),
59         last_wanted_range(0),
60         camera_impact(0.f),
61         last_animation(NO_ANIM),
62         hotbar_image(""),
63         hotbar_selected_image(""),
64         light_color(255,255,255,255),
65         hurt_tilt_timer(0.0f),
66         hurt_tilt_strength(0.0f),
67         m_position(0,0,0),
68         m_sneak_node(32767,32767,32767),
69         m_sneak_node_bb_top(0,0,0,0,0,0),
70         m_sneak_node_exists(false),
71         m_need_to_get_new_sneak_node(true),
72         m_sneak_ladder_detected(false),
73         m_ledge_detected(false),
74         m_old_node_below(32767,32767,32767),
75         m_old_node_below_type("air"),
76         m_can_jump(false),
77         m_breath(PLAYER_MAX_BREATH),
78         m_yaw(0),
79         m_pitch(0),
80         camera_barely_in_ceiling(false),
81         m_collisionbox(-BS * 0.30, 0.0, -BS * 0.30, BS * 0.30, BS * 1.75, BS * 0.30),
82         m_cao(NULL),
83         m_client(client)
84 {
85         // Initialize hp to 0, so that no hearts will be shown if server
86         // doesn't support health points
87         hp = 0;
88         eye_offset_first = v3f(0,0,0);
89         eye_offset_third = v3f(0,0,0);
90 }
91
92 LocalPlayer::~LocalPlayer()
93 {
94 }
95
96 static aabb3f getTopBoundingBox(const std::vector<aabb3f> &nodeboxes)
97 {
98         aabb3f b_max;
99         b_max.reset(-BS, -BS, -BS);
100         for (std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
101                         it != nodeboxes.end(); ++it) {
102                 aabb3f box = *it;
103                 if (box.MaxEdge.Y > b_max.MaxEdge.Y)
104                         b_max = box;
105                 else if (box.MaxEdge.Y == b_max.MaxEdge.Y)
106                         b_max.addInternalBox(box);
107         }
108         return aabb3f(v3f(b_max.MinEdge.X, b_max.MaxEdge.Y, b_max.MinEdge.Z), b_max.MaxEdge);
109 }
110
111 #define GETNODE(map, p3, v2, y, valid) \
112         (map)->getNodeNoEx((p3) + v3s16((v2).X, y, (v2).Y), valid)
113
114 // pos is the node the player is standing inside(!)
115 static bool detectSneakLadder(Map *map, INodeDefManager *nodemgr, v3s16 pos)
116 {
117         // Detects a structure known as "sneak ladder" or "sneak elevator"
118         // that relies on bugs to provide a fast means of vertical transportation,
119         // the bugs have since been fixed but this function remains to keep it working.
120         // NOTE: This is just entirely a huge hack and causes way too many problems.
121         bool is_valid_position;
122         MapNode node;
123         // X/Z vectors for 4 neighboring nodes
124         static const v2s16 vecs[] = { v2s16(-1, 0), v2s16(1, 0), v2s16(0, -1), v2s16(0, 1) };
125
126         for (u16 i = 0; i < ARRLEN(vecs); i++) {
127                 const v2s16 vec = vecs[i];
128
129                 // walkability of bottom & top node should differ
130                 node = GETNODE(map, pos, vec, 0, &is_valid_position);
131                 if (!is_valid_position)
132                         continue;
133                 bool w = nodemgr->get(node).walkable;
134                 node = GETNODE(map, pos, vec, 1, &is_valid_position);
135                 if (!is_valid_position || w == nodemgr->get(node).walkable)
136                         continue;
137
138                 // check one more node above OR below with corresponding walkability
139                 node = GETNODE(map, pos, vec, -1, &is_valid_position);
140                 bool ok = is_valid_position && w != nodemgr->get(node).walkable;
141                 if (!ok) {
142                         node = GETNODE(map, pos, vec, 2, &is_valid_position);
143                         ok = is_valid_position && w == nodemgr->get(node).walkable;
144                 }
145
146                 if (ok)
147                         return true;
148         }
149
150         return false;
151 }
152
153 static bool detectLedge(Map *map, INodeDefManager *nodemgr, v3s16 pos)
154 {
155         bool is_valid_position;
156         MapNode node;
157         // X/Z vectors for 4 neighboring nodes
158         static const v2s16 vecs[] = {v2s16(-1, 0), v2s16(1, 0), v2s16(0, -1), v2s16(0, 1)};
159
160         for (u16 i = 0; i < ARRLEN(vecs); i++) {
161                 const v2s16 vec = vecs[i];
162
163                 node = GETNODE(map, pos, vec, 1, &is_valid_position);
164                 if (is_valid_position && nodemgr->get(node).walkable) {
165                         // Ledge exists
166                         node = GETNODE(map, pos, vec, 2, &is_valid_position);
167                         if (is_valid_position && !nodemgr->get(node).walkable)
168                                 // Space above ledge exists
169                                 return true;
170                 }
171         }
172
173         return false;
174 }
175
176 #undef GETNODE
177
178 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
179                 std::vector<CollisionInfo> *collision_info)
180 {
181         Map *map = &env->getMap();
182         INodeDefManager *nodemgr = m_client->ndef();
183
184         v3f position = getPosition();
185
186         // Copy parent position if local player is attached
187         if(isAttached)
188         {
189                 setPosition(overridePosition);
190                 m_sneak_node_exists = false;
191                 return;
192         }
193
194         // Skip collision detection if noclip mode is used
195         bool fly_allowed = m_client->checkLocalPrivilege("fly");
196         bool noclip = m_client->checkLocalPrivilege("noclip") &&
197                 g_settings->getBool("noclip");
198         bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
199         if (free_move) {
200                 position += m_speed * dtime;
201                 setPosition(position);
202                 m_sneak_node_exists = false;
203                 return;
204         }
205
206         /*
207                 Collision detection
208         */
209
210         bool is_valid_position;
211         MapNode node;
212         v3s16 pp;
213
214         /*
215                 Check if player is in liquid (the oscillating value)
216         */
217
218         // If in liquid, the threshold of coming out is at higher y
219         if (in_liquid)
220         {
221                 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
222                 node = map->getNodeNoEx(pp, &is_valid_position);
223                 if (is_valid_position) {
224                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
225                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
226                 } else {
227                         in_liquid = false;
228                 }
229         }
230         // If not in liquid, the threshold of going in is at lower y
231         else
232         {
233                 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
234                 node = map->getNodeNoEx(pp, &is_valid_position);
235                 if (is_valid_position) {
236                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
237                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
238                 } else {
239                         in_liquid = false;
240                 }
241         }
242
243
244         /*
245                 Check if player is in liquid (the stable value)
246         */
247         pp = floatToInt(position + v3f(0,0,0), BS);
248         node = map->getNodeNoEx(pp, &is_valid_position);
249         if (is_valid_position) {
250                 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
251         } else {
252                 in_liquid_stable = false;
253         }
254
255         /*
256                 Check if player is climbing
257         */
258
259
260         pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
261         v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
262         node = map->getNodeNoEx(pp, &is_valid_position);
263         bool is_valid_position2;
264         MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
265
266         if (!(is_valid_position && is_valid_position2)) {
267                 is_climbing = false;
268         } else {
269                 is_climbing = (nodemgr->get(node.getContent()).climbable
270                                 || nodemgr->get(node2.getContent()).climbable) && !free_move;
271         }
272
273
274         /*
275                 Collision uncertainty radius
276                 Make it a bit larger than the maximum distance of movement
277         */
278         //f32 d = pos_max_d * 1.1;
279         // A fairly large value in here makes moving smoother
280         f32 d = 0.15*BS;
281
282         // This should always apply, otherwise there are glitches
283         sanity_check(d > pos_max_d);
284
285         // Max. distance (X, Z) over border for sneaking determined by collision box
286         // * 0.49 to keep the center just barely on the node
287         v3f sneak_max = m_collisionbox.getExtent() * 0.49;
288         if (m_sneak_ladder_detected) {
289                 // restore legacy behaviour (this makes the m_speed.Y hack necessary)
290                 sneak_max = v3f(0.4 * BS, 0, 0.4 * BS);
291         }
292
293         /*
294                 If sneaking, keep in range from the last walked node and don't
295                 fall off from it
296         */
297         if (control.sneak && m_sneak_node_exists &&
298                         !(fly_allowed && g_settings->getBool("free_move")) &&
299                         !in_liquid && !is_climbing &&
300                         physics_override_sneak && !got_teleported) {
301                 v3f sn_f = intToFloat(m_sneak_node, BS);
302                 const v3f bmin = m_sneak_node_bb_top.MinEdge;
303                 const v3f bmax = m_sneak_node_bb_top.MaxEdge;
304
305                 position.X = rangelim(position.X,
306                                 sn_f.X+bmin.X - sneak_max.X, sn_f.X+bmax.X + sneak_max.X);
307                 position.Z = rangelim(position.Z,
308                                 sn_f.Z+bmin.Z - sneak_max.Z, sn_f.Z+bmax.Z + sneak_max.Z);
309
310                 // Because we keep the player collision box on the node, limiting
311                 // position.Y is not necessary but useful to prevent players from
312                 // being inside a node if sneaking on e.g. the lower part of a stair
313                 if (!m_sneak_ladder_detected) {
314                         position.Y = MYMAX(position.Y, sn_f.Y+bmax.Y);
315                 } else {
316                         // legacy behaviour that sometimes causes some weird slow sinking
317                         m_speed.Y = MYMAX(m_speed.Y, 0);
318                 }
319         }
320
321         if (got_teleported)
322                 got_teleported = false;
323
324         // TODO: this shouldn't be hardcoded but transmitted from server
325         float player_stepheight = touching_ground ? (BS*0.6) : (BS*0.2);
326
327 #ifdef __ANDROID__
328         player_stepheight += (0.6 * BS);
329 #endif
330
331         v3f accel_f = v3f(0,0,0);
332
333         collisionMoveResult result = collisionMoveSimple(env, m_client,
334                 pos_max_d, m_collisionbox, player_stepheight, dtime,
335                 &position, &m_speed, accel_f);
336
337         /*
338                 If the player's feet touch the topside of any node, this is
339                 set to true.
340
341                 Player is allowed to jump when this is true.
342         */
343         bool touching_ground_was = touching_ground;
344         touching_ground = result.touching_ground;
345
346         // We want the top of the sneak node to be below the players feet
347         f32 position_y_mod;
348         if (m_sneak_node_exists)
349                 position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - 0.05 * BS;
350         else
351                 position_y_mod = (0.5 - 0.05) * BS;
352         v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
353         /*
354                 Check the nodes under the player to see from which node the
355                 player is sneaking from, if any.  If the node from under
356                 the player has been removed, the player falls.
357         */
358         if (m_sneak_node_exists &&
359                         nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
360                         m_old_node_below_type != "air") {
361                 // Old node appears to have been removed; that is,
362                 // it wasn't air before but now it is
363                 m_need_to_get_new_sneak_node = false;
364                 m_sneak_node_exists = false;
365         } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
366                 // We are on something, so make sure to recalculate the sneak
367                 // node.
368                 m_need_to_get_new_sneak_node = true;
369         }
370
371         if (m_need_to_get_new_sneak_node && physics_override_sneak) {
372                 v2f player_p2df(position.X, position.Z);
373                 f32 min_distance_f = 100000.0 * BS;
374                 v3s16 new_sneak_node = m_sneak_node;
375                 for(s16 x=-1; x<=1; x++)
376                 for(s16 z=-1; z<=1; z++)
377                 {
378                         v3s16 p = current_node + v3s16(x,0,z);
379                         v3f pf = intToFloat(p, BS);
380                         v2f node_p2df(pf.X, pf.Z);
381                         f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
382
383                         if (distance_f > min_distance_f ||
384                                         fabs(player_p2df.X-node_p2df.X) > (.5+.1)*BS + sneak_max.X ||
385                                         fabs(player_p2df.Y-node_p2df.Y) > (.5+.1)*BS + sneak_max.Z)
386                                 continue;
387
388
389                         // The node to be sneaked on has to be walkable
390                         node = map->getNodeNoEx(p, &is_valid_position);
391                         if (!is_valid_position || !nodemgr->get(node).walkable)
392                                 continue;
393                         // And the node(s) above have to be nonwalkable
394                         bool ok = true;
395                         if (!physics_override_sneak_glitch) {
396                                 u16 height = ceilf(
397                                                 (m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS
398                                 );
399                                 for (u16 y = 1; y <= height; y++) {
400                                         node = map->getNodeNoEx(p + v3s16(0,y,0), &is_valid_position);
401                                         if (!is_valid_position || nodemgr->get(node).walkable) {
402                                                 ok = false;
403                                                 break;
404                                         }
405                                 }
406                         } else {
407                                 // legacy behaviour: check just one node
408                                 node = map->getNodeNoEx(p + v3s16(0,1,0), &is_valid_position);
409                                 ok = is_valid_position && !nodemgr->get(node).walkable;
410                         }
411                         if (!ok)
412                                 continue;
413
414                         min_distance_f = distance_f;
415                         new_sneak_node = p;
416                 }
417
418                 bool sneak_node_found = (min_distance_f < 100000.0 * BS);
419                 m_sneak_node = new_sneak_node;
420                 m_sneak_node_exists = sneak_node_found;
421
422                 if (sneak_node_found) {
423                         // Update saved top bounding box of sneak node
424                         MapNode n = map->getNodeNoEx(m_sneak_node);
425                         std::vector<aabb3f> nodeboxes;
426                         n.getCollisionBoxes(nodemgr, &nodeboxes);
427                         m_sneak_node_bb_top = getTopBoundingBox(nodeboxes);
428
429                         m_sneak_ladder_detected = physics_override_sneak_glitch &&
430                                         detectSneakLadder(map, nodemgr, floatToInt(position, BS));
431                 } else {
432                         m_sneak_ladder_detected = false;
433                 }
434         }
435
436         /*
437                 If 'sneak glitch' enabled detect ledge for old sneak-jump
438                 behaviour of climbing onto a ledge 2 nodes up.
439         */
440         if (physics_override_sneak_glitch && control.sneak && control.jump)
441                 m_ledge_detected = detectLedge(map, nodemgr, floatToInt(position, BS));
442
443         /*
444                 Set new position
445         */
446         setPosition(position);
447
448         /*
449                 Report collisions
450         */
451
452         // Dont report if flying
453         if(collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
454                 for(size_t i=0; i<result.collisions.size(); i++) {
455                         const CollisionInfo &info = result.collisions[i];
456                         collision_info->push_back(info);
457                 }
458         }
459
460         if(!result.standing_on_object && !touching_ground_was && touching_ground) {
461                 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
462                 m_client->event()->put(e);
463
464                 // Set camera impact value to be used for view bobbing
465                 camera_impact = getSpeed().Y * -1;
466         }
467
468         {
469                 camera_barely_in_ceiling = false;
470                 v3s16 camera_np = floatToInt(getEyePosition(), BS);
471                 MapNode n = map->getNodeNoEx(camera_np);
472                 if(n.getContent() != CONTENT_IGNORE){
473                         if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
474                                 camera_barely_in_ceiling = true;
475                         }
476                 }
477         }
478
479         /*
480                 Update the node last under the player
481         */
482         m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS);
483         m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
484
485         /*
486                 Check properties of the node on which the player is standing
487         */
488         const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
489         // Determine if jumping is possible
490         m_can_jump = touching_ground && !in_liquid;
491         if (itemgroup_get(f.groups, "disable_jump"))
492                 m_can_jump = false;
493         else if (control.sneak && m_sneak_ladder_detected && !in_liquid && !is_climbing)
494                 m_can_jump = true;
495
496         // Jump key pressed while jumping off from a bouncy block
497         if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
498                 m_speed.Y >= -0.5 * BS) {
499                 float jumpspeed = movement_speed_jump * physics_override_jump;
500                 if (m_speed.Y > 1) {
501                         // Reduce boost when speed already is high
502                         m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
503                 } else {
504                         m_speed.Y += jumpspeed;
505                 }
506                 setSpeed(m_speed);
507                 m_can_jump = false;
508         }
509 }
510
511 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d)
512 {
513         move(dtime, env, pos_max_d, NULL);
514 }
515
516 void LocalPlayer::applyControl(float dtime)
517 {
518         // Clear stuff
519         swimming_vertical = false;
520
521         setPitch(control.pitch);
522         setYaw(control.yaw);
523
524         // Nullify speed and don't run positioning code if the player is attached
525         if(isAttached)
526         {
527                 setSpeed(v3f(0,0,0));
528                 return;
529         }
530
531         v3f move_direction = v3f(0,0,1);
532         move_direction.rotateXZBy(getYaw());
533
534         v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
535         v3f speedV = v3f(0,0,0); // Vertical (Y)
536
537         bool fly_allowed = m_client->checkLocalPrivilege("fly");
538         bool fast_allowed = m_client->checkLocalPrivilege("fast");
539
540         bool free_move = fly_allowed && g_settings->getBool("free_move");
541         bool fast_move = fast_allowed && g_settings->getBool("fast_move");
542         // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
543         bool fast_climb = fast_move && control.aux1 && !g_settings->getBool("aux1_descends");
544         bool continuous_forward = g_settings->getBool("continuous_forward");
545         bool always_fly_fast = g_settings->getBool("always_fly_fast");
546
547         // Whether superspeed mode is used or not
548         bool superspeed = false;
549
550         if (always_fly_fast && free_move && fast_move)
551                 superspeed = true;
552
553         // Old descend control
554         if(g_settings->getBool("aux1_descends"))
555         {
556                 // If free movement and fast movement, always move fast
557                 if(free_move && fast_move)
558                         superspeed = true;
559
560                 // Auxiliary button 1 (E)
561                 if(control.aux1)
562                 {
563                         if(free_move)
564                         {
565                                 // In free movement mode, aux1 descends
566                                 if(fast_move)
567                                         speedV.Y = -movement_speed_fast;
568                                 else
569                                         speedV.Y = -movement_speed_walk;
570                         }
571                         else if(in_liquid || in_liquid_stable)
572                         {
573                                 speedV.Y = -movement_speed_walk;
574                                 swimming_vertical = true;
575                         }
576                         else if(is_climbing)
577                         {
578                                 speedV.Y = -movement_speed_climb;
579                         }
580                         else
581                         {
582                                 // If not free movement but fast is allowed, aux1 is
583                                 // "Turbo button"
584                                 if(fast_move)
585                                         superspeed = true;
586                         }
587                 }
588         }
589         // New minecraft-like descend control
590         else
591         {
592                 // Auxiliary button 1 (E)
593                 if(control.aux1)
594                 {
595                         if(!is_climbing)
596                         {
597                                 // aux1 is "Turbo button"
598                                 if(fast_move)
599                                         superspeed = true;
600                         }
601                 }
602
603                 if(control.sneak)
604                 {
605                         if(free_move)
606                         {
607                                 // In free movement mode, sneak descends
608                                 if (fast_move && (control.aux1 || always_fly_fast))
609                                         speedV.Y = -movement_speed_fast;
610                                 else
611                                         speedV.Y = -movement_speed_walk;
612                         }
613                         else if(in_liquid || in_liquid_stable)
614                         {
615                                 if(fast_climb)
616                                         speedV.Y = -movement_speed_fast;
617                                 else
618                                         speedV.Y = -movement_speed_walk;
619                                 swimming_vertical = true;
620                         }
621                         else if(is_climbing)
622                         {
623                                 if(fast_climb)
624                                         speedV.Y = -movement_speed_fast;
625                                 else
626                                         speedV.Y = -movement_speed_climb;
627                         }
628                 }
629         }
630
631         if (continuous_forward)
632                 speedH += move_direction;
633
634         if (control.up) {
635                 if (continuous_forward) {
636                         if (fast_move)
637                                 superspeed = true;
638                 } else {
639                         speedH += move_direction;
640                 }
641         }
642         if (control.down) {
643                 speedH -= move_direction;
644         }
645         if (!control.up && !control.down) {
646                 speedH -= move_direction *
647                         (control.forw_move_joystick_axis / 32767.f);
648         }
649         if (control.left) {
650                 speedH += move_direction.crossProduct(v3f(0,1,0));
651         }
652         if (control.right) {
653                 speedH += move_direction.crossProduct(v3f(0,-1,0));
654         }
655         if (!control.left && !control.right) {
656                 speedH -= move_direction.crossProduct(v3f(0,1,0)) *
657                         (control.sidew_move_joystick_axis / 32767.f);
658         }
659         if(control.jump)
660         {
661                 if (free_move) {
662                         if (g_settings->getBool("aux1_descends") || always_fly_fast) {
663                                 if (fast_move)
664                                         speedV.Y = movement_speed_fast;
665                                 else
666                                         speedV.Y = movement_speed_walk;
667                         } else {
668                                 if(fast_move && control.aux1)
669                                         speedV.Y = movement_speed_fast;
670                                 else
671                                         speedV.Y = movement_speed_walk;
672                         }
673                 }
674                 else if(m_can_jump)
675                 {
676                         /*
677                                 NOTE: The d value in move() affects jump height by
678                                 raising the height at which the jump speed is kept
679                                 at its starting value
680                         */
681                         v3f speedJ = getSpeed();
682                         if(speedJ.Y >= -0.5 * BS) {
683                                 if (m_ledge_detected) {
684                                         // Limit jump speed to a minimum that allows
685                                         // jumping up onto a ledge 2 nodes up.
686                                         speedJ.Y = movement_speed_jump *
687                                                         MYMAX(physics_override_jump, 1.3f);
688                                         setSpeed(speedJ);
689                                         m_ledge_detected = false;
690                                 } else {
691                                         speedJ.Y = movement_speed_jump * physics_override_jump;
692                                         setSpeed(speedJ);
693                                 }
694
695                                 MtEvent *e = new SimpleTriggerEvent("PlayerJump");
696                                 m_client->event()->put(e);
697                         }
698                 }
699                 else if(in_liquid)
700                 {
701                         if(fast_climb)
702                                 speedV.Y = movement_speed_fast;
703                         else
704                                 speedV.Y = movement_speed_walk;
705                         swimming_vertical = true;
706                 }
707                 else if(is_climbing)
708                 {
709                         if(fast_climb)
710                                 speedV.Y = movement_speed_fast;
711                         else
712                                 speedV.Y = movement_speed_climb;
713                 }
714         }
715
716         // The speed of the player (Y is ignored)
717         if(superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
718                 speedH = speedH.normalize() * movement_speed_fast;
719         else if(control.sneak && !free_move && !in_liquid && !in_liquid_stable)
720                 speedH = speedH.normalize() * movement_speed_crouch;
721         else
722                 speedH = speedH.normalize() * movement_speed_walk;
723
724         // Acceleration increase
725         f32 incH = 0; // Horizontal (X, Z)
726         f32 incV = 0; // Vertical (Y)
727         if((!touching_ground && !free_move && !is_climbing && !in_liquid) || (!free_move && m_can_jump && control.jump))
728         {
729                 // Jumping and falling
730                 if(superspeed || (fast_move && control.aux1))
731                         incH = movement_acceleration_fast * BS * dtime;
732                 else
733                         incH = movement_acceleration_air * BS * dtime;
734                 incV = 0; // No vertical acceleration in air
735         }
736         else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
737                 incH = incV = movement_acceleration_fast * BS * dtime;
738         else
739                 incH = incV = movement_acceleration_default * BS * dtime;
740
741         // Accelerate to target speed with maximum increment
742         accelerateHorizontal(speedH * physics_override_speed, incH * physics_override_speed);
743         accelerateVertical(speedV * physics_override_speed, incV * physics_override_speed);
744 }
745
746 v3s16 LocalPlayer::getStandingNodePos()
747 {
748         if(m_sneak_node_exists)
749                 return m_sneak_node;
750         return floatToInt(getPosition() - v3f(0, BS, 0), BS);
751 }
752
753 v3s16 LocalPlayer::getFootstepNodePos()
754 {
755         if (touching_ground)
756                 // BS * 0.05 below the player's feet ensures a 1/16th height
757                 // nodebox is detected instead of the node below it.
758                 return floatToInt(getPosition() - v3f(0, BS * 0.05f, 0), BS);
759         // A larger distance below is necessary for a footstep sound
760         // when landing after a jump or fall. BS * 0.5 ensures water
761         // sounds when swimming in 1 node deep water.
762         return floatToInt(getPosition() - v3f(0, BS * 0.5f, 0), BS);
763 }
764
765 v3s16 LocalPlayer::getLightPosition() const
766 {
767         return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
768 }
769
770 v3f LocalPlayer::getEyeOffset() const
771 {
772         float eye_height = camera_barely_in_ceiling ? 1.5f : 1.625f;
773         return v3f(0, BS * eye_height, 0);
774 }
775
776 // Horizontal acceleration (X and Z), Y direction is ignored
777 void LocalPlayer::accelerateHorizontal(const v3f &target_speed, const f32 max_increase)
778 {
779         if (max_increase == 0)
780                 return;
781
782         v3f d_wanted = target_speed - m_speed;
783         d_wanted.Y = 0;
784         f32 dl = d_wanted.getLength();
785         if (dl > max_increase)
786                 dl = max_increase;
787
788         v3f d = d_wanted.normalize() * dl;
789
790         m_speed.X += d.X;
791         m_speed.Z += d.Z;
792 }
793
794 // Vertical acceleration (Y), X and Z directions are ignored
795 void LocalPlayer::accelerateVertical(const v3f &target_speed, const f32 max_increase)
796 {
797         if (max_increase == 0)
798                 return;
799
800         f32 d_wanted = target_speed.Y - m_speed.Y;
801         if (d_wanted > max_increase)
802                 d_wanted = max_increase;
803         else if (d_wanted < -max_increase)
804                 d_wanted = -max_increase;
805
806         m_speed.Y += d_wanted;
807 }
808