177 lines
4.6 KiB
Lua
177 lines
4.6 KiB
Lua
-- LUALOCALS < ---------------------------------------------------------
|
|
local ItemStack, math, minetest, nodecore, string, type, vector
|
|
= ItemStack, math, minetest, nodecore, string, type, vector
|
|
local math_random, string_format
|
|
= math.random, string.format
|
|
-- LUALOCALS > ---------------------------------------------------------
|
|
|
|
local modname = minetest.get_current_modname()
|
|
local api = _G[modname]
|
|
local modstore = api.store
|
|
|
|
local storekey = "falling"
|
|
local s = modstore:get_string(storekey)
|
|
local cache = s and s ~= "" and minetest.deserialize(s) or {}
|
|
|
|
local function getfallingthings(ipos)
|
|
local poskey = minetest.pos_to_string(ipos)
|
|
local found = cache[poskey] or {item = {}, node = {}}
|
|
return found, function()
|
|
cache[poskey] = found
|
|
return modstore:set_string(storekey, minetest.serialize(cache))
|
|
end
|
|
end
|
|
|
|
local function fallingfor(self)
|
|
local pos = self.object:get_pos()
|
|
if not (pos and api.in_sky_realm(pos)) then return end
|
|
local vel = self.object:get_velocity()
|
|
if (not vel) or vel.y > -30 then return end
|
|
|
|
local oy = pos.y
|
|
while true do
|
|
local node = minetest.get_node(pos)
|
|
if node.name == "ignore" then break end
|
|
if node.name ~= "air" then return end
|
|
pos.y = pos.y - 1
|
|
end
|
|
pos.y = oy
|
|
|
|
return api.island_near(pos) or api.island_near(pos, {x = 0, y = 1, z = 0})
|
|
end
|
|
|
|
local function itemeffects(pos, thing)
|
|
api.teleportsound(pos)
|
|
if type(thing) == "string" then
|
|
thing = ItemStack(thing):get_name()
|
|
thing = thing and minetest.registered_items[thing]
|
|
end
|
|
return api.particleburst(pos, vector.new(0.25, 0.25, 0.25), thing)
|
|
end
|
|
|
|
local function poof(self, def)
|
|
if not def then return self.object:remove() end
|
|
local pos = self.object:get_pos()
|
|
itemeffects(pos, def)
|
|
return self.object:remove()
|
|
end
|
|
|
|
local function itemshortdesc(stack)
|
|
stack = ItemStack(stack)
|
|
local copy = ItemStack(stack:get_name())
|
|
copy:set_count(stack:get_count())
|
|
return copy:to_string()
|
|
end
|
|
|
|
nodecore.register_item_entity_step(function(self)
|
|
local ipos = fallingfor(self)
|
|
if not ipos then return end
|
|
|
|
local pt, save = getfallingthings(ipos)
|
|
pt = pt.item
|
|
local stack = ItemStack(self.itemstring)
|
|
local iname = stack:get_name()
|
|
for i = 1, #pt do
|
|
local pts = ItemStack(pt[i])
|
|
stack = pts:add_item(stack)
|
|
pt[i] = pts:to_string()
|
|
if stack:is_empty() then break end
|
|
end
|
|
if not stack:is_empty() then
|
|
pt[#pt + 1] = stack:to_string()
|
|
end
|
|
save()
|
|
|
|
nodecore.log("action", string_format("skyrealm %s dropped item %q at %s",
|
|
api.islandhash(ipos), itemshortdesc(stack),
|
|
minetest.pos_to_string(self.object:get_pos(), 0)))
|
|
|
|
local def = minetest.registered_items[iname]
|
|
return poof(self, def)
|
|
end)
|
|
|
|
nodecore.register_falling_node_step(function(self)
|
|
local ipos = fallingfor(self)
|
|
if not ipos then return end
|
|
|
|
local pt, save = getfallingthings(ipos)
|
|
pt = pt.node
|
|
pt[#pt + 1] = {
|
|
n = self.node,
|
|
m = self.meta
|
|
}
|
|
save()
|
|
|
|
nodecore.log("action", string_format("skyrealm %s dropped node %q at %s",
|
|
api.islandhash(ipos), self.node.name,
|
|
minetest.pos_to_string(self.get_pos(), 0)))
|
|
|
|
local def = minetest.registered_items[self.node.name]
|
|
return poof(self, def)
|
|
end)
|
|
|
|
local function findspot_start(pos)
|
|
if nodecore.near_unloaded(pos, nil, 5) then return end
|
|
for rel in nodecore.settlescan() do
|
|
local p = vector.add(pos, rel)
|
|
if nodecore.buildable_to(p) then return p end
|
|
end
|
|
end
|
|
local function findspot(pos)
|
|
pos = findspot_start(pos)
|
|
if not pos then return end
|
|
local tpos = vector.add(pos, {
|
|
x = math_random() * 10 - 5,
|
|
y = math_random() * 10 + 5,
|
|
z = math_random() * 10 - 5,
|
|
})
|
|
for hit in minetest.raycast(pos, tpos, false, false) do
|
|
if hit.above and not vector.equals(pos, hit.above)
|
|
and hit.under and not vector.equals(pos, hit.under)
|
|
and nodecore.buildable_to(hit.above) then return hit.above end
|
|
end
|
|
return tpos
|
|
end
|
|
function api.return_falling(pos, ipos)
|
|
local data, save = getfallingthings(ipos)
|
|
|
|
local pt = data.item
|
|
for i = #pt, 1, -1 do
|
|
local p = findspot(pos)
|
|
if p then
|
|
itemeffects(p, pt[i])
|
|
nodecore.item_eject(p, pt[i], 1)
|
|
nodecore.log("action", string_format(
|
|
"skyrealm %s item %q arrived at %s",
|
|
api.islandhash(ipos), itemshortdesc(pt[i]),
|
|
minetest.pos_to_string(p)))
|
|
pt[i] = nil
|
|
else
|
|
break
|
|
end
|
|
end
|
|
|
|
pt = data.node
|
|
for i = #pt, 1, -1 do
|
|
local p = findspot(pos)
|
|
if p then
|
|
local obj = minetest.add_entity(p, "__builtin:falling_node")
|
|
if obj then
|
|
itemeffects(p, pt[i].n.name)
|
|
obj:get_luaentity():set_node(pt[i].n, pt[i].m)
|
|
nodecore.log("action", string_format(
|
|
"skyrealm %s node %q arrived at %s",
|
|
api.islandhash(ipos), pt[i],
|
|
minetest.pos_to_string(p)))
|
|
pt[i] = nil
|
|
else
|
|
break
|
|
end
|
|
else
|
|
break
|
|
end
|
|
end
|
|
|
|
save()
|
|
end
|