-- magic wands
-- first we need to go through and register all the
-- possible base wands. a base is a three-tuple of
-- (wood, maybe wire, maybe gem). wood determines base
-- affinity; wire alters how the wand uses energy
local u = sorcery.lib
sorcery.wands = {
kinds = {};
materials = {
wood = {
pine = {
tex = u.image('default_pine_wood.png');
};
apple = {
tex = u.image('default_wood.png');
tree = 'default:tree';
plank = 'default:wood';
};
acacia = {
tex = u.image('default_acacia_wood.png');
};
aspen = {
tex = u.image('default_aspen_wood.png');
};
jungle = {
tex = u.image('default_junglewood.png');
tree = 'default:jungletree';
plank = 'default:junglewood';
};
};
core = {
obsidian = {
item = 'default:obsidian_shard';
wandprops = { sturdiness = 1.5 };
};
diamond = {
item = 'sorcery:shard_diamond';
wandprops = { sturdiness = 1.7, reliability = 0.85 };
};
mese = {
item = 'default:mese_crystal_fragment';
wandprops = { generate = 2 };
};
cobalt = {
item = 'sorcery:powder_cobalt';
wandprops = { power = 1.4 };
};
iridium = {
item = 'sorcery:powder_iridium';
wandprops = { sturdiness = 1.25, power = 1.25 };
};
lithium = {
item = 'sorcery:powder_lithium';
wandprops = { power = 1.7, reliability = 0.70 };
};
gold = {
item = 'sorcery:powder_gold';
wandprops = { duration = 1.3, power = 1.3 };
};
tungsten = {
item = 'sorcery:powder_tungsten';
wandprops = { duration = 1.7, sturdiness = 1.25 };
};
platinum = {
item = 'sorcery:powder_platinum';
wandprops = { bond = 1; }
};
vidrium = {
item = 'sorcery:powder_vidrium';
wandprops = { bond = 2; }
};
impervium = {
item = 'sorcery:powder_impervium';
wandprops = { bond = 1, power = 1.5 };
};
};
wire = {
gold = {
-- gold limits the amount of wear-and-tear on
-- the wand, but causes the power to weaken as
-- it empties
tone = u.color(255,255,59);
tex = u.image('default_gold_block.png');
wandprops = { sturdiness = 1.2, weaken = 1 };
};
copper = {
-- copper causes the wand to recharge more quickly
-- but power levels are unpredictable
tone = u.color(255,117,40);
tex = u.image('default_copper_block.png');
wandprops = { flux = 0.7, chargetime = 0.5 };
};
silver = {
tone = u.color(215,238,241);
tex = u.image('default_gold_block.png'):colorize(u.color(255,238,241), 255);
wandprops = {};
};
steel = {
tone = u.color(255,255,255);
tex = u.image('default_steel_block.png');
wandprops = {};
};
};
gem = sorcery.data.gems;
};
util = {
baseid = function(wand)
local elts = {wand.wood}
if wand.gem ~= nil then elts[#elts + 1] = wand.gem end
if wand.wire ~= nil then elts[#elts + 1] = wand.wire end
return 'sorcery:wand_' .. table.concat(elts,'_')
end;
basename = function(wand,full)
local name = wand.wood .. 'wood wand'
if wand.core ~= nil then name = wand.core .. '-core ' .. name end
if full then
if wand.gem ~= nil then name = wand.gem .. ' ' .. name end
if wand.wire ~= nil then name = wand.wire .. 'clad ' .. name end
end
return u.str.capitalize(name)
end;
fullname = function(stack)
local proto = sorcery.wands.util.getproto(stack)
local wm = stack:get_meta()
local spell = wm:get_string('sorcery_wand_spell')
if spell ~= '' then
local sd = sorcery.data.spells[spell]
return u.str.capitalize(sd.name) .. ' wand';
else
return sorcery.wands.util.basename(proto)
end
end;
wear = function(item)
local meta = item:get_meta()
local spell = meta:get_string('sorcery_wand_spell')
local proto = sorcery.wands.util.getproto(item)
if spell == "" then return 0 end
local uses = sorcery.data.spells[spell].uses
if proto.core then
local core = sorcery.wands.materials.core[proto.core]
if not core then goto nocore end
if core.sturdiness then uses = uses * core.sturdiness end
::nocore::end
return 65536 / uses
end;
getproto = function(stack)
local proto = stack:get_definition()._proto
local core = stack:get_meta():get_string('sorcery_wand_core')
if core ~= '' then
proto = table.copy(proto)
proto.core = core
end
return proto
end;
matprops = function(proto)
local matprops = {}
for k,v in pairs(proto) do
if sorcery.wands.materials[k] then
local mp = sorcery.wands.materials[k].wandprops
if mp then
matprops = sorcery.lib.tbl.deepmerge(matprops, mp,
function(a,b,k)
if key == 'bond'
then return a+b
else return a*b
end
end)
end
end
end
return matprops
end;
basedesc = function(wand)
local desc = 'wand fashioned from the wood of the ' .. wand.wood .. ' tree'
if wand.gem ~= nil then
desc = wand.gem .. '-tipped ' .. desc
end
if wand.wire ~= nil then
desc = desc .. ', clad in ' .. wand.wire
end
if wand.core ~= nil then
desc = desc .. ', with a core of ' .. wand.core
end
if u.tbl.has({'a', 'e', 'i', 'o', 'u'}, string.sub(desc, 1,1)) then
return 'An ' .. desc
else
return 'A ' .. desc
end
end;
};
}
-- this feels extremely lazy but whatever
local treetoplank, planktotree = {}, {}
for k,v in pairs(sorcery.wands.materials.wood) do
local plank = v.plank or 'default:' .. k .. '_wood'
local tree = v.tree or 'default:' .. k .. '_tree'
treetoplank[tree] = plank
planktotree[plank] = tree
end
local wand_cast = function(stack, user, target)
local meta = stack:get_meta()
local wand = sorcery.wands.util.getproto(stack)
if meta:contains('sorcery_wand_spell') == false then return nil end
local spell = meta:get_string('sorcery_wand_spell')
local spelldata = sorcery.data.spells[spell]
-- wands don't work in anti-magic fields
local probe = sorcery.spell.probe(user:get_pos())
if probe.disjunction and not spelldata.ignore_disjunction then return nil end
local castfn = spelldata.cast
if castfn == nil then return nil end
local matprops = sorcery.wands.util.matprops(wand)
if matprops.bond then
local userct, found = 0, false
for i=1,matprops.bond do
local prop = 'bound_user_' .. tostring(i)
if meta:contains(prop) then
userct = i
local name = meta:get_string(prop)
print('wand bound to',name,i)
if name == user:get_player_name() then found = true break end
else break end
end
if not found then
if userct < matprops.bond then
print('binding wand to caster')
minetest.sound_play("xdecor_enchanting", { --FIXME make own sounds
pos = user:get_pos();
gain = 0.8;
})
sorcery.vfx.cast_sparkle(user, sorcery.lib.color(25,129,255), 2)
meta:set_string('bound_user_' .. tostring(userct+1), user:get_player_name())
return stack
else
-- user not in table AND no binding slots left. UH OH
sorcery.vfx.cast_sparkle(user, sorcery.lib.color(255,0,0), 4)
sorcery.vfx.bloodburst(user:get_pos())
user:punch(user, 1.0, {
full_punch_interval = 1.0;
damage_groups = { fleshy = math.random(1,5) };
}, nil)
return stack
end
end
end
local uprops = user:get_properties();
local context = {
base = wand;
stats = matprops;
meta = meta;
item = stack;
caster = user;
target = target;
probe = probe;
today = minetest.get_day_count();
heading = {
pos = user:get_pos();
yaw = user:get_look_dir();
pitch = user:get_look_vertical();
angle = user:get_look_horizontal();
eyeheight = uprops.eye_height;
};
wearmult = 1;
}
local result = castfn(context)
if result ~= false then
minetest.sound_play(sorcery.data.spells[spell].sound or "default_item_smoke", { --FIXME make own sounds
pos = user:get_pos();
gain = 0.8;
})
-- minetest.add_particle {
-- pos = vector.add(vector.add(user:get_pos(), vector.multiply(user:get_look_dir(),1.1)), {y=1.6,z=0,x=0});
-- velocity = user:get_velocity();
-- expirationtime = 0.5;
-- size = 4;
-- glow = 14;
-- texture = u.image('sorcery_crackle.png'):multiply(u.color(sorcery.data.spells[spell].color):brighten(1.3)):render();
-- animation = {
-- type = 'vertical_frames';
-- aspect_w = 16, aspect_h = 16;
-- length = 0.6;
-- }
-- }
local fac = matprops and matprops.sturdiness or 1
stack:add_wear((sorcery.wands.util.wear(stack) / fac) * context.wearmult)
end
return stack
end
sorcery.wands.util.enumerate_kinds = function()
local addid = function(k)
k.id = sorcery.wands.util.baseid(k)
return k
end
local kinds = {}
for woodname, wood in pairs(sorcery.wands.materials.wood) do
kinds[#kinds + 1] = addid {wood = woodname}
for gemname, gem in pairs(sorcery.wands.materials.gem) do
kinds[#kinds + 1] = addid { wood = woodname; gem = gemname; }
end
for wirename, wire in pairs(sorcery.wands.materials.wire) do
kinds[#kinds + 1] = addid {wood = woodname, wire = wirename}
for gemname, gem in pairs(sorcery.wands.materials.gem) do
kinds[#kinds + 1] = addid {
wood = woodname;
wire = wirename;
gem = gemname;
}
end
end
end
return kinds
end
-- TODO: allow new kinds of wood, wire, and gems to be
-- registered in the usual way
sorcery.wands.util.imgfor = function(kind)
local img = {}
img.base = u.image('sorcery_wand_base_' .. kind.wood .. '.png')
img.whole = img.base
if kind.wire then
img.wire = u.image('sorcery_wand_' .. kind.wire .. '_wire.png')
img.whole = img.wire:blit(img.whole)
end
if kind.gem then
img.gem = u.image('sorcery_wand_' .. kind.gem .. '_tip.png')
img.whole = img.gem:blit(img.whole)
end
return img
end
local update_stand_info = function(pos)
local woodname = minetest.registered_nodes[minetest.get_node(pos).name]._proto.wood
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if inv:is_empty('wand') then
meta:set_string('infotext',u.str.capitalize(woodname) .. ' wand stand')
else
local stack = inv:get_stack('wand',1)
local spell = stack:get_meta():get_string('sorcery_wand_spell')
local color = u.color(127,127,127)
if spell ~= '' then
color = u.color(sorcery.data.spells[spell].color):readable()
end
local wand_proto = sorcery.wands.util.getproto(stack)
meta:set_string('infotext',color:fmt(sorcery.wands.util.fullname(stack) .. ' stand'))
end
end
local createstand = function(name, wood, desc, tex, extra)
local hitbox = {
type = "fixed";
fixed = {
-0.5, -0.5, -0.3;
0.5, -0.1, 0.3;
};
}
local images = {}
for k,v in pairs(tex) do images[k] = v:render() end
local auto = {
description = desc;
drawtype = 'mesh';
mesh = 'sorcery-wand-stand.obj';
sunlight_propagates = true;
paramtype = 'light';
paramtype2 = 'facedir';
tiles = images;
selection_box = hitbox;
collision_box = hitbox;
after_dig_node = sorcery.lib.node.purge_container;
use_texture_alpha = true;
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size('wand', 1)
update_stand_info(pos)
end;
_proto = {
wood = wood;
};
groups = {
sorcery_wand_stand = 1;
choppy = 2;
oddly_breakable_by_hand = 2;
};
}
minetest.register_node(name, u.tbl.merge(auto,extra))
end
local rack_update = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local wandcount = 0
local mkslot = function(slot,x,y)
local stack = inv:get_stack('wands',slot)
local im = stack:get_meta()
local r = string.format([[ list[context;wands;%f,%f;1,1;%u] ]], x, y, slot-1)
if stack:is_empty() then
r = r .. string.format([[ image[%f,%f;1,1;sorcery_ui_ghost_wand.png] ]], x, y)
else
wandcount = wandcount + 1
if im:contains('sorcery_wand_spell') then
local spell = im:get_string('sorcery_wand_spell')
local spname = u.str.capitalize(sorcery.data.spells[spell].name)
local spclr = u.color(sorcery.data.spells[spell].color or {255,255,255})
r = r .. string.format([[
label[%f,%f;%s]
]], x + 1.25, y + 0.5, minetest.formspec_escape(spclr:fmt(spname)))
end
end
return r
end
local spec = [[
formspec_version[3] size[10.25,11.75] real_coordinates[true]
list[current_player;main;0.25,6.75;8,4;]
listring[current_player;main] listring[context;wands]
]]
for i=1,inv:get_size('wands') do
local yo = ((i-1) % 5) * 1.25
local xo = i > 5 and 5 or 0
spec = spec .. mkslot(i, 0.25 + xo, 0.25 + yo)
end
meta:set_string('formspec',spec)
if wandcount > 0 then
meta:set_string('infotext',string.format('Wand rack with %u wands', wandcount))
else
meta:set_string('infotext','Wand rack')
end
end
local createrack = function(name, wood, tex, desc)
local hitbox = {
type = "fixed";
fixed = {
-0.5, -0.5, 0.5;
0.5, 0.5, 0.35;
};
}
local rack = {
description = desc;
drawtype = 'mesh';
mesh = 'sorcery-wand-rack.obj';
sunlight_propagates = true;
paramtype = 'light';
paramtype2 = 'facedir';
tiles = {
u.image('default_diamond_block.png'):
multiply(u.color{50,255,70}):render();
tex:render();
'default_diamond_block.png';
'default_copper_block.png';
'default_pine_wood.png';
'default_junglewood.png';
};
selection_box = hitbox;
collision_box = hitbox;
use_texture_alpha = true;
after_dig_node = sorcery.lib.node.purge_container;
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size('wands',10)
rack_update(pos)
end;
allow_metadata_inventory_put = function(pos, lst, idx, stack, user)
if minetest.get_item_group(stack:get_name(), 'sorcery_wand') ~= 0
then return 1
else return 0
end
end;
on_metadata_inventory_move = rack_update;
on_metadata_inventory_take = rack_update;
on_metadata_inventory_put = rack_update;
_proto = { wood = wood; };
groups = {
sorcery_wand_rack = 1;
choppy = 2;
oddly_breakable_by_hand = 2;
};
}
minetest.register_node(name, rack)
end
for woodname, wood in pairs(sorcery.wands.materials.wood) do
local blank = u.image('sorcery_transparent.png'); -- haaaaack
local name = 'sorcery:wand_stand_' .. woodname
local rackid = 'sorcery:wand_rack_' .. woodname
createstand(name, woodname,
u.str.capitalize(woodname) .. 'wood wand stand',
{ wood.tex; blank; blank; blank; }, {
on_rightclick = function(pos,node,user,stack)
local meta = minetest.get_meta(pos)
local stand = meta:get_inventory()
local wand_proto = sorcery.wands.util.getproto(stack)
if minetest.get_item_group(stack:get_name(), 'sorcery_wand') ~= 0 then
stand:set_stack('wand',1,stack)
minetest.swap_node(pos, {
name = sorcery.wands.util.baseid(wand_proto) .. '_stand_' .. woodname;
param2 = node.param2;
})
stack = ItemStack(nil)
end
update_stand_info(pos)
return stack
end
}
)
createrack(rackid,woodname,wood.tex,
u.str.capitalize(woodname) .. 'wood wand rack')
local plank = wood.plank or 'default:' .. woodname .. '_wood'
minetest.register_craft {
output = name;
recipe = {
-- TODO: whittling/carving knife
{plank, 'default:stick', plank};
{plank, plank, plank};
};
}
minetest.register_craft {
output = rackid;
recipe = {
{plank,'default:stick',plank};
{'sorcery:screw_steel','screwdriver:screwdriver','sorcery:screw_steel'};
{plank,name,plank};
};
replacements = {
{'screwdriver:screwdriver','screwdriver:screwdriver'};
};
}
end
sorcery.wands.createstands = function(kind)
-- big oof
for woodname, wood in pairs(sorcery.wands.materials.wood) do
local gemimg = u.image('default_diamond_block.png')
if kind.gem
then gemimg = gemimg:multiply(u.color(sorcery.wands.materials.gem[kind.gem].tone))
else gemimg = gemimg:fade(1) end
createstand(
kind.id .. '_stand_' .. woodname,
woodname,
u.str.capitalize(woodname) .. 'wood wand stand with ' .. string.lower(sorcery.wands.util.basename(kind,true)), {
wood.tex;
sorcery.wands.materials.wood[kind.wood].tex;
gemimg;
(kind.wire and sorcery.wands.materials.wire[kind.wire].tex) or u.image('sorcery_transparent.png'); -- haaaaack
}, {
drop = 'sorcery:wand_stand_' .. woodname;
after_dig_node = function(pos,node,meta,digger)
local stack = meta.inventory.wand[1]
if stack and not stack:is_empty() then
-- luv 2 defensive coding
minetest.add_item(pos, stack)
end
end;
groups = {
not_in_creative_inventory = 1;
sorcery_wand_stand = 1;
choppy = 2;
oddly_breakable_by_hand = 2;
};
on_rightclick = function(pos,node,user,stack)
local meta = minetest.get_meta(pos)
local stand = meta:get_inventory()
local wand = stand:get_stack('wand',1)
if stack:is_empty() then
stack = wand
else
local inv = user:get_inventory()
if inv:room_for_item('main', wand) then
inv:add_item('main', wand)
else goto failure end
end
stand:set_stack('wand',1,ItemStack(nil))
minetest.swap_node(pos, {
name = 'sorcery:wand_stand_' .. woodname;
param2 = node.param2;
})
::failure::
update_stand_info(pos)
return stack
end;
}
)
end
end
sorcery.wands.createkind = function(kind)
if sorcery.wands.kinds[kind.id] then return false end
local basis = u.tbl.copy(kind)
basis.img = sorcery.wands.util.imgfor(basis)
minetest.register_tool(kind.id, {
description = u.ui.tooltip {
title = sorcery.wands.util.basename(kind);
desc = sorcery.wands.util.basedesc(kind);
};
inventory_image = basis.img.whole:render();
groups = {
tool = 1;
sorcery_wand = 1;
not_in_creative_inventory = 1;
};
node_dig_prediction = "";
on_use = wand_cast;
on_secondary_use = function(stack,user,target)
return wand_cast(stack,user,nil)
end;
-- on_place if we need to use rightclick
_proto = basis;
})
sorcery.wands.createstands(kind)
return true
end
sorcery.wands.createallkinds = function()
local allkinds = sorcery.wands.util.enumerate_kinds()
for _,k in pairs(allkinds) do sorcery.wands.createkind(k) end
end
local update_wand_description = function(stack)
local proto = sorcery.wands.util.getproto(stack)
local wm = stack:get_meta()
local spell = wm:get_string('sorcery_wand_spell')
if spell ~= "" then
local sd = sorcery.data.spells[spell]
wm:set_string('description', u.ui.tooltip {
title = sorcery.wands.util.fullname(stack);
desc = sorcery.wands.util.basedesc(proto);
props = {
{ color = u.color(sd.color); desc = sd.desc }
};
})
else
wm:set_string('description', u.ui.tooltip {
title = sorcery.wands.util.basename(proto);
desc = sorcery.wands.util.basedesc(proto);
})
end
return stack
end
sorcery.wands.createallkinds()
local wandwork_soak = function(pos, elapsed)
-- first, make sure there's still water in the station
local node = minetest.get_node(pos)
if node.name ~= 'sorcery:wandworking_station_water' then return false end
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local philters, wands = {}, {}
for i=0,inv:get_size('tank') do
local stack = inv:get_stack('tank', i)
if minetest.get_item_group(stack:get_name(),'sorcery_philter') > 0 then
philters[#philters + 1] = { idx = i, stack = stack }
elseif minetest.get_item_group(stack:get_name(),'sorcery_wand') > 0 then
wands[#wands + 1] = { idx = i, stack = stack }
end
end
if #wands == 0 or #philters == 0 then return false end
local duration = 600
--((4 * #wands) + (2 * #philters)) * 1 -- 600
--nonconstant duration doesn't actually make sense, unless we
--base it on the specific wood and philters
local totaltime = elapsed + meta:get_float('soaktime')
if totaltime < duration then
meta:set_float('soaktime',totaltime)
return true
end
meta:set_float('soaktime',0)
-- iterate through every wand in the tank to see if anything
-- needs to be done
local success = false
for i,wand in pairs(wands) do
local proto = wand.stack:get_definition()._proto
local wood = sorcery.wands.materials.wood[proto.wood]
for spell,def in pairs(sorcery.data.spells) do
if not def.affinity then goto skip_spell end
local potions, found = {}, false
for _,a in pairs(def.affinity) do
if a == proto.wood then found = true else
potions[#potions + 1] = a
end
end
if not found then goto skip_spell end
-- check whether all the necessary philters
-- are accounted for
if #potions ~= #philters then goto skip_spell end
for _,p in pairs(potions) do
for _,ph in pairs(philters) do
local def = ph.stack:get_definition()
if def._protoname == p then goto found end
end
goto skip_spell
::found::end
success = true
-- we've confirmed that all the philters for this spell
-- are present, now we need to apply it to the wand
wand.stack:get_meta():set_string('sorcery_wand_spell',spell)
update_wand_description(wand.stack)
inv:set_stack('tank',wand.idx,wand.stack)
do break end -- }:<<<
::skip_spell::end
end
if success == true then
-- empty out the philters
for _,v in pairs(philters) do
inv:set_stack('tank', v.idx, ItemStack('vessels:glass_bottle'))
end
-- drain out the water
minetest.swap_node(pos, {
name = 'sorcery:wandworking_station';
param2 = node.param2;
})
end
return false
end;
local wandwork_form = function(pos, water)
local slot = function(name,x,y,w,h)
return string.format('list[nodemeta:%d,%d,%d;%s;%f,%f;%f,%f;]',
pos.x, pos.y, pos.z,
name, x,y, w,h
)
end
return 'size[8,6.25]' ..
slot('tank', 0.5,0, 2,2) ..
slot('wandparts', 5.5,0, 1,2) ..
slot('preview', 6.5,0.5, 1,1) ..
slot('input', 4.5,0.5, 1,1) .. [[
list[current_player;main;0,2.5;8,4;]
listring[]
]]
end
local wandwork_rightclick = function(pos,node,user,stack)
local swapout = function(new)
minetest.swap_node(pos, {
name = new;
param2 = node.param2;
})
end
local water = node.name == 'sorcery:wandworking_station_water'
if water then
if stack:get_name() == 'bucket:bucket_empty' then
swapout('sorcery:wandworking_station')
stack = ItemStack('bucket:bucket_water')
else goto nobucket end
else
if minetest.get_item_group(stack:get_name(), 'water_bucket') > 0 then
swapout('sorcery:wandworking_station_water')
stack = ItemStack('bucket:bucket_empty')
else goto nobucket end
end
do return stack end
::nobucket::
minetest.show_formspec(user:get_player_name(),'sorcery:wandstation_inventory',wandwork_form(pos,water))
end
local wand_in_station = function(inv)
local wand = inv:get_stack('input',1)
if wand:is_empty() or minetest.get_item_group(wand:get_name(), 'sorcery_wand') == 0
then return false
else return true
end
end
local ensure_wand = function(inv)
if not wand_in_station(inv) then
for i=1,inv:get_size('wandparts') do
inv:set_stack('wandparts',i,ItemStack(nil))
end
return false
end
return true
end
local update_wand = function(inv)
if not ensure_wand(inv) then return false end
local parts = inv:get_list('wandparts')
local oldwand = inv:get_stack('input',1)
local newwand = {
wood = oldwand:get_definition()._proto.wood;
}
for i=1,#parts do
if parts[i]:is_empty() then goto skip end
local item = parts[i]:get_name()
for name,gem in pairs(sorcery.wands.materials.gem) do
local id = (gem.foreign or 'sorcery:gem_' .. name)
if item == id then newwand.gem = name break end
end
for name,wire in pairs(sorcery.wands.materials.wire) do
local id = (wire.foreign or 'basic_materials:' .. name .. '_wire')
if item == id then newwand.wire = name break end
end
::skip::end
--print(newwand.wood,newwand.gem,newwand.wire)
oldwand:set_name(sorcery.wands.util.baseid(newwand))
update_wand_description(oldwand)
inv:set_stack('input',1, oldwand)
end
local disasm_wand = function(stack,wwi)
if not ensure_wand(wwi) then return false end
if minetest.get_item_group(stack:get_name(), 'sorcery_wand') ~= 0 then
local wand = stack:get_definition()._proto
if wand.gem then
local gem = sorcery.wands.materials.gem[wand.gem]
local id = gem.foreign or 'sorcery:gem_' .. wand.gem
wwi:set_stack('wandparts',1,ItemStack(id))
end
if wand.wire then
local wire = sorcery.wands.materials.wire[wand.wire]
local id = wire.foreign or 'basic_materials:' .. wand.wire .. '_wire'
wwi:set_stack('wandparts',2,ItemStack(id))
end
return true
else return false end
end
local find_core = function(stack)
for k,v in pairs(sorcery.wands.materials.core) do
if stack:get_name() == v.item then return k,v end
end
return nil
end
local update_preview = function(wwi)
if wwi:is_empty('preview') then return end
local corename, core
for i=1,wwi:get_size('wandparts') do
corename, core = find_core(wwi:get_stack('wandparts',i))
if corename ~= nil then break end
end
local wand = wwi:get_stack('preview',1)
local meta = wand:get_meta()
meta:set_string('sorcery_wand_core',corename)
wwi:set_stack('preview',1,update_wand_description(wand))
end
local station_handle_input = function(stack,wwi)
for name,wood in pairs(sorcery.wands.materials.wood) do
if stack:get_name() == (wood.tree or 'default:' .. name .. '_tree') then
wwi:set_stack('preview',1,ItemStack{
name = 'sorcery:wand_' .. name; wear = 0;
})
goto found
end
end
wwi:set_stack('preview',1,ItemStack(nil))
if disasm_wand(stack,wwi) then return end
::found:: update_preview(wwi)
end
local replace_input = function(wwi)
local treename = wwi:get_stack('input',1):get_name()
wwi:set_stack('input',1, ItemStack {
name = treetoplank[treename];
count = 3;
})
for i=1,wwi:get_size('wandparts') do
wwi:set_stack('wandparts',i,ItemStack(nil))
end
end
local register_station = function(water)
local tilebase = {
"default_aspen_wood.png";
"sorcery_wandworking_station_side.png";
}
local base = {
description = "Wandworking Station";
groups = {
choppy = 2;
not_in_creative_inventory = water and 1 or nil;
};
paramtype2 = 'facedir';
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size('tank',4)
inv:set_size('input',1)
inv:set_size('wandparts',2)
inv:set_size('preview',1)
-- meta:set_string('formspec',wandwork_form(false))
end;
on_timer = function(...)
if water then return wandwork_soak(...);
else return false end
end;
on_rightclick = wandwork_rightclick;
after_dig_node = sorcery.lib.node.purge_container;
allow_metadata_inventory_put = function(pos, list, index, stack, user)
local meta = minetest.get_meta(pos)
local wwi = meta:get_inventory()
if list == 'preview' then return 0
elseif list == 'wandparts' then
if (not wwi:is_empty('preview')) and
find_core(stack) then return 1
elseif not wand_in_station(wwi) then return 0 end
elseif list == 'tank' then
if water then return 1 else return 0 end
end
return 1
end;
allow_metadata_inventory_move = function(pos, fromlist, fromidx, tolist, toidx, count, user)
if tolist == 'preview' then return 0
elseif tolist == 'wandparts' then
local meta = minetest.get_meta(pos)
local wwi = meta:get_inventory()
if (not wwi:is_empty('preview')) and
find_core(wwi:get_stack(fromlist,fromidx)) then return 1
elseif not
wand_in_station(minetest.get_meta(pos):get_inventory())
then return 0 end
elseif tolist == 'tank' then
if water then return 1 else return 0 end
end
return 1
end;
on_metadata_inventory_move = function(pos, fromlist, fromidx, tolist, toidx, count, user)
local meta = minetest.get_meta(pos)
local wwi = meta:get_inventory()
if fromlist == 'preview' then
replace_input(wwi)
elseif fromlist == 'input' or tolist == 'input' then
if wwi:is_empty('preview') then
for i=1,wwi:get_size('wandparts') do
wwi:set_stack('wandparts',i,ItemStack(nil))
end
else wwi:set_stack('preview',1,ItemStack(nil)) end
station_handle_input(wwi:get_stack(tolist,toidx),wwi)
elseif fromlist == 'wandparts' or tolist == 'wandparts' then
if wwi:is_empty('preview') then update_wand(wwi)
else update_preview(wwi) end
elseif tolist == 'tank' then
minetest.get_node_timer(pos):start(1)
end
end;
on_metadata_inventory_take = function(pos, list, index, stack, user)
local meta = minetest.get_meta(pos)
local wwi = meta:get_inventory()
if list == 'preview' then
replace_input(wwi)
elseif list == 'input' then
if wwi:is_empty('preview') then
for i=1,wwi:get_size('wandparts') do
wwi:set_stack('wandparts',i,ItemStack(nil))
end
else wwi:set_stack('preview',1,ItemStack(nil)) end
elseif list == 'wandparts' then
if wwi:is_empty('preview') then update_wand(wwi)
else update_preview(wwi) end
end
end;
on_metadata_inventory_put = function(pos, list, index, stack, user)
local meta = minetest.get_meta(pos)
local wwi = meta:get_inventory()
if list == 'input' then
station_handle_input(stack,wwi)
elseif list == 'wandparts' then
if wwi:is_empty('preview') then update_wand(wwi)
else update_preview(wwi) end
elseif list == 'tank' then
minetest.get_node_timer(pos):start(1)
end
end;
_sorcery = {
recipe = {
note = 'Construct wands from tree blocks and gems; fill with water and soak wands with philters to enchant them';
};
};
}
local id
if water then
id = 'sorcery:wandworking_station_water'
base = u.tbl.merge(base, {
description = "Wandworking Station (full)";
tiles = u.tbl.append({"sorcery_wandworking_station_top_water.png"}, tilebase)
})
else
id = 'sorcery:wandworking_station'
base = u.tbl.merge(base, {
description = "Wandworking Station";
drop = "sorcery:wandworking_station";
tiles = u.tbl.append({"sorcery_wandworking_station_top.png"}, tilebase)
})
end
minetest.register_node(id, base)
end
register_station(false)
register_station(true)
minetest.register_craft {
recipe = {
{ 'stairs:slab_stone', 'default:steel_ingot', 'stairs:slab_stone' };
{ 'group:wood', 'bucket:bucket_empty', 'group:wood' };
{ 'group:wood', 'group:wood', 'group:wood' };
};
output = 'sorcery:wandworking_station';
}