Update init.lua (#3)

* Update init.lua

Implements quick escape for newly buried drops.

* Update init.lua

Added param to distinguish resting and newly buried drops, restoring reload consistency. Pruned a pointless cond.

* Update init.lua (feature complete)

Added one public function for other mods to invoke mechanism in cases droplift ignores.
Restored fix for default sink-on-load behaviour of buried drops.

* More precise and specific information.

* Reduce MT-specific terminology
master
Aftermoth 2016-04-19 04:29:33 +12:00
parent d71b073c98
commit 684b0f2475
3 changed files with 139 additions and 20 deletions

View File

@ -1,10 +1,10 @@
==== Droplift ====
Droplift lifts drops out of walkable nodes. ("drop" = "__builtin:item")
Droplift lifts drops out of solid blocks.
This mod adds no in-world items or blocks, just additional physics.
Droplift also prevents "entombed" drops from sinking below the floor
Droplift also prevents buried drops from sinking below the floor
when the game reloads.
Goals:

43
details.txt Normal file
View File

@ -0,0 +1,43 @@
Upon burial, drops may escape to one of the 26 surrounding nodes if any are non-obstructing ('walkable'==false).
If the nearest player is within 8.5 nodes (by taxicab metric), spaces closer to that player are preferred, otherwise they are prioritised by +x, +y, +z.
If no such spaces are found, the drop is "entombed," and remains subject to lift physics until free of obstructing nodes.
Lift physics holds a drop for one second before moving it upwards by one node every step, and does not seek other escape routes.
Droplift does not distinguish between differently shaped node boxes, only what their 'walkable' setting is.
This makes it easy to manually entomb drops using common node types like slabs and glass panes.
Entombed/free status is preserved across game reloads rather than retested.
All drop velocities are zeroed on reload. This is to prevent buried drops from being sunk below their current floor.
-------
* API *
-------
In general, drops are expected to spawn in non-obstructing nodes, like 'air.'
Therefore droplift ignores newly spawned drops, and only checks them when they are newly buried.
If you want droplift to handle drops spawned inside obstructing nodes, use:
droplift.invoke(dropObject, entomb)
entomb = <boolean> Bypass initial escape phase and use only lift physics, otherwise follow normal burial behaviour.
** Drops that are already being lifted should not be called again with invoke. **
That would produce multiple unsyncronized handlers for the same object. It will speed things up, but it might also go wrong.
...However,
If you want to force an entombed drop to break free, AND you're sure it has an escape space, you can:
dropEntity.is_entombed = false
droplift.invoke(dropObject, false)
If nothing weird happens, the handlers will be cleared from the newly freed drop.
But if that's what you need, it may be preferable to refine the code accordingly.

112
init.lua
View File

@ -1,4 +1,4 @@
--[[
Copyright (C) 2016 Aftermoth, Zolan Davis
@ -13,6 +13,7 @@ http://www.gnu.org/licenses/lgpl-2.1.html
--]]
droplift = {}
local function in_walkable(p)
local n = minetest.get_node_or_nil(p)
@ -20,8 +21,77 @@ local function in_walkable(p)
end
-- Update drop physics and flags.
local function disentomb(obj)
-- * Local escape *
-- get nearest player in range (taxicab)
local function near_player(dpos)
local near = 8.5
local pp, d, ppos
for _,player in ipairs(minetest.get_connected_players()) do
pp = player:getpos()
pp.y = pp.y + 1
d = math.abs(pp.x-dpos.x) + math.abs(pp.y-dpos.y) + math.abs(pp.z-dpos.z)
if d < near then
near = d
ppos = pp
end
end
if near < 8.5 then return ppos else return false end
end
local function usign(r)
if r < 0 then return -1 else return 1 end
end
local function quick_escape(ent,pos)
local bias = {x = 1, y = 1, z = 1}
local o = {a="x", b="y", c="z"}
local pref = near_player(pos)
if pref then
bias = {x = usign(pref.x - pos.x), y = usign(pref.y - pos.y), z = usign(pref.z - pos.z)}
local mag={x=math.abs(pref.x - pos.x), y=math.abs(pref.y - pos.y), z=math.abs(pref.z - pos.z)}
if mag.z > mag.y then
if mag.y > mag.x then
o={a="z",b="y",c="x"}
elseif mag.z > mag.x then
o={a="z",b="x",c="y"}
else
o={a="x",b="z",c="y"}
end
else
if mag.z > mag.x then
o={a="y",b="z",c="x"}
elseif mag.y > mag.x then
o={a="y",b="x",c="z"}
end
end
end
local p
for a = pos[o.a] + bias[o.a], pos[o.a] - bias[o.a], -bias[o.a] do
for b = pos[o.b] + bias[o.b], pos[o.b] - bias[o.b], -bias[o.b] do
for c = pos[o.c] + bias[o.c], pos[o.c] - bias[o.c], -bias[o.c] do
p = {[o.a]=a, [o.b]=b, [o.c]=c}
if not in_walkable(p) then
ent.object:setpos(p)
return p
end
end
end
end
return false
end
-- * Entombment physics *
local function disentomb(obj, reset)
local p = obj:getpos()
if p then
@ -36,22 +106,27 @@ local function disentomb(obj)
obj:setpos(p2)
end
ent.is_entombed = in_walkable(p2)
else
if w then
obj:setpos({x = p.x, y = brace, z = p.z})
ent.is_entombed = true
end
elseif w and not (reset and quick_escape(ent,p)) then
obj:setpos({x = p.x, y = brace, z = p.z})
ent.is_entombed = true
end
if ent.is_entombed then
obj:setvelocity({x = 0, y = 0, z = 0})
obj:setacceleration({x = 0, y = 0, z = 0})
minetest.after(1.0, disentomb, obj)
minetest.after(1.0, disentomb, obj, false)
end
end
end
function droplift.invoke(obj, entomb)
disentomb(obj, not entomb)
end
-- * Events *
-- Poll until defaults are ready before continuing.
@ -63,13 +138,10 @@ local function wait_itemstring(ent, c)
return
end
if ent.is_entombed then
disentomb(ent.object)
end
disentomb(ent.object, false)
end
local function append_to_core_defns()
local dropentity=minetest.registered_entities["__builtin:item"]
@ -77,10 +149,14 @@ local function append_to_core_defns()
local on_activate_copy = dropentity.on_activate
dropentity.on_activate = function(ent, staticdata, dtime_s)
on_activate_copy(ent, staticdata, dtime_s)
if staticdata ~= "" then
ent.is_entombed = minetest.deserialize(staticdata).is_entombed
if staticdata ~= "" then
if minetest.deserialize(staticdata).is_entombed then
ent.is_entombed = true
minetest.after(0.1, wait_itemstring, ent, 1)
else
ent.object:setvelocity({x = 0, y = 0, z = 0})
end
end
wait_itemstring(ent, 0)
end
-- Preserve state across reloads
@ -98,7 +174,7 @@ local function append_to_core_defns()
return s
end
-- Update drops inside newly placed (including fallen) nodes.
-- Update drops inside newly placed nodes.
local add_node_copy = minetest.add_node
minetest.add_node = function(pos,node)
add_node_copy(pos, node)
@ -106,7 +182,7 @@ local function append_to_core_defns()
for _,obj in ipairs(a) do
local ent = obj:get_luaentity()
if ent and ent.name == "__builtin:item" then
disentomb(obj)
disentomb(obj, true)
end
end
end