local infuser_formspec = function(percent)
return string.format([[
size[8,7]
list[context;infusion;3.5,0;1,1;]
list[context;potions;2.5,1.7;1,1;0]
list[context;potions;3.5,2;1,1;1]
list[context;potions;4.5,1.7;1,1;2]
image[2.5,1.7;1,1;vessels_shelf_slot.png]
image[3.5,2;1,1;vessels_shelf_slot.png]
image[4.5,1.7;1,1;vessels_shelf_slot.png]
image[3.5,1;1,1;gui_furnace_arrow_bg.png^[lowpart:%d:gui_furnace_arrow_fg.png^[transformR180]
list[current_player;main;0,3.3;8,4;]
listring[context;infusion]
listring[current_player;main]
listring[context;potions]
listring[current_player;main]
listring[context;infusion]
]], percent)
end
local infuser_stop = function(pos)
local meta = minetest.get_meta(pos)
meta:set_float('runtime', 0)
meta:set_string('formspec', infuser_formspec(0))
meta:set_string('infotext', 'Infuser')
minetest.get_node_timer(pos):stop()
end
local elixir_can_apply = function(elixir, potion)
-- accepts an elixir def and potion def
if elixir == nil or
elixir._proto == nil or
potion == nil then return false end
if elixir._proto.apply and potion.on_use then
-- the ingredient is an elixir and at least one potion
-- is a fully enchanted, usable potion
if elixir._proto.flag and potion._proto and
potion._proto['no_' .. elixir._proto.flag] == true then
-- does the elixir have a property used to denote
-- compatibility? if so, check the potion to see if it's
-- marked as incompatible
return false
else
return true
end
end
return false
end
local effects_table = function(potion)
local meta = potion:get_meta()
local tbl = {}
for k,v in pairs(sorcery.data.elixirs) do
if not v.flag then goto skip end
local val = meta:get_int(v.flag)
if val > 0 then
local aff, title, desc = v.describe(potion)
if val > 3 then title = title .. ' x' .. val
elseif val == 3 then title = 'thrice-' .. title
elseif val == 2 then title = 'twice-' .. title
end
tbl[#tbl + 1] = {
title = sorcery.lib.str.capitalize(title);
desc = desc;
affinity = aff;
}
end
::skip::end
return tbl
end
local infuser_timer = function(pos, elapsed)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local infusion = inv:get_list('infusion')
local potions = inv:get_list('potions')
local elixir = infusion[1]:get_definition()
local potionct = 0
do
local ingredient -- *eyeroll*
if infusion[1]:is_empty() then goto cancel end
ingredient = infusion[1]:get_name()
for i = 1,#potions do
if potions[i]:is_empty() then goto skip end
potionct = potionct + 1
local base = potions[i]:get_name()
local potion = potions[i]:get_definition()
if elixir_can_apply(elixir,potion) then
-- at least one combination makes a valid potion;
-- we can start the infuser
goto start
end
for _,v in pairs(sorcery.data.infusions) do
if v.infuse == ingredient and v.into == base then
-- at least one combination makes a valid
-- potion; we can start the infuser
goto start
end
end
::skip:: end
::cancel:: do
infuser_stop(pos)
return false
end
::start::
end
local time = meta:get_float("runtime") or 0
local newtime = time + elapsed
local infusion_time = potionct * (15 * 60) -- 15 minutes per potion
-- FIXME make dependent on recipe
local percent = math.min(100, math.floor(100 * (newtime / infusion_time)))
local spawn = function(particle, scale, amt)
minetest.add_particlespawner {
amount = amt;
time = 15;
minpos = pos;
maxpos = pos;
minvel = {x = -0.1, y = 0.05, z = -0.1};
maxvel = {x = 0.1, y = 0.1, z = 0.1};
minacc = {x = 0, y = 0.1, z = 0};
maxacc = {x = 0, y = 0.4, z = 0};
minexptime = 2;
maxexptime = 4;
minsize = 0.5 * scale;
maxsize = 3 * scale;
glow = 14;
texture = particle;
animation = {
type = "vertical_frames";
aspect_h = 16;
aspect_w = 16;
length = 4.1;
};
}
end
-- for i=0,4 do
spawn('sorcery_spark.png^[multiply:#FF8FDD', 1, 32 * 4)
-- end
-- for i=0,4 do
spawn('sorcery_spark.png^[multiply:#FFB1F6', 0.5, 64 * 4)
-- end
local discharge = sorcery.lib.node.discharger(pos)
if newtime >= infusion_time then
-- finished
local ingredient = infusion[1]:get_name()
for i = 1,#potions do
if potions[i]:is_empty() then goto skip end
local base = potions[i]:get_name()
local potion = potions[i]:get_definition()
if elixir_can_apply(elixir, potion) then
local newstack = inv:get_stack('potions',i)
elixir._proto.apply(newstack, potion._proto)
newstack:get_meta():set_string('description', sorcery.lib.ui.tooltip {
title = potion._proto.name .. ' Draught';
desc = potion._proto.desc;
color = sorcery.lib.color(potion._proto.color):readable();
props = effects_table(newstack);
});
inv:set_stack('potions',i,discharge(newstack))
else
for _,v in pairs(sorcery.data.infusions) do
if v.infuse == ingredient and v.into == base then
-- transform the base into the infusion
inv:set_stack('potions',i,discharge(ItemStack(v.output)))
end
end
end
::skip:: end
inv:set_stack('infusion',1,ItemStack(sorcery.data.infusion_leftovers[ingredient]))
infuser_stop(pos)
return false
else
meta:set_float('runtime', newtime)
meta:set_string('formspec', infuser_formspec(percent))
meta:set_string('infotext', 'Infuser (active)')
return true
end
end
local infuser_start = function(pos)
local meta = minetest.get_meta(pos)
infuser_stop(pos)
infuser_timer(pos,0)
minetest.get_node_timer(pos):start(15)
end
minetest.register_node("sorcery:infuser", {
description = "Infuser";
drawtype = "mesh";
mesh = "sorcery-infuser.obj";
paramtype2 = "facedir";
after_dig_node = sorcery.lib.node.purge_container;
tiles = { -- FIXME
"default_stone.png",
"default_copper_block.png",
"default_steel_block.png",
"default_bronze_block.png",
"default_tin_block.png",
};
paramtype2 = 'facedir';
groups = {
cracky = 2, oddly_breakable_by_hand = 1, heavy = 1;
sorcery_alchemy = 1, sorcery_magitech = 1;
};
selection_box = {
type = 'fixed';
fixed = {
-0.37, -0.5, -0.37,
0.37, 0.5, 0.37
};
};
collision_box = {
type = 'fixed';
fixed = {
-0.37, -0.5, -0.37,
0.37, 0.5, 0.37
};
};
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size('infusion', 1)
inv:set_size('potions', 3)
meta:set_string('infotext','Infuser')
infuser_timer(pos,0)
end;
on_timer = infuser_timer;
on_metadata_inventory_move = infuser_start;
on_metadata_inventory_put = infuser_start;
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if not inv:get_stack(listname,index):is_empty() then
return 0
end
if listname == 'infusion' then
return 1
elseif listname == 'potions' then
if minetest.get_item_group(stack:get_name(), "vessel") >= 1 then
return 1
end
end
return 0
end;
allow_metadata_inventory_move = function(pos, from_list, from_idx, to_list, to_idx, count, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if inv:get_stack(to_list, to_idx):is_empty() then
if to_list == 'potions' and to_list ~= from_list then
if minetest.get_item_group(
--[[name]] inv:get_stack(from_list, from_idx):get_name(),
--[[group]] "vessel") >= 1 then
return 1
else
return 0
end
else
return 1
end
else
return 0
end
end;
})