296 lines
7.2 KiB
C++
296 lines
7.2 KiB
C++
/*
|
|
Minetest
|
|
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "localplayer.h"
|
|
|
|
#include "main.h" // For g_settings
|
|
#include "event.h"
|
|
#include "collision.h"
|
|
#include "gamedef.h"
|
|
#include "nodedef.h"
|
|
#include "settings.h"
|
|
#include "environment.h"
|
|
#include "map.h"
|
|
#include "util/numeric.h"
|
|
|
|
/*
|
|
LocalPlayer
|
|
*/
|
|
|
|
LocalPlayer::LocalPlayer(IGameDef *gamedef):
|
|
Player(gamedef),
|
|
parent(0),
|
|
isAttached(false),
|
|
overridePosition(v3f(0,0,0)),
|
|
last_position(v3f(0,0,0)),
|
|
last_speed(v3f(0,0,0)),
|
|
last_pitch(0),
|
|
last_yaw(0),
|
|
last_keyPressed(0),
|
|
m_sneak_node(32767,32767,32767),
|
|
m_sneak_node_exists(false),
|
|
m_old_node_below(32767,32767,32767),
|
|
m_old_node_below_type("air"),
|
|
m_need_to_get_new_sneak_node(true),
|
|
m_can_jump(false)
|
|
{
|
|
// Initialize hp to 0, so that no hearts will be shown if server
|
|
// doesn't support health points
|
|
hp = 0;
|
|
}
|
|
|
|
LocalPlayer::~LocalPlayer()
|
|
{
|
|
}
|
|
|
|
void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d,
|
|
std::list<CollisionInfo> *collision_info)
|
|
{
|
|
}
|
|
|
|
void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d)
|
|
{
|
|
move(dtime, env, pos_max_d, NULL);
|
|
}
|
|
|
|
void LocalPlayer::applyControl(float dtime)
|
|
{
|
|
// Clear stuff
|
|
swimming_vertical = false;
|
|
|
|
setPitch(control.pitch);
|
|
setYaw(control.yaw);
|
|
|
|
// Nullify speed and don't run positioning code if the player is attached
|
|
if(isAttached)
|
|
{
|
|
setSpeed(v3f(0,0,0));
|
|
return;
|
|
}
|
|
|
|
v3f move_direction = v3f(0,0,1);
|
|
move_direction.rotateXZBy(getYaw());
|
|
|
|
v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
|
|
v3f speedV = v3f(0,0,0); // Vertical (Y)
|
|
|
|
bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
|
|
bool fast_allowed = m_gamedef->checkLocalPrivilege("fast");
|
|
|
|
bool free_move = fly_allowed && g_settings->getBool("free_move");
|
|
bool fast_move = fast_allowed && g_settings->getBool("fast_move");
|
|
// When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
|
|
bool fast_climb = fast_move && control.aux1 && !g_settings->getBool("aux1_descends");
|
|
bool continuous_forward = g_settings->getBool("continuous_forward");
|
|
|
|
// Whether superspeed mode is used or not
|
|
bool superspeed = false;
|
|
|
|
if(g_settings->getBool("always_fly_fast") && free_move && fast_move)
|
|
superspeed = true;
|
|
|
|
// Old descend control
|
|
if(g_settings->getBool("aux1_descends"))
|
|
{
|
|
// If free movement and fast movement, always move fast
|
|
if(free_move && fast_move)
|
|
superspeed = true;
|
|
|
|
// Auxiliary button 1 (E)
|
|
if(control.aux1)
|
|
{
|
|
if(free_move)
|
|
{
|
|
// In free movement mode, aux1 descends
|
|
if(fast_move)
|
|
speedV.Y = -movement_speed_fast;
|
|
else
|
|
speedV.Y = -movement_speed_walk;
|
|
}
|
|
else if(in_liquid || in_liquid_stable)
|
|
{
|
|
speedV.Y = -movement_speed_walk;
|
|
swimming_vertical = true;
|
|
}
|
|
else if(is_climbing)
|
|
{
|
|
speedV.Y = -movement_speed_climb;
|
|
}
|
|
else
|
|
{
|
|
// If not free movement but fast is allowed, aux1 is
|
|
// "Turbo button"
|
|
if(fast_move)
|
|
superspeed = true;
|
|
}
|
|
}
|
|
}
|
|
// New minecraft-like descend control
|
|
else
|
|
{
|
|
// Auxiliary button 1 (E)
|
|
if(control.aux1)
|
|
{
|
|
if(!is_climbing)
|
|
{
|
|
// aux1 is "Turbo button"
|
|
if(fast_move)
|
|
superspeed = true;
|
|
}
|
|
}
|
|
|
|
if(control.sneak)
|
|
{
|
|
if(free_move)
|
|
{
|
|
// In free movement mode, sneak descends
|
|
if(fast_move && (control.aux1 || g_settings->getBool("always_fly_fast")))
|
|
speedV.Y = -movement_speed_fast;
|
|
else
|
|
speedV.Y = -movement_speed_walk;
|
|
}
|
|
else if(in_liquid || in_liquid_stable)
|
|
{
|
|
if(fast_climb)
|
|
speedV.Y = -movement_speed_fast;
|
|
else
|
|
speedV.Y = -movement_speed_walk;
|
|
swimming_vertical = true;
|
|
}
|
|
else if(is_climbing)
|
|
{
|
|
if(fast_climb)
|
|
speedV.Y = -movement_speed_fast;
|
|
else
|
|
speedV.Y = -movement_speed_climb;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(continuous_forward)
|
|
speedH += move_direction;
|
|
|
|
if(control.up)
|
|
{
|
|
if(continuous_forward)
|
|
superspeed = true;
|
|
else
|
|
speedH += move_direction;
|
|
}
|
|
if(control.down)
|
|
{
|
|
speedH -= move_direction;
|
|
}
|
|
if(control.left)
|
|
{
|
|
speedH += move_direction.crossProduct(v3f(0,1,0));
|
|
}
|
|
if(control.right)
|
|
{
|
|
speedH += move_direction.crossProduct(v3f(0,-1,0));
|
|
}
|
|
if(control.jump)
|
|
{
|
|
if(free_move)
|
|
{
|
|
if(g_settings->getBool("aux1_descends") || g_settings->getBool("always_fly_fast"))
|
|
{
|
|
if(fast_move)
|
|
speedV.Y = movement_speed_fast;
|
|
else
|
|
speedV.Y = movement_speed_walk;
|
|
} else {
|
|
if(fast_move && control.aux1)
|
|
speedV.Y = movement_speed_fast;
|
|
else
|
|
speedV.Y = movement_speed_walk;
|
|
}
|
|
}
|
|
else if(m_can_jump)
|
|
{
|
|
/*
|
|
NOTE: The d value in move() affects jump height by
|
|
raising the height at which the jump speed is kept
|
|
at its starting value
|
|
*/
|
|
v3f speedJ = getSpeed();
|
|
if(speedJ.Y >= -0.5 * BS)
|
|
{
|
|
speedJ.Y = movement_speed_jump * physics_override_jump;
|
|
setSpeed(speedJ);
|
|
|
|
MtEvent *e = new SimpleTriggerEvent("PlayerJump");
|
|
m_gamedef->event()->put(e);
|
|
}
|
|
}
|
|
else if(in_liquid)
|
|
{
|
|
if(fast_climb)
|
|
speedV.Y = movement_speed_fast;
|
|
else
|
|
speedV.Y = movement_speed_walk;
|
|
swimming_vertical = true;
|
|
}
|
|
else if(is_climbing)
|
|
{
|
|
if(fast_climb)
|
|
speedV.Y = movement_speed_fast;
|
|
else
|
|
speedV.Y = movement_speed_climb;
|
|
}
|
|
}
|
|
|
|
// The speed of the player (Y is ignored)
|
|
if(superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
|
|
speedH = speedH.normalize() * movement_speed_fast;
|
|
else if(control.sneak && !free_move && !in_liquid && !in_liquid_stable)
|
|
speedH = speedH.normalize() * movement_speed_crouch;
|
|
else
|
|
speedH = speedH.normalize() * movement_speed_walk;
|
|
|
|
// Acceleration increase
|
|
f32 incH = 0; // Horizontal (X, Z)
|
|
f32 incV = 0; // Vertical (Y)
|
|
if((!touching_ground && !free_move && !is_climbing && !in_liquid) || (!free_move && m_can_jump && control.jump))
|
|
{
|
|
// Jumping and falling
|
|
if(superspeed || (fast_move && control.aux1))
|
|
incH = movement_acceleration_fast * BS * dtime;
|
|
else
|
|
incH = movement_acceleration_air * BS * dtime;
|
|
incV = 0; // No vertical acceleration in air
|
|
}
|
|
else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
|
|
incH = incV = movement_acceleration_fast * BS * dtime;
|
|
else
|
|
incH = incV = movement_acceleration_default * BS * dtime;
|
|
|
|
// Accelerate to target speed with maximum increment
|
|
accelerateHorizontal(speedH * physics_override_speed, incH * physics_override_speed);
|
|
accelerateVertical(speedV * physics_override_speed, incV * physics_override_speed);
|
|
}
|
|
|
|
v3s16 LocalPlayer::getStandingNodePos()
|
|
{
|
|
if(m_sneak_node_exists)
|
|
return m_sneak_node;
|
|
return floatToInt(getPosition(), BS);
|
|
}
|
|
|