diff --git a/doc/lua_api.txt b/doc/lua_api.txt index a801c6019..dac242f67 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1868,7 +1868,9 @@ to games. * `attached_node`: if the node under it is not a walkable block the node will be dropped as an item. If the node is wallmounted the wallmounted direction is checked. -* `bouncy`: value is bounce speed in percent +* `bouncy`: value is bounce speed in percent. + If positive, jump/sneak on floor impact will increase/decrease bounce height. + Negative value is the same bounciness, but non-controllable. * `connect_to_raillike`: makes nodes of raillike drawtype with same group value connect to each other * `dig_immediate`: Player can always pick up node without reducing tool wear diff --git a/src/client/localplayer.cpp b/src/client/localplayer.cpp index f9caf9e8b..ef249235b 100644 --- a/src/client/localplayer.cpp +++ b/src/client/localplayer.cpp @@ -331,8 +331,8 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, } /* - If the player's feet touch the topside of any node, this is - set to true. + If the player's feet touch the topside of any node + at the END of clientstep, then this is set to true. Player is allowed to jump when this is true. */ @@ -432,23 +432,47 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, const ContentFeatures &f = nodemgr->get(map->getNode(m_standing_node)); const ContentFeatures &f1 = nodemgr->get(map->getNode(m_standing_node + v3s16(0, 1, 0))); + // We can jump from a bouncy node we collided with this clientstep, + // even if we are not "touching" it at the end of clientstep. + int standing_node_bouncy = 0; + if (result.collides && m_speed.Y > 0.0f) { + // must use result.collisions here because sometimes collision_info + // is passed in prepopulated with a problematic floor. + for (const auto &colinfo : result.collisions) { + if (colinfo.axis == COLLISION_AXIS_Y) { + // we cannot rely on m_standing_node because "sneak stuff" + standing_node_bouncy = itemgroup_get(nodemgr->get(map->getNode(colinfo.node_p)).groups, "bouncy"); + if (standing_node_bouncy != 0) + break; + } + } + } + // Determine if jumping is possible m_disable_jump = itemgroup_get(f.groups, "disable_jump") || itemgroup_get(f1.groups, "disable_jump"); - m_can_jump = ((touching_ground && !is_climbing) || sneak_can_jump) && !m_disable_jump; + m_can_jump = ((touching_ground && !is_climbing) || sneak_can_jump || standing_node_bouncy != 0) + && !m_disable_jump; - // Jump key pressed while jumping off from a bouncy block - if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") && - m_speed.Y >= -0.5f * BS) { - float jumpspeed = movement_speed_jump * physics_override.jump; - if (m_speed.Y > 1.0f) { - // Reduce boost when speed already is high - m_speed.Y += jumpspeed / (1.0f + (m_speed.Y / 16.0f)); + // Jump/Sneak key pressed while bouncing from a bouncy block + float jumpspeed = movement_speed_jump * physics_override.jump; + if (m_can_jump && (control.jump || control.sneak) && standing_node_bouncy > 0) { + // controllable (>0) bouncy block + if (!control.jump) { + // sneak pressed, but not jump + // Subjective testing indicates 1/3 bounce decrease works well. + jumpspeed = -m_speed.Y / 3.0f; } else { - m_speed.Y += jumpspeed; + // jump pressed + // Reduce boost when speed already is high + jumpspeed = jumpspeed / (1.0f + (m_speed.Y * 2.8f / jumpspeed)); } + m_speed.Y += jumpspeed; setSpeed(m_speed); m_can_jump = false; + } else if(m_speed.Y > jumpspeed && standing_node_bouncy < 0) { + // uncontrollable bouncy is limited to normal jump height. + m_can_jump = false; } // Autojump @@ -897,8 +921,8 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d, m_standing_node = floatToInt(m_position, BS); /* - If the player's feet touch the topside of any node, this is - set to true. + If the player's feet touch the topside of any node + at the END of clientstep, then this is set to true. Player is allowed to jump when this is true. */ @@ -1028,22 +1052,45 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d, */ const ContentFeatures &f = nodemgr->get(map->getNode(getStandingNodePos())); + // We can jump from a bouncy node we collided with this clientstep, + // even if we are not "touching" it at the end of clientstep. + int standing_node_bouncy = 0; + if (result.collides && m_speed.Y > 0.0f) { + // must use result.collisions here because sometimes collision_info + // is passed in prepopulated with a problematic floor. + for (const auto &colinfo : result.collisions) { + if (colinfo.axis == COLLISION_AXIS_Y) { + // we cannot rely on m_standing_node because "sneak stuff" + standing_node_bouncy = itemgroup_get(nodemgr->get(map->getNode(colinfo.node_p)).groups, "bouncy"); + if (standing_node_bouncy != 0) + break; + } + } + } + // Determine if jumping is possible m_disable_jump = itemgroup_get(f.groups, "disable_jump"); - m_can_jump = touching_ground && !m_disable_jump; + m_can_jump = (touching_ground || standing_node_bouncy != 0) && !m_disable_jump; - // Jump key pressed while jumping off from a bouncy block - if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") && - m_speed.Y >= -0.5f * BS) { - float jumpspeed = movement_speed_jump * physics_override.jump; - if (m_speed.Y > 1.0f) { - // Reduce boost when speed already is high - m_speed.Y += jumpspeed / (1.0f + (m_speed.Y / 16.0f)); + // Jump/Sneak key pressed while bouncing from a bouncy block + float jumpspeed = movement_speed_jump * physics_override.jump; + if (m_can_jump && (control.jump || control.sneak) && standing_node_bouncy > 0) { + // controllable (>0) bouncy block + if (!control.jump) { + // sneak pressed, but not jump + // Subjective testing indicates 1/3 bounce decrease works well. + jumpspeed = -m_speed.Y / 3.0f; } else { - m_speed.Y += jumpspeed; + // jump pressed + // Reduce boost when speed already is high + jumpspeed = jumpspeed / (1.0f + (m_speed.Y * 2.8f / jumpspeed)); } + m_speed.Y += jumpspeed; setSpeed(m_speed); m_can_jump = false; + } else if(m_speed.Y > jumpspeed && standing_node_bouncy < 0) { + // uncontrollable bouncy is limited to normal jump height. + m_can_jump = false; } // Autojump