]> git.lizzy.rs Git - dragonfireclient.git/blob - src/localplayer.cpp
Add wielded (and CAOs) shader
[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 "gamedef.h"
25 #include "nodedef.h"
26 #include "settings.h"
27 #include "environment.h"
28 #include "map.h"
29 #include "util/numeric.h"
30
31 /*
32         LocalPlayer
33 */
34
35 LocalPlayer::LocalPlayer(IGameDef *gamedef, const char *name):
36         Player(gamedef, name),
37         parent(0),
38         isAttached(false),
39         overridePosition(v3f(0,0,0)),
40         last_position(v3f(0,0,0)),
41         last_speed(v3f(0,0,0)),
42         last_pitch(0),
43         last_yaw(0),
44         last_keyPressed(0),
45         last_animation(NO_ANIM),
46         hotbar_image(""),
47         hotbar_selected_image(""),
48         light_color(255,255,255,255),
49         m_sneak_node(32767,32767,32767),
50         m_sneak_node_exists(false),
51         m_old_node_below(32767,32767,32767),
52         m_old_node_below_type("air"),
53         m_need_to_get_new_sneak_node(true),
54         m_can_jump(false),
55         m_cao(NULL)
56 {
57         // Initialize hp to 0, so that no hearts will be shown if server
58         // doesn't support health points
59         hp = 0;
60         eye_offset_first = v3f(0,0,0);
61         eye_offset_third = v3f(0,0,0);
62 }
63
64 LocalPlayer::~LocalPlayer()
65 {
66 }
67
68 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
69                 std::vector<CollisionInfo> *collision_info)
70 {
71         Map *map = &env->getMap();
72         INodeDefManager *nodemgr = m_gamedef->ndef();
73
74         v3f position = getPosition();
75
76         // Copy parent position if local player is attached
77         if(isAttached)
78         {
79                 setPosition(overridePosition);
80                 m_sneak_node_exists = false;
81                 return;
82         }
83
84         // Skip collision detection if noclip mode is used
85         bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
86         bool noclip = m_gamedef->checkLocalPrivilege("noclip") &&
87                 g_settings->getBool("noclip");
88         bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
89         if (free_move) {
90                 position += m_speed * dtime;
91                 setPosition(position);
92                 m_sneak_node_exists = false;
93                 return;
94         }
95
96         /*
97                 Collision detection
98         */
99
100         bool is_valid_position;
101         MapNode node;
102         v3s16 pp;
103
104         /*
105                 Check if player is in liquid (the oscillating value)
106         */
107
108         // If in liquid, the threshold of coming out is at higher y
109         if (in_liquid)
110         {
111                 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
112                 node = map->getNodeNoEx(pp, &is_valid_position);
113                 if (is_valid_position) {
114                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
115                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
116                 } else {
117                         in_liquid = false;
118                 }
119         }
120         // If not in liquid, the threshold of going in is at lower y
121         else
122         {
123                 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
124                 node = map->getNodeNoEx(pp, &is_valid_position);
125                 if (is_valid_position) {
126                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
127                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
128                 } else {
129                         in_liquid = false;
130                 }
131         }
132
133
134         /*
135                 Check if player is in liquid (the stable value)
136         */
137         pp = floatToInt(position + v3f(0,0,0), BS);
138         node = map->getNodeNoEx(pp, &is_valid_position);
139         if (is_valid_position) {
140                 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
141         } else {
142                 in_liquid_stable = false;
143         }
144
145         /*
146                 Check if player is climbing
147         */
148
149
150         pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
151         v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
152         node = map->getNodeNoEx(pp, &is_valid_position);
153         bool is_valid_position2;
154         MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
155
156         if (!(is_valid_position && is_valid_position2)) {
157                 is_climbing = false;
158         } else {
159                 is_climbing = (nodemgr->get(node.getContent()).climbable
160                                 || nodemgr->get(node2.getContent()).climbable) && !free_move;
161         }
162
163
164         /*
165                 Collision uncertainty radius
166                 Make it a bit larger than the maximum distance of movement
167         */
168         //f32 d = pos_max_d * 1.1;
169         // A fairly large value in here makes moving smoother
170         f32 d = 0.15*BS;
171
172         // This should always apply, otherwise there are glitches
173         sanity_check(d > pos_max_d);
174
175         // Maximum distance over border for sneaking
176         f32 sneak_max = BS*0.4;
177
178         /*
179                 If sneaking, keep in range from the last walked node and don't
180                 fall off from it
181         */
182         if(control.sneak && m_sneak_node_exists &&
183                         !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
184                         physics_override_sneak)
185         {
186                 f32 maxd = 0.5*BS + sneak_max;
187                 v3f lwn_f = intToFloat(m_sneak_node, BS);
188                 position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd);
189                 position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd);
190
191                 if(!is_climbing)
192                 {
193                         f32 min_y = lwn_f.Y + 0.5*BS;
194                         if(position.Y < min_y)
195                         {
196                                 position.Y = min_y;
197
198                                 if(m_speed.Y < 0)
199                                         m_speed.Y = 0;
200                         }
201                 }
202         }
203
204         // this shouldn't be hardcoded but transmitted from server
205         float player_stepheight = touching_ground ? (BS*0.6) : (BS*0.2);
206
207 #ifdef __ANDROID__
208         player_stepheight += (0.5 * BS);
209 #endif
210
211         v3f accel_f = v3f(0,0,0);
212
213         collisionMoveResult result = collisionMoveSimple(env, m_gamedef,
214                         pos_max_d, m_collisionbox, player_stepheight, dtime,
215                         position, m_speed, accel_f);
216
217         /*
218                 If the player's feet touch the topside of any node, this is
219                 set to true.
220
221                 Player is allowed to jump when this is true.
222         */
223         bool touching_ground_was = touching_ground;
224         touching_ground = result.touching_ground;
225
226     //bool standing_on_unloaded = result.standing_on_unloaded;
227
228         /*
229                 Check the nodes under the player to see from which node the
230                 player is sneaking from, if any.  If the node from under
231                 the player has been removed, the player falls.
232         */
233         v3s16 current_node = floatToInt(position - v3f(0,BS/2,0), BS);
234         if(m_sneak_node_exists &&
235            nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
236            m_old_node_below_type != "air")
237         {
238                 // Old node appears to have been removed; that is,
239                 // it wasn't air before but now it is
240                 m_need_to_get_new_sneak_node = false;
241                 m_sneak_node_exists = false;
242         }
243         else if(nodemgr->get(map->getNodeNoEx(current_node)).name != "air")
244         {
245                 // We are on something, so make sure to recalculate the sneak
246                 // node.
247                 m_need_to_get_new_sneak_node = true;
248         }
249         if(m_need_to_get_new_sneak_node && physics_override_sneak)
250         {
251                 v3s16 pos_i_bottom = floatToInt(position - v3f(0,BS/2,0), BS);
252                 v2f player_p2df(position.X, position.Z);
253                 f32 min_distance_f = 100000.0*BS;
254                 // If already seeking from some node, compare to it.
255                 /*if(m_sneak_node_exists)
256                 {
257                         v3f sneaknode_pf = intToFloat(m_sneak_node, BS);
258                         v2f sneaknode_p2df(sneaknode_pf.X, sneaknode_pf.Z);
259                         f32 d_horiz_f = player_p2df.getDistanceFrom(sneaknode_p2df);
260                         f32 d_vert_f = fabs(sneaknode_pf.Y + BS*0.5 - position.Y);
261                         // Ignore if player is not on the same level (likely dropped)
262                         if(d_vert_f < 0.15*BS)
263                                 min_distance_f = d_horiz_f;
264                 }*/
265                 v3s16 new_sneak_node = m_sneak_node;
266                 for(s16 x=-1; x<=1; x++)
267                 for(s16 z=-1; z<=1; z++)
268                 {
269                         v3s16 p = pos_i_bottom + v3s16(x,0,z);
270                         v3f pf = intToFloat(p, BS);
271                         v2f node_p2df(pf.X, pf.Z);
272                         f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
273                         f32 max_axis_distance_f = MYMAX(
274                                         fabs(player_p2df.X-node_p2df.X),
275                                         fabs(player_p2df.Y-node_p2df.Y));
276
277                         if(distance_f > min_distance_f ||
278                                         max_axis_distance_f > 0.5*BS + sneak_max + 0.1*BS)
279                                 continue;
280
281
282                         // The node to be sneaked on has to be walkable
283                         node = map->getNodeNoEx(p, &is_valid_position);
284                         if (!is_valid_position || nodemgr->get(node).walkable == false)
285                                 continue;
286                         // And the node above it has to be nonwalkable
287                         node = map->getNodeNoEx(p + v3s16(0,1,0), &is_valid_position);
288                         if (!is_valid_position || nodemgr->get(node).walkable) {
289                                 continue;
290                         }
291                         if (!physics_override_sneak_glitch) {
292                                 node =map->getNodeNoEx(p + v3s16(0,2,0), &is_valid_position);
293                                 if (!is_valid_position || nodemgr->get(node).walkable)
294                                         continue;
295                         }
296
297                         min_distance_f = distance_f;
298                         new_sneak_node = p;
299                 }
300
301                 bool sneak_node_found = (min_distance_f < 100000.0*BS*0.9);
302
303                 m_sneak_node = new_sneak_node;
304                 m_sneak_node_exists = sneak_node_found;
305
306                 /*
307                         If sneaking, the player's collision box can be in air, so
308                         this has to be set explicitly
309                 */
310                 if(sneak_node_found && control.sneak)
311                         touching_ground = true;
312         }
313
314         /*
315                 Set new position
316         */
317         setPosition(position);
318
319         /*
320                 Report collisions
321         */
322         bool bouncy_jump = false;
323         // Dont report if flying
324         if(collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
325                 for(size_t i=0; i<result.collisions.size(); i++) {
326                         const CollisionInfo &info = result.collisions[i];
327                         collision_info->push_back(info);
328                         if(info.new_speed.Y - info.old_speed.Y > 0.1*BS &&
329                                         info.bouncy)
330                                 bouncy_jump = true;
331                 }
332         }
333
334         if(bouncy_jump && control.jump){
335                 m_speed.Y += movement_speed_jump*BS;
336                 touching_ground = false;
337                 MtEvent *e = new SimpleTriggerEvent("PlayerJump");
338                 m_gamedef->event()->put(e);
339         }
340
341         if(!touching_ground_was && touching_ground){
342                 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
343                 m_gamedef->event()->put(e);
344
345                 // Set camera impact value to be used for view bobbing
346                 camera_impact = getSpeed().Y * -1;
347         }
348
349         {
350                 camera_barely_in_ceiling = false;
351                 v3s16 camera_np = floatToInt(getEyePosition(), BS);
352                 MapNode n = map->getNodeNoEx(camera_np);
353                 if(n.getContent() != CONTENT_IGNORE){
354                         if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
355                                 camera_barely_in_ceiling = true;
356                         }
357                 }
358         }
359
360         /*
361                 Update the node last under the player
362         */
363         m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS);
364         m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
365
366         /*
367                 Check properties of the node on which the player is standing
368         */
369         const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
370         // Determine if jumping is possible
371         m_can_jump = touching_ground && !in_liquid;
372         if(itemgroup_get(f.groups, "disable_jump"))
373                 m_can_jump = false;
374 }
375
376 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d)
377 {
378         move(dtime, env, pos_max_d, NULL);
379 }
380
381 void LocalPlayer::applyControl(float dtime)
382 {
383         // Clear stuff
384         swimming_vertical = false;
385
386         setPitch(control.pitch);
387         setYaw(control.yaw);
388
389         // Nullify speed and don't run positioning code if the player is attached
390         if(isAttached)
391         {
392                 setSpeed(v3f(0,0,0));
393                 return;
394         }
395
396         v3f move_direction = v3f(0,0,1);
397         move_direction.rotateXZBy(getYaw());
398
399         v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
400         v3f speedV = v3f(0,0,0); // Vertical (Y)
401
402         bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
403         bool fast_allowed = m_gamedef->checkLocalPrivilege("fast");
404
405         bool free_move = fly_allowed && g_settings->getBool("free_move");
406         bool fast_move = fast_allowed && g_settings->getBool("fast_move");
407         // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
408         bool fast_climb = fast_move && control.aux1 && !g_settings->getBool("aux1_descends");
409         bool continuous_forward = g_settings->getBool("continuous_forward");
410         bool always_fly_fast = g_settings->getBool("always_fly_fast");
411
412         // Whether superspeed mode is used or not
413         bool superspeed = false;
414
415         if (always_fly_fast && free_move && fast_move)
416                 superspeed = true;
417
418         // Old descend control
419         if(g_settings->getBool("aux1_descends"))
420         {
421                 // If free movement and fast movement, always move fast
422                 if(free_move && fast_move)
423                         superspeed = true;
424
425                 // Auxiliary button 1 (E)
426                 if(control.aux1)
427                 {
428                         if(free_move)
429                         {
430                                 // In free movement mode, aux1 descends
431                                 if(fast_move)
432                                         speedV.Y = -movement_speed_fast;
433                                 else
434                                         speedV.Y = -movement_speed_walk;
435                         }
436                         else if(in_liquid || in_liquid_stable)
437                         {
438                                 speedV.Y = -movement_speed_walk;
439                                 swimming_vertical = true;
440                         }
441                         else if(is_climbing)
442                         {
443                                 speedV.Y = -movement_speed_climb;
444                         }
445                         else
446                         {
447                                 // If not free movement but fast is allowed, aux1 is
448                                 // "Turbo button"
449                                 if(fast_move)
450                                         superspeed = true;
451                         }
452                 }
453         }
454         // New minecraft-like descend control
455         else
456         {
457                 // Auxiliary button 1 (E)
458                 if(control.aux1)
459                 {
460                         if(!is_climbing)
461                         {
462                                 // aux1 is "Turbo button"
463                                 if(fast_move)
464                                         superspeed = true;
465                         }
466                 }
467
468                 if(control.sneak)
469                 {
470                         if(free_move)
471                         {
472                                 // In free movement mode, sneak descends
473                                 if (fast_move && (control.aux1 || always_fly_fast))
474                                         speedV.Y = -movement_speed_fast;
475                                 else
476                                         speedV.Y = -movement_speed_walk;
477                         }
478                         else if(in_liquid || in_liquid_stable)
479                         {
480                                 if(fast_climb)
481                                         speedV.Y = -movement_speed_fast;
482                                 else
483                                         speedV.Y = -movement_speed_walk;
484                                 swimming_vertical = true;
485                         }
486                         else if(is_climbing)
487                         {
488                                 if(fast_climb)
489                                         speedV.Y = -movement_speed_fast;
490                                 else
491                                         speedV.Y = -movement_speed_climb;
492                         }
493                 }
494         }
495
496         if(continuous_forward)
497                 speedH += move_direction;
498
499         if(control.up)
500         {
501                 if(continuous_forward)
502                         superspeed = true;
503                 else
504                         speedH += move_direction;
505         }
506         if(control.down)
507         {
508                 speedH -= move_direction;
509         }
510         if(control.left)
511         {
512                 speedH += move_direction.crossProduct(v3f(0,1,0));
513         }
514         if(control.right)
515         {
516                 speedH += move_direction.crossProduct(v3f(0,-1,0));
517         }
518         if(control.jump)
519         {
520                 if (free_move) {
521                         if (g_settings->getBool("aux1_descends") || always_fly_fast) {
522                                 if (fast_move)
523                                         speedV.Y = movement_speed_fast;
524                                 else
525                                         speedV.Y = movement_speed_walk;
526                         } else {
527                                 if(fast_move && control.aux1)
528                                         speedV.Y = movement_speed_fast;
529                                 else
530                                         speedV.Y = movement_speed_walk;
531                         }
532                 }
533                 else if(m_can_jump)
534                 {
535                         /*
536                                 NOTE: The d value in move() affects jump height by
537                                 raising the height at which the jump speed is kept
538                                 at its starting value
539                         */
540                         v3f speedJ = getSpeed();
541                         if(speedJ.Y >= -0.5 * BS)
542                         {
543                                 speedJ.Y = movement_speed_jump * physics_override_jump;
544                                 setSpeed(speedJ);
545
546                                 MtEvent *e = new SimpleTriggerEvent("PlayerJump");
547                                 m_gamedef->event()->put(e);
548                         }
549                 }
550                 else if(in_liquid)
551                 {
552                         if(fast_climb)
553                                 speedV.Y = movement_speed_fast;
554                         else
555                                 speedV.Y = movement_speed_walk;
556                         swimming_vertical = true;
557                 }
558                 else if(is_climbing)
559                 {
560                         if(fast_climb)
561                                 speedV.Y = movement_speed_fast;
562                         else
563                                 speedV.Y = movement_speed_climb;
564                 }
565         }
566
567         // The speed of the player (Y is ignored)
568         if(superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
569                 speedH = speedH.normalize() * movement_speed_fast;
570         else if(control.sneak && !free_move && !in_liquid && !in_liquid_stable)
571                 speedH = speedH.normalize() * movement_speed_crouch;
572         else
573                 speedH = speedH.normalize() * movement_speed_walk;
574
575         // Acceleration increase
576         f32 incH = 0; // Horizontal (X, Z)
577         f32 incV = 0; // Vertical (Y)
578         if((!touching_ground && !free_move && !is_climbing && !in_liquid) || (!free_move && m_can_jump && control.jump))
579         {
580                 // Jumping and falling
581                 if(superspeed || (fast_move && control.aux1))
582                         incH = movement_acceleration_fast * BS * dtime;
583                 else
584                         incH = movement_acceleration_air * BS * dtime;
585                 incV = 0; // No vertical acceleration in air
586         }
587         else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
588                 incH = incV = movement_acceleration_fast * BS * dtime;
589         else
590                 incH = incV = movement_acceleration_default * BS * dtime;
591
592         // Accelerate to target speed with maximum increment
593         accelerateHorizontal(speedH * physics_override_speed, incH * physics_override_speed);
594         accelerateVertical(speedV * physics_override_speed, incV * physics_override_speed);
595 }
596
597 v3s16 LocalPlayer::getStandingNodePos()
598 {
599         if(m_sneak_node_exists)
600                 return m_sneak_node;
601         return floatToInt(getPosition() - v3f(0, BS, 0), BS);
602 }
603