-- contains functions for determining information about
-- the nearest leyline and its currents
sorcery.ley = {}
-- leylines are invisible force-currents that rise up from the core of the earth, carrying magical energy upwards. they weaken as they get closer to the surface. each leyline also has between one and three 'affinities', which control how easily they can be wielded to perform particular sorts of magic. for instance, praxic-affine leylines will charge wands enchanted with praxic spells more quickly than leylines lacking this affinity.
-- leylines are one of two mystic energy forms; the other is aetheric energy, which is beamed down from Heaven by the sun during the day and is the power wielded by the gods. mortals can make limited use of aetheric force by collecting it and beaming it from place to place -- see aether.lua (aether is stored and manipulated by use of diamond)
-- leylines are always available, unlike aetheric force, which can only be collected during the day. but aetheric force is accessible wherever one can see the sky, and the higher up you are, the more you can collect, whereas leylines vary randomly in strength and affinity by position.
sorcery.ley.estimate = function(pos)
local affs = {
'praxic'; 'counterpraxic'; 'cognic';
'mandatic'; 'occlutic'; 'imperic';
'syncretic'; 'entropic';
};
local forcemap = minetest.get_perlin(0xe9a01d, 3, 2, 150)
local aff1map = minetest.get_perlin(0x10eb03, 3, 2, 300)
local aff2map = minetest.get_perlin(0x491e12, 3, 2, 240)
local txpos = {
x = pos.x;
y = pos.z; --- :( :( :( :(
z = pos.y;
}
local normalize = function(map)
local v = map:get_2d(txpos)
return (v + 6) / 12 -- seriously??
end
local zfac = (txpos.z / -1024) + 1
local force = math.min(1, normalize(forcemap) * zfac)
local aff1 = affs[math.ceil(#affs * normalize(aff1map))] or 'fail'
local aff2v, aff2 = math.ceil(normalize(aff2map) * (#affs * 2))
if aff2v <= #affs then aff2 = affs[aff2v] end
return {
force = force;
aff = { aff1, aff2 };
}
end
minetest.register_chatcommand('leyline', {
description = 'See details about local ley force';
privs = { server = true };
func = function(caller,params)
local pos = minetest.get_player_by_name(caller):get_pos()
local ley = sorcery.ley.estimate(pos)
minetest.chat_send_player(caller, 'Leyline force ' .. tostring(ley.force) .. ' with affinities ' .. table.concat(ley.aff, ','))
end;
})
sorcery.ley.chargetype = function(stack)
if minetest.get_item_group(stack:get_name(),'sorcery_wand') ~= 0 then
return 'wear'
else
local e = sorcery.enchant.get(stack)
if e and #e.spells > 0 then
return 'enchant'
end
end
return false
end
sorcery.ley.getcharge = function(stack)
local chargetype = sorcery.ley.chargetype(stack)
if not chargetype then return false end
if chargetype == 'wear' then
return (65535 - stack:get_wear()) / 15, 65535 / 15
elseif chargetype == 'enchant' then
local e = sorcery.enchant.get(stack)
local mat = sorcery.itemclass.get(stack:get_name(), 'material')
return e.energy, mat.data.maxenergy
end
end
sorcery.ley.setcharge = function(stack, charge, overcharge)
local max = select(2, sorcery.ley.getcharge(stack))
if not max then return false end
if charge > max and not overcharge then charge = max end
local chargetype = sorcery.ley.chargetype(stack)
if chargetype == 'wear' then
stack:set_wear(65535 - charge * 15)
elseif chargetype == 'enchant' then
local e = sorcery.enchant.get(stack)
e.energy = charge
sorcery.enchant.set(stack,e)
end
return stack
end
-- leyline energy can be transmitted via a conduit from a leysink. however, it cannot be stored like aetheric energy can be; leyline energy must be drawn when needed unless it is bound up in an enchantment (which simply delays its expression). leysinks provide a constant source of ley-force.
-- there are two nodes for transmitting leyline energy, wires and conduits. wires transmit a limited amount of energy, but are cheap and small. conduits transmit much more, but are expensive and take up full blocks. both are composed of a carrier metal and copper, which prevents the ley-force from leaking out as dangerous radiance.
minetest.register_node('sorcery:conduit', {
description = 'Conduit';
tiles = {
'sorcery_conduit_copper_top.png';
'sorcery_conduit_copper_top.png';
'sorcery_conduit_copper_side.png';
};
groups = {
sorcery_ley_device = 1;
cracky = 3;
};
_sorcery = {
ley = { mode = 'signal'; power = 100 };
recipe = { note = 'Conducts up to <b>100 thaum</b>' };
};
})
minetest.register_craft {
output = 'sorcery:conduit 4';
recipe = {
{'default:copper_ingot', 'default:copper_ingot', 'default:copper_ingot'};
{'default:copper_ingot', 'sorcery:electrumblock', 'default:copper_ingot'};
{'default:copper_ingot', 'default:copper_ingot', 'default:copper_ingot'};
};
};
local makeswitch = function(switch, desc, tex, tiles, power)
for _,active in pairs{true,false} do
local turn = function(pos)
local n = minetest.get_node(pos)
minetest.sound_play('doors_steel_door_open', {
gain = 0.7;
pos = pos;
}, true)
local leymap = active and sorcery.ley.mapnet(pos) or nil
minetest.swap_node(pos, {
name = active and (switch .. '_off')
or switch;
param1 = n.param1;
param2 = n.param2;
})
if active then
-- if we're turning it off, use the old map,
-- because post-swap the network will be
-- broken and notify won't reach everyone
leymap.map[leymap.startpos] = nil
sorcery.ley.notifymap(leymap.map)
else sorcery.ley.notify(pos) end
end
local tl = table.copy(tiles)
tl[6] = tex .. '^sorcery_ley_switch_panel.png^sorcery_ley_switch_' .. (active and 'down' or 'up') .. '.png';
minetest.register_node(switch .. (active and '' or '_off'), {
description = desc;
drop = switch;
tiles = tl;
paramtype2 = 'facedir';
groups = {
cracky = 2; choppy = 1;
punch_operable = 1;
sorcery_ley_device = active and 1 or 0;
};
_sorcery = {
ley = active and {
mode = 'signal'; power = power;
} or nil;
};
on_punch = function(pos,node,puncher,point)
if puncher ~= nil then
if puncher:get_wielded_item():is_empty() then
turn(pos)
end
end
return minetest.node_punch(pos,node,puncher,point)
end;
on_rightclick = turn;
})
end
end
for _,b in pairs {
{'Applewood', 'wood', 'default_wood.png'};
{'Junglewood', 'junglewood', 'default_junglewood.png'};
{'Pine', 'pine_wood', 'default_pine_wood.png'};
{'Acacia', 'acacia_wood', 'default_pine_wood.png'};
{'Aspen', 'aspen_wood', 'default_aspen_wood.png'};
{'Stone', 'stone', 'default_stone.png'};
{'Cobblestone', 'cobble', 'default_cobble.png'};
{'Stone Brick', 'stonebrick', 'default_stone_brick.png'};
{'Brick', 'brick', 'default_brick.png'};
} do
local id = 'sorcery:conduit_half_' .. b[2]
local switch = 'sorcery:conduit_switch_' .. b[2]
local item = (b[4] or 'default') .. ':' .. b[2]
local tex = b[3]
local mod = '^[lowpart:50:'
local sidemod = '^[transformR270^[lowpart:50:'
local unflip = '^[transformR90'
local tiles = {
'sorcery_conduit_copper_top.png'..mod..tex; -- top
tex..mod..'sorcery_conduit_copper_top.png';
tex .. sidemod .. 'sorcery_conduit_copper_side.png' .. unflip; -- side
'sorcery_conduit_copper_side.png' .. sidemod .. tex .. unflip; -- side
'sorcery_conduit_copper_side.png'; -- back
tex; -- front
}
minetest.register_node(id, {
description = 'Half-' .. b[1] .. ' Conduit';
paramtype2 = 'facedir';
groups = {
cracky = 2;
choppy = 1;
sorcery_ley_device = 1;
};
_sorcery = {
ley = { mode = 'signal'; power = 50 };
recipe = { note = 'Conducts up to <b>50 thaum</b>' };
};
tiles = tiles;
})
minetest.register_craft {
output = id .. ' 4';
recipe = {
{item, 'sorcery:conduit'};
{item, 'sorcery:conduit'};
};
};
makeswitch(switch, b[1] .. " Conduit Switch", tex, tiles, 5)
minetest.register_craft {
output = switch;
recipe = {
{'xdecor:lever_off',id};
};
}
end
makeswitch('sorcery:conduit_switch', "Conduit Switch", 'sorcery_conduit_copper_side.png', {
'sorcery_conduit_copper_top.png';
'sorcery_conduit_copper_top.png';
'sorcery_conduit_copper_side.png';
'sorcery_conduit_copper_side.png';
'sorcery_conduit_copper_side.png';
'sorcery_conduit_copper_side.png';
}, 10)
minetest.register_craft {
output = 'sorcery:conduit_switch';
recipe = {
{'xdecor:lever_off','sorcery:conduit'};
};
}
for name,metal in pairs(sorcery.data.metals) do
if metal.conduct then
local cable = 'sorcery:cable_' .. name
minetest.register_node(cable, {
description = sorcery.lib.str.capitalize(name) .. " Cable";
drawtype = 'nodebox';
groups = {
sorcery_ley_device = 1; snappy = 3; attached = 1;
sorcery_ley_cable = 1;
};
_sorcery = {
ley = { mode = 'signal', power = metal.conduct };
recipe = { note = 'Conducts up to <b>' .. metal.conduct .. ' thaum</b>'; };
};
sunlight_propagates = true;
node_box = {
type = 'connected';
disconnected = { -0.05, -0.35, -0.40; 0.05, -0.25, 0.40 };
connect_front = { -0.05, -0.35, -0.50; 0.05, -0.25, 0.05 };
connect_back = { -0.05, -0.35, -0.05; 0.05, -0.25, 0.50 };
connect_right = { -0.05, -0.35, -0.05; 0.50, -0.25, 0.05 };
connect_left = { -0.50, -0.35, -0.05; 0.05, -0.25, 0.05 };
connect_top = { -0.05, -0.35, -0.05; 0.05, 0.50, 0.05 };
connect_bottom = { -0.05, -0.50, -0.05; 0.05, -0.35, 0.05 };
};
connects_to = { 'group:sorcery_ley_device', 'default:mese' };
-- harcoding mese is kind of cheating -- figure out a
-- better way to do this for the longterm
paramtype = 'light';
-- paramtype2 = 'facedir';
after_place_node = function(pos, placer, stack, point)
local vec = vector.subtract(point.under, pos)
local n = minetest.get_node(pos)
n.param2 = minetest.dir_to_facedir(vec)
minetest.swap_node(pos,n)
end;
tiles = { 'sorcery_ley_plug.png' };
})
minetest.register_craft {
output = cable .. ' 8';
recipe = {
{'basic_materials:copper_wire','basic_materials:copper_wire','basic_materials:copper_wire'};
{ metal.parts.fragment, metal.parts.fragment, metal.parts.fragment };
{'basic_materials:copper_wire','basic_materials:copper_wire','basic_materials:copper_wire'};
};
replacements = {
{'basic_materials:copper_wire', 'basic_materials:empty_spool'};
{'basic_materials:copper_wire', 'basic_materials:empty_spool'};
{'basic_materials:copper_wire', 'basic_materials:empty_spool'};
{'basic_materials:copper_wire', 'basic_materials:empty_spool'};
{'basic_materials:copper_wire', 'basic_materials:empty_spool'};
{'basic_materials:copper_wire', 'basic_materials:empty_spool'};
};
};
end
end
-- ley.notify will normally be called automatically, but if a
-- ley-producer or consume has fluctuating levels of energy
-- consumption, it should call this function when levels change
sorcery.ley.notifymap = function(map)
for pos,name in pairs(map) do
local props = minetest.registered_nodes[name]._sorcery
if props and props.on_leychange then
props.on_leychange(pos)
end
end
end
sorcery.ley.notify = function(pos)
local n = sorcery.ley.mapnet(pos)
if n then sorcery.ley.notifymap(n.map) end
end
sorcery.ley.field_to_current = function(strength,time)
local ley_factor = 0.25
-- a ley harvester will produce this much current with
-- access to a full-strength leyline
return (strength * ley_factor) * time;
end
do -- register condenser
local gem = sorcery.lib.image('default_diamond_block.png')
local amethyst = gem:multiply(sorcery.lib.color(sorcery.data.gems.amethyst.tone))
local emerald = gem:multiply(sorcery.lib.color(sorcery.data.gems.emerald.tone))
local box = {
type = 'fixed';
fixed = {
-0.5, -0.5, -0.5;
0.5, 1.2, 0.5;
};
};
minetest.register_node('sorcery:condenser', {
description = 'Condenser';
drawtype = 'mesh';
paramtype2 = 'facedir';
mesh = 'sorcery-condenser.obj';
selection_box = box;
collision_box = box;
tiles = {
amethyst:render();
'sorcery_condenser.png';
'default_tin_block.png';
'default_stone.png';
'default_copper_block.png';
emerald:render();
};
groups = {
cracky = 2;
sorcery_ley_device = 1;
sorcery_magitech = 1;
};
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string('infotext','Condenser')
end;
_sorcery = {
ley = { mode = 'produce';
power = function(pos,time)
return sorcery.ley.field_to_current(sorcery.ley.estimate(pos).force, time);
end;
affinity = function(pos)
return sorcery.ley.estimate(pos).aff
end;
};
recipe = {
note = 'Captures radiant force and suffuses it through distribution net. Energy production varies with local leyline strength.';
};
};
})
minetest.register_abm {
name = 'Condenser sound effects';
nodenames = {'sorcery:condenser'};
neighbors = {'group:sorcery_ley_device'};
interval = 5.6, chance = 1, catch_up = false;
action = function(pos)
local force = sorcery.ley.estimate(pos).force
minetest.sound_play('sorcery_condenser_bg', {
pos = pos, max_hear_distance = 5 + 4*force, gain = force*0.3;
})
end;
}
end
minetest.register_craft {
output = 'sorcery:condenser';
recipe = {
{'sorcery:accumulator'};
{'sorcery:conduit'};
};
}
sorcery.ley.txofs = {
{x = 0, z = 0, y = 0};
{x = -1, z = 0, y = 0};
{x = 1, z = 0, y = 0};
{x = 0, z = -1, y = 0};
{x = 0, z = 1, y = 0};
{x = 0, z = 0, y = -1};
{x = 0, z = 0, y = 1};
}
sorcery.ley.mapnet = function(startpos,power)
-- this function returns a list of all the nodes accessible from
-- a ley network and their associated positions
local net,checked = {},{}
power = power or 0
local devices = {
consume = {};
produce = {};
signal = {};
}
local numfound = 0
local maxconduct = 0
local minconduct
local startkey
local foundp = function(p)
for _,k in pairs(checked) do
if vector.equals(p,k) then return true end
end
return false
end
-- we're implementing this with a recursive function to start with
-- but this could rapidly lead to stack overflows so we should
-- replace it with a linear one at some point
local function find(positions)
local searchnext = {}
for _,pos in pairs(positions) do
for _,p in pairs(sorcery.ley.txofs) do
local sum = vector.add(pos,p)
if not foundp(sum) then
checked[#checked + 1] = sum
local nodename = sorcery.lib.node.force(sum).name
if minetest.get_item_group(nodename,'sorcery_ley_device') ~= 0
or sorcery.data.compat.ley[nodename] then
local d = sorcery.ley.sample(pos,1,nodename,{query={mode=true}})
assert(d.mode == 'signal'
or d.mode == 'consume'
or d.mode == 'produce')
devices[d.mode][#(devices[d.mode]) + 1] = {
id = nodename; pos = sum;
}
if d.mode == 'signal' then
d.power = sorcery.ley.sample(pos,1,nodename,{query={power=true}}).power
if d.power > power then
if minconduct then
if d.power < minconduct then
minconduct = d.power
end
else minconduct = d.power end
if d.power > maxconduct then
maxconduct = d.power
end
end
end
numfound = numfound + 1;
net[sum] = nodename;
if not startkey then
if vector.equals(startpos,sum) then
startkey = sum
end
end
searchnext[#searchnext + 1] = sum;
end
end
end
end
if #searchnext > 0 then find(searchnext) end
end
find{startpos}
if numfound > 0 then
return {
count = numfound;
map = net;
devices = devices;
startpos = startkey;
conduct = {
min = minconduct;
max = maxconduct;
};
}
else return nil end
end
do local afftbl = {
[1] = 'praxic'; [2] = 'counterpraxic';
[3] = 'cognic'; [4] = 'syncretic';
[5] = 'mandatic'; [6] = 'occlutic';
[7] = 'imperic'; [8] = 'entropic';
}
local modetbl = {
[0] = 'none';
[1] = 'consume';
[2] = 'produce';
[3] = 'signal';
}
for i=1,#afftbl do afftbl [afftbl [i]] = i end
for i=1,#modetbl do modetbl[modetbl[i]] = i end
local m = sorcery.lib.marshal
local enc, dec = m.transcoder {
mode = m.t.u8;
minpower = m.t.u32; -- min power generated/consumed * 10,000
maxpower = m.t.u32; -- max power generated/consumed * 10,000
affinity = m.g.array(m.t.u8); -- indexes into afftbl
}
sorcery.ley.encode = function(l)
local idxs = {}
for _,k in pairs(l.affinity) do
idxs[#idxs+1] = afftbl[k]
end
return meta_armor(enc {
mode = modetbl[l.mode];
minpower = l.minpower * 10000;
maxpower = l.maxpower * 10000;
affinity = idxs;
}, true)
end
sorcery.ley.decode = function(str)
local obj = dec(meta_dearmor(str,true))
local affs = {}
for _,k in pairs(obj.affinity) do
affs[#affs+1] = afftbl[k]
end
return {
mode = modetbl[obj.mode];
minpower = obj.minpower / 10000.0;
maxpower = obj.maxpower / 10000.0;
power = (obj.minpower == obj.maxpower) and obj.minpower or nil;
affinity = affs;
}
end
end
sorcery.ley.setnode = function(pos,l)
local meta = minetest.get_meta(pos)
meta:set_string('sorcery:ley',sorcery.ley.encode(l))
end
sorcery.ley.sample = function(pos,timespan,name,flags)
-- returns how much ley-force can be transmitted by a
-- device over timespan
local ret = {}
minetest.load_area(pos)
name = name or minetest.get_node(pos).name
flags = flags or {}
flags.query = flags.query or {
mode = true; power = true; affinity = true;
minpower = true; maxpower = true;
}
local props = minetest.registered_nodes[name]._sorcery
local evaluate = function(v)
if type(v) == 'function' then
return v(pos)
else return v end
end
local leymeta do
local nm = minetest.get_meta(pos)
if nm:contains('sorcery:ley') then
leymeta = sorcery.ley.decode(nm:get_string('sorcery:ley'))
end
end
local compat = sorcery.data.compat.ley[name]
local lookup = function(k,default)
if leymeta and leymeta[k] then return leymeta[k]
elseif props and props.ley and props.ley[k] then return props.ley[k]
elseif compat and compat[k] then return compat[k]
else return default end
end
if flags.query.mode then ret.mode = evaluate(lookup('mode','none')) end
if flags.query.affinity then ret.affinity = evaluate(lookup('affinity',{})) end
if flags.query.minpower or flags.query.maxpower or flags.query.power then
local condset = function(name,var)
if flags.query[name] then ret[name] = var end
end
local p = lookup('power')
if p then
if type(p) == 'function' then
-- we have a single function to calculate power usage; we need to
-- check whether it returns min,max or a constant
local min, max = p(pos,timespan)
if (not max) or min == max then
ret.power = min
condset('power',min)
condset('minpower',min)
condset('maxpower',min)
else
condset('minpower',min)
condset('maxpower',max)
end
else -- power usage is simply a constant
condset('power',p * timespan)
condset('minpower',p * timespan)
condset('maxpower',p * timespan)
end
else
local feval = function(v)
if type(v) == 'function' then
return v(pos,timespan)
else return v * timespan end
end
local min = feval(lookup('minpower'))
local max = feval(lookup('maxpower'))
condset('minpower',min)
condset('maxpower',max)
if min == max then condset('power',min) end
end
end
if ret.power then
if flags.query.minpower and not ret.minpower then ret.minpower = power end
if flags.query.maxpower and not ret.maxpower then ret.maxpower = power end
end
return ret
end
sorcery.ley.netcaps = function(pos,timespan,exclude,minconduct)
local net = sorcery.ley.mapnet(pos,minconduct)
local maxpower = 0
local freepower = 0
local affs,usedaffs = {},{}
local flexpowerdevs = {}
local devself
for _,n in pairs(net.devices.produce) do
if vector.equals(pos,n.pos) then devself = n end
if not exclude or not vector.equals(n.pos,exclude) then
local ln = sorcery.ley.sample(n.pos,timespan,n.id)
n.powersupply = ln.power
n.affinity = ln.affinity
maxpower = maxpower + ln.power
-- production power does not vary, tho at some point it
-- might be useful to enable some kind of power scaling
for _,a in pairs(ln.affinity) do
affs[a] = (affs[a] or 0) + 1
end
end
end
freepower = maxpower;
for _,n in pairs(net.devices.consume) do
if vector.equals(pos,n.pos) then devself = n end
if not exclude or not vector.equals(n.pos,exclude) then
local ln = sorcery.ley.sample(n.pos,timespan,n.id, {
query = { power = true; minpower = true; maxpower = true; affinity = true; };
})
n.powerdraw = (ln.minpower <= freepower) and ln.minpower or 0
freepower = freepower - n.powerdraw
-- merge in sample data and return it along with the map
n.minpower = ln.minpower
n.maxpower = ln.maxpower
n.affinity = ln.affinity
if ln.maxpower > ln.minpower then
flexpowerdevs[#flexpowerdevs+1] = n
end
for _,a in pairs(ln.affinity) do
usedaffs[a] = (usedaffs[a] or 0) + 1
end
end
end
-- now we know the following: all devices; if possible, have been
-- given the minimum amount of power they need to run. if freepower
-- < 0 then the network is overloaded and inoperable. if freepower>0,
-- we now need to distribute the remaining power to devices that
-- have a variable power consumption. there's no clean way of doing
-- this, so we use the following algorithm:
-- 1. take a list of devices that want more power
-- 2. divide the amount of free power by the number of such devices
-- to derive the maximum power that can be allocated to any device
-- 3. iterate through the devices. increase their power consumption by
-- the maximum term. any device that is satiated can be removed from
-- the list.
-- 4. if there is still power remaining, repeat until there is not.
while freepower > 0 and #flexpowerdevs > 0 do
local nextiter = {}
local maxgive = freepower / #flexpowerdevs
for _,d in pairs(flexpowerdevs) do
local give = math.min(maxgive,d.maxpower - d.powerdraw)
freepower = freepower - give
d.powerdraw = d.powerdraw + give
if d.powerdraw < d.maxpower then
nextiter[#nextiter+1] = d
end
end
flexpowerdevs = nextiter
end
return {
net = net;
freepower = freepower;
maxpower = maxpower;
affinity = affs;
affinity_balance = usedaffs;
self = devself;
}
end
minetest.register_on_placenode(function(pos, node)
if minetest.get_item_group(node.name, 'sorcery_ley_device') ~= 0 then
sorcery.ley.notify(pos)
end
end)
local constants = {
generator_max_energy_output = 5;
-- how much energy a generator makes after
generator_time_to_max_energy = 150;
-- seconds of activity
generator_power_drain_speed = 0.1;
-- points of energy output drained per second of no fuel
}
local update_generator = function(pos)
minetest.get_node_timer(pos):start(1)
end
local generator_update_formspec = function(pos)
local meta = minetest.get_meta(pos)
local burnprog = math.min(1,meta:get_float('burnleft') / meta:get_float('burntime'))
local power = meta:get_float('power')
local inv = meta:get_inventory()
local lamps = ''
for i=0,4 do
local color
if power - i >= 1 then
color = 'red'
elseif power - i > 0 then
color = 'yellow'
else
color = 'off'
end
lamps = lamps .. string.format([[
image[%f,0.5;1,1;sorcery_statlamp_%s.png]
]], 2.5 + i, color)
end
meta:set_string('formspec', string.format([[
size[8,5.8]
list[context;fuel;0.5,0.5;1,1]
list[current_player;main;0,2;8,4]
image[1.5,0.5;1,1;default_furnace_fire_bg.png^[lowpart:%u%%:default_furnace_fire_fg.png]
]], math.floor(burnprog * 100)) .. lamps)
end
for _,active in pairs{true,false} do
local id = 'sorcery:generator' .. (active and '_active' or '')
minetest.register_node(id, {
description = 'Generator';
paramtype2 = 'facedir';
groups = {
cracky = 2;
sorcery_ley_device = 1;
sorcery_device_generator = active and 1 or 2;
not_in_creative_inventory = active and nil or 1;
};
drop = 'sorcery:generator';
tiles = {
'sorcery_ley_generator_top.png';
'sorcery_ley_generator_bottom.png';
'sorcery_ley_generator_side.png';
'sorcery_ley_generator_side.png';
'sorcery_ley_generator_back.png';
'sorcery_ley_generator_front_' .. (active and 'on' or 'off') .. '.png';
};
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
meta:set_string('infotext','Generator')
meta:set_float('burntime',0)
meta:set_float('burnleft',0)
meta:set_float('power',0)
generator_update_formspec(pos)
inv:set_size('fuel',1)
end;
after_dig_node = sorcery.lib.node.purge_container;
on_metadata_inventory_put = update_generator;
on_metadata_inventory_take = update_generator;
on_timer = function(pos,delta)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local self = sorcery.lib.node.force(pos)
local timeleft = meta:get_float('burnleft') - delta
local again = false
local power = meta:get_float('power')
local burning = active
if timeleft < 0 then timeleft = 0 end
if not active or timeleft == 0 then
if inv:is_empty('fuel') then
-- no fuel, can't start/keep going. drain power if
-- necessary, otherwise bail
burning = false
if power > 0 then
power = math.max(0, power - constants.generator_power_drain_speed)
again = true
end
else
-- fuel is present, let's burn it
local res,decin = minetest.get_craft_result {
method = 'fuel';
items = {inv:get_stack('fuel',1)};
}
meta:set_float('burntime',res.time)
timeleft = res.time
inv:set_stack('fuel',1,decin.items[1])
again = true
burning = true
end
else
local eps = constants.generator_max_energy_output / constants.generator_time_to_max_energy
power = math.min(constants.generator_max_energy_output, power + eps*delta)
again = true
end
::stop:: meta:set_float('power',power)
meta:set_float('burnleft',timeleft)
generator_update_formspec(pos)
if burning and not active then
minetest.swap_node(pos, {
name = 'sorcery:generator_active';
param1 = self.param1, param2 = self.param2;
})
elseif active and not burning then
minetest.swap_node(pos, {
name = 'sorcery:generator';
param1 = self.param1, param2 = self.param2;
})
end
return again
end;
allow_metadata_inventory_put = function(pos,listname,index,stack,user)
local res = minetest.get_craft_result {
method = 'fuel';
items = {stack};
}
if res.time ~= 0 then return stack:get_count()
else return 0 end
end;
_sorcery = {
ley = {
mode = 'produce', affinity = {'praxic'};
power = function(pos,delta)
local meta = minetest.get_meta(pos)
return meta:get_float('power') * delta;
end;
};
recipe = {
note = 'Temporarily provide up to <b>' ..tostring(constants.generator_max_energy_output) .. ' thaum</b> of ley-force from heat by burning fuel';
};
};
})
end