diff --git a/builtin/game/item_entity.lua b/builtin/game/item_entity.lua index c0e36be2d..c1e3061d2 100644 --- a/builtin/game/item_entity.lua +++ b/builtin/game/item_entity.lua @@ -99,8 +99,8 @@ core.register_entity(":__builtin:item", { self.itemstring = staticdata end self.object:set_armor_groups({immortal = 1}) - self.object:setvelocity({x = 0, y = 2, z = 0}) - self.object:setacceleration({x = 0, y = -10, z = 0}) + self.object:set_velocity({x = 0, y = 2, z = 0}) + self.object:set_acceleration({x = 0, y = -10, z = 0}) self:set_item(self.itemstring) end, @@ -177,8 +177,8 @@ core.register_entity(":__builtin:item", { local in_unloaded = (node == nil) if in_unloaded then -- Don't infinetly fall into unloaded map - self.object:setvelocity({x = 0, y = 0, z = 0}) - self.object:setacceleration({x = 0, y = 0, z = 0}) + self.object:set_velocity({x = 0, y = 0, z = 0}) + self.object:set_acceleration({x = 0, y = 0, z = 0}) self.physical_state = false self.object:set_properties({physical = false}) return @@ -186,7 +186,8 @@ core.register_entity(":__builtin:item", { local nn = node.name -- If node is not registered or node is walkably solid and resting on nodebox local v = self.object:getvelocity() - if not core.registered_nodes[nn] or core.registered_nodes[nn].walkable and v.y == 0 then + if not core.registered_nodes[nn] or (core.registered_nodes[nn].walkable and + core.get_item_group(nn, "slippery") == 0) and v.y == 0 then if self.physical_state then local own_stack = ItemStack(self.object:get_luaentity().itemstring) -- Merge with close entities of the same item @@ -199,17 +200,28 @@ core.register_entity(":__builtin:item", { end end end - self.object:setvelocity({x = 0, y = 0, z = 0}) - self.object:setacceleration({x = 0, y = 0, z = 0}) + self.object:set_velocity({x = 0, y = 0, z = 0}) + self.object:set_acceleration({x = 0, y = 0, z = 0}) self.physical_state = false self.object:set_properties({physical = false}) end else if not self.physical_state then - self.object:setvelocity({x = 0, y = 0, z = 0}) - self.object:setacceleration({x = 0, y = -10, z = 0}) + self.object:set_velocity({x = 0, y = 0, z = 0}) + self.object:set_acceleration({x = 0, y = -10, z = 0}) self.physical_state = true self.object:set_properties({physical = true}) + elseif minetest.get_item_group(nn, "slippery") ~= 0 then + if math.abs(v.x) < 0.2 and math.abs(v.z) < 0.2 then + self.object:set_velocity({x = 0, y = 0, z = 0}) + self.object:set_acceleration({x = 0, y = 0, z = 0}) + self.physical_state = false + self.object:set_properties({ + physical = false + }) + else + self.object:set_acceleration({x = -v.x, y = -10, z = -v.z}) + end end end end, diff --git a/doc/lua_api.txt b/doc/lua_api.txt index b5ab30d58..66f8ccb25 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1424,6 +1424,9 @@ Another example: Make red wool from white wool and red dye: * `soil`: saplings will grow on nodes in this group * `connect_to_raillike`: makes nodes of raillike drawtype with same group value connect to each other +* `slippery`: Players and items will slide on the node. + Only use `slippery = 3` for now to ensure forwards compatibility. + ### Known damage and digging time defining groups * `crumbly`: dirt, sand diff --git a/src/client.cpp b/src/client.cpp index 39bb1e2ff..f7834a02b 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -403,7 +403,7 @@ void Client::step(float dtime) // Control local player (0ms) LocalPlayer *player = m_env.getLocalPlayer(); assert(player); - player->applyControl(dtime); + player->applyControl(dtime, &m_env); // Step environment m_env.step(dtime); diff --git a/src/localplayer.cpp b/src/localplayer.cpp index f04be07d6..f72da1b18 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -444,7 +444,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d) move(dtime, env, pos_max_d, NULL); } -void LocalPlayer::applyControl(float dtime) +void LocalPlayer::applyControl(float dtime, ClientEnvironment *env) { // Clear stuff swimming_vertical = false; @@ -660,9 +660,16 @@ void LocalPlayer::applyControl(float dtime) else incH = incV = movement_acceleration_default * BS * dtime; + INodeDefManager *nodemgr = env->getGameDef()->ndef(); + Map *map = &env->getMap(); + bool slippery = false; + const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos())); + slippery = itemgroup_get(f.groups, "slippery"); // 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); + accelerateHorizontal(speedH * physics_override_speed, + incH * physics_override_speed, slippery); + accelerateVertical(speedV * physics_override_speed, + incV * physics_override_speed); } v3s16 LocalPlayer::getStandingNodePos() @@ -699,12 +706,20 @@ v3f LocalPlayer::getEyeOffset() const } // Horizontal acceleration (X and Z), Y direction is ignored -void LocalPlayer::accelerateHorizontal(const v3f &target_speed, const f32 max_increase) +void LocalPlayer::accelerateHorizontal(const v3f &target_speed, + const f32 max_increase, bool slippery) { if (max_increase == 0) return; - v3f d_wanted = target_speed - m_speed; + v3f d_wanted = target_speed - m_speed; + if (slippery) { + if (target_speed == v3f(0)) + d_wanted = -m_speed * 0.05f; + else + d_wanted = target_speed * 0.1f - m_speed * 0.1f; + } + d_wanted.Y = 0; f32 dl = d_wanted.getLength(); if (dl > max_increase) diff --git a/src/localplayer.h b/src/localplayer.h index 9f7e92128..67b22b656 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -29,6 +29,7 @@ class Client; class Environment; class GenericCAO; class ClientActiveObject; +class ClientEnvironment; class IGameDef; enum LocalPlayerAnimations @@ -78,7 +79,7 @@ public: void old_move(f32 dtime, Environment *env, f32 pos_max_d, std::vector *collision_info); - void applyControl(float dtime); + void applyControl(float dtime, ClientEnvironment *env); v3s16 getStandingNodePos(); v3s16 getFootstepNodePos(); @@ -143,7 +144,8 @@ public: void setCollisionbox(const aabb3f &box) { m_collisionbox = box; } private: - void accelerateHorizontal(const v3f &target_speed, const f32 max_increase); + void accelerateHorizontal(const v3f &target_speed, + const f32 max_increase, bool slippery); void accelerateVertical(const v3f &target_speed, const f32 max_increase); bool updateSneakNode(Map *map, const v3f &position, const v3f &sneak_max);