local log = sorcery.logger('tap')
local sap_interval = 20;
local function tapdrip(liq, pos)
return sorcery.vfx.drip(liq, vector.offset(pos, 0, -0.3, 0), math.random(5,12), sap_interval, 2)
end
minetest.register_node('sorcery:tap',{
description = 'Tree Tap';
drawtype = 'mesh';
mesh = 'sorcery-tap.obj';
inventory_image = 'sorcery_tap_inv.png';
tiles = {
'default_copper_block.png';
'default_steel_block.png';
};
groups = {
dig_immediate = 2;
attached_node = 1;
};
sunlight_propagates = true;
paramtype = 'light', paramtype2 = 'wallmounted';
selection_box = { type='fixed', fixed = {-0.2,-0.5,-0.35; 0.3,0.1,0.4} };
collision_box = { type='fixed', fixed = {-0.2,-0.5,-0.35; 0.3,0.1,0.4} };
node_placement_prediction = '';
on_place = function(stack,who,where)
if where.type ~= 'node' then return end
local bl = minetest.get_node(where.under)
local tree = sorcery.tree.get(where.under)
if not tree or tree.def.sap == false then return end;
-- disallow vertical attachment, bc that makes no sense
if vector.subtract(where.under,where.above).y ~= 0 then return end
minetest.set_node(where.above, {
name = 'sorcery:tap';
param2 = minetest.dir_to_wallmounted(vector.subtract(where.under,where.above))
})
if sorcery.lib.node.tree_is_live(where.under) then
-- start dripping immediately to indicate the tree is alive
tapdrip(tree.def.sapliq, where.above)
end
stack:take_item(1)
return stack
end;
on_screwdriver = function() return false end;
_sorcery = {
recipe = {
note = 'Extract syrups and oils from trees';
};
};
})
minetest.register_craft {
output = 'sorcery:tap';
recipe = {
{'','sorcery:screw_steel','basic_materials:steel_bar'};
{'sorcery:pipe','sorcery:valve','sorcery:screw_steel'};
{'','sorcery:pipe',''};
};
}
local abm_cache
local abm_cache_time
minetest.register_abm {
label = 'Sap drip';
nodenames = {'sorcery:tap'};
neighbors = {'group:tree'};
interval = sap_interval;
chance = 4;
catch_up = true;
action = function(pos, node)
local now = os.time()
if abm_cache_time == nil or now > abm_cache_time + (sap_interval-1) then
abm_cache = { treehash = {} }
abm_cache_time = now
end
local tpos = vector.add(pos,minetest.wallmounted_to_dir(node.param2))
local tnode = minetest.get_node(tpos)
if tnode.name == 'air' then return end --pathological case
local tree
for id,t in pairs(sorcery.data.trees) do
if t.node == tnode.name then
tree = t
goto found
end
end do
return
end ::found::
local tposhash = vector.to_string(tpos)
local live, should_cache
local mass_leaves, mass_trunk, topnode, prevalidate
if abm_cache.treehash[tposhash] then
live = true
local c = abm_cache.treehash[tposhash]
mass_leaves = c.mass_leaves
mass_trunk = c.mass_trunk
prevalidate = true
else
local tbody
live, tbody = sorcery.lib.node.tree_is_live(tpos)
if live then
should_cache = tbody.nodes[tbody.trunk]
mass_leaves = #(tbody.nodes[tbody.leaves])
mass_trunk = #(tbody.nodes[tbody.trunk]) * 12
topnode = tbody.topnode
end
end
if (not live)
or tree.sap == false
or not tree.sapliq then return end
if mass_trunk < 12*3 then return end -- too small
tapdrip(tree.sapliq,pos)
local mass = mass_leaves + mass_trunk
local max_mass = 400
local ltratio = mass_leaves / mass_trunk
local mratio = mass / max_mass
local outof = 15 / mratio
local chance = math.max(1, math.floor(outof - (25 * ltratio))) / 3
local diceroll = math.random(1,chance)
-- log.act('rolling dice: ', chance,diceroll, '(lt ratio =', ltratio, '; mass ratio = ', mratio, '; tree mass =', mass, '; outof =', outof)
if diceroll ~= 1 then return end -- failed roll
if not prevalidate then
if minetest.get_natural_light(vector.offset(topnode,0,1,0), 0.5) < 13
then return false end
end
for i=1,8 do
local at = vector.offset(pos, 0,-i,0)
if sorcery.lib.node.is_air(at) then goto skip end
local trough = minetest.get_node(at)
if minetest.get_item_group(trough.name, 'sorcery_trough') ~= 0 then
local n = minetest.registered_nodes[trough.name]
local l = sorcery.register.liquid.db[tree.sapliq]
local C = sorcery.liquid.constants
if n._sorcery and n._sorcery.container then
local ctr = n._sorcery.container
if not ctr.has or (ctr.has == tree.sapliq and ctr.charge < ctr.max) then
if ctr.set_node_liq then
ctr.set_node_liq(at, l, (ctr.charge or 0) + C.glasses_per_bottle)
else --legacy code, kept for pathological cases
local nct = (l.containers[trough.name] or l.containers[ctr.empty]) -- oof
if not nct then
log.err('no container of type',trough.name,'for sap',n.sapliq,'available')
return
end
if type(nct) == 'string' then -- pathological case
node.name = nct
else
node.name = nct.make((ctr.charge or 0) + nct.res,1):get_name()
end
minetest.swap_node(at, node)
end
if should_cache then
for _,v in pairs(should_cache) do
abm_cache.treehash[v:to_string()] = {
mass_leaves = mass_leaves;
mass_trunk = mass_trunk;
}
end
end
end
else
log.err('item',trough.name,'is marked as a trough but lacks a _sorcery.container property table')
end
end
do return end
::skip::end
end;
}