nodecore-cd2025/mods/nc_doors/craft_catapult.lua
Aaron Suen b7e4809e85 Make rakes at least somewhat useful with doors
- Normal non-selective raking mode works when
  pushing a rake with a door.
- The rake does not pick itself up.
- Collected things are dumped at the location of
  the direct raking target.

This doesn't seem super useful right now, but
a rake digging a full stack of some item will cause
all additional stacks of items in its range to settle
near the full stack, which could end up over a chute
allowing the item to fall down, and thus could be
used to collect items that scatter over a wider area.

Before releasing this we might consider making
rake digging selective by default, so these can be
used to sort and filter items.

May also consider making it possible to dig with a
rake in other circumstances, e.g. pushing a rake
against an open side of a storebox that has no room
for the rake will cause the rake to dig that stack and
all nearby matches?

May also consider cleaning up the raking API entirely
to make it easier to directly invoke a rake via
machine digging ... or tidy up the machine digging
API so it's no so hacky.
2021-12-16 18:01:23 -05:00

200 lines
5.3 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local ItemStack, minetest, nodecore, pairs, vector
= ItemStack, minetest, nodecore, pairs, vector
-- LUALOCALS > ---------------------------------------------------------
local presstoolcaps = {}
minetest.after(0, function()
for name, def in pairs(minetest.registered_items) do
if def.tool_capabilities then
presstoolcaps[name] = "dig"
elseif def.tool_head_capabilities then
presstoolcaps[name] = def.tool_head_capabilities.groupcaps
end
end
end)
local function checktarget(data, stack)
local target = vector.subtract(vector.multiply(
data.pointed.under, 2), data.pointed.above)
data.presstarget = target
local node = minetest.get_node(target)
local def = minetest.registered_items[node.name] or {walkable = true}
-- Inject item into available storebox
if def.groups and def.groups.visinv and (def.groups.is_stack_only
or def.storebox_access and def.storebox_access({
type = "node",
above = target,
under = vector.subtract(vector.multiply(
target, 2), data.pointed.under)
})) then
-- Never insert from bottom, so we can always dig
local dir = vector.subtract(data.pointed.under, data.pointed.above)
if dir.y <= 0 then
local one = ItemStack(stack:to_string())
one:set_count(1)
local tstack = nodecore.stack_get(target)
if tstack:item_fits(one) then
data.intostorebox = target
return true
end
end
end
-- Try to dig item
local caps = presstoolcaps[stack:get_name()]
if caps == "dig" and def and def.groups
and nodecore.tool_digs(stack, def.groups) then
data.pressdig = {
pos = target,
tool = stack,
toolpos = data.pointed.under
}
return true
end
-- Eject item as entity
if not def.walkable then return true end
if not caps then return end
local pumdata = {
action = "pummel",
pos = target,
pointed = {
type = "node",
above = data.pointed.under,
under = target
},
node = node,
nodedef = def,
duration = 3600,
toolgroupcaps = caps
}
local recipe = nodecore.craft_search(target, node, pumdata)
data.presscommit = recipe
return recipe
end
local hashpos = minetest.hash_node_position
local toolfxqueue
local function toolfx(toolpos, actpos)
nodecore.node_sound(toolpos, "dig")
if not toolfxqueue then
toolfxqueue = {}
minetest.after(0, function()
for _, ent in pairs(minetest.luaentities) do
local target = ent.is_stack and ent.poskey
and toolfxqueue[ent.poskey]
if target then
local obj = ent.object
local pos = ent.pos
obj:set_pos(target)
minetest.after(0.1, function()
obj:move_to(pos)
end)
end
end
toolfxqueue = nil
end)
end
toolfxqueue[hashpos(toolpos)] = actpos
end
local function doitemeject(pos, data)
if data.pressdig then
toolfx(pos, data.presstarget)
nodecore.machine_digging = data.pressdig
minetest.dig_node(data.pressdig.pos)
nodecore.machine_digging = nil
nodecore.witness(pos, "door dig")
return
end
if data.presscommit then
toolfx(pos, data.presstarget)
data.presscommit()
nodecore.witness(pos, "door pummel")
return
end
local stack = nodecore.stack_get(pos)
if (not stack) or stack:is_empty() then return end
local one = ItemStack(stack:to_string())
one:set_count(1)
if data.intostorebox then
nodecore.witness(pos, "door store")
one = nodecore.stack_add(data.intostorebox, one)
nodecore.stack_sounds(data.intostorebox, "place")
if not one:is_empty() then return end
else
local ctr = {
x = data.axis.x ~= 0 and data.axis.x or pos.x,
y = data.axis.y ~= 0 and data.axis.y or pos.y,
z = data.axis.z ~= 0 and data.axis.z or pos.z
}
local vel = vector.add(
vector.subtract(pos, ctr),
vector.subtract(data.pointed.under, data.pointed.above)
)
local doorlv = minetest.get_item_group(minetest.get_node(
data.pointed.above).name, "door") or 0
nodecore.item_eject(
vector.add(pos, vector.multiply(vel, 0.25)),
one, 0, 1, vector.multiply(vel, 2 + doorlv)
)
end
nodecore.stack_sounds(pos, "dig")
stack:take_item(1)
if stack:is_empty() and nodecore.node_group("is_stack_only", pos) then
return minetest.remove_node(pos)
end
nodecore.stack_set(pos, stack)
return nodecore.witness(pos, "door catapult")
end
nodecore.register_craft({
action = "press",
label = "eject item",
priority = 2,
nodes = {
{match = {stacked = true, count = false}}
},
check = function(pos, data)
local stack = nodecore.stack_get(pos)
if (not stack) or stack:is_empty() then return end
return checktarget(data, stack)
end,
after = doitemeject
})
nodecore.register_craft({
action = "press",
label = "eject from storebox",
priority = -1,
nodes = {
{match = {groups = {storebox = true}}}
},
check = function(pos, data)
local stack = nodecore.stack_get(pos)
if (not stack) or stack:is_empty() then return end
if not checktarget(data, stack) then return end
local pt = data.pointed
local node = minetest.get_node(pt.under)
local def = minetest.registered_items[node.name] or {}
if not def.storebox_access then return end
local access = {
type = "node",
above = vector.add(vector.multiply(
vector.subtract(pt.above, pt.under),
-1), pt.under),
under = pt.under
}
return def.storebox_access(access)
end,
after = doitemeject
})