diff options
-rw-r--r-- | builtin/game/item_entity.lua | 104 |
1 files changed, 56 insertions, 48 deletions
diff --git a/builtin/game/item_entity.lua b/builtin/game/item_entity.lua index 968daac97..a85eba977 100644 --- a/builtin/game/item_entity.lua +++ b/builtin/game/item_entity.lua @@ -34,7 +34,6 @@ core.register_entity(":__builtin:item", { itemstring = "", moving_state = true, - slippery_state = false, physical_state = true, -- Item expiry age = 0, @@ -157,7 +156,7 @@ core.register_entity(":__builtin:item", { end end, - on_step = function(self, dtime) + on_step = function(self, dtime, moveresult) self.age = self.age + dtime if time_to_live > 0 and self.age > time_to_live then self.itemstring = "" @@ -178,6 +177,36 @@ core.register_entity(":__builtin:item", { return end + if self.force_out then + -- This code runs after the entity got a push from the is_stuck code. + -- It makes sure the entity is entirely outside the solid node + local c = self.object:get_properties().collisionbox + local s = self.force_out_start + local f = self.force_out + local ok = (f.x > 0 and pos.x + c[1] > s.x + 0.5) or + (f.y > 0 and pos.y + c[2] > s.y + 0.5) or + (f.z > 0 and pos.z + c[3] > s.z + 0.5) or + (f.x < 0 and pos.x + c[4] < s.x - 0.5) or + (f.z < 0 and pos.z + c[6] < s.z - 0.5) + if ok then + -- Item was successfully forced out + self.force_out = nil + self:enable_physics() + return + end + end + + if not self.physical_state then + return -- Don't do anything + end + + assert(moveresult) + if not moveresult.collides then + -- future TODO: items should probably decelerate in air + return + end + + -- Push item out when stuck inside solid node local is_stuck = false local snode = core.get_node_or_nil(pos) if snode then @@ -187,7 +216,6 @@ core.register_entity(":__builtin:item", { and (sdef.node_box == nil or sdef.node_box.type == "regular") end - -- Push item out when stuck inside solid node if is_stuck then local shootdir local order = { @@ -223,69 +251,49 @@ core.register_entity(":__builtin:item", { self.force_out_start = vector.round(pos) return end - elseif self.force_out then - -- This code runs after the entity got a push from the above code. - -- It makes sure the entity is entirely outside the solid node - local c = self.object:get_properties().collisionbox - local s = self.force_out_start - local f = self.force_out - local ok = (f.x > 0 and pos.x + c[1] > s.x + 0.5) or - (f.y > 0 and pos.y + c[2] > s.y + 0.5) or - (f.z > 0 and pos.z + c[3] > s.z + 0.5) or - (f.x < 0 and pos.x + c[4] < s.x - 0.5) or - (f.z < 0 and pos.z + c[6] < s.z - 0.5) - if ok then - -- Item was successfully forced out - self.force_out = nil - self:enable_physics() - end end - if not self.physical_state then - return -- Don't do anything + node = nil -- ground node we're colliding with + if moveresult.touching_ground then + for _, info in ipairs(moveresult.collisions) do + if info.axis == "y" then + node = core.get_node(info.node_pos) + break + end + end end -- Slide on slippery nodes - local vel = self.object:get_velocity() local def = node and core.registered_nodes[node.name] - local is_moving = (def and not def.walkable) or - vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0 - local is_slippery = false + local keep_movement = false - if def and def.walkable then + if def then local slippery = core.get_item_group(node.name, "slippery") - is_slippery = slippery ~= 0 - if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then + local vel = self.object:get_velocity() + if slippery ~= 0 and (math.abs(vel.x) > 0.1 or math.abs(vel.z) > 0.1) then -- Horizontal deceleration - local slip_factor = 4.0 / (slippery + 4) - self.object:set_acceleration({ - x = -vel.x * slip_factor, + local factor = math.min(4 / (slippery + 4) * dtime, 1) + self.object:set_velocity({ + x = vel.x * (1 - factor), y = 0, - z = -vel.z * slip_factor + z = vel.z * (1 - factor) }) - elseif vel.y == 0 then - is_moving = false + keep_movement = true end end - if self.moving_state == is_moving and - self.slippery_state == is_slippery then - -- Do not update anything until the moving state changes - return + if not keep_movement then + self.object:set_velocity({x=0, y=0, z=0}) end - self.moving_state = is_moving - self.slippery_state = is_slippery - - if is_moving then - self.object:set_acceleration({x = 0, y = -gravity, z = 0}) - else - self.object:set_acceleration({x = 0, y = 0, z = 0}) - self.object:set_velocity({x = 0, y = 0, z = 0}) + if self.moving_state == keep_movement then + -- Do not update anything until the moving state changes + return end + self.moving_state = keep_movement - --Only collect items if not moving - if is_moving then + -- Only collect items if not moving + if self.moving_state then return end -- Collect the items around to merge with |